2017-03-28 32 views
0

我看過一篇MSDN文章,徹底困惑:我怎樣才能取消LengthyOperation在WindowProc中

HWND hwnd; 
BOOL fDone; 
MSG msg; 

// Begin the operation and continue until it is complete 
// or until the user clicks the mouse or presses a key. 

fDone = FALSE; 
while (!fDone) 
{ 
fDone = DoLengthyOperation(); // application-defined function 



while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) 
{ 
    switch(msg.message) 
    { 
     case WM_LBUTTONDOWN: 
     case WM_RBUTTONDOWN: 
     case WM_KEYDOWN: 
      // 
      // Perform any required cleanup. 
      // 
      fDone = TRUE; 
    } 
} 
} 

MSDN說,與此代碼一個漫長的操作過程中,我們可以檢查消息隊列 &取消以案例的鼠標單擊或鍵盤KeyDown。 這是怎麼回事?

當DoLengthyOperation開始時,直到它完成並且PeekMessage不會在此時間內調用並且不能取消操作時纔會返回。

MSDN鏈接:https://msdn.microsoft.com/en-us/library/windows/desktop/ms644928

+0

假設該函數返回* false *一段時間,表明冗長的操作還沒有完成。關鍵是要把一個長期的操作分解成許多較小的操作。 –

+0

您不能在* GUI *線程中調用'DoLengthyOperation();' - 需要在單獨的工作線程中調用它。直到'DoLengthyOperation();'在您的代碼示例中執行 - 您沒有調用PeekMessage'因此沒有任何Windows消息,並且您的UI凍結 – RbMm

+0

@HansPassant如果函數在一段時間內返回false,從前一次調用的最後一行代碼中執行?在下一次調用函數中再次運行第一行 –

回答

0

要做到你所要求的,你需要從內部DoLengthyOperation()本身窺視消息隊列,例如:

BOOL fDone = FALSE; 
do 
{ 
    fDone = DoLengthyOperation(); 
} 
while (!fDone); 

... 

BOOL DoLengthyOperation() 
{ 
    MSG msg; 

    ... 

    if (PeekMessage(&msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 
     PeekMessage(&msg, hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
     return TRUE; 
    } 

    ... 

    if (PeekMessage(&msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 
     PeekMessage(&msg, hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
     return TRUE; 
    } 

    ... 

    return FALSE; 
} 

否則,你應該將冗長的操作改爲單獨的工作線程,根本不要阻止主UI消息隊列。當主消息循環正常接收到鼠標/鍵盤輸入時,如果線程正在運行,您可以發信號通知線程自行終止。