2013-03-06 54 views
1

我試圖關閉從C++應用程序中的C#.NET 4 WPF應用程序。 C++的應用程序使用枚舉窗戶,發現對應於給定進程ID之一,經由PostMessage的發送窗口WM_CLOSE,然後WaitForSingleObject的(PID,5000)的標準技術。但是,我的WPF應用程序從不關閉,即WaitForSingleObject超時。WPF應用程序不響應WM_CLOSE

我的WPF應用程序覆蓋了窗口:: OnClosed():

  • 如果我手動點擊窗口的X關閉WPF應用程序,調用此方法。
  • 同樣,如果在Windows的任務管理器中的應用程序選項卡我做的WPF程序‘結束任務’,此方法被調用(顯然該選項卡上使用WM_CLOSE消息,而在進程選項卡上結束任務用途WM_QUIT消息)。
  • 當我的C++程序發送WM_CLOSE,這種方法不會被調用
  • 當我的C++應用發送WM_QUIT代替(除了所發送的消息,因此所有的C++源碼不變),我的WPF應用程序被終止。
  • 我曾嘗試在WPF應用程序創建我自己的WndProc()處理程序,方法不被調用,如果我將鼠標放在WPF界面,但同樣,當我的C++應用程序發送WM_CLOSE,這種方法不會被調用,這幾乎就像我的WPF應用程序沒有得到WM_CLOSE消息。
  • 我已創建從哪裏可以使用Process.GetProcessById(PID)和proc.CloseMainWindow()一個C#應用程序,這是應該做相同WM_CLOSE。這個工作:OnClosed()方法被調用。

PostMessage(hwnd,WM_CLOSE)是從C++應用程序中正常關閉WPF應用程序的正確方法嗎?

+0

我同時使用Spy ++驗證了WM_CLOSE在C++應用程序發送WM_CLOSE時沒有到達我的WPF應用程序。 – Schollii 2013-03-06 05:05:17

+0

剛碰到同樣的問題。希望有一個解決方案。 – 2013-04-15 19:44:25

+0

@KevinGale你可能想檢查我提供給我自己的問題的答案,因爲我最終找到了答案,也許它也會幫助你! – Schollii 2013-08-12 21:58:50

回答

1

我最終確實找到了答案,它很簡單:問題是與「找到與給定進程ID相對應的代碼」有關的代碼。問題是我沒有做很多低級別的win32的東西,所以我錯過了一個重要的細節。這裏是發生了什麼和解決方案,以防它可以幫助某人:

C++函數closeProc()打開必須關閉的現有進程的句柄,並導致爲每個窗口調用一個回調函數requestMainWindowClose()通過win32函數EnumWindows找到,並假定requestMainWindowClose()已將關閉消息發送到感興趣的進程,因此它等待進程退出。如果進程沒有在特定時間內退出,它將嘗試通過TerminateProcess()強制終止它。如果仍然不起作用,它會放棄。所述closeProc()看起來像這樣:

void closeProc() 
{ 
    HANDLE ps = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, dwProcessId); 
    if (ps == NULL) 
     throw std::runtime_error(...); 

    EnumWindows(requestMainWindowClose, dwProcessId); 

    static const int MAX_WAIT_MILLISEC = 5000; 
    const DWORD result = WaitForSingleObject(ps, MAX_WAIT_MILLISEC); 
    if (result != WAIT_OBJECT_0) 
    { 
     if (result == WAIT_TIMEOUT) 
     { 
      LOGF_ERROR("Could not clcose proc (PID %s): did not exit within %s ms", 
       dwProcessId << MAX_WAIT_MILLISEC); 
     } 
     else 
     { 
      LOGF_ERROR("Could not close proc (PID %s): %s", 
       dwProcessId << getLastWin32Error()); 
     } 

     LOGF_ERROR("Trying to *terminate* proc (PID %s)", dwProcessId); 
     if (TerminateProcess(ps, 0)) 
      exited = true; 
     } 
    } 

    CloseHandle(ps) ; 
} 

的問題是在requestMainWindowClose,這裏是原來的代碼:

BOOL CALLBACK 
requestMainWindowClose(HWND nextWindow, LPARAM closePid) 
{ 
    DWORD windowPid; 
    GetWindowThreadProcessId(nextWindow, &windowPid); 
    if (windowPid==(DWORD)closePid) 
    { 
     ::PostMessage(nextWindow, WM_CLOSE, 0, 0); 
     return false; 
    } 

    return true; 
} 

如上回調函數定義確定窗口的進程ID句柄賦予它通過EnumWindows()(nextWindow)並與我們想要關閉的期望進程(closePid)進行比較。如果匹配,則函數發送一條CLOSE消息並返回。

所有的已經很不錯了。問題是它返回false,所以EnumWindows()只會將消息發送到進程的一個窗口,並且它看起來像WPF應用程序有多個窗口:即使您的代碼只創建一個窗口,隱藏窗口也會在幕後創建由WPF。它們都是由EnumWindows找到的;但第一個很少,如果有的話,主要應用程序窗口。所以requestMainWindowClose()永遠不會將CLOSE發送到我的WPF應用程序的主窗口,從來沒有機會。

事實上,修復是簡單的,即不返回false:

BOOL CALLBACK 
requestMainWindowClose(HWND nextWindow, LPARAM closePid) 
{ 
    DWORD windowPid; 
    GetWindowThreadProcessId(nextWindow, &windowPid); 
    if (windowPid==(DWORD)closePid) 
     ::PostMessage(nextWindow, WM_CLOSE, 0, 0); 

    return true; 
} 

只有頂部的應用程序一個WPF的窗口將在關閉消息作出響應。

1

系統菜單上的關閉命令的直接對應的是:

PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); 

你可以試試吧。

+0

這應該也可以工作,這是一個很好的嘗試,但是如果PostMessage(hwnd,WM_SYSCOMMAND,SC_CLOSE,0)可以工作並且PostMessage(hwnd,WM_CLOSE,0,0)有任何情況,不。沒有區別,也沒有區別。 – Schollii 2013-03-06 05:04:55