看《Windows程序设计》,看到队列消息非队列消息那里,看不下去了。
首先,“系统”是什么?我认为,我们可以调用系统(调用API),系统也可以调用我们(调用窗口过程),但归根结底还是我们调用系统,因为地址空间是我们的。“系统”只是这些的东西:线程调度、消息派送以及API(只对windows程序开发者而言;我理解的就这样,大牛们要笑了)。线程调度很好理解。消息派送很简单,只是存到消息队列中,并没有直接调用窗口过程,窗口过程是API们调用的,而这些API们是我们一手调用的。所以归根结底到这儿,说“到底还是我们调用的系统”。API们背着我们做了太多事情,甚至MessageBox期间都会频繁调用窗口过程,这使我们相当不爽(起码理解起来如此)。
第一个问题:以上分析对吗?
第二个问题,我先继续说我的分析。
那么我们从哪里起先调用的API呢?WinMain函数。除掉消息循环之前的ShowWindow、UpdateWindow。只有GetMessage与DispatchMessage是调用窗口过程的源头(TranslateMessage我想不会被设计得很复杂以至于可能调用窗口过程吧)。按《Windows核心编程》的说法,GetMessage首先检查“发送消息队列”里有没有消息,如果发现有,是会直接调用窗口过程处理,处理完之后,才检查Post的消息QUIT消息虚拟输入消息PaintTimer等等,而所有这些都是填充到MSG结构后直接返回的。如此看来,若发现GetMessage在调用窗口过程,那肯定是在处理“发送消息队列”的消息。但是,在窗口过程中添加这一句:
int source=InSendMessageEx(NULL);
下断点,看调用堆栈,当出现GetMessage时,source值是0!继续,发现绝大多数通过GetMessage处理的消息的source值都是0,就是说这些消息都是线程内发送的了。
第二个问题:若如之前分析,这些消息都是线程内发送的而且是填入“发送消息队列”的,那么,这些消息时从哪里来的?消息的来源如果是线程内的“系统”(API),它为什么不直接调用窗口过程?消息的来源如果是线程外的“系统”,那么InSendMessageEx为什么返回0呢?
请高手们快来讲一讲这些消息时怎么一回事!附上那段被我改得面目全非的Charles那段代码:#include <windows.h>
#include <stdio.h>FILE *fp1;LRESULT CALLBACK WndProc1(HWND,UINT,WPARAM,LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{
    MSG msg1;
    HWND hwnd1;
    WNDCLASS wndclass1;    wchar_t s[24];    FILE *fp=fopen("MessageLoop.txt","w");
    fp1=fopen("WndProc.txt","w");
    
    MessageBox(0,_itow((int)GetThreadId(GetCurrentThread()),s,10),L"ThreadId",0);
    /*
    GetMessage(&msg1,NULL,0,0);
    MessageBox(0,_itow((int)msg1.hwnd,s,10),L"msg1.hwnd",0);
    MessageBox(0,_itow((int)msg1.message,s,10),L"msg1.message",0);
    MessageBox(0,_itow((int)msg1.wParam,s,10),L"msg1.wParam",0);
    MessageBox(0,_itow((int)msg1.lParam,s,10),L"msg1.lParam",0);
    */
    //MessageBox(0,_itow(sizeof(HWND),s,10),L"AAA",0);//8    wndclass1.style=CS_HREDRAW|CS_VREDRAW;
    wndclass1.lpfnWndProc=WndProc1;
    wndclass1.cbClsExtra=0;
    wndclass1.cbWndExtra=0;
    wndclass1.hInstance=hInstance;
    wndclass1.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndclass1.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndclass1.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass1.lpszMenuName=NULL;
    wndclass1.lpszClassName=L"WndClass1";
    RegisterClass(&wndclass1);
    hwnd1=CreateWindow(
        L"WndClass1",//窗口类名 window class name
        L"Caption1",//窗口标题 window caption
        WS_OVERLAPPEDWINDOW,//window style
        /*WS_OVERLAPPED|
        WS_CAPTION|
        WS_SYSMENU|
        WS_THICKFRAME|
        WS_MINIMIZEBOX|
        WS_MAXIMIZEBOX,*/
        CW_USEDEFAULT,//x位置 initial x position
        CW_USEDEFAULT,//y位置 initial y position
        CW_USEDEFAULT,//x大小 initial x size
        CW_USEDEFAULT,//y大小 initial y size
        NULL,//父窗口句柄 parent window handle
        NULL,//window menu handle
        hInstance,//program instance handle
        NULL);//creation parameters    //MessageBox(0,L"WindowCreated\nnext:ShowWindow",L"Process",0);
    ShowWindow(hwnd1,iCmdShow);//SW_SHOWMINNOACTIVE
    //MessageBox(0,L"ShowWindowEnd\nnext:UpdateWindow",L"Process",0);
    UpdateWindow(hwnd1);
    //MessageBox(0,L"UpdateWindowEnded\nnext:Messages",L"Process",0);    //MessageBox(hwnd1,_itow(SendMessage(hwnd1,WM_USER+5,9,10),s,10),L"ReturnValue",0);
    //MessageBox(hwnd1,_itow((int)hwnd1,s,10),L"hwnd1",0);
    //GetMessage(&msg1,NULL,0,0);
    SendNotifyMessage(hwnd1,WM_USER+5,999,9999);    while (GetMessage(&msg1,NULL,0,0))
    {
        //fprintf(fp,"hwnd:%04d message:%08d wP:%010d lP:%010d time:%06u x:%04d y:%04d\n",msg1.hwnd,msg1.message,msg1.wParam,msg1.lParam,msg1.time,msg1.pt.x,msg1.pt.y);
        //MessageBox(0,L"WhileEnded\nnext:TranslateMessage",L"Process",0);
        TranslateMessage(&msg1);
        //MessageBox(0,L"TranslateMessageEnded\nnext:DispatchMessage",L"Process",0);
        //msg1.lParam=123456789;
        DispatchMessage(&msg1);//if (msg1.message==WM_NCLBUTTONDOWN) 
        //MessageBox(0,L"DispatchWindowEnded\nnext:nextWhile",L"Process",0);
    }
    //MessageBox(0,_itow((int)msg1.hwnd,s,10),L"msg1.hwnd",0);
    //MessageBox(0,_itow((int)msg1.message,s,10),L"msg1.message",0);
    //MessageBox(0,_itow((int)msg1.wParam,s,10),L"msg1.wParam",0);
    //MessageBox(0,_itow((int)msg1.lParam,s,10),L"msg1.lParam",0);
    fclose(fp);
    fclose(fp1);
    return msg1.wParam;
}LRESULT CALLBACK WndProc1(HWND hwnd,UINT message,WPARAM wP,LPARAM lP)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;    wchar_t s[24];    //if (message!=28) MessageBox(0,_itow(message,s,10),L"Message",0);
    int source=InSendMessageEx(NULL);
    if (source)
    {
        source=source;
    }
    if (message==161)
    {
        source=source;
    }
    //fprintf(fp1,"hwnd:%04d message:%08d wP:%010d lP:%010d time:%06u Pos:%04d source:%d\n",hwnd,message,wP,lP,GetMessageTime(),GetMessagePos(),source);    switch (message)
    {
    case WM_CREATE:
        MessageBox(hwnd,_itow((int)hwnd,s,10),L"Hello, Windows 7!",0);
        //MessageBox(hwnd, L"Hello, Windows 7!",L"HelloMsg", 0);
        PlaySound(L"hellowin.wav",NULL,SND_FILENAME|SND_ASYNC);
        return 0;    case WM_PAINT:
        hdc=BeginPaint(hwnd,&ps);
        GetClientRect(hwnd,&rect);
        DrawText(hdc,L"Hello, Windows 7!",-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
        EndPaint(hwnd,&ps);
        return 0;    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;    case WM_USER+5:
        return 99;    case WM_MOVE:
        source=source;
    default:
        return DefWindowProc(hwnd,message,wP,lP);
    }
}source=source是用来下断点的

解决方案 »

  1.   

    你会意错中文了,,所谓的发送消息队列,是指 SendMessage,而不是PostMessage发出的消息的队列。
      

  2.   

    消息的来源很多,键盘、鼠标、窗口、系统等,而且exe对很多消息都不做处理,因此得有给函数接收、分发、并最终处理消息
      

  3.   

    我知道是SendMessage的消息的队列。
    I just wonder why:
    我发现GetMessage在处理来自自身线程的消息,而之前我了解到GetMessage只处理这个”发送消息队列“里的消息。
      

  4.   

    消息队列中的消息,可以是外部的消息,也可以是自身线程的消息.
    外部消息就不说了,内部消息如在窗口过程中调用DestroyWindows,
    DestroyWindow向消息队列发送WM_DESTROY消息.
      

  5.   

    呵呵,应该是下一步的标准响应WM_DESTROY的WM_QUIT消息.
      

  6.   

    要这么说那引导了谁谁就是老大了。
    系统调度对程序写作者是透明的,我们不会感受到系统有没有停止我们的线程。
    只要我们的线程开始执行,除了处理器的特权指令及受操作系统保护的内存区域,我们可以随便折腾,虽然API会干很多事情,但调不调用API是我们的权利,我们随时可以终止消息循环而使程序变为一个控制台程序。像这样:
    将WinMain函数消息循环及之后代码改为下一段: for (i=0;i<500;++i)
    {
    GetMessage(&msg1,NULL,0,0);
    TranslateMessage(&msg1);
    DispatchMessage(&msg1);//if (msg1.message==WM_NCLBUTTONDOWN) 
    }
    DestroyWindow(hwnd1);
    AllocConsole();
    freopen("CONOUT$","w+t",stdout);
    freopen("CONIN$","r+t",stdin);

    printf("HaHaHaHa!\n");
    fclose(fp);
    fclose(fp1);
    getch();
    return 0;或者不DestroyWindow,Hide之后,只要不调用API,窗口过程是绝对没机会被执行的。
    所以说我们拥有足够多的控制权。我不是说你说的不对,只是从不同角度看问题而已!!!
      

  7.   

    奥,9楼代码还要加上#include <conio.h>
      

  8.   

    据我实验,DestroyWindow发送WM_DESTROY消息是直接调用(就是直接call)窗口过程,没放到Post队列,更没放到Send队列。这个消息不足以解释”GetMessage在处理自己线程的消息“这个问题。
      

  9.   

    “一个用户只允许连续回复3次”,so bad a rule!
    我是马甲。
    比如这个134消息(134是WM_NCACTIVATE)
      

  10.   

    不知道这个讨论是不是属于WINDOWS的“黑盒”范畴。WINDOWS貌似现在还有不少黑盒不少人解不开,是吧?要是WINDOWS把源码公开就好了
      

  11.   


    确实如你所说,我已经在8楼说明了。举个简单的例子,既然我们可以在窗口过程中调用PostMessage发送消息
    ,不排除windows也会这么干。
      

  12.   

    can't agree with you more.