代码之家  ›  专栏  ›  技术社区  ›  Pierre Arnaud

ClickOnce应用程序不会通过Process.Start(“x.abc”)启动,与ClickOnce应用程序关联的*.abc

  •  17
  • Pierre Arnaud  · 技术社区  · 16 年前

    例如,我成功地开发和部署了一个clickOnce应用程序,它注册了一个相关的文件扩展名。 *.abc . 当我单击一个名为 x.abc 或者如果我打字 X.ABC 在命令提示下,ClickOnce应用程序启动,我可以通过专用API检索文件。我还可以使用以下代码以编程方式启动应用程序:

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

    在我的Windows Vista 64位设备上一切正常。

    但是,如果我尝试在Windows7上执行完全相同的操作(也是64位),我会遇到一个非常奇怪的问题。我观察到:

    1. 手动启动 X.ABC 从资源管理器双击它就可以工作了。
    2. 手动启动 X.ABC 从命令提示开始工作。
    3. Process.Start("x.abc") 不启动应用程序;但是,返回的进程对象显示没有错误,并且ClickOnce应用程序以某种方式立即退出。但即使是 Trace 在ClickOnce应用程序的最开始,它从未到达。
    4. 陌生人, Process.Start("x.bat") 用一个文件 x.bat 包含单行 X.ABC 也不启动ClickOnce应用程序!同样 X.蝙蝠 从Explorer Works(当然)开始。

    试图分析发生了什么 ProcMon 不是很有帮助,因为从我的角度来看,启动应用程序的ClickOnce过程很难遵循。我观察 rundll32 开始工作,但没有任何失败的迹象。

    正在执行的程序 Process.Start 是一个完全信任的控制台应用程序,没有什么特别之处。

    我看不出在Windows7上如何处理ClickOnce应用程序以及为什么 过程.开始 不会与从资源管理器启动文件完全相同。值得一提的是,使用 Start 方法与 ProcessStartInfo 设置 UseShellExecute true 也没有帮助。

    启动 cmd 具有 开始过程 然后试着发射 X.ABC 显示了完全相同的问题。如果我将环境设置与 命令 手动启动,我看到了 ProgramFiles 定义(第一个点指向 C:\Program Files (x86) 第二点是 C:\Program Files )从.NET应用程序启动的应用程序在32位仿真层(sysw64)上启动。

    我能够重现 X.ABC 通过启动32位版本的命令提示符(即, %windir%\SysWoW64\cmd.exe )然后打字 X.ABC 在提示。我还发现了一个丑陋的解决方法,即通过启动从32位环境启动64位命令提示符 %windir%\Sysnative\cmd.exe /C x.abc 而不是 X.ABC .

    但是我宁愿用一种干净的方式来做(或者让微软代表告诉我这确实是Windows7和/或ClickOnce的问题,而且很快就会解决)。

    4 回复  |  直到 12 年前
        1
  •  10
  •   Peter Mortensen Pieter Jan Bonestroo    12 年前

    看起来您已经使用“x32”作为目标平台构建了您的应用程序, Process.Start 生成一个x32位进程。我猜Windows7分别存储32位和64位应用程序的文件关联。

    如果没有COM或非托管32位依赖项,可以尝试为“任意”目标平台而不是“x32”构建应用程序。

    我进一步调查了一下,发现ClickOnce安装程序为任何关联的文件扩展名创建了以下打开谓词(每个应用程序的guid都是唯一的):

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

    使用 Process Monitor ,我发现32位版本无法打开 HKCU\Software\Classes\Wow6432Node\CLSID\{dce01888-35e8-4df3-af35-cd971f520d8d} 注册表项。(64位版本在以下位置成功打开它 HKCU\Software\Classes\CLSID\{dce01888-35e8-4df3-af35-cd971f520d8d} )

    所以对我来说,这确实是一个ClickOnce错误。如果我是你,我会用那脏东西 %WinDir%\system32\cmd.exe /C test.abc 解决问题。(这似乎有效——在x32任务管理器中尝试过。)

    我已将此问题添加到 Microsoft Connect (更新2013-02-13:该链接已损坏)。

        2
  •  0
  •   Kristina    16 年前

    你试过用吗 外壳执行程序() 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);
    

    你也可以试试 外壳(); 作为框架一部分的函数

        3
  •  0
  •   Pierre Arnaud    15 年前

    我提出了一个基于.bat的解决方案,它很容易实现。假设您要启动与 *.abc 文件,然后您只需将具有相同名称的文件 *.bat 扩展名位于同一文件夹中,然后改为执行批处理文件。以下是批处理脚本:

    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
    

    这可以直接在 *abc 文件,但有时批处理文件有助于转换…

        4
  •  0
  •   Peter Mortensen Pieter Jan Bonestroo    12 年前

    只会启动系统范围的扩展,比如 .bat 甚至 .txt 但它不能总是通过扩展来启动正确的程序。

    相反,在 .NET :

    可执行文件: 壳牌32.DLL 别名 : “查找可执行表A” / “查找可执行文件” 返回类型: int 参数: ···· L文件 指向以空结尾的字符串的指针,该字符串指定 文件名。这可以是一个文档,也可以是 可执行文件。 ···· LP目录 指向以空结尾的字符串的指针,该字符串指定 默认目录。 ···· 雷普尔特 指向缓冲区的指针,当 函数返回。此文件名是 以空结尾的字符串,指定 可执行文件在__打开__时启动 关联在文件上运行 在lpfile参数中指定。

    如果成功且char值将包含 null-terminated string 指向启动此文件扩展名的可执行文件 然后你可以这样使用它

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

    而不是 program.exe ,您将使用API函数的结果,并将使用文件的路径,该路径用空格分隔,就像命令行一样。

    至于应用程序失败,它可能表明程序需要管理权限才能正确运行。 cmd 已经拥有管理权限,因此它可以使子应用程序继承它,但不能继承Windows API。 createprocess 允许您使用 LPSECURITY 有助于以正确权限启动此程序的属性。

    推荐文章