2011-02-08 99 views
2

在我的WiX安裝程序中,我想優雅地關閉即將運行的即將更新的應用程序。我不想提醒用戶關閉,我不想殺死這個進程。在關閉應用程序之前,我需要有機會進行清理等。在通過Wix管理的自定義操作進行安裝之前,優雅地關閉應用程序

該應用程序是在系統托盤中運行的WinForms應用程序。主窗體有一個標題,比如說「mainwindow」,但隱藏並且有ShowInTaskbar = false。

通過一些不同的測試應用程序試圖Process.Kill() Process.CloseMainWindow() FindWindow, SendMessage, PostMessage等玩弄我發現,對我來說,做到這一點的最好辦法是使用PostMessage

var hWnd = FindWindow(null, "mainwindowtitle"); 
PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 

這樣我可以覆蓋OnFormClosing並執行任何清除我需要。這從我扔在一起的測試應用程序工作正常。問題是在WiX安裝程序中運行時無法正常工作。我有一個c#自定義操作CA.dll和安裝程序明確調用自定義操作 - 我可以看到從msiexec日誌,如果我將自定義操作代碼更改爲Process.Kill()它確實停止應用程序正確。但是,當它與PostMessage代碼一起運行時,應用程序不會關閉,並且OnFormClosing也不會被調用。

這裏是我的CustomAction代碼

 private const int WM_CLOSE = 0x0010; 

    [DllImport("user32.dll", SetLastError = true)] 
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

    [DllImport("user32.dll", SetLastError = true)] 
    static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

    [CustomAction] 
    public static ActionResult CloseApplicationGracefully(Session session) 
    { 
     session.Log("Starting the CloseApplicationGracefully Custom Action - attempting to stop DUC."); 

     var hWnd = FindWindow(null, "mainwindowtitle"); 

     session.Log("Window handle found: " + hWnd); 

     bool result = PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 

     session.Log("Result of calling app to close: " + result); 

     if (result) 
     { 
      return ActionResult.Success; 
     } 
     return ActionResult.Failure; 
    } 

這裏是WX設置代碼

<Binary Id="WixCustomAction.dll" 
     SourceFile="$(var.WixCustomAction.TargetDir)$(var.WixCustomAction.TargetName).CA.dll" /> 
<CustomAction Id="WixCustomAction" 
       BinaryKey="WixCustomAction.dll" 
       DllEntry="CloseDeploymentUpdater" /> 
<InstallExecuteSequence> 
    <Custom Action="WixCustomAction" After="FindRelatedProducts"></Custom> 
</InstallExecuteSequence> 

我曾嘗試調用不同的序列這個自定義操作,但沒有運氣... 的代碼工作一個測試程序應用程序和自定義操作在我使用Process.Kill時起​​作用,但在放入自定義操作時代碼不起作用 - 必須是事件序列?

編輯

使用WixCloseApplications CA作爲一個答案業績低於建議在下面的日誌條目

WixCloseApplications: App: DUC.exe found running, 1 processes, attempting to send close message. 
WixCloseApplications: Sending close message to process id 0x1978 
WixCloseApplications: Result 0x12 
WixCloseApplications: Sending close message to process id 0x1978 
WixCloseApplications: Result 0x0 
WixCloseApplications: Sending close message to process id 0x1978 
WixCloseApplications: Result 0x578 
WixCloseApplications: Sending close message to process id 0x1978 
WixCloseApplications: Result 0x0 
. 
. 
. 
MSI (s) (C8!D4) [15:00:47:985]: PROPERTY CHANGE: Adding WixCloseApplicationsDeferred property. Its value is 'DUC.exe5'. 
MSI (s) (C8!D4) [15:00:48:000]: Doing action: WixCloseApplicationsDeferred 
. 
. 
Action 15:00:48: WixCloseApplicationsDeferred. 
Action start 15:00:48: WixCloseApplicationsDeferred. 
. 
. 
Action ended 15:00:48: WixCloseApplicationsDeferred. Return value 1. 
Action ended 15:00:48: WixCloseApplications. Return value 1. 
+0

您是否在自定義操作中嘗試了SendMessage調用而不是PostMessage? –

+0

@Vijay Sirigiri是的 - 我試着SendMessage(使用SC_CLOSE),並再次在我的測試應用程序,但不是從WiX安裝程序。有趣的是,OnFormClosing的EventArgs有一個CloseReason枚舉,並且使用WM_CLOSE的PostMessage使得它看起來像是taskmanager請求關閉的原因,而使用SC_CLOSE的SendMessage使得它看起來像用戶請求關閉。 –

+0

@rene我可以得到一個有效的句柄,但PostMessage的結果是錯誤的,所以它由於某種原因無法正常工作。 MSDN建議不要在PostMessage中使用WM_QUIT。我會嘗試它,看看會發生什麼,但我懷疑在這種情況下OnFormClosing事件不會觸發。 –

回答

2

如果瞭解從維克斯的CloseApp CustomAction正確,您應該枚舉所有窗口在一個過程中。

http://wix.codeplex.com/SourceControl/changeset/view/175af30efe78#src%2fca%2fwixca%2fdll%2fCloseApps.cpp

所以,你需要實現一個EnumWindows的(EnumCallBack,拉手processToClose) 而在EnumCallBack你實際上PostMessage的WM_CLOSE每個窗口。

+0

有用的指向CloseApp的源代碼但不是內置的CA WixCloseApplications使用的是什麼?我已經嘗試過了,它關閉了應用程序,但並沒有這樣做,即OnFormClosing事件沒有被觸發。 –

+0

@彼得凱利我在想如果MSI運行是否升高或者CA是否正在運行。你可以發佈日誌嗎? msiexec/i [你的msi]/l * vx logfile.log – rene

+0

@rene我在使用util後發佈了一些日誌條目:CloseApplication。推遲的影響是什麼? –

相關問題