$GetMessage-PeekMessage-SendMessage内核解析


    忙公司项目(毕设吧)发现长时间没总结该换换脑子
    什没SendThreadMessage呢?问题时实现程序逻辑中具体场景中样初学者说喜欢通windwos消息机制完成UI线程worker线程间步通信号量做问题直困惑久现搞明白
    google问题牛(Raymond Chen)httpblogsmsdncomboldnewthingarchive200812239248851aspx)博客中提引发讨里简单翻译Raymond Chen法
    想象中SendThreadMessage工作呢?调SendMessage 消息直接分发窗口程?没消息泵想象中SendThreadMessage会消息分发谁呢?没thread window procedure’样东东处理消息
    线程中做消息泵想象中SendThreadMessage需等消息处理完毕够知道消息处理完毕?等DispatchMessage返回DispatchMessage失败知道应该窗口分发消息window manager线程发送消息仅已
    会认等知道GetMessage or PeekMessage样确定消息解决保证消息检索函数(GetMessage PeekMessage)前消息泵线程消息启动模态窗口消息检索函数告诉消息已处理完毕事实模态窗口创建消息泵
    段然长头GetMessage   DispatchMessage2基函数天天行知甚少算第次写HelloWorld 现少1年然朦胧感十分惭愧篇总结做确庞工程解2函数需握windows消息机制windwos 没源代码参考里参考ReactOS实现然windows正统应该差远少win2003相似开始步入正题
    首先需解UI线程 普通Worker线程间区什
    msdn httpmsdnmicrosoftcomenuslibraryms644927提:
    To avoid the overhead of creating a message queue for non–GUI threads all threads are created initially without a message queue The system creates a threadspecific message queue only when the thread makes its first call to one of the specific user functions no GUI function calls result in the creation of a message queue
    然系统创建线程时普通non–GUI thread直GDI User函数调线程创建消息队列函数调开始
    windwos开始时linux样 图形部分户空间中进程负责面减少进程间环境切换放入核中系统调层2种情况种调原核调种新加进原户空间调部分称扩充系统调部分代码放动态安装模块win32ksys应系统调表2包括前核系统调前基础增加图形图系统调系统调发现扩充系统调时原表满足求windwos会会扩充系统调表装载win32ksys模块普普通通线程开始变GUI线程
    激动心旅程里开始
    开源代码意够贴出
    NTSTATUS
    NTAPI
    PsConvertToGuiThread(VOID)
    {
    ULONG_PTR NewStack
    PVOID OldStack
    PETHREAD Thread PsGetCurrentThread()
    PEPROCESS Process PsGetCurrentProcess()
    NTSTATUS Status
    PAGED_CODE()

    * Validate the previous mode *
    if (KeGetPreviousMode() KernelMode) return STATUS_INVALID_PARAMETER

    * If no win32k crashes later *
    ASSERT(PspW32ProcessCallout NULL)

    * Make sure win32k is here *
    if (PspW32ProcessCallout) return STATUS_ACCESS_DENIED

    * Make sure it's not already win32 *
    if (Thread>TcbServiceTable KeServiceDescriptorTable)
    {
    * We're already a win32 thread *
    return STATUS_ALREADY_WIN32
    }

    * Check if we don't already have a kernelmode stack *
    if (Thread>TcbLargeStack)
    {
    * We don't create one *
    NewStack (ULONG_PTR)MmCreateKernelStack(TRUE 0)
    if (NewStack)
    {
    * Panic in usermode *
    NtCurrentTeb()>LastErrorValue ERROR_NOT_ENOUGH_MEMORY
    return STATUS_NO_MEMORY
    }

    * We're about to switch stacks Enter a guarded region *
    KeEnterGuardedRegion()

    * Switch stacks *
    OldStack KeSwitchKernelStack((PVOID)NewStack
    (PVOID)(NewStack KERNEL_STACK_SIZE))

    * Leave the guarded region *
    KeLeaveGuardedRegion()

    * Delete the old stack *
    MmDeleteKernelStack(OldStack FALSE)
    }

    * This check is bizare Check out win32k later *
    if (Process>Win32Process)
    {
    * Now tell win32k about us *
    Status PspW32ProcessCallout(Process TRUE)
    if (NT_SUCCESS(Status)) return Status
    }

    * Set the new service table *
    Thread>TcbServiceTable KeServiceDescriptorTableShadow
    ASSERT(Thread>TcbWin32Thread 0)

    * Tell Win32k about our thread *
    Status PspW32ThreadCallout(Thread PsW32ThreadCalloutInitialize)
    if (NT_SUCCESS(Status))
    {
    * Revert our table *
    Thread>TcbServiceTable KeServiceDescriptorTable
    }

    * Return status *
    return Status
    }

    前没提里判断线程system stackGUI线程普通线程增加更嵌套调需更system stackMmCreateKernelStack分配空间函数里分配64K普通thread system stack12K然惯例里64K堆栈提交中12K设置guard page超12K产生异常然分配空间进程果线程GUI线程进程GUI 进程果GUI进程然先进程转PspW32ProcessCallout函数指针指Win32kProcessCallback里干会初始化系列结构体键盘格式GDI 句柄表等等里略细节
    系统ServiceTable换成表PspW32ThreadCallout指Win32kThreadCallback里完成普通线程转换成GUI线程程操作系统复杂东东说初始化结构体真茫茫里关注点Win32kThreadCallback中找创建消息队列入口Win32Thread>MessageQueue MsqCreateMessageQueue(Thread)
    系统消息队列构成真正win32应程序开发者需窗口程序中构造简单Message DumpGetMessage底做什
    GetMessage会调NtUserGetMessage
    BOOL APIENTRY
    NtUserGetMessage(PMSG pMsg
    HWND hWnd
    UINT MsgFilterMin
    UINT MsgFilterMax )
    {
    MSG Msg
    BOOL Ret

    if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
    {
    EngSetLastError(ERROR_INVALID_PARAMETER)
    return FALSE
    }

    UserEnterExclusive()

    RtlZeroMemory(&Msg sizeof(MSG))

    Ret co_IntGetPeekMessage(&Msg hWnd MsgFilterMin MsgFilterMax PM_REMOVE TRUE)

    UserLeave()

    if (Ret)
    {
    _SEH2_TRY
    {
    ProbeForWrite(pMsg sizeof(MSG) 1)
    RtlCopyMemory(pMsg &Msg sizeof(MSG))
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
    SetLastNtError(_SEH2_GetExceptionCode())
    Ret FALSE
    }
    _SEH2_END
    }

    return Ret
    }

    原谅略茫茫细节
    BOOL FASTCALL
    co_IntGetPeekMessage( PMSG pMsg
    HWND hWnd
    UINT MsgFilterMin
    UINT MsgFilterMax
    UINT RemoveMsg
    BOOL bGMSG )
    {

    do
    {
    Present co_IntPeekMessage( pMsg
    Window
    MsgFilterMin
    MsgFilterMax
    RemoveMsg
    bGMSG )
    if (Present)
    {
    * GetMessage or PostMessage must never get messages that contain pointers *
    ASSERT(FindMsgMemory(pMsg>message) NULL)

    if (pMsg>message WM_PAINT && pMsg>message WM_QUIT)
    {
    pti>timeLast pMsg>time
    pti>ptLast pMsg>pt
    }

    The WH_GETMESSAGE hook enables an application to monitor messages about to
    be returned by the GetMessage or PeekMessage function

    co_HOOK_CallHooks( WH_GETMESSAGE HC_ACTION RemoveMsg & PM_REMOVE (LPARAM)pMsg)

    if ( bGMSG )
    {
    Present (WM_QUIT pMsg>message)
    break
    }
    }

    if ( bGMSG )
    {
    if ( co_IntWaitMessage(Window MsgFilterMin MsgFilterMax) )
    {
    Present 1
    break
    }
    }
    else
    {
    if ((RemoveMsg & PM_NOYIELD))
    {
    IdlePing()
    Yield this thread
    UserLeave()
    ZwYieldExecution()
    UserEnterExclusive()
    Fall through to exit
    IdlePong()
    }
    break
    }
    }
    while( bGMSG && Present )

    Been spinning time to swap vinyl
    if (pti>pClientInfo>cSpins > 100)
    {
    Clear the spin cycle to fix the mix
    pti>pClientInfo>cSpins 0
    if ((pti>TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl
    }
    return Present
    }

    IntGetPeekMessage循环断调co_IntPeekMessage 消息队列中取出消息果没消息调co_IntWaitMessage等消息然复非遇WM_QUIT
    co_IntPeekMessage 实现关键PeekMessage关键部分样略繁琐细节然指重实太函数整消息机制核心部分需慢慢
    说知道消息队列啥模样
    typedef struct _USER_MESSAGE_QUEUE
    {
    * Reference counter only access this variable with interlocked functions *
    LONG References

    * Owner of the message queue *
    struct _ETHREAD *Thread
    * Queue of messages sent to the queue *
    LIST_ENTRY SentMessagesListHead 发送消息队列
    * Queue of messages posted to the queue *
    LIST_ENTRY PostedMessagesListHead Post消息队列
    * Queue for hardware messages for the queue *
    LIST_ENTRY HardwareMessagesListHead 硬件消息队列



    * messages that are currently dispatched by other threads *
    LIST_ENTRY DispatchingMessagesHead 已发送方尚未处理消息队列
    * messages that are currently dispatched by this message queue required for cleanup *
    LIST_ENTRY LocalDispatchingMessagesHead 正分发消息队列



    } USER_MESSAGE_QUEUE *PUSER_MESSAGE_QUEUE
    SentMessagesListHead 队列东西发送消息队列消息 方调SendMessage消息队列时消息会放队列中
    PostedMessagesListHead 理方调PostMessage然消息放队列中
    PostMessage函数较容易实现需挂目标PostedMessagesListHead队列中SendMessage复杂
    果发送方接收方线程中SendMessage会直接调窗口窗口程函数处理消息
    果发送方接收方线程中发送方必须等接收方运行结果继续执行形成感觉步程感觉似复杂简单线程步问题
    想问题GUI线程AGUI线程B发送消息时线程B处理A消息时需线程A发送消息2线程会死锁? 然会知道windwos搞套构造完整消息驱动机制更抽象讲消息机制算线程通信机制套东东复杂东东需户程序结合起真正运行起说应程序必须符合windwos程序规范windwos消息机制参起参中重东东前提GetMessageDispatchingMessagesHead LocalDispatchingMessagesHead 实现套机制中非常重部分
    DispatchingMessagesHead  SendMessage方时消息需等面结果需等消息放置里里会windwos菜鸟觉困惑困惑什够形成队列呢?里先问题留
    站接受者消息队列角度SendMessage需里处理Message Dispatch搞出消息返回值时接受方必须等面消息返回值走消息算搞定里线程甚进程间数传递东西必须考虑消息放里呢?LocalDispatchingMessagesHead 跳出解决问题
    总说SendMessage消息时会挂接收方SentMessagesListHead队列中挂发送方DispatchingMessagesHead
    接受方先查SentMessagesListHead 否消息话SendMessageListHead中删掉添加LocalDispatchingMessagesHead队列中等消息处理完毕LocalDispatchingMessagesHead消息删
    首先关注4队列硬件队列鼠标键盘东东
    第次点晕急笼统概念细节部分非常复杂
    *
    * Internal version of PeekMessage() doing all the work
    *
    BOOL FASTCALL
    co_IntPeekMessage( PMSG Msg
    PWND Window
    UINT MsgFilterMin
    UINT MsgFilterMax
    UINT RemoveMsg
    BOOL bGMSG )
    {

    do
    {

    * Dispatch sent messages here *
    while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
    {

    }



    * Now check for normal messages *
    if ((ProcessMask & QS_POSTMESSAGE) &&
    MsqPeekMessage( ThreadQueue
    RemoveMessages
    Window
    MsgFilterMin
    MsgFilterMax
    ProcessMask
    Msg ))
    {
    return TRUE
    }

    * Now look for a quit message *
    if (ThreadQueue>QuitPosted)
    {
    * According to the PSDK WM_QUIT messages are always returned regardless
    of the filter specified *
    Msg>hwnd NULL
    Msg>message WM_QUIT
    Msg>wParam ThreadQueue>QuitExitCode
    Msg>lParam 0
    if (RemoveMessages)
    {
    ThreadQueue>QuitPosted FALSE
    ClearMsgBitsMask(ThreadQueue QS_POSTMESSAGE)
    pti>pcti>fsWakeBits & ~QS_ALLPOSTMESSAGE
    pti>pcti>fsChangeBits & ~QS_ALLPOSTMESSAGE
    }
    return TRUE
    }

    * Check for hardware events *
    if ((ProcessMask & QS_MOUSE) &&
    co_MsqPeekMouseMove( ThreadQueue
    RemoveMessages
    Window
    MsgFilterMin
    MsgFilterMax
    Msg ))
    {
    return TRUE
    }

    if ((ProcessMask & QS_INPUT) &&
    co_MsqPeekHardwareMessage( ThreadQueue
    RemoveMessages
    Window
    MsgFilterMin
    MsgFilterMax
    ProcessMask
    Msg))
    {
    return TRUE
    }

    * Check for sent messages again *
    while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
    {
    if (HIWORD(RemoveMsg) && bGMSG) Hit TRUE
    }
    if (Hit) return FALSE

    * Check for paint messages *
    if ((ProcessMask & QS_PAINT) &&
    pti>cPaintsReady &&
    IntGetPaintMessage( Window
    MsgFilterMin
    MsgFilterMax
    pti
    Msg
    RemoveMessages))
    {
    return TRUE
    }

    * This is correct check for the current threads timers waiting to be
    posted to this threads message queue If any we loop again
    *
    if ((ProcessMask & QS_TIMER) &&
    PostTimerMessages(Window))
    {
    continue
    }

    return FALSE
    }
    while (TRUE)

    return TRUE
    }

    co_MsqDispatchOneSentMessage 里做SendMessageListHead 中取出SendMessage里消息 SendMessage消息处理完跳出循环MsqPeekMessage 搞定PostMessage消息次检查次co_MsqDispatchOneSentMessage没发送SendMessage消息间间隔新SendMessage消息然IntGetPaintMessage PostTimerMessages名字容易理解里出消息优先级提高Paint效率Paint统处理Timer消息事实出优先级低Paint样timer中绘制函数次处理timer前够保证Paint消息已处理出timer确准前面太东西做
    需解消息结构Post消息挂队列中
    typedef struct _USER_MESSAGE
    {
    LIST_ENTRY ListEntry
    MSG Msg
    DWORD QS_Flags
    } USER_MESSAGE *PUSER_MESSAGE
    Send消息里麻烦
    typedef struct _USER_SENT_MESSAGE
    {
    LIST_ENTRY ListEntry 接受方队列
    MSG Msg
    DWORD QS_Flags Original QS bits used to create this message
    PKEVENT CompletionEvent 做线程唤醒操作
    LRESULT* Result
    LRESULT lResult
    struct _USER_MESSAGE_QUEUE* SenderQueue
    struct _USER_MESSAGE_QUEUE* CallBackSenderQueue
    SENDASYNCPROC CompletionCallback
    ULONG_PTR CompletionCallbackContext
    * entry in the dispatching list of the sender's message queue *
    LIST_ENTRY DispatchingListEntry 发送方DispatchingMessageList
    INT HookMessage
    BOOL HasPackedLParam
    } USER_SENT_MESSAGE *PUSER_SENT_MESSAGE
    家伙真正挂发送队列中数结构MSG中数成员里前提消息2队列中存边发送方DispatchingMessageList表示消息正分发边接受方SentMessagesListHead表示消息发送等处理
    co_MsqDispatchOneSentMessage究竟
    BOOLEAN FASTCALL
    co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
    {
    PUSER_SENT_MESSAGE SaveMsg Message
    PLIST_ENTRY Entry
    LRESULT Result
    PTHREADINFO pti

    if (IsListEmpty(&MessageQueue>SentMessagesListHead))
    {
    return(FALSE)
    }

    * remove it from the list of pending messages *
    Entry RemoveHeadList(&MessageQueue>SentMessagesListHead)
    Message CONTAINING_RECORD(Entry USER_SENT_MESSAGE ListEntry)

    pti MessageQueue>Thread>TcbWin32Thread

    SaveMsg pti>pusmCurrent
    pti>pusmCurrent Message

    Processing a message sent to it from another thread
    if ( ( Message>SenderQueue && MessageQueue Message>SenderQueue) ||
    ( Message>CallBackSenderQueue && MessageQueue Message>CallBackSenderQueue ))
    { most likely but to be sure
    pti>pcti>CTI_flags | CTI_INSENDMESSAGE Let the user know
    }

    * insert it to the list of messages that are currently dispatched by this
    message queue *
    InsertTailList(&MessageQueue>LocalDispatchingMessagesHead
    &Message>ListEntry)

    ClearMsgBitsMask(MessageQueue Message>QS_Flags)

    if (Message>HookMessage MSQ_ISHOOK)
    { Direct Hook Call processor
    Result co_CallHook( Message>Msgmessage HookId
    (INT)(INT_PTR)Message>Msghwnd Code
    Message>MsgwParam
    Message>MsglParam)
    }
    else if (Message>HookMessage MSQ_ISEVENT)
    { Direct Event Call processor
    Result co_EVENT_CallEvents( Message>Msgmessage
    Message>Msghwnd
    Message>MsgwParam
    Message>MsglParam)
    }
    else
    { * Call the window procedure *
    Result co_IntSendMessage( Message>Msghwnd
    Message>Msgmessage
    Message>MsgwParam
    Message>MsglParam)
    }

    * remove the message from the local dispatching list because it doesn't need
    to be cleaned up on thread termination anymore *
    RemoveEntryList(&Message>ListEntry)

    * remove the message from the dispatching list if needed so lock the sender's message queue *
    if ((Message>HookMessage & MSQ_SENTNOWAIT))
    {
    if (Message>DispatchingListEntryFlink NULL)
    {
    * only remove it from the dispatching list if not already removed by a timeout *
    RemoveEntryList(&Message>DispatchingListEntry)
    }
    }
    * still keep the sender's message queue locked so the sender can't exit the
    MsqSendMessage() function (if timed out) *

    if (Message>QS_Flags & QS_SMRESULT)
    {
    Result Message>lResult
    }

    * Let the sender know the result *
    if (Message>Result NULL)
    {
    *Message>Result Result
    }

    if (Message>HasPackedLParam TRUE)
    {
    if (Message>MsglParam)
    ExFreePool((PVOID)Message>MsglParam)
    }

    * Notify the sender *
    if (Message>CompletionEvent NULL)
    {
    KeSetEvent(Message>CompletionEvent IO_NO_INCREMENT FALSE)
    }

    * Call the callback if the message was sent with SendMessageCallback *
    if (Message>CompletionCallback NULL)
    {
    co_IntCallSentMessageCallback(Message>CompletionCallback
    Message>Msghwnd
    Message>Msgmessage
    Message>CompletionCallbackContext
    Result)
    }

    * Only if it is not a no wait message *
    if ((Message>HookMessage & MSQ_SENTNOWAIT))
    {
    IntDereferenceMessageQueue(Message>SenderQueue)
    IntDereferenceMessageQueue(MessageQueue)
    }

    * free the message *
    ExFreePoolWithTag(Message TAG_USRMSG)

    * do not hangup on the user if this is reentering *
    if (SaveMsg) pti>pcti>CTI_flags & ~CTI_INSENDMESSAGE
    pti>pusmCurrent SaveMsg

    return(TRUE)
    }

    首先SentMessagesListHead消息移动LocalDispatchingMessagesHead略掉细节标志位hook部分co_IntSendMessage消息发送出然结果然消息接收方LocalDispatchingMessagesHead删掉果发送方等消息发送方DispatchingMessagesHead中删掉条消息(消息时间限制已早DispatchingMessagesHead删掉)然返回结果保存起然消息附件资源需释放里消息里赘述关心然通Message>CompletionEvent通知发送方该醒果消息回调函数里没直接调回调函数通消息机制发送消息(Post队列中)确容易理解MSDN相关意思时候真MS文档什全源代码源代码需详细文档?文档真彻底说清楚
    转远问题迭代co_IntSendMessage co_IntSendMessage 实co_IntSendMessageTimeout 特殊调
    LRESULT FASTCALL
    co_IntSendMessageTimeout( HWND hWnd
    UINT Msg
    WPARAM wParam
    LPARAM lParam
    UINT uFlags
    UINT uTimeout
    ULONG_PTR *uResult )
    {
    PWND DesktopWindow
    HWND *Children
    HWND *Child

    if (HWND_BROADCAST hWnd)
    {
    return co_IntSendMessageTimeoutSingle(hWnd Msg wParam lParam uFlags uTimeout uResult)
    }

    DesktopWindow UserGetWindowObject(IntGetDesktopWindow())
    if (NULL DesktopWindow)
    {
    EngSetLastError(ERROR_INTERNAL_ERROR)
    return 0
    }

    * Send message to the desktop window too *
    co_IntSendMessageTimeoutSingle(DesktopWindow>headh Msg wParam lParam uFlags uTimeout uResult)

    Children IntWinListChildren(DesktopWindow)
    if (NULL Children)
    {
    return 0
    }

    for (Child Children NULL *Child Child++)
    {
    co_IntSendMessageTimeoutSingle(*Child Msg wParam lParam uFlags uTimeout uResult)
    }

    ExFreePool(Children)

    return (LRESULT) TRUE
    }

    考虑广播情况简单单窗口发送消息co_IntSendMessageTimeoutSingle
    static LRESULT FASTCALL
    co_IntSendMessageTimeoutSingle( HWND hWnd
    UINT Msg
    WPARAM wParam
    LPARAM lParam
    UINT uFlags
    UINT uTimeout
    ULONG_PTR *uResult )
    {
    NTSTATUS Status
    PWND Window NULL
    PMSGMEMORY MsgMemoryEntry
    INT lParamBufferSize
    LPARAM lParamPacked
    PTHREADINFO Win32Thread
    ULONG_PTR Result 0
    DECLARE_RETURN(LRESULT)
    USER_REFERENCE_ENTRY Ref

    if ((Window UserGetWindowObject(hWnd)))
    {
    RETURN( FALSE)
    }

    UserRefObjectCo(Window &Ref)

    Win32Thread PsGetCurrentThreadWin32Thread()

    IntCallWndProc( Window hWnd Msg wParam lParam)

    if ( NULL Win32Thread &&
    Window>headpti>MessageQueue Win32Thread>MessageQueue)
    {
    线程消息直接调户窗口回调函数终结束
    Result (ULONG_PTR)co_IntCallWindowProc( Window>lpfnWndProc
    Window>Unicode
    hWnd
    Msg
    wParam
    lParamPacked
    lParamBufferSize )
    if(uResult)
    {
    *uResult Result
    }

    ObDereferenceObject(Win32Thread>pEThread)

    IntCallWndProcRet( Window hWnd Msg wParam lParam (LRESULT *)uResult)

    if ( NT_SUCCESS(UnpackParam(lParamPacked Msg wParam lParam FALSE)))
    {
    DPRINT1(Failed to unpack message parameters\n)
    RETURN( TRUE)
    }

    RETURN( TRUE)
    }

    线程转发消息

    do
    {
    Status co_MsqSendMessage( Window>headpti>MessageQueue
    hWnd
    Msg
    wParam
    lParam
    uTimeout
    (uFlags & SMTO_BLOCK)
    MSQ_NORMAL
    uResult )
    }
    while ((STATUS_TIMEOUT Status) &&
    (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
    MsqIsHung(Window>headpti>MessageQueue))

    IntCallWndProcRet( Window hWnd Msg wParam lParam (LRESULT *)uResult)

    if (STATUS_TIMEOUT Status)
    {
    *
    MSDN says
    Microsoft Windows 2000 If GetLastError returns zero then the function
    timed out
    XP+ If the function fails or times out the return value is zero
    To get extended error information call GetLastError If GetLastError
    returns ERROR_TIMEOUT then the function timed out
    *
    EngSetLastError(ERROR_TIMEOUT)
    RETURN( FALSE)
    }
    else if ( NT_SUCCESS(Status))
    {
    SetLastNtError(Status)
    RETURN( FALSE)
    }

    RETURN( TRUE)

    CLEANUP
    if (Window) UserDerefObjectCo(Window)
    END_CLEANUP
    }

    里终结果然里带出问题系统调写函数呢?什时候调?通什方式?样特第次写windwos程序菜鸟遇第问题问题说清楚挺麻烦部分里先留
    脑堆栈弹开始
    问题系统调写函数呢?什时候调?通什方式?现回答问题回答系统什时候调窗口程函数
    调系统代码说调系统服务API等什通中断机制完成通查找系统调表找相应系统函数时利中断机制执行系统代码(然限制)系统时执行户空间代码?点难思考复杂机制做类似工作思考中种调窗口程函数
    容易想时执行户代码难没硬件支持完成类似中断机制系统特定方机会执行窗口程函数显然GetMessage执行户窗口程函数方户程序处理消息时系统没办法作等户次调GetMessage类似函数重新获代码控制co_IntPeekMessage中出端倪果消息队列中没消息GetMessage会退出执行权户代码进入等状态果时SendMessage消息线程会唤醒执行代码非Post消息会GetMessage返回户空间
    换句话果Sendmessage发线程GetMessage函数部执行果接收方线程阻塞SendMessage会返回没执行GetMessage
    思考问题Sendmessage线程线程没执行GetMessage执行代码线程起显然挂起等?接受线程发送消息显然处理处理前讨种情况确意思windwos角度需实现种强壮消息机制什程呢?清楚点实需种机制等方线程处理完毕前处理发消息哈哈WaitForMultipleObjects等2event等处理完毕消息等sendmessage新消息醒时判断什清醒果面线程力继续循环等sendmessage程
    NTSTATUS FASTCALL
    co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
    HWND Wnd UINT Msg WPARAM wParam LPARAM lParam
    UINT uTimeout BOOL Block INT HookMessage
    ULONG_PTR *uResult)
    {
    PTHREADINFO pti
    PUSER_SENT_MESSAGE Message
    KEVENT CompletionEvent
    NTSTATUS WaitStatus
    PUSER_MESSAGE_QUEUE ThreadQueue
    LARGE_INTEGER Timeout
    PLIST_ENTRY Entry
    LRESULT Result 0 Result could be trashed

    if((Message ExAllocatePoolWithTag(PagedPool sizeof(USER_SENT_MESSAGE) TAG_USRMSG)))
    {
    DPRINT1(MsqSendMessage() Not enough memory to allocate a message)
    return STATUS_INSUFFICIENT_RESOURCES
    }

    KeInitializeEvent(&CompletionEvent NotificationEvent FALSE)

    pti PsGetCurrentThreadWin32Thread()
    ThreadQueue pti>MessageQueue
    ASSERT(ThreadQueue MessageQueue)

    TimeoutQuadPart (LONGLONG) uTimeout * (LONGLONG) 10000

    * FIXME increase reference counter of sender's message queue here *

    Message>Msghwnd Wnd
    Message>Msgmessage Msg
    Message>MsgwParam wParam
    Message>MsglParam lParam
    Message>CompletionEvent &CompletionEvent
    Message>Result &Result
    Message>lResult 0
    Message>QS_Flags 0
    Message>SenderQueue ThreadQueue
    Message>CallBackSenderQueue NULL
    IntReferenceMessageQueue(ThreadQueue)
    Message>CompletionCallback NULL
    Message>CompletionCallbackContext 0
    Message>HookMessage HookMessage
    Message>HasPackedLParam FALSE

    IntReferenceMessageQueue(MessageQueue)

    * add it to the list of pending messages *
    InsertTailList(&ThreadQueue>DispatchingMessagesHead &Message>DispatchingListEntry)

    * queue it in the destination's message queue *
    InsertTailList(&MessageQueue>SentMessagesListHead &Message>ListEntry)

    Message>QS_Flags QS_SENDMESSAGE
    MsqWakeQueue(MessageQueue QS_SENDMESSAGE TRUE)

    * we can't access the Message anymore since it could have already been deleted *

    if(Block)
    {
    绝部分阻塞
    }
    else
    {
    PVOID WaitObjects[2]

    WaitObjects[0] &CompletionEvent
    WaitObjects[1] ThreadQueue>NewMessages
    do
    {
    UserLeaveCo()

    WaitStatus KeWaitForMultipleObjects(2 WaitObjects WaitAny UserRequest
    UserMode FALSE (uTimeout &Timeout NULL) NULL)

    UserEnterCo()

    if(WaitStatus STATUS_TIMEOUT)
    {

    }
    while (co_MsqDispatchOneSentMessage(ThreadQueue))

    }
    while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 WaitStatus)
    }

    if(WaitStatus STATUS_TIMEOUT)
    *uResult (STATUS_WAIT_0 WaitStatus Result 1)

    return WaitStatus
    }

    GetMessage返回般跑2函数
    TranslateMessage(&msg) 
    DispatchMessage(&msg)
    里讨TranslateMessage辅助硬件消息相关
    DispatchMessage事情做调相窗口程部分部分系统调代码目前没什兴趣
    类似模态窗口产生模态窗口窗口会阻塞消息阻塞消息线程然发SendMessage什呢?间会联系?



    Win32k(2) 报文驱动通信机制
    .应层api
    int APIENTRY _tWinMain(HINSTANCE hInstance
                         HINSTANCE hPrevInstance
                         LPTSTR    lpCmdLine
    intnCmdShow)
    {
        WNDCLASSEXwcex
        wcexlpfnWndProc  WndProc
        wcexcbClsExtra      0
    RegisterClassEx(&wcex)
     
        hWnd CreateWindow(szWindowClass szTitle WS_OVERLAPPEDWINDOWCW_USEDEFAULT 0CW_USEDEFAULT 0 NULL NULL hInstance NULL)
     
        while(GetMessage(&msg NULL 0 0))NtUserGetMessage
        {
    NtUserGetMessage目循环获取普通报文
    循环中会检查发送报文方sendmessage会NtUserGetMessage部直接调wndproc立响应
    果没普通报文(post 硬件报文定时器报文等)睡眠循环等
           if(TranslateAccelerator(msghwnd hAccelTable &msg))
           {
               TranslateMessage(&msg)键盘扫描码变成unicode
               DispatchMessage(&msg)wndproc调
           }
        }
     
    然WndProc函数中调SendMessagePostQuitMessage等等函数
     
    应层消息结构
    struct MSG
    {
       HWND hwnd
       UINT message
       WPARAM wParam
       LPARAM lParam
       DWORD time
       POINT pt
    }
     
    二.创建窗口NtUserCreateWindowEx
    控件什算window
    创建窗口应window_object返回句柄
    Window_object里面包含许字段里面户填充WndProc址消息队列结构

    三接收报文NtUserGetMessage
     
    根HWNDhWnd全局句柄表中找窗口
     
    关注co_IntPeekMessage调w32thread里面拆取消息队列中消息
    Win
    typedefstruct _tagTHREADINFO           156 elements 0x208 bytes (sizeof)
    {
    *0x0BC*     struct _tagQ* pq input queue
    *0x0E0*     struct _tagSMS* psmsSent send queue (sent)
    *0x0E4*     struct _tagSMS* psmsCurrent send queue (current)
    *0x0E8*     struct _tagSMS* psmsReceiveList send queue (received)
    *0x174*     struct _tagMLISTmlPost post queue
    } tagTHREADINFO *PtagTHREADINFO
     
    Ros
    typedefstruct_USER_MESSAGE_QUEUE
    {
    * Reference counter only access this variable with interlocked functions *
    LONGReferences
    * Owner of the message queue *
    struct _ETHREAD *Thread
    * Queue of messages sent to the queue *
    LIST_ENTRYSentMessagesListHead
    * Queue of messages posted to the queue *
    LIST_ENTRYPostedMessagesListHead
    * Queue of sentmessage notifies for the queue *
    LIST_ENTRYNotifyMessagesListHead
    * Queue for hardware messages for the queue *
    LIST_ENTRYHardwareMessagesListHead
    * List of timers sorted on expiry time (earliest first) *
    LIST_ENTRYTimerListHead
     
    * messages that are currently dispatched by other threads *
    LIST_ENTRYDispatchingMessagesHead
    * messages that are currently dispatched by this message queue required for cleanup *
    LIST_ENTRYLocalDispatchingMessagesHead
     
    (1)获取send报文:
    步方式消息传递
     
    发送方消息挂入发送方DispatchingMessagesHead挂入接收方SentMessagesListHead等Message>CompletionEvent
     
    接收方SentMessagesListHead提出消息挂入LocalDispatchingMessagesHead调窗口wndproc者消息钩子完成摘Message>CompletionEvent通知发送方
    BOOLFASTCALL
    co_IntPeekMessage(PUSER_MESSAGEMsg
    PWINDOW_OBJECTWindow
    UINTMsgFilterMin
    UINTMsgFilterMax
    UINTRemoveMsg)
    {
     

    while (co_MsqDispatchOneSentMessage(ThreadQueue))

    句循环摘消息发送消息
     
    BOOLEAN FASTCALL
    co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
    {

     
    SentMessagesListHead中获取消息
       Entry RemoveHeadList(&MessageQueue>SentMessagesListHead)
       Message CONTAINING_RECORD(Entry USER_SENT_MESSAGE ListEntry)
     
    放入LocalDispatchingMessagesHead
    InsertTailList(&MessageQueue>LocalDispatchingMessagesHead
    &Message>ListEntry)
    消息钩子行处理
    if (Message>HookMessage MSQ_ISHOOK)
       {
          Result co_HOOK_CallHooks()

       }
    elseif (Message>HookMessage MSQ_ISEVENT)
       {
          Result co_EVENT_CallEvents()                                  
       }
    else
       {
    调应层窗口函数wndproc
            Result co_IntSendMessage()
       }
    已送达删
    RemoveEntryList(&Message>ListEntry)
     
    * remove the message from the dispatching list so lock the sender's message queue *
    SenderReturned (Message>DispatchingListEntryFlink NULL)
    if(SenderReturned)
       {
    DispatchingListEntry中移
    RemoveEntryList(&Message>DispatchingListEntry)
       }
    * Let the sender know the result *
    if (Message>Result NULL)
       {
    返回wndproc执行结果
          *Message>Result Result
       }
     
    * Notify the sender *
    if (Message>CompletionEvent NULL)
       {
    通知发送方唤醒
    KeSetEvent(Message>CompletionEvent IO_NO_INCREMENT FALSE)
       }
     
    方回调函数处理略
    * Notify the sender if they specified a callback *
    if (SenderReturned&& Message>CompletionCallback NULL)
       {

       }

    * free the message *
    ExFreePool(Message)
    return(TRUE)
    }
     
     
    里面co_IntSendMessage终调co_IntCallWindowProc
    调KeUserModeCallback(USER32_CALLBACK_WINDOWPROC返回r3
    处暂略
     
    (2)获取报文
     
    NtUserGetMessage co_IntPeekMessage    
     
     
     
    BOOLFASTCALL
    co_IntPeekMessage(PUSER_MESSAGEMsg
    PWINDOW_OBJECTWindow
    UINTMsgFilterMin
    UINTMsgFilterMax
    UINTRemoveMsg)
    {
     
    sent报文处理已分析
    while (co_MsqDispatchOneSentMessage(ThreadQueue))
    接报文伪代码
     
    般post报文
    * Now check for normal messages *
    Present co_MsqFindMessage(ThreadQueue
    if (Present)
    {
    gotoMessageFound
    }
    硬件报文
    * Check for hardware events *
    Present co_MsqFindMessage(ThreadQueue
    if (Present)
    {
    gotoMessageFound
    }
    次检查sent报文
    * Check for sent messages again *
    while (co_MsqDispatchOneSentMessage(ThreadQueue))
    paint报文
    * Check for paint messages *
    if (IntGetPaintMessage(Window MsgFilterMin MsgFilterMax pti &Msg>Msg RemoveMessages))
    {
    Msg>FreeLParam FALSE
    gotoMsgExit
    }
    定时器报文(包括鼠标)
    Present MsqGetTimerMessage(ThreadQueue Window MsgFilterMin MsgFilterMax
    &Msg>Msg RemoveMessages)
    if (Present)
    {
    Msg>FreeLParam FALSE
    gotoMessageFound
    }
     
    报文窗口程序发送鼠标键盘线程投递
     
     
    (3)DispatchMessage应NtUserDispatchMessage简单消息派发出调wndproc者hook
    四.发送视窗报文
    (1)Post message
    Post简单插入链表发送消息根Wnd找应window object然插入post链表时间通知消息
     
     
    NtUserPostMessage–UserPostMessage UserPostThreadMessage MsqPostMessage
     
    VOIDFASTCALL
    MsqPostMessage(PUSER_MESSAGE_QUEUEMessageQueue MSG* Msg BOOLEANFreeLParam
    DWORDMessageBits)
    {
    PUSER_MESSAGEMessage
     
    if((Message MsqCreateMessage(Msg FreeLParam)))
       {
    return
       }
    InsertTailList(&MessageQueue>PostedMessagesListHead
    &Message>ListEntry)
    MessageQueue>QueueBits | MessageBits
    MessageQueue>ChangedBits | MessageBits
    if (MessageQueue>WakeMask&MessageBits)
    KeSetEvent(MessageQueue>NewMessages IO_NO_INCREMENT FALSE)
    }
    (2)send message
    果身线程发送消息send直接回调线程wndproc
    否话调co_MsqSendMessage
     
    co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue接收方队列
                      HWND Wnd UINT Msg WPARAM wParam LPARAM lParam
                      UINT uTimeout BOOL Block INT HookMessage
                      ULONG_PTR *uResult)
    {
    ……
    if((Message ExAllocatePoolWithTag(PagedPool sizeof(USER_SENT_MESSAGE) TAG_USRMSG)))
    ……
     
    KeInitializeEvent(&CompletionEvent NotificationEvent FALSE)
     
    pti PsGetCurrentThreadWin32Thread()
    ThreadQueue pti>MessageQueue 发送方队列
     
    TimeoutQuadPart (LONGLONG) uTimeout * (LONGLONG) 10000
     
    ……初始化Message结构
     
    * 挂入两队列进程DispatchingListEntry方进程SentMessagesListHead*
    InsertTailList(&ThreadQueue>DispatchingMessagesHead &Message>DispatchingListEntry)
    InsertTailList(&MessageQueue>SentMessagesListHead &Message>ListEntry)
     
    ……果方正等报文唤醒
    if (MessageQueue>WakeMask&QS_SENDMESSAGE)
    KeSetEvent(MessageQueue>NewMessages IO_NO_INCREMENT FALSE)
     

    if(Block)阻塞方式单纯等消息完成事件CompletionEvent
       {
    ……
    * 等报文处理*
    WaitStatus KeWaitForSingleObject(&CompletionEvent UserRequest UserMode
                                             FALSE (uTimeout &Timeout NULL))
     
    ……
    超时话
    if(WaitStatus STATUS_TIMEOUT)
          {
    * 方sent链表里面消消息*
             Entry MessageQueue>SentMessagesListHeadFlink
    while (Entry &MessageQueue>SentMessagesListHead)
             {
    if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry USER_SENT_MESSAGE ListEntry)
                      Message)
                {
                   Message>CompletionEvent NULL
                   Message>Result NULL
    break
                }
                Entry Entry>Flink
             }
     
    *Dispatching消消息 *
             Entry ThreadQueue>DispatchingMessagesHeadFlink
    while (Entry &ThreadQueue>DispatchingMessagesHead)
             {
    if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry USER_SENT_MESSAGE DispatchingListEntry)
                      Message)
                {
                   Message>CompletionEvent NULL
                   Message>Result NULL
    RemoveEntryList(&Message>DispatchingListEntry)
                   Message>DispatchingListEntryFlink NULL
    break
                }
                Entry Entry>Flink
             }
          }
    里捎带脚吧发消息处理
    while (co_MsqDispatchOneSentMessage(ThreadQueue))
       }
    else非阻塞方式等消息完成事件CompletionEvent方报文贴时短暂唤醒处理
       {
     PVOID WaitObjects[2]
     
    WaitObjects[0] &CompletionEvent
    WaitObjects[1] ThreadQueue>NewMessages
    do
          {
    IdlePing()
     
    UserLeaveCo()
     
    WaitStatus KeWaitForMultipleObjects(2 WaitObjects WaitAny UserRequest
    UserMode FALSE (uTimeout &Timeout NULL) NULL)
     
    ……
    超时话面样移两链表中消息处理sent链表方发送消息
          }
    while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 WaitStatus) CompletionEvent满足等
       }
     
    if(WaitStatus STATUS_TIMEOUT)
          *uResult (STATUS_WAIT_0 WaitStatus Result 1)
     
    returnWaitStatus
    }

    文档香网(httpswwwxiangdangnet)户传

    《香当网》用户分享的内容,不代表《香当网》观点或立场,请自行判断内容的真实性和可靠性!
    该内容是文档的文本内容,更好的格式请下载文档

    下载文档到电脑,查找使用更方便

    文档的实际排版效果,会与网站的显示效果略有不同!!

    需要 10 香币 [ 分享文档获得香币 ]

    下载文档

    相关文档

    $windows内核情景分析学习笔记

    windows内核情景分析学习笔记6分类: windows MFC2010-10-19 11:37226人阅读评论(0)收藏举报1、用于数据存储的内存区间分类①全局数据所占空间。由编译器在编译...

    3年前   
    373    0

    2021年reactos仿windows系统内核源代码研究

    引导序号引导过程引导执行代码位数目标文件名称1.         主引导代码(Master Boot Record (MBR)code),主要寻找活动分区,然后读入引导扇区代码16位执行代码r...

    3个月前   
    182    0

    老党员发挥余热 提升偏坡文化内核

    “老主席,区委组织部到你家来采访了,请问你现在在家不?”,“我还在下院村参加老年协会活动,今天恐怕要忙到下午才能回来,你请他们明天来吧。”

    3年前   
    494    0

    有感于青啤集团总裁《把社会责任感纳入企业内核》

    有感于青啤集团总裁《把社会责任感纳入企业内核》提高企业社会责任感          —有感于青啤集团总裁《把社会责任感纳入企业内核》    “一个没有责任感的企业是不可能持续成长的,也不可能成...

    10年前   
    361    0

    常用成语解析

    常用成语汇编   A 黯然销魂:形容非常悲伤或愁苦。 安步当车:慢慢的步行,就当是坐车。 按部就班:按照一定的步骤、顺序进行。也指按老规矩办事,缺乏创新精神。 按图索骥:比喻按照线...

    10年前   
    8306    0

    解析项目管理

    解析项目管理文章来源:中国计算机用户 作者:北京中科项目管理研究所所长 席相霖提起项目管理,人们好像都能侃几句,可是要再多说几句,却又说不出个所以然。不过,尽管这样,人们对它的前景倒还是很看...

    10年前   
    486    0

    解析LG精神

    解析LG精神   韩国LG公司的企业徽标是一张象形的人脸。许多人说,它上面那一只张着一只闭着的眼代表乐观看世界;LG的人说,它象征着韩国人的生机活力。而对于在LG公司工作了36年的现任副会长卢...

    12年前   
    624    0

    合同效力解析

    论合同的效力   摘要 合同,从根本说体现着民事法律的精髓,体现着当事人通过自己的意思表示和行为,创建法律上的权利义务的自主权,从根本上说,合同制度是对当事人意志的尊重和对市场制度下分散...

    11年前   
    11307    0

    易经重要术语解析

    易经重要术语解析太极宇宙原始而混沌的状态太极,是原始,也是无穷,是宇宙原始而混沌的状态。大家知道,原始的数是一,《说文解字》中说:“惟初太极,道立于一,造分天地,化成万物。”可见太极既为初为一...

    10年前   
    668    0

    职代会报告解析

    职代会报告解析 公司“二届三次”职代会报告不仅对公司2011年的工作进行了科学、客观、系统的总结分析,而且对公司2012年的工作详细、科学的规划,是一篇全局性、战略性、指导性很强的报告,对于...

    10年前   
    9300    0

    精品解析:2024中考道德与法治真题(解析版)

    1. 2020年5月7日电,________已通过生态环境部组织的国家生态省建设试点验收,建成中国首个生态省。( )A. 浙江省 B. 江苏省 C. 山东省 D. 福建省【答案】A【解析】...

    10个月前   
    422    1

    精品解析:2023年 中考道德与法治真题(解析版)

    1. 中学生要把握机遇,从点滴做起,为实现远大理想( )A. 不懈努力 B. 听天由命 C. 拒绝帮助 D. 依赖父母【答案】A【解析】【详解】本题考查对实现梦想的认识和理解。

    10个月前   
    564    1

    2.2气温 同步练习(含解析)

    一、单选题1.2020年8月份杭州市某区气象台多次发布高温橙色预警信号:受副热带高压影响,预计我区部分地区的最高气温可达38C或以上,望各有关方面注意做好防暑降温工作。而该区的西天目山、清凉峰等...

    1年前   
    512    0

    2017年实习报告题目解析

    实习报告题目解析  一.从实习的工作内容出发。比如,某教育专业的学生到某学校实习,题目可以“化学教师实习报告”“英语教师实习报告”等等;某学生做咨询的实习,题目可以是“投资咨询实习报告”“法律...

    7年前   
    491    0

    促销深度解析

    促销深度解析中国营销传播网, 2004-12-10, 作者: 毛浓月, 访问人数: 341  不少企业只要销量一下滑,首先想到的对策就是举办促销活动。因为促销可以迅速见效应,可以造成一派繁荣的...

    11年前   
    507    0

    ADSS安装手册解析

    全介质自承式〔ADSS〕光缆安装培训手册四川汇源光通信四川汇源光通信目 录安装培训手册第一局部 光缆根底学问 1其次局部 ADSS 光缆安装 5第一章 根底学问 5第 1 节 光缆挂点的选择...

    1年前   
    251    0

    目标成本规划解析

    目标成本规划解析 本文深入分析了目标成本规划法所体现的战略性成本管理思想,认为目标成本规划的中心问题是如何设计和传递各种成本压力。本文的分析还表明,虽然邯钢经验与目标成本规划在某些...

    8年前   
    5938    0

    ITV故障处理解析

    ?ITV故障处理解析 1. 1. 网络侧故障:一  1.1303(本地网络未连接,请检查网线或ADSL MODEM状态)                         2.1305(1...

    9年前   
    8782    0

    HRBP的角色定位解析

    HR BP的角色定位解析朱帅标题起的有点吓人,谈不上解析,更多是这10年来HR转型过程中的一些体会,不知从标题的抓眼球功能上能帮我多挣点百度文库的经验值。选育用留,六大模块,谈到HR自然而然会...

    12年前   
    777    0

    中考真题解析 物理

    中考真题解析 物理

    4年前   
    1187    0

    文档贡献者

    奋斗不止500年

    贡献于2021-07-11

    下载需要 10 香币 [香币充值 ]
    亲,您也可以通过 分享原创文档 来获得香币奖励!
    下载文档

    该用户的其他文档