我创建了一个类似下面这样的线程 while (GetMessage(&msg,g_hWnd,0,0)) 
{
TranslateMessage(&msg);
DispatchMessage(&msg);
                  ......处理消息........
}我想在这个线程中接收消息,但是运行时并没有收到任何消息.我应该怎么做?

解决方案 »

  1.   

    GetMessage调用时用参数g_hWnd,为取得窗口g_hWnd的消息。改为NULL取得该线程的所有消息,但你的线程必须有消息队列。
      

  2.   

    用PostThreadMessage 发送消息
      

  3.   

    The thread to which the message is posted must have created a message queue, or else the call to PostThreadMessage fails.
      

  4.   

    About Messages and Message Queues windows应用程序是事件驱动的。他们不明确进行函数调用来获得输入。相反,他们等待系统将输入传递给他们。
    系统将所有输入传递给应用程序的不同窗口。每一个窗口都有一个函数叫做窗口过程。操作系统调用他只要有输入发生。窗口过程处理输入然后返回控制给操作系统。
    详细信息请看窗口过程Microsoft? Windows? XP: 如果顶层窗口停止响应几秒钟,系统认为窗口已经挂起。这种情况, 系统隐藏窗口用ghost窗口取代他以同样的z-order坐标,位置,大小,属性。
    这个允许用户移动,改变,甚至关闭应用程序。然而, 这些行为只有窗口被挂起才产生。当窗口在debugger模式,系统在不产生ghost窗口。
    这个章节主要讨论一下主题:Windows 消息
    消息类型
    消息传递
    消息处理
    消息过滤
    Posting 消息、 Sending 消息
    消息 死锁
    广播消息
    Query Messageswindows消息系统传递输入给窗口过程in the form of messages。消息可以由系统或者应用程序产生。系统在发生输入事件时产生消息。举个例子, 当用户敲键, 移动鼠标或者单击控件。系统也产生消息以响应由应用程序带来的变化, 比如应用程序改变系统字体改变窗体大小。应用程序可以产生消息使窗体执行任务,或者与其他应用程序中的窗口通讯。 系统发送消息给窗口过程并传递4个参数,windows句柄, 消息标识符, 2个消息参数。系统使用窗体句柄来决定那个窗口过程来接受消息。 消息标识符以常量命名指出消息的含义。当窗口过程接收到消息,使用消息标识符决定如何处理消息。例如、WM_PAINT告诉窗口过程窗体客户区被改变了需要重绘。消息参数指定被窗口过程使用的数据。其含义和值取决于消息类型。消息参数可以包含一个整数, 标志位,一个指针等。 当消息不使用消息参数时,他们被设置位NULL。一个Window窗口过程必须根据消息标识符来决定如何杰是消息参数。 消息类型
    主要解释2个消息类型 系统定义消息
    应用程序定义消息系统定义消息
    系统post和send系统定义消息当系统和应用程序通讯。他使用消息来控制应用程序,提供输入和其他信息让应用程序处理。应用程序也可以post或者send系统定义消息。 Applications generally use these messages to control the operation of control windows created by using preregistered window classes. 每一个系统定义消息由一个唯一的标识符与一致的常量。例如 WM_PAINT 要求窗口绘制它的内容。符号常量指定系统消息属于的类别,常量的前缀指定处理解释消息的窗体的类型。以下使一些前缀和他们相关的消息类别。 Prefix Message category 
    ABM 任务栏
    BM 按钮  
    CB Combo box控件
    CBEM 扩展 combo box 控件
    CDM 通用对话框  
    DBT 设备 
    DL Drag list box  
    DM Default push button control  
    DTM 日期事件提取器控件
    EM 文本框 
    HDM Header control  
    HKM Hot key control 
    IPM 地址栏控件
    LB 列表控件  
    LVM 列表视图控件 
    MCM Month calendar control 
    PBM 进度条 
    PGM Pager control 
    PSM 属性单 
    RB Rebar control 
    SB 状态条 
    SBM 滚动条 
    STM Static control  
    TB 工具栏
    TBM Trackbar  
    TCM Tab control  
    TTM Tooltip control  
    TVM Tree-view control  
    UDM Up-down control 
    WM 通用窗口  通用窗体消息覆盖了很大一个信息和请求的范围, 包括鼠标键盘消息, 菜单对话框的输入, 窗体产生与管理, 动态数据交换 (DDE). 应用程序定义消息
    应用程序可以产生自己用的消息或者与其他进程中窗体通讯。如果应用程序产生自己的消息,窗口过程接受并且必须提供合适的处理。消息标识符得值:系统保留消息标识符的值在0x0000在0x03ff(WM_USER-1)范围。这些值被系统定义消息使用。 应用程序不能使用这些值给自己的消息。 
    private window用0x0400(WM_USER)到0x7fff消息标识符
    If your application is ed version 4.0, you can use message-identifier values in the range 0x8000 (WM_APP) through 0xBFFF for private messages. 
    系统使用RegisterWindowMessage来返回一个消息标识符范围在0XC000到0XFFFF,使用这个函数来保证整个范围内是唯一的。Message Routing
    系统有两个方法将消息传递到窗口过程。Post一个消息到先进先出的消息队列。系统定义的临时内存对象。和直接 send消息到窗口过程。被发送到消息队列的消息称做 queued messages。他们主要是由鼠标键盘输入,例如 WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR messages。还包括定时器, 刷新, 退出: WM_TIMER, WM_PAINT, and WM_QUIT。其他直接发送到窗口过程的消息被称为 nonqueued messages. Queued Messages系统可以显示任何数量的窗体同一时间。为了传递鼠标键盘消息到合适的窗口,系统使用消息队列。 
    系统维护一个系统消息队列和每一个GUI线程的消息队列,为避免给non-GUI现成创建消息队列,所有线程产生时并没有消息队列
    仅当线程第一次调用GDI函数数系统给线程创建一个消息队列。只要用户移动鼠标,点击鼠标,敲键,驱动程序将其转换为消息将他们放在系统消息队列中。系统将他们从系统消息队列中移走,检查他们的目标窗口,然后将他们发送到创建目标窗口的线程的消息队列。现成消息队列接受由这个线程创建的所有窗口的消息队列。线程删除消息系统调用窗口过程进行处理。
    WM_PAINT是一个例外,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而, is kept in the queue and is forwarded to the window procedure only when the queue contains no other messages.同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN减少了刷新窗口的次数。 系统通过填充MSG结构并将它复制到消息队列来发送消息到线程队列。MSG结构包括:窗口句柄,消息标识符,两个消息参数。 the time the message was posted, and the mouse cursor position. 线程可以使用PostMessage和PostThreadMessage来给发送消息到自己消息队列或者另一个线成的消息队列。 
    应用程序可以使用GetMessage从消息队列删除消息。可以使用 PeekMessage来检查一个消息而不删除它。 这个函数将消息队列的消息填充到MSG结构。 
    在从消息队列删除了一个消息,应用程序可以使用DispatchMessage使系统将消息发送到窗口过程来处理。DispatchMessage拥有一个由GetMessage或者PeekMessage填充的结构的指针,传递窗口句柄,消息标识符,消息参数给窗口过程。但它并不传递消息发送的时间和鼠标的位置(???),应用程序可以通过GetMessageTime和GetMessagePos来得到这些信息。
    A thread can use the WaitMessage function to yield control to other threads when it has no messages in its message queue. 这个函数挂起线程,并不返回,直到新的消息放置于消息队列中。 
    你可以调用SetMessageExtraInfo函数来关联一个值到消息队列。调用GetMessageExtraInfo来得到这个值。
    Nonqueued Messages非入队消息即直接发送到窗口过程的消息,绕过系统队列和消息队列。系统发送非入队消息通知窗口,系统发送消息通知窗口(The system typically sends nonqueued messages to notify a window of events that affect it)。 例如,当用户激活一个窗口系统发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知窗口它被激活了。that keyboard input is being directed to the window, and that the mouse cursor has been moved within the borders of the window. 非入队消息也可以由当应用程序调用系统函数产生。例如,当程序调用SetWindowPos系统发送WM_WINDOWPOSCHANGED消息。
    一些函数也发送非入队消息如 BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout, and SendNotifyMessage. Message Handling
    应用程序必须移除和处理被发送到消息队列的消息。但线程应用程序通常在WinMain使用消息循环来移除和分发消息到何时窗口过程来处理。多线程应用程序可以在每一个创建窗口的线程中中包含消息循环。
      

  5.   

    Message Loop
    A simple message loop consists of one function call to each of these three functions: GetMessage, TranslateMessage, and DispatchMessage. 注意如果有错误GetMessage 返回 -1 -thus the need for the special testing.例子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); 
        }
    }
    GetMessage 函数从消息队列获得一个消息并将它复制到MSG结构。他返回一个非0值,除非遇到WM_QUIT消息。否则它返回0然后结束循环。In a single-threaded application, ending the message loop is often the first step in closing the application. 应用程序可以使用PostQuitMessage来结束自己的消息循环。通常在主窗口的WM_DESTROY消息中调用。 
    如果你将一个窗口句柄作为第二个参数传入GetMessage,那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。详细见消息过滤。
    一个线程循环必须包括TranslateMessage如果线程接受键盘的字符输入。每一次用户按键系统产生虚拟键消息,一个虚拟键消息包含虚拟键用来标志那个键被按下,要获得这个值消息循环必须调用TranslateMessage,用于将虚拟键转换为字符消息WM_CHAR然后将它放回应用程序消息队列。The character message can then be removed upon a subsequent iteration of the message loop and dispatched to a window procedure. 
    DispatchMessage 函数分发消息到MSG结构中的窗口句柄关联的窗口过程。如果窗口句柄是HWND_TOPMOST,DispatchMessage分发消息到系统中的所有的top-level窗口的窗口过程。如果句柄是NULL,DispatchMessage不做任何事。
    应用程序得主线程在初始化击创建至少一个窗口后启动它的消息,一旦启动消息循环持续从线程队列中获得消息,然后分发他们到合适的窗口。消息循环在得到WM_QUIT后结束。
    Only one message loop is needed for a message queue, even if an application contains many windows. DispatchMessage 总是分发消息到合适的窗口,这是因为MSG结构包含消息所属的窗口的句柄。
    你可以用各种方式修改消息循环。例如,从消息队列获得消息消息但不把他们分发到窗口中去。当应用程序发送一个消息但不指定窗口时是有用的。你可以用GetMessage获得一个特定的消息,而保留其他消息在消息队列。当你需要改变先进先出的顺序时是有用的。
    应用程序使用加速键必须将键盘消息转换为WM_COMMAND消息。所以消息循环必须包括TranslateAccelerator函数。详细信息参见加速键。
    如果线程使用非模态对话框,消息循环必须包括 IsDialogMessage 以使非模态对话框获得键盘输入。 Window Procedure窗口过程是一个用于处理所有发送到这个窗口的消息的函数。任何一个窗口类都有一个窗口过程。同一个类的窗口使用同样的窗口过程来响应消息。 
    系统发送消息给窗口过程将消息数据作为参数传递给他,窗口过程使用参数产生合适行为。
    一个窗口过程不经常忽略消息,如果他不处理,它会将消息传回到执行默认的处理。窗口过程通过调用DefWindowProc来做这个处理。窗口过程必须return一个值作为它的消息处理结果。大多数窗口只处理小部分消息和将其他的通过DefWindowProc传递给系统做默认的处理。
    窗口过程被所有属于同一个类的窗口共享,能为不同的窗口处理消息。Message Filter
    应用程序可以从消息队列选择特定的消息。使用GetMessage或者PeekMessage并指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用程序要查找一个后入消息队列的消息是很有用。 It is also useful if an application must process input (hardware) messages before processing posted messages. 
    WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的键盘消息。 the WM_MOUSEFIRST 和 WM_MOUSELAST 常量用于接受所有的鼠标消息。 
    Any application that filters messages must ensure that a message satisfying the message filter can be posted. For example, if an application filters for a WM_CHAR message in a window that does not receive keyboard input, the GetMessage function does not return. This effectively "hangs" the application. Posting and Sending Messages
    应用程序可以post和send消息,通过将消息复制到消息队列即post消息,send消息则绕过了消息队列直接传递消息数据到窗口过程。
    可以使用PostMessage来post消息,SendMessage来send消息。Posting Messages
    应用程序post消息通知指定窗体执行任务。PostMessage可以创建MSG结构并将它Copy到消息队列。消息循环最终捕获消息并分发到合适的窗口过程。
    给PostMessage传递一个NULL句柄不指定哪一个窗口,这个消息就被发送到当前线程消息队列,应用程序必须在消息处理中处理这个消息。这是为整个应用程序发送消息的一个方法。
    偶尔你可以使用HWND_TOPMOST 这个参数作为句柄参数向所有的top-level窗口发送消息。
    当消息队列满的时候PostMessage并不发送消息,应用程序需要检查PostMessage函数的返回值来确定消息是否被发送,或者没有需要重发。Sending Messages
    通过Send消息来通知窗口过程立即执行任务。SendMessage将消息发送给指定窗口的窗口过程。函数将等待窗口过程处理完才返回一个消息结果。父窗口和子窗口通常使用Send消息来互相通讯。例如,一个父窗口拥有以一个文本框作为它的子窗口,它可以通过发送消息到子窗口来给文本框设置文字。子窗口也可将文字被用户改变的消息发送给父窗口。
    SendMessageCallback也将消息发送给指定窗口的窗口过程,但是他立即返回。在窗口过程处理完消息后,系统调用指定的回调函数,回调函数的详细资料参见SendAsyncProc
    偶尔,你可以发送消息系统中到所有的top-level窗口,例如,应用程序改变了系统时间。它必须以HWND_TOPMOST作为句柄参数发送一个WM_TIMECHANGE 消息通知所有的top-level窗口,你也可以使用以BSM_APPLICATIONS作为参数的BroadcastSystemMessage函数向所有应用程序广播。
    可以使用InSendMessage或者InSendMessageEx函数,窗口过程可以判断它处理的消息是否是由其他线程调用SendMessage发送过来的。This capability is useful when message processing depends on the origin of the message. Message Deadlocks
    一个线程调用SendMessage函数发送一个消息给另一个线程不能执行知道接受消息的窗口过程返回。If the receiving thread yields control while processing the message, 发送线程不能继续执行,因为它在等待SendMessage返回。If the receiving thread is attached to the same queue as the sender, 将引起死锁。
    Note that the receiving thread need not yield control explicitly; calling any of the following functions can cause a thread to yield control implicitly. DialogBox
    DialogBoxIndirect
    DialogBoxIndirectParam
    DialogBoxParam
    GetMessage
    MessageBox
    PeekMessage
    SendMessage
    为了避免潜在的死锁,可以使用SendNotifyMessage 或者 SendMessageTimeout,否则窗口过程,将用InSendMessage或者InSendMessageEx判断消息是否由另一个线程发送过来。当调用前面任何一个函数窗口过程将首先调用InSendMessage或者InSendMessagEx,如果函数返回true窗口过程必须调用ReplyMessage before any function that causes the thread to yield control. Broadcasting Messages
    每一个消息包括消息标识符和两个参数,wParam和lParam,消息标识符是唯一的代表这个消息的含义。参数提供与消息相关的额外的信息,但是wParam参数通常是一个类型值提供更多的消息信息。
    消息广播是简单的将消息发送到系统中的多个接收者。使用BroadcastSystemMessage函数来广播消息,你必须制定一个或者多个接收者类型,这些类型可以是applications, installable drivers, network drivers, and system-level device drivers。系统将消息发送给指定类型的所有成员。
    当系统级的设备驱动或者相关组件发生变化了系统通常用广播消息来响应这些变化。For example, the component responsible for disk drives broadcasts a message whenever the device driver for the floppy disk drive detects a change of media such as when the user inserts a disk in the drive.
    The system broadcasts messages to recipients in this order: system-level device drivers, network drivers, installable drivers, and applications. This means that system-level device drivers, if chosen as recipients, always get the first opportunity to respond to a message. Within a given recipient type, no driver is guaranteed to receive a given message before any other driver. This means that a message intended for a specific driver must have a globally-unique message identifier so that no other driver unintentionally processes it.
    You can also broadcast messages to all top-level windows by specifying HWND_BROADCAST in the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. 
    Applications receive messages through the window procedure of their top-level windows. Messages are not sent to child windows. Services can receive messages through a window procedure or their service control handlers.
    Note  System-level device drivers use a related, system-leve