2009-12-11 43 views
17

我已經成功開發並部署了註冊關聯文件擴展名的ClickOnce應用程序,例如*.abc。當我點擊名爲x.abc的文件時,或者如果從命令提示符鍵入x.abc,ClickOnce應用程序將啓動,並且可以通過專用API檢索文件。我還可以通過編程用下面的代碼啓動應用程序:ClickOnce應用程序不是通過Process.Start(「x.abc」)啓動的,並且* .abc與ClickOnce應用程序關聯

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

一切正常,在我的Windows Vista的鑽頭箱。但是,如果我嘗試在Windows 7(也是64  位)上執行完全相同的操作,則會出現一個非常奇怪的問題。這裏是我觀察到的:

  1. 手動啓動x.abc通過雙擊它從資源管理器工程。
  2. 手動啓動x.abc從命令提示符起作用。
  3. Process.Start("x.abc")不啓動應用程序;但是,返回的過程對象顯示沒有錯誤,並且ClickOnce應用程序立即退出。但即使在ClickOnce應用程序的最初階段,也不會達到Trace
  4. 陌生人,但Process.Start("x.bat")與文件x.bat包含單行x.abc也不啓動ClickOnce應用程序!相同的x.bat從資源管理器開始工作(當然)。

試圖分析ProcMon會發生什麼並不是很有用,因爲從我的角度來看,啓動應用程序的ClickOnce過程非常難以遵循。我觀察到rundll32開始工作,但沒有任何失敗的證據。

正在做Process.Start的程序是一個完全沒有任何花哨的完全信任控制檯應用程序。

我無法看到在Windows 7上如何處理ClickOnce應用程序以及爲什麼Process.Start與從Explorer啓動文件不同。值得一提的是,使用Start方法的更高級版本與ProcessStartInfo並且設置UseShellExecutetrue也沒有幫助。

cmd開始Process.Start然後嘗試啓動x.abc顯示完全相同的問題。如果我將環境設置與手動啓動的cmd進行比較,我會看到ProgramFiles的定義差異(第一個指向C:\Program Files (x86),而第二個指向C:\Program Files)。從我的.NET應用程序啓動的應用程序在32位仿真層(SysWoW64)上啓動。

通過啓動32位版本的命令提示符(即%windir%\SysWoW64\cmd.exe),然後在提示符處輸入x.abc,我能夠重現x.abc的啓動失敗。我還發現了一個醜陋的解決方法,即通過啓動%windir%\Sysnative\cmd.exe /C x.abc而不是x.abc從32位環境啓動64位命令提示符。

但我寧願使用乾淨的方式來做到這一點(或者有一位微軟代表告訴我這確實是Windows 7和/或ClickOncce的一個問題,而且它很快就會被修復)。

+0

好像很多啊想看到一個答案這裏。如果有人深入調查問題並找到答案,那將會很好。 – 2009-12-12 15:19:05

+0

知道這是一件好事,至少,我不是唯一遇到這個問題的人! – 2009-12-12 22:18:17

回答

0

我想出了一個基於.BAT的解決方案,它很容易實現。假設您想要啓動與*.abc文件關聯的ClickOnce應用程序,那麼您只需在同一文件夾中放置一個具有相同名稱但*.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文件的調用來實現,但有時一個批處理文件,有助於在轉型...

0

只能啓動系統範圍的擴展程序,如.bat甚至.txt,但它不能始終通過擴展啓動正確的程序。

相反試試這個API或類似的替代在.NET

FindExecutable:shell32.dll中別名 :「FindExecutableA」/ 「FindExecutableW」返回類型:INT參數: ·lpFile指向以NULL結尾的字符串的指針指定一個 文件名。這可以是一個文檔或 可執行文件。 ·lpDirectory指向空終止字符串的指針,指定 默認目錄。 ·lpResult指向緩衝區的指針,當 函數返回時接收文件名。該文件名是 以NULL結尾的字符串,指定在lpFile參數中指定的文件 上運行「打開」 關聯時啓動的 可執行文件。

這將返回一個整數大於零,如果成功,char值將包含一個null-terminated string指向一個啓動該文件擴展名 可執行文件,那麼你可以使用它像這樣

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

代替program.exe,您將使用API​​函數的結果,並且您將使用與命令行一樣用空格分隔的文件路徑。

至於應用程序失敗,它可能表明程序需要管理權限才能正常運行。 cmd已經獲得了管理權限,所以它可以讓子應用程序繼承它,但不是Windows API。 createprocess允許您使用LPSECURITY屬性,這有助於以正確的權限啓動該程序。

+0

不錯的嘗試,但你對CMD工作原因的解釋是不正確的。我所有的CMD實例都沒有特權。無法啓動ClickOnce應用程序的應用程序以32位運行,成功運行的應用程序以64位運行。但是,只要我能夠訪問出現故障的機器,我會盡快給您建議如何啓動ClickOnce應用程序。 – 2009-12-14 06:32:25

+0

對不起,但FindExecutable不適用於ClickOnce文件關聯。下面的示例代碼對於其他文件擴展名非常有用: class Program static void Main(string [] args) var result = new StringBuilder(512); var code = Program.FindExecutable(@「C:\ x.abc」,null,result); ... } [DllImport(「shell32.dll」)] static extern IntPtr FindExecutable(string lpFile, string lpDirectory,StringBuilder lpResult); } Dead end here too ... – 2009-12-16 16:53:24

10

它看起來像你已經建立你的應用程序使用'x32'作爲目標平臺,這使得Process.Start產卵x32位進程。據我猜測,Windows 7分別爲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:該鏈接已爛)。

+0

感謝您的提示。不,我無法將我的應用程序編譯爲64位應用程序;它會解決我的問題。現在,您建議爲x32和x64應用程序分別存儲文件關聯。這很奇怪。你有這方面的支持論據嗎? – 2009-12-14 20:43:54

+0

我深入了一點,發現即使在XP中,文件關聯也有邏輯上分離的註冊表分支,但指向相同的邏輯位置......到目前爲止,它看起來像ClickOnce bug ... 您能否驗證文件關聯是否出現在HKEY_LOCAL_MACHINE \ SOFTWARE \ Classes和HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Classes註冊表項中? – Regent 2009-12-15 10:40:02

+0

在Windows 7上,HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Classes不包含任何文件關聯信息。我必須強調的是,使用ClickOnce,文件關聯不會出現在HKEY_LOCAL_MACHINE \ SOFTWARE \ Classes下,而是出現在HKEY_CURRENT_USER分支(例如HKCU \ Software \ Classes \ .abc)中。不,沒有關於HKCU的Wow6432Node的有趣的文件關聯信息。 – 2009-12-16 16:50:16

0

您是否嘗試過使用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); 

你也可以試試Shell();功能是框架的一部分

+0

Process.Start()與UseShellExecute設置爲true有效調用本地ShellExecuteEx()。無論如何它會調用x32。 – Regent 2009-12-18 10:07:34

+0

確實,它確實 - 唉 - 沒有解決問題。無論如何,感謝您的幫助。 – 2009-12-19 14:24:51