.net windows-7 clickonce file-association processstartinfo

.net - La aplicación ClickOnce no se inicia a través de Process.Start("x.abc") con*.abc asociado a la aplicación ClickOnce



windows-7 file-association (4)

He desarrollado e implementado con éxito una aplicación ClickOnce que registra una extensión de archivo asociada, por ejemplo *.abc . Cuando hago clic en un archivo llamado x.abc o si x.abc desde el símbolo del sistema, la aplicación ClickOnce se inicia y puedo recuperar el archivo a través de la API dedicada. También puedo iniciar la aplicación programáticamente con el siguiente código:

System.Diagnostics.Process.Start ("x.abc");

Todo funciona bien en mi caja de Windows Vista de 64 bits.

Sin embargo, si trato de hacer exactamente lo mismo en un Windows 7 (también de 64 bits), tengo un problema muy extraño. Esto es lo que observo:

  1. El inicio manual de x.abc haciendo doble clic en él desde el Explorador funciona.
  2. El inicio manual de x.abc desde el símbolo del sistema funciona.
  3. Process.Start("x.abc") no inicia la aplicación; sin embargo, el objeto de proceso devuelto muestra que no hubo error y que la aplicación ClickOnce de alguna manera salió inmediatamente. Pero ni siquiera se alcanza un Trace al principio de la aplicación ClickOnce.
  4. Aún más extraño, Process.Start("x.bat") con un archivo x.bat contiene la línea única x.abc tampoco inicia la aplicación ClickOnce. El mismo x.bat iniciado desde el Explorer funciona (por supuesto).

Tratar de analizar lo que sucede con ProcMon no fue muy útil, ya que el proceso ClickOnce para iniciar una aplicación es muy difícil de seguir, desde mi punto de vista. rundll32 que rundll32 se rundll32 a trabajar, pero no hay evidencia de ningún fracaso.

El programa que está haciendo el Process.Start es una aplicación de consola de confianza completa con realmente nada sofisticado.

No puedo ver qué ha cambiado con respecto a cómo se manejan las aplicaciones de ClickOnce en Windows 7 y por qué Process.Start no haría exactamente lo mismo que lanzar el archivo desde Explorer. Vale la pena mencionar que el uso de versiones más avanzadas del método Start con ProcessStartInfo y la configuración de UseShellExecute en true tampoco ayudaron.

Iniciar cmd con Process.Start y luego intentar iniciar x.abc muestra exactamente el mismo problema. Si comparo la configuración del entorno con un cmd iniciado manualmente, veo diferencias en cómo se define ProgramFiles (el primero apunta a C:/Program Files (x86) mientras que el segundo apunta a C:/Program Files ). Las aplicaciones iniciadas desde mi aplicación .NET se inician en la capa de emulación de 32 bits (SysWoW64).

Pude reproducir el error de x.abc de x.abc iniciando una versión de 32 bits del indicador de comandos (es decir, %windir%/SysWoW64/cmd.exe ) y luego escribiendo x.abc en el indicador. También he encontrado una solución fea, que es iniciar un indicador de comandos de 64 bits desde el entorno de 32 bits al iniciar %windir%/Sysnative/cmd.exe /C x.abc lugar de x.abc .

Pero prefiero usar una forma limpia de hacerlo (o pídale a un representante de Microsoft que me diga que este es un problema con Windows 7 y / o ClickOncce y que se solucionará pronto).


¿Has intentado usar ShellExecute () ; API?

[DllImport("Shell32.dll",CharSet=CharSet.Auto)] public static extern IntPtr ShellExecute( IntPtr hwnd, string lpVerb, string lpFile, string lpParameters, string lpDirectory, int nShowCmd ); ShellExecute(this.Handle,"open","x.abc","","",3);

También puedes probar el Shell (); Función que forma parte del framework.


Eso solo podría iniciar extensiones de todo el sistema como .bat o incluso .txt , pero no siempre puede iniciar programas correctos a través de extensiones.

En su lugar, intente esta API o una alternativa similar en .NET :

FindExecutable: shell32.dll Alias: "FindExecutableA" / "FindExecutableW" tipo de devolución: int parámetros: · lpFile Pointer a una cadena terminada en nulo que especifica un nombre de archivo. Esto puede ser un documento o archivo ejecutable. · LpDirectory Puntero a una cadena terminada en nulo que especifica el directorio predeterminado. · LpResult Puntero a un búfer para recibir el nombre del archivo cuando se devuelve la función. Este nombre de archivo es una cadena terminada en nulo que especifica el archivo ejecutable que se inicia cuando se ejecuta una asociación "abierta" en el archivo especificado en el parámetro lpFile.

Esto devuelve un entero más grande que cero si es exitoso y el valor char contendrá una cadena terminada en nulo que apunta al ejecutable que inicia esta extensión de archivo, entonces puede usarlo así

System.Diagnostics.Process.Start ("program.exe $:/path/x.abc");

En lugar de program.exe , program.exe el resultado de la función API y usarás la ruta al archivo separado con un espacio como una línea de comando.

En cuanto a la falla de la aplicación, podría indicar que el programa necesita derechos administrativos para ejecutarse correctamente. cmd ya tiene derechos administrativos, por lo que puede hacer que las aplicaciones secundarias lo hereden, pero no la API de Windows. createprocess permite usar los atributos de LPSECURITY que pueden ayudarlo a iniciar este programa con los privilegios correctos.


He ideado una solución basada en .BAT, que es fácil de implementar. Digamos que desea iniciar la aplicación ClickOnce asociada con los archivos *.abc , luego simplemente coloque un archivo con el mismo nombre, pero con la extensión *.bat en la misma carpeta, y luego ejecute el archivo por lotes. Aquí está el script por lotes:

if exist "%windir%/sysnative/cmd.exe" goto :mode64bit rem For a file named "C:/foo/xyz.bat", this will generate the corresponding rem "C:/foo/xyz.abc" file, built as the concatenation of the drive (%~d0), rem the folder (%~p0) and the file name (%~n0), plus ".abc": "%~d0%~p0%~n0.abc" goto :end :mode64bit rem When running in a 32-bit emulation environment on a real 64-bit system, rem start the 64-bit version of CMD.EXE, and make if start the ".abc" file rem for us: C:/Windows/sysnative/cmd.exe /c "%~d0%~p0%~n0.xgen" :end

Esto podría implementarse directamente en el llamador de los archivos *.abc , pero a veces un archivo por lotes ayuda en la transición ...


Parece que ha creado su aplicación usando ''x32'' como la plataforma objetivo que hace que Process.Start genere un proceso de x32 bits. Y como supongo, Windows 7 almacena las asociaciones de archivos para aplicaciones de 32 y 64 bits por separado.

Si no tiene COM o dependencias de 32 bits no administradas, puede intentar crear su aplicación para la plataforma de destino ''Cualquier'' en lugar de ''x32''.

Investigué un poco más y descubrí que el instalador de ClickOnce crea el siguiente verbo abierto para cualquier extensión de archivo asociada (GUID es único por aplicación):

rundll32.exe dfshim.dll, ShOpenVerbExtension {dce01888-35e8-4df3-af35-cd971f520d8d} %1

Al usar Process Monitor , descubrí que la versión de 32 bits no abre la clave de registro HKCU/Software/Classes/Wow6432Node/CLSID/{dce01888-35e8-4df3-af35-cd971f520d8d} . (La versión de 64 bits lo abre con éxito en HKCU/Software/Classes/CLSID/{dce01888-35e8-4df3-af35-cd971f520d8d} .)

Así que para mí es un error de ClickOnce. Si yo fuera usted, usaría esa solución sucia de %WinDir%/system32/cmd.exe /C test.abc . (Lo que parece funcionar, lo he intentado desde el Administrador de tareas x32).

He agregado este problema a Microsoft Connect (actualización 2013-02-13: ese enlace está dañado).