2012-03-02 20 views
12

A veces es deseable que su aplicación abra la aplicación predeterminada para un archivo. Por ejemplo, para abrir un archivo PDF que puede utilizar:¿Está asociada una aplicación con una extensión determinada?

System.Diagnostics.Process.Start("Filename.pdf"); 


Para abrir una imagen, usted sólo tiene que utilizar el mismo código con un nombre diferente:

System.Diagnostics.Process.Start("Filename.gif"); 


Algunas extensiones (.gif por ejemplo) casi siempre tiene un controlador predeterminado, incluso en una instalación base de Windows. Sin embargo, algunas extensiones (.pdf por ejemplo) a menudo no tienen una aplicación instalada para manejarlas.

En estos casos, sería deseable determinar si una aplicación está asociada con la extensión del archivo que desea abrir antes de realizar la llamada a Process.Start (fileName).

Me pregunto cómo se puede aplicar mejor algo como esto:

static bool ApplicationAssociated(string extension) 
{ 
    var extensionHasAssociatedApplication = false; 

    var condition = // Determine if there is an application installed that is associated with the provided file extension.; 
    if (condition) 
    { 
     extensionHasAssociatedApplication = true; 
    } 

    return extensionHasAssociatedApplication; 
} 
+0

Está en algún lugar del editor de registros. Junto con los controladores para imán :, mailto :, llame: esquemas, etc. Está casi en la raíz si recuerdo correcto – f2lollpll

Respuesta

25

Yo recomendaría siguiendo el consejo de David's answer pero ya que se necesita para detectar una asociación:

Para comprobar si un archivo tiene una asociación puede utilizar la función nativa FindExecutable que es básicamente lo que el Explorador de Windows utiliza internamente ... da un buen código de error (SE_ERR_NOASSOC) si no hay asociación. Tras el éxito, da una ruta al ejecutable respectivo.

Ti DllImport porque es

[DllImport("shell32.dll")] 
static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); 

Otra opción sería caminar el registro, por ejemplo (no se recomienda ya complejo debido a varios aspets como WoW64 etc.):

La asociación real se almacena en la clave a la que apunta HKEY_CLASSES_ROOT\.pdf - en mi caso AcroExch.Document, por lo que comprobamos HKEY_CLASSES_ROOT\AcroExch.Document. Allí se puede ver (y modificar) el comando que va a ser utilizado para poner en marcha ese tipo de archivo:

HKEY_CLASSES_ROOT\AcroExch.Document\shell\open\command 
5

En una situación como esta el mejor enfoque es tratar de abrir el documento y detectar el fallo. Tratar de predecir si una asociación de archivos está implementada solo lo lleva a reimplementar las API de ejecución de shell. ¡Es muy difícil hacerlo exactamente correcto y más bien innecesario ya que ya existen!

+0

Estoy de acuerdo, este es el más simple. Sin embargo, el principal problema con este enfoque es que tiene que ocultar de alguna manera el documento que está abriendo; realmente no desea que el usuario lo vea. – zmbq

+0

Gracias por el comentario constructivo. Yo preferiría ese enfoque también. No puedo, por razones que no te aburriré. La especificación es muy específica, y aunque no estoy de acuerdo con las razones, tengo un trabajo que hacer. –

+0

@zmbq Si no desea que el usuario vea el documento, simplemente absténgase de abrirlo. –

1

También deberá consultar el registro para obtener esa información.

que puede seguir a partir de:

HKEY_CLASSES_ROOT\.extension 

y por lo general conduce a algo así como HKEY_CLASSES_ROOT\extfile\Shell\Open\Command

y se llega al comando para abrir el tipo de archivo.

Dependiendo de lo que está haciendo, puede ser ideal para pedir sólo para el perdón (es decir, basta con abrir el archivo y ver)

+0

¿Estás seguro de que es suficiente? Visual Studio es una especie de magia vudú, donde los archivos .sln tienen un ícono diferente basado en la versión de Visual Studio que los creó. Esto es espeluznante, y probablemente no almacenado donde dijiste. – zmbq

+0

@zmbq - Si ve el 'HKEY_CLASSES_ROOT', verá una definición diferente para un archivo sln, manejado por una versión diferente de VS. El icono se define en 'DefaultIcon'. Básicamente, toda la información está allí. http://stackoverflow.com/questions/4693562/how-does-windows-know-what-version-of-visual-studio-a-sln-file-relates-to – manojlds

1

Toda esa información vive en el registro .. usted podría desplazarse a HKEY_CLASSES_ROOT , encuentre la extensión y vaya desde allí para encontrar el controlador predeterminado. Pero dependiendo del tipo de archivo y de los manejadores asociados, necesitarás entrar en los CLSID y otras cosas ... en su lugar, es mejor que detectes una excepción.

1

Esta información se encuentra en el registro. Por ejemplo:

# Mount the HKCR drive in powershell 
ps c:\> new-psdrive hkcr registry hkey_classes_root 
ps c:\> cd hkcr:\.cs 

# get default key for .cs 
PS hkcr:\.cs> gp . "" 
(default) : VisualStudio.cs.10.0 
... 

# dereference the "open" verb 
PS hkcr:\.cs> dir ..\VisualStudio.cs.10.0\shell\open 

    Hive: hkey_classes_root\VisualStudio.cs.10.0\shell\open 

Name       Property 
----       -------- 
Command      (default) : "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" /dde 
ddeexec      (default) : Open("%1") 
4

@Yahia recibe el visto bueno. Estoy publicando mi solución rápida para la posteridad para que pueda ver a qué me refería. Hay muchas mejoras posibles en este código, pero esto le dará la idea:

public static bool HasExecutable(string path) 
{ 
    var executable = FindExecutable(path); 
    return !string.IsNullOrEmpty(executable); 
} 

private static string FindExecutable(string path) 
{ 
    var executable = new StringBuilder(1024); 
    FindExecutable(path, string.Empty, executable); 
    return executable.ToString(); 
} 

[DllImport("shell32.dll", EntryPoint = "FindExecutable")] 
private static extern long FindExecutable(string lpFile, string lpDirectory, StringBuilder lpResult); 
+0

¿Por qué usaste StringBuilder (1024) en lugar de StringBuilder()? – mggSoft

+3

@mggSoft El método nativo FindExecutable requiere un búfer para devolver la ruta del ejecutable. La documentación especifica _Este parámetro debe contener un valor válido no nulo y se supone que es de longitud MAX_PATH_. Entonces, aunque 1024 es un poco exagerado, se recomienda anular la capacidad predeterminada de StringBuilder con el valor de MAX_PATH (260). – Yaurthek

Cuestiones relacionadas