【问题标题】:How Can I Cancel LengthyOperation In WindowProc如何在 WindowProc 中取消 LongyOperation
【发布时间】:2017-03-28 06:48:59
【问题描述】:

我读过一篇 MSDN 文章,完全糊涂了:

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

【问题讨论】:

  • 假设该函数返回false一会,说明冗长的操作还没有完成。关键是将一项较长的操作分解为许多较小的操作。
  • 你不能在 GUI 线程中调用DoLengthyOperation(); - 需要在单独的工作线程中调用它。直到在您的代码示例中执行 DoLengthyOperation(); - 您没有调用 PeekMessage 所以根本没有收到任何 Windows 消息并且您的 UI 被冻结
  • @HansPassant 如果函数返回 false 一段时间,在下一次调用中,函数如何从上一次调用中执行的最后一行代码继续?在下一个调用函数中再次从第一行运行
  • @RbMm if DoLengthyOperation();在另一个线程中调用,不需要以这种方式查看消息循环,DoLengthyOperation() 在同一个线程中调用。
  • 只是概念代码sn-p,不是实际代码。你通常需要一个 InitializeLengthyOperation() 函数来初始化一个计数器。和一个 CancelLengthyOperation() 来清理。请记住,您不会经常编写这样的代码,尽管传统的游戏循环与此类似。包含这个 sn-p 肯定是为了提醒程序员,保持程序的 UI 线程响应用户输入是很重要的。就是这样。

标签: windows win32gui peekmessage


【解决方案1】:

要执行您的要求,您需要从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 消息队列。当主消息循环正常接收到鼠标/键盘输入时,如果线程正在运行,您可以向线程发出信号以自行终止。

【讨论】:

    猜你喜欢
    • 2011-05-21
    • 2013-01-16
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    相关资源
    最近更新 更多