[ATL/WTL]_[初级]_[Windows消息循环初解]

Windows 消息循环初解

场景

  1. Win32窗口编程, 肯定涉及到消息循环. Win32编程基本就是通过处理消息来处理系统任务, 所以Win32窗口编程, 弄懂消息循环是必然的.

说明

1.对于GUI线程,Win32消息循环使用两个队列来来存储消息, 一个是系统消息队列, 一个线程指定的队列. 消息队列是fifo的队列.

 The system maintains a single system message queue and one thread-specific message 
    queue for each GUI thread.

2.系统在创建线程时不会自动创建一个消息队列, 因为这样会浪费资源,并不是每个线程都需要响应系统消息的. 只有用户执行了一个需要消息队列的操作时系统才会创建消息队列. 比如GetMessage(),PeekMessage().

The system does not automatically create a message queue for each thread. Instead, the system creates a message queue only for threads that perform operations which require a message queue. 

3.线程指定的消息循环是自己创建的, 消息队列是系统创建的, 一般的格式如下.

MSG msg;
BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

4.PostMessage 会发送一个消息到消息队列末尾,并立即返回.

 PostMessage places a message at the end of a thread's message queue and returns immediately, without waiting for the thread to process the message. 

5.SendMessage 发送消息MSDN没说是发送到队列末尾, 但应该不会违反规则. SendMessage 发送消息到队列末尾并等待消息循环执行完消息才返回. 窗口过程仍旧是在GUI线程里执行,不是在其他线程里执行.

The SendMessage function is used to send a message directly to a window procedure. SendMessage calls a window procedure and waits for that procedure to process the message and return a result.

6.注意, 线程指定的消息循环不一定需要创建窗口. 我们也可以利用线程消息循环来处理非窗口任务, 看以下例子, 可以使用线程指定内置的消息队列来线程安全的执行消息任务. 这样就不需要自己写临界区或加锁在queue上了.

// test_message_loop1.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>  

#include <assert.h>
#include <iostream>

#include "test_message_loop1.h"

int PressAnyKey( const wchar_t *prompt )  
{  
  DWORD        mode;  
  HANDLE       hstdin;  
  INPUT_RECORD inrec;  
  DWORD        count;  
  wchar_t         default_prompt[] = L"Press a key to continue...\n";  

  /* Set the console mode to no-echo, raw input, */  
  /* and no window or mouse events.              */  
  hstdin = GetStdHandle( STD_INPUT_HANDLE );  
  if (hstdin == INVALID_HANDLE_VALUE  
    || !GetConsoleMode( hstdin, &mode )  
    || !SetConsoleMode( hstdin, 0 ))  
    return 0;  

  if (!prompt) prompt = default_prompt;  

  /* Instruct the user */  
  WriteConsole(  
    GetStdHandle( STD_OUTPUT_HANDLE ),  
    prompt,  
    lstrlen( prompt ),  
    &count,  
    NULL  
    );  

  FlushConsoleInputBuffer( hstdin );  

  /* Get a single key RELEASE */  
  do ReadConsoleInput( hstdin, &inrec, 1, &count );  
  while ((inrec.EventType != KEY_EVENT) || inrec.Event.KeyEvent.bKeyDown);  

  /* Restore the original console mode */  
  SetConsoleMode( hstdin, mode );  

  return inrec.Event.KeyEvent.uChar.AsciiChar;  
}  

typedef enum MyMessage1
{
    kMessageCopyFile = WM_USER+100
}MyMessage;

DWORD WINAPI StartThread(void* data)
{
    MSG msg;
    BOOL bRet;
    std::cout << "StartThread: " << ::GetCurrentThreadId() << std::endl;
    while( (bRet = GetMessage( &msg, (HWND)-1, 0, 0 )) != 0)
    {
        std::cout << "GetMessage: " << msg.message 
                  << " ThreadID: " << ::GetCurrentThreadId() 
                  << " wParam: " << msg.wParam
                  << " lParam: " << msg.lParam
                  << std::endl;
        Sleep(2000);
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            //TranslateMessage(&msg); 
            //DispatchMessage(&msg); 
        }
    }

    std::cout << "StartThread END: " << ::GetCurrentThreadId() << std::endl;
    return 0;
}

class A
{
public:
    virtual ~A(){std::cout << "~A" << std::endl;}
};

class B : public A
{
public:
    ~B(){std::cout << "~B" << std::endl;}
};

int main(int argv,char* args[])
{

    std::cout << "main: " << ::GetCurrentThreadId() << std::endl;

    DWORD IDThread;
    HANDLE h1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) StartThread,NULL,0,&IDThread);
    assert(h1);

    DWORD IDThread2;
    HANDLE h2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) StartThread,NULL,0,&IDThread2);
    assert(h2);

    int code = 0;
    while((code = PressAnyKey(NULL))!= 'q')
    {
        std::cout << code << std::endl;

        if(code == 'c')
        {
            PostThreadMessage(IDThread,WM_QUIT,8,9);
            PostThreadMessage(IDThread2,WM_QUIT,8,9);
        }else
        {
            PostThreadMessage(IDThread,kMessageCopyFile,8,9);
            PostThreadMessage(IDThread2,kMessageCopyFile,8,9);
        }
    }

    return 0;
}

参考

About Messages and Message Queues

Using Messages and Message Queues

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值