看《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是用来下断点的
首先,“系统”是什么?我认为,我们可以调用系统(调用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是用来下断点的
I just wonder why:
我发现GetMessage在处理来自自身线程的消息,而之前我了解到GetMessage只处理这个”发送消息队列“里的消息。
外部消息就不说了,内部消息如在窗口过程中调用DestroyWindows,
DestroyWindow向消息队列发送WM_DESTROY消息.
系统调度对程序写作者是透明的,我们不会感受到系统有没有停止我们的线程。
只要我们的线程开始执行,除了处理器的特权指令及受操作系统保护的内存区域,我们可以随便折腾,虽然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,窗口过程是绝对没机会被执行的。
所以说我们拥有足够多的控制权。我不是说你说的不对,只是从不同角度看问题而已!!!
我是马甲。
比如这个134消息(134是WM_NCACTIVATE)
确实如你所说,我已经在8楼说明了。举个简单的例子,既然我们可以在窗口过程中调用PostMessage发送消息
,不排除windows也会这么干。