void OneThreadclass::Idle(
UInt32 milliseconds)
{
DWORD done = timeGetTime() + milliseconds;
do
{
Sleep(1); // yield to all threads // NOTE: PeekMessage() does the following:
// 1. Permits any queued SendMessage() calls to windows owned by this thread to execute.
// 2. Effectively yields execution to other threads waiting for this thread to go idle.
// 3. Applications simply wishing to yield the remainder of their timeslice should call Sleep(0).
MSG msg;
PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
}
while (timeGetTime() < done);
}
请问这里PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);起了什么作用?光收了消息,然后什么都没做。放在这里干嘛?

解决方案 »

  1.   

    The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a posted message, and retrieves the message (if any exist).During this call, the system delivers pending, nonqueued messages, that is, messages sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. Then the first queued message that matches the specified filter is retrieved. The system may also process internal events. If no filter is specified, messages are processed in the following order:    * Sent messages
        * Posted messages
        * Input (hardware) messages and system internal events
        * Sent messages (again)
        * WM_PAINT messages
        * WM_TIMER messages
      

  2.   

    默认情况下,每一个消息被返回到应用程序后,PeekMessage和 GetMessage都会把消息和事件从系统队列中删除。然而有些时候,某个应用程序可能需要扫描队列中现存的消息而并不删除它们。例如,某个应用程序在做一些处理过程,这些处理过程期望“一但发现有可用的消息,就尽快终止”。这里指定PM_NOREMOVE,是指查看过后不移走消息队列中刚刚被查看到的消息,也就是说这里的PeekMessage只起到一个检测作用
      

  3.   

    PeekMessage 一大特点就是每次都来看看有没有信息,没有的话就休息,把cpu让给别的线程。
    如果这里没有PeekMessage ,那么在跳出循环前,会占用大量cpu的工作时间。
      

  4.   

    关于PeekMessage的其他用法,我可以举个例子:
    如果你在一个主线程里面开了如下一个循环,则程序就不会响应其他任何windows消息:for (;;)
    {
        //其他代码
        ...
        Sleep(100);
    }如果必须实时响应windows,则必须如下写,你可以做个测试.for (;;)
    {
        //其他代码
        ...
        MSG msg;
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }    Sleep(100);
    }
      

  5.   

    如果当前实例消息队列中无消息,程序主执行线程挂起.当操作系统再一次返回执行时,发现仍是空的
    GetMessage :过门不入,操作系统再去照顾其它人           PeekMessage:取会控制权,使程序得以执行一段时间.
      

  6.   

    这是个带有Window的线程比较常用的等待一段时间的做法。从这个函数的名字,很明显,这个线程想歇段时间。最简单的方法当然是Sleep(milliseconds);但是这回阻塞这个Thread的Message Queue的Enque。如果别的程序或者线程向这个Thread发个Message,就死等了。比如一个简单的GetWindowText就不动了,你如果用Task Manager看,这个窗口就会显示(No response - 没有反应),所以歇的时候一定不能堵住SendMessage。举个不恰当的例子,你的Thread是收发室老头儿,老头儿的任务就是接受信件(GetMessage),然后立即送出(DispatchMessage)。邮递员不停地来送信(SendMessage), 你这个函数,老头决定休息一会儿,不送信了(DispatchMessage),但是不能让邮递员干等,人还要干别的事情。所以老头还是瞄了一眼有没有邮递员(PeekMessage),有的话就把信拿到收发室里。 这样邮递员就走了,信留在收发室(Message Queue)。这时候因为不想送信(DispatchMessage),所以一定不能把信给扔了(PM_NOREMOVE),否则信丢了。等老头休息完了,就可以把信从收发室拿出来(GetMessage),再Dispatch出去。所以PeekMessage如果后面没有紧跟DispatchMessage, 一定得用PM_NOREMOVE(除非老头儿想过滤,比如把骚扰的信扔了).
      

  7.   

    你们怎么不看书呢,
    windows核心编程上面讲的很详细呀.
      

  8.   

    一句话:等待消息全部处理后结束自已。YIELD
      

  9.   

    hi feimingbiao:我按照你所说的试验了一下,验证了
    “如果别的程序或者线程向这个Thread发个Message,就死等了。比如一个简单的GetWindowText(或者直接显式的调用SendMessage(..., WM_GETTEXT,...,...)就不动了,...,所以歇的时候一定不能堵住SendMessage。”PeekMessage的确有“让其他线程向此线程SendMessage过来不阻塞的功效”。谢谢。
    现在我有一个问题:试验中,我发现PeekMessage里的 LOWORD(msg.message)收不到自线程发过来的WM_GETTEXT这个消息,不知道为何?unsigned __stdcall SubThreadFun( void* pArguments )
    {
    DWORD done;
    done = timeGetTime() + 3000;
    while (timeGetTime() != done)
    {
    } HWND mywnd = (HWND)pArguments; char strWindowText[80];
    // GetWindowText(mywnd, strWindowText, 100);   //will also send WM_GETTEXT
    ::SendMessage(mywnd, WM_GETTEXT, 100, (LPARAM)strWindowText); 
    MessageBox(NULL, strWindowText, "MainWindowText is:", 0); _endthreadex( 0 );
    return 0;
    }  
    主线程如下:
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc; switch (message) 
    {
    case WM_COMMAND:
    wmId    = LOWORD(wParam); 
    wmEvent = HIWORD(wParam); 
    // 分析菜单选择:
    switch (wmId)
    {
    case IDM_ABOUT:
    //DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
    DWORD done;
    done = timeGetTime() + 8000;

    do
    {
    Sleep(1); 
             MSG msg;
    if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
    {
    char outbuff[80];
    sprintf(outbuff, "%d", msg.message);
    OutputDebugString(outbuff); OutputDebugString("\n");
    WORD lowword1 = LOWORD(msg.message);
    if (lowword1 == WM_GETTEXT)  //就是这里,收不到WM_GETTEXT,奇怪
    {
    int a, b =3;
    a = b;
    MessageBox(NULL, "I am here", "I am here", 0);
    }
    }

    }
    while (timeGetTime() < done); MessageBox(NULL, "while finished", "while finished", 0); break;
    case IDM_EXIT:
    DestroyWindow(hWnd);
    break;
    case IDM_startsubthread:
    hThread = (HANDLE)_beginthreadex( NULL, 0, &SubThreadFun, (void*)hWnd, 0, &threadID );
    break;
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    break;
    case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    // TODO: 在此添加任意绘图代码...
    EndPaint(hWnd, &ps);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    case WM_GETTEXT:
    break;    //add for test
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
    }
      

  10.   

    为什么收发室的老头看不到 WM_GETTEXT?
      

  11.   

    PeekMessage()..in WndProc()? What did you mean to do?
    Maybe that'll just be fine, you can do that in theory. But remember this:
     
    "The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a posted message, and retrieves the message (if any exist)."which means, sent messages(those transferred by SendMessage() or equivalent) will be "internally and directly" diapatched to your WndProc, and you can never "Peek" or "Get" it out.