2017-03-28 47 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消息队列。当主消息循环正常接收到鼠标/键盘输入时,如果线程正在运行,您可以发信号通知线程自行终止。