当用USER32.DLL里调用获取消息之后,就调用到WIN32K.SYS里处理的函数NtUserGetMessage,这个函数实现的代码如下:
#001 BOOL APIENTRY
#002 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
#003 HWND hWnd,
#004 UINT MsgFilterMin,
#005 UINT MsgFilterMax)
#006 /*
#007 * FUNCTION: Get a message from the calling thread's message queue.
#008 * ARGUMENTS:
#009 * UnsafeMsg - Pointer to the structure which receives the returned message.
#010 * Wnd - Window whose messages are to be retrieved.
#011 * MsgFilterMin - Integer value of the lowest message value to be
#012 * retrieved.
#013 * MsgFilterMax - Integer value of the highest message value to be
#014 * retrieved.
#015 */
#016 {
#017 BOOL GotMessage;
#018 NTUSERGETMESSAGEINFO Info;
#019 NTSTATUS Status;
#020 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
#021 PWINDOW_OBJECT Window = NULL;
#022 PMSGMEMORY MsgMemoryEntry;
#023 PVOID UserMem;
#024 UINT Size;
#025 USER_MESSAGE Msg;
#026 DECLARE_RETURN(BOOL);
#027 // USER_REFERENCE_ENTRY Ref;
#028
#029 DPRINT("Enter NtUserGetMessage/n");
进入临界区代码。
#030 UserEnterExclusive();
#031
#032 /* Validate input */
获取窗口对象,并检查窗口句柄是否有效。
#033 if (hWnd && !(Window = UserGetWindowObject(hWnd)))
#034 {
#035 RETURN(-1);
#036 }
#037
#038 // if (Window) UserRefObjectCo(Window, &Ref);
#039
如果设置消息最大值比最小值还小,就使用缺省的方式。
#040 if (MsgFilterMax < MsgFilterMin)
#041 {
#042 MsgFilterMin = 0;
#043 MsgFilterMax = 0;
#044 }
#045
循环地获取消息,直到成功为止。
#046 do
#047 {
这里调用函数co_IntPeekMessage来查看消息队列是否有消息。
#048 GotMessage = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
#049 if (GotMessage)
#050 {
如果获取消息成功。
#051 Info.Msg = Msg.Msg;
#052 /* See if this message type is present in the table */
查找消息是否在消息表里,如果不在里面不需要分配消息保存的内存,否则就需要给消息分配内存。
#053 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
#054 if (NULL == MsgMemoryEntry)
#055 {
#056 /* Not present, no copying needed */
#057 Info.LParamSize = 0;
#058 }
#059 else
#060 {
检测消息所需要内存的大小。
#061 /* Determine required size */
#062 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
#063 Info.Msg.lParam);
#064 /* Allocate required amount of user-mode memory */
#065 Info.LParamSize = Size;
#066 UserMem = NULL;
给用户分配消息占用的内存。
#067 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
#068 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
#069
#070 if (! NT_SUCCESS(Status))
#071 {
#072 SetLastNtError(Status);
#073 RETURN( (BOOL) -1);
#074 }
#075 /* Transfer lParam data to user-mode mem */
把消息拷贝到用户空间的内存。
#076 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
#077 if (! NT_SUCCESS(Status))
#078 {
#079 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
#080 &Info.LParamSize, MEM_DECOMMIT);
#081 SetLastNtError(Status);
#082 RETURN( (BOOL) -1);
#083 }
#084 Info.Msg.lParam = (LPARAM) UserMem;
#085 }
#086 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
#087 {
#088 ExFreePool((void *) Msg.Msg.lParam);
#089 }
#090 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
#091 if (! NT_SUCCESS(Status))
#092 {
#093 SetLastNtError(Status);
#094 RETURN( (BOOL) -1);
#095 }
#096 }
在这里调用co_IntWaitMessage函数继续等到窗口出现消息。
#097 else if (! co_IntWaitMessage(hWnd, MsgFilterMin, MsgFilterMax))
#098 {
#099 RETURN( (BOOL) -1);
#100 }
#101 }
#102 while (! GotMessage);
#103
如果消息不等于退出消息,就返回TRUE,否则返回FALSE,也就是0值。
#104 RETURN( WM_QUIT != Info.Msg.message);
#105
#106 CLEANUP:
#107 // if (Window) UserDerefObjectCo(Window);
#108
#109 DPRINT("Leave NtUserGetMessage/n");
#110 UserLeave();
#111 END_CLEANUP;
#112 }