.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:
- El inicio manual de
x.abc
haciendo doble clic en él desde el Explorador funciona. - El inicio manual de
x.abc
desde el símbolo del sistema funciona. -
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 unTrace
al principio de la aplicación ClickOnce. - Aún más extraño,
Process.Start("x.bat")
con un archivox.bat
contiene la línea únicax.abc
tampoco inicia la aplicación ClickOnce. El mismox.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).