当前位置: 首页 > article >正文

xxxSendMessageBSM函数分析


BSM的意思:Broadcast Special Message
第一部分A:
//Broadcast Special Message Recipient list
#define BSM_ALLCOMPONENTS       0x00000000
#define BSM_VXDS                0x00000001
#define BSM_NETDRIVER           0x00000002
#define BSM_INSTALLABLEDRIVERS  0x00000004
#define BSM_APPLICATIONS        0x00000008
#define BSM_ALLDESKTOPS         0x00000010
#define BSM_COMPONENTS          0x0000000F     ;internal
#define BSM_VALID               0x0000001F     ;internal

//Broadcast Special Message Flags
#define BSF_QUERY               0x00000001
#define BSF_IGNORECURRENTTASK   0x00000002
#define BSF_FLUSHDISK           0x00000004
#define BSF_NOHANG              0x00000008
#define BSF_POSTMESSAGE         0x00000010
#define BSF_FORCEIFHUNG         0x00000020
#define BSF_NOTIMEOUTIFNOTHUNG  0x00000040
;begin_if_(_WIN32_WINNT)_500
#define BSF_ALLOWSFW            0x00000080
#define BSF_SENDNOTIFYMESSAGE   0x00000100
;end_if_(_WIN32_WINNT)_500
;begin_if_(_WIN32_WINNT)_501
#define BSF_RETURNHDESK         0x00000200
#define BSF_LUID                0x00000400
;end_if_(_WIN32_WINNT)_501
#define BSF_QUEUENOTIFYMESSAGE  0x20000000      ;internal
#define BSF_SYSTEMSHUTDOWN      0x40000000      ;internal
#define BSF_MSGSRV32OK          0x80000000      ;internal
#define BSF_VALID               0x000007FF      ;internal
;begin_internal
#define BSF_ASYNC               (BSF_POSTMESSAGE | BSF_SENDNOTIFYMESSAGE)
;end_internal

第一部分B:
typedef struct {
    DWORD dwRecipients;
    DWORD dwFlags;
    BSMINFO;
} BROADCASTSYSTEMMSGPARAMS, *LPBROADCASTSYSTEMMSGPARAMS;
第一部分C:
typedef struct tagWND               * KPTR_MODIFIER PWND;
typedef struct tagWND {
    THRDESKHEAD   head;

    WW;         // WOW-USER common fields. Defined in wowuserp.h
                // The presence of "state" at the start of this structure is
                // assumed by the STATEOFFSET macro.

    PWND                 spwndNext;    // Handle to the next window
    PWND                 spwndPrev;    // Handle to the previous window
    PWND                 spwndParent;  // Backpointer to the parent window.
    PWND                 spwndChild;   // Handle to child
    PWND                 spwndOwner;   // Popup window owner field

    RECT                 rcWindow;     // Window outer rectangle
    RECT                 rcClient;     // Client rectangle

    WNDPROC_PWND         lpfnWndProc;  // Can be WOW address or standard address

    PCLS                 pcls;         // Pointer to window class

    KHRGN                hrgnUpdate;   // Accumulated paint region

    PPROPLIST            ppropList;    // Pointer to property list
    PSBINFO              pSBInfo;      // Words used for scrolling

    PMENU                spmenuSys;    // Handle to system menu
    PMENU                spmenu;       // Menu handle or ID

    KHRGN                hrgnClip;     // Clipping region for this window

    LARGE_UNICODE_STRING strName;
    int                  cbwndExtra;   // Extra bytes in window
    PWND                 spwndLastActive; // Last active in owner/ownee list
    KHIMC                hImc;         // Associated input context handle
    KERNEL_ULONG_PTR     dwUserData;   // Reserved for random application data
    struct _ACTIVATION_CONTEXT  * KPTR_MODIFIER pActCtx;
} WND;


第二部分:
BOOL xxxSendBSMtoDesktop(
    PWND pwndDesk,
    UINT message,
    WPARAM wParam,
    LPARAM lParam,
    LPBROADCASTSYSTEMMSGPARAMS pbsmParams)
{
    PBWL pbwl;
    HWND *phwnd;
    PWND pwnd;
    TL tlpwnd;
    BOOL fReturnValue = TRUE;
    BOOL fFilterDriveMsg = FALSE;
    PTHREADINFO ptiCurrent = PtiCurrent();
    BOOL fPrivateMessage = (message >= WM_USER) && (message < MAXINTATOM);
    DEV_BROADCAST_VOLUME dbv;


    if (fPrivateMessage) {
        RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to broadcast a private message");
    }

    pbwl = BuildHwndList(pwndDesk->spwndChild, BWL_ENUMLIST, NULL);

    if (pbwl == NULL)
        return 0;

    if (!(pbsmParams->dwFlags & BSF_POSTMESSAGE)) {
        /*呼叫者想让接收者占据前台吗
在处理通知时?
         * Does the caller want to allow the receivers to take the foreground
         *  while processing the notification?
         */
        /*为了允许AppsHelp窗口进入
前台我们将ptiLastWoken设置为NULL,这将允许任何窗口
插入CD后,它会出现在前台。
         * Bug 412159. In order to allow the AppsHelp window to come to the
         * foreground we set ptiLastWoken to NULL, which will allow any window
         * to come to the foreground after a CD's been inserted.
         */
        if ((pbsmParams->dwFlags & BSF_ALLOWSFW) &&
           (GETPDESK(pwndDesk) == grpdeskRitInput) &&
           ((ptiCurrent->TIF_flags & TIF_CSRSSTHREAD)
            || CanForceForeground(ptiCurrent->ppi FG_HOOKLOCK_PARAM(ptiCurrent)))) {
             glinp.ptiLastWoken = NULL;
         }

    }

    /*
     * Determine if we need to filter the Drive Letter mask in fnINDEVICECHANGE
     * WM_DEVICECHANGE message are sent synchronously
     * LUID DosDevices maps must be enabled
     */
    if ((gLUIDDeviceMapsEnabled == TRUE) &&
        (message == WM_DEVICECHANGE) &&
        ((wParam == DBT_DEVICEREMOVECOMPLETE) || (wParam == DBT_DEVICEARRIVAL)) &&
        (((struct _DEV_BROADCAST_HEADER *)lParam)->dbcd_devicetype == DBT_DEVTYP_VOLUME)
        ) {
        LUID luidClient;
        NTSTATUS Status;

        if( ((DEV_BROADCAST_VOLUME *)lParam)->dbcv_unitmask & DBV_FILTER_MSG ) {
            return 0;
        }
        else {
            dbv = *((DEV_BROADCAST_VOLUME *)lParam);
            dbv.dbcv_unitmask |= DBV_FILTER_MSG;
        }

        /*
         * Caller must be LocalSystem and BSF_LUID is not specified
         */
        if (!(pbsmParams->dwFlags & BSF_LUID)) {
            Status = GetProcessLuid(NULL, &luidClient);
            if (NT_SUCCESS(Status) &&
                    RtlEqualLuid(&luidClient, &luidSystem)) {
                fFilterDriveMsg = TRUE;
            }
        }
    }

    for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
        BOOL UseFilterLparam = FALSE;

        /*确保这个hwnd还在
         * Make sure this hwnd is still around.
         */
        if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
            continue;

        if (pbsmParams->dwFlags &  BSF_IGNORECURRENTTASK) {
        // Don't deal with windows in the current task.不要在当前任务中处理窗口。
            if (GETPTI(pwnd)->pq == ptiCurrent->pq)
                continue;
        }

        if (pbsmParams->dwFlags &  BSF_LUID) {
            LUID luidWnd;

            luidWnd.LowPart = luidWnd.HighPart = 0;
            /*
             * Now we have the window Luid LuidWindow
             * Check to see if it is equal to the callers Luid or not
             */检查它是否等于呼叫者Luid
            if (!NT_SUCCESS(GetWindowLuid(pwnd, &luidWnd)) ||
                    !RtlEqualLuid(&pbsmParams->luid, &luidWnd)) {
                continue;
            }
        }

        if (fFilterDriveMsg == TRUE) {
            LUID luidWnd;

            if (!NT_SUCCESS(GetWindowLuid(pwnd, &luidWnd))) {
                continue;
            }

            /*由于LocalSystem使用Global DosDevices
             * Since LocalSystem uses the Global DosDevices,
             * don't filter for windows owned by LocalSystem
             */不筛选LocalSystem拥有的窗口
            if(!RtlEqualLuid(&luidSystem, &luidWnd)) {
                UseFilterLparam = TRUE;
            }
        }

        /*确保此窗口可以处理广播消息
         * Make sure this window can handle broadcast messages
         */

        if (!fBroadcastProc(pwnd)) {
            continue;
        }

        if (fPrivateMessage && TestWF(pwnd, WFWIN40COMPAT)) { // Don't broadcast
            continue;                                         // private message
        }                                                     // to 4.0 apps.

        ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);

    //BSF_POSTMESSAGE,寄送消息。BroadcastSystemMessage
        // Now, send message; This could be a query; so, remember the return value.
        if (pbsmParams->dwFlags & BSF_POSTMESSAGE) {
            _PostMessage(pwnd, message, wParam, lParam);
        } else if (pbsmParams->dwFlags & BSF_SENDNOTIFYMESSAGE) {
            /*
             * We don't want to wait for an answer, but we don't want to use
             * PostMessage either. This is useful if you need to maintain the
             * order in which messages are delivered, but you only want to
             * wait for some of them. See WM_POWERBROADCAST for an example.
             */
            xxxSendNotifyMessage(pwnd, message, wParam, lParam);
        } else if (pbsmParams->dwFlags & BSF_QUEUENOTIFYMESSAGE) {
            /*
             * We don't want to wait for an answer, but we don't want to use
             * PostMessage either. This is useful if you need to maintain the
             * order in which messages are delivered, but you only want to
             * wait for some of them. See WM_POWERBROADCAST for an example.
             */
            QueueNotifyMessage(pwnd, message, wParam, lParam);
        } else {
            /*
             * pbsmParams->dwFlags can be changed while we loop here
             *  so we need to check it in every iteration.
             */
            BOOL fNoHang = (BOOL)pbsmParams->dwFlags & BSF_NOHANG;
            BOOL fForce = (BOOL)pbsmParams->dwFlags & BSF_FORCEIFHUNG;
            DWORD dwTimeout;
            ULONG_PTR dwResult = 0;

            if (fNoHang)
                dwTimeout = CMSWAITTOKILLTIMEOUT;
            else
                dwTimeout = 0;

            if (xxxSendMessageTimeout(pwnd, message, wParam,
                (UseFilterLparam ? (LPARAM)&dbv : lParam),
                (fNoHang ? SMTO_ABORTIFHUNG : SMTO_NORMAL) |
                ((pbsmParams->dwFlags & BSF_NOTIMEOUTIFNOTHUNG) ? SMTO_NOTIMEOUTIFNOTHUNG : 0),
                dwTimeout, &dwResult)) {

                if (pbsmParams->dwFlags & BSF_QUERY) {
                    // For old messages, returning 0 means a deny
                    if(message == WM_QUERYENDSESSION)
                        fReturnValue = (dwResult != 0);
                    else
                    // For all new messages, returning BROADCAST_QUERY_DENY is
                    // the way to deny a query.
                        fReturnValue = (dwResult != BROADCAST_QUERY_DENY);
                }
            } else {
                fReturnValue = fForce;
            }

            /*如果我们的查询被拒绝,请立即返回。
             * If our query was denied, return immediately.
             */
            if (fReturnValue == 0) {
                // Store who denied the query.
                pbsmParams->hwnd = HWq(pwnd);
                if (pbsmParams->dwFlags & BSF_RETURNHDESK) {
                    NTSTATUS Status;
                    HDESK hdesk = NULL;
                    if (pwnd->head.rpdesk) {
                        Status = ObOpenObjectByPointer(pwnd->head.rpdesk,
                                                       0,
                                                       NULL,
                                                       EVENT_ALL_ACCESS,
                                                       NULL,
                                                       UserMode,
                                                       &hdesk);
                        if (!NT_SUCCESS(Status)) {
                            RIPMSG2(RIP_WARNING, "Could not get a handle for pdesk %#p Status %x",
                                    pwnd->head.rpdesk, Status);
                        }
                    }
                    pbsmParams->hdesk = hdesk;
                }

                if (message == WM_POWERBROADCAST && wParam == PBT_APMQUERYSUSPEND) {
                    WCHAR wchTask[40];
                    ULONG cbTask;

                    /*
                     * Get the application name and log an error.
                     */
                    cbTask = GetTaskName(GETPTI(pwnd), wchTask, sizeof(wchTask));
                    UserLogError(wchTask, cbTask, WARNING_POWER_QUERYSUSPEND_CANCELLED);
                }
                ThreadUnlock(&tlpwnd);
                break;
            }
        }
        ThreadUnlock(&tlpwnd);
    }

    FreeHwndList(pbwl);

    return fReturnValue;
}

第三部分:
LONG xxxSendMessageBSM(
    PWND pwnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam,
    LPBROADCASTSYSTEMMSGPARAMS pbsmParams)

{
    PTHREADINFO ptiCurrent = PtiCurrent();
    LONG        lRet;

    if (pbsmParams->dwRecipients & BSM_ALLDESKTOPS) {
        PWINDOWSTATION  pwinsta;
        PDESKTOP        pdesk;
        TL              tlpwinsta;
        TL              tlpdesk;

        /*
         * Walk through all windowstations and desktop looking for
         * top-level windows.
         */
        ThreadLockWinSta(ptiCurrent, NULL, &tlpwinsta);
        ThreadLockDesktop(ptiCurrent, NULL, &tlpdesk, LDLT_FN_SENDMESSAGEBSM);
        for (pwinsta = grpWinStaList; pwinsta != NULL; ) {
            ThreadLockExchangeWinSta(ptiCurrent, pwinsta, &tlpwinsta);
            for (pdesk = pwinsta->rpdeskList; pdesk != NULL; ) {
                ThreadLockExchangeDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_SENDMESSAGEBSM);

                lRet = xxxSendBSMtoDesktop(pdesk->pDeskInfo->spwnd,
                              message, wParam, lParam, pbsmParams);

                /*
                 * If our query was denied, return immediately.
                 */
                if ((lRet == 0) && (pbsmParams->dwFlags & BSF_QUERY)) {
                    ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SENDMESSAGEBSM1);
                    ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
                    return 0;
                }
                pdesk = pdesk->rpdeskNext;
            }
            pwinsta = pwinsta->rpwinstaNext;
        }
        ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SENDMESSAGEBSM2);
        ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);

    } else {
        lRet = xxxSendBSMtoDesktop(pwnd, message, wParam, lParam,
                    pbsmParams);
    }

    return lRet;
}

第四部分:
/core/ntuser/kernel/input.c:1244:BOOL _PostMessage(

/***************************************************************************\
* _PostMessage (API)
*
* Writes a message to the message queue for pwnd.  If pwnd == -1, the message
* is broadcasted to all windows.
*
* History:
* 11-06-90 DavidPe      Created.
\***************************************************************************/
BOOL _PostMessage(
    PWND pwnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
{
    PQMSG pqmsg;
    BOOL fPwndUnlock;
    BOOL fRet;
    DWORD dwPostCode;
    TL tlpwnd;
    PTHREADINFO pti;

    /*
     * First check to see if this message takes DWORDs only. If it does not,
     * fail the post. Cannot allow an app to post a message with pointers or
     * handles in it - this can cause the server to fault and cause other
     * problems - such as causing apps in separate address spaces to fault.
     * (or even an app in the same address space to fault!)
     *
     * Block certain messages cross LUIDs to avoid security threats.
     */
    if (TESTSYNCONLYMESSAGE(message, wParam) ||
        BLOCKMESSAGECROSSLUID(message,
                              PpiCurrent(),
                              GETPTI(pwnd)->ppi)) {
        RIPERR1(ERROR_MESSAGE_SYNC_ONLY,
                RIP_WARNING,
                "Invalid parameter \"message\" (%ld) to _PostMessage",
                message);

        return FALSE;
    }

    /*
     * Is this a BroadcastMsg()?
     */
    if (pwnd == PWND_BROADCAST) {
        xxxBroadcastMessage(NULL, message, wParam, lParam, BMSG_POSTMSG, NULL);
        return TRUE;
    }

    pti = PtiCurrent();

    /*
     * Is this posting to the current thread info?
     */
    if (pwnd == NULL) {
        return _PostThreadMessage(pti, message, wParam, lParam);
    }

    fPwndUnlock = FALSE;
    if (message >= WM_DDE_FIRST && message <= WM_DDE_LAST) {
        ThreadLockAlwaysWithPti(pti, pwnd, &tlpwnd);
        dwPostCode = xxxDDETrackPostHook(&message, pwnd, wParam, &lParam, FALSE);

        if (dwPostCode != DO_POST) {
            ThreadUnlock(&tlpwnd);
            return (BOOL)dwPostCode;
        }

        fPwndUnlock = TRUE;
    }

    pti = GETPTI(pwnd);

    /*
     * Check to see if this message is in the multimedia coalescing range.
     * If so, see if it can be coalesced with the previous message.
     */
    AdjustForCoalescing(&pti->mlPost, HWq(pwnd), message);

#ifdef GENERIC_INPUT
#if LOCK_HIDDATA
    /*
     * If someone is posting this message, we need to bump up the reference
     * count of the HID data so it doesn't get freed too early.
     */
    if (message == WM_INPUT) {
        // lParam is an HRAWINPUT
        PHIDDATA pHidData = HMValidateHandle((HANDLE)lParam, TYPE_HIDDATA);

        TAGMSG1(DBGTAG_PNP, "_PostMessage: Got WM_INPUT pHidData=%p", pHidData);
        if (pHidData != NULL) {
            HMLockObject(pHidData);
        } else {
            RIPMSG1(RIP_WARNING, "_PostMessage: invalid handle %p for WM_INPUT", lParam);
            return FALSE;
        }
    } else
#endif
#endif // GENERIC_INPUT

    /*
     * Allocate a key state update event if needed.
     */
    if (message >= WM_KEYFIRST && message <= WM_KEYLAST) {
        PostUpdateKeyStateEvent(pti->pq);
    }

    /*将此消息添加到“发送”队列中。重要。
     * Put this message on the 'post' list.
     */
    fRet = FALSE;
    if ((pqmsg = AllocQEntry(&pti->mlPost)) != NULL) {
        /*设置QS_POSTMESSAGE位,以便线程知道它有消息。
         * Set the QS_POSTMESSAGE bit so the thread knows it has a message.
         */
        StoreQMessage(pqmsg, pwnd, message, wParam, lParam, 0, 0, 0);
        SetWakeBit(pti, QS_POSTMESSAGE | QS_ALLPOSTMESSAGE);

        /*
         * If it's a hotkey, set the QS_HOTKEY bit since we have a separate
         * bit for those messages.
         */
        if (message == WM_HOTKEY)
            SetWakeBit(pti, QS_HOTKEY);

        fRet = TRUE;
    }

    /*
     * Are we posting to the thread currently reading from the input queue?
     * If so, update idSysLock with this pqmsg so that the input queue will
     * not be unlocked until this message is read.
     */
    if (pti == pti->pq->ptiSysLock)
        pti->pq->idSysLock = (ULONG_PTR)pqmsg;

    if (fPwndUnlock)
        ThreadUnlock(&tlpwnd);

    return fRet;
}

第五部分:
VOID StoreQMessage(
    PQMSG pqmsg,
    PWND  pwnd,
    UINT  message,
    WPARAM wParam,
    LPARAM lParam,
    DWORD time,
    DWORD dwQEvent,
    ULONG_PTR dwExtraInfo)
{
    CheckCritIn();

    pqmsg->msg.hwnd    = HW(pwnd);
    pqmsg->msg.message = message;
    pqmsg->msg.wParam  = wParam;
    pqmsg->msg.lParam  = lParam;
    pqmsg->msg.time    = (time == 0) ? NtGetTickCount() : time;

#ifdef REDIRECTION
    if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) {
        pqmsg->msg.pt.x = LOWORD(lParam);
        pqmsg->msg.pt.y = HIWORD(lParam);
    } else {
        pqmsg->msg.pt = gpsi->ptCursor;
    }
#else
    pqmsg->msg.pt      = gpsi->ptCursor;
#endif
    pqmsg->dwQEvent    = dwQEvent;
    pqmsg->ExtraInfo   = dwExtraInfo;
}


http://www.kler.cn/a/289264.html

相关文章:

  • 自动化工具 Gulp
  • 第三十一天|贪心算法| 56. 合并区间,738.单调递增的数字 , 968.监控二叉树
  • 时序论文20|ICLR20 可解释时间序列预测N-BEATS
  • uniapp在app模式下组件传值
  • C++中的栈(Stack)和堆(Heap)
  • 探索Pillow库:Python图像处理的瑞士军刀
  • HarmonyOS NEXT应用开发: 常用页面模板
  • 使用docker compose一键部署 Openldap
  • el-table中文排序-前端
  • Java 输入与输出之 NIO.2【AIO】【内存映射文件】【自动资源管理】探索之【四】
  • java-URLDNS 链条审计
  • 9、设计模式
  • Spring 学习笔记
  • 【Rust光年纪】解密Rust语言在经济学计算领域的全面应用与潜力展望
  • 【docker】docker 镜像仓库的管理
  • 39. 数组中出现次数超过一半的数字
  • 【专项刷题】— 哈希表
  • 阅读笔记——《阿里巴巴Java开发规范》
  • Unity实战案例 2D小游戏HappyGlass(游戏管理类脚本)
  • git进阶·团队开发的时候为何要创建临时分支来修复bug
  • 2708. 一个小组的最大实力值(24.9.3)
  • ADB 获取屏幕坐标,并模拟滑动和点击屏幕
  • 深入理解 JavaScript DOM 操作
  • js处理echarts tooltip定时轮播
  • 一款基于Vue的低代码可视化表单设计器工具,6K star的可视化表单设计器工具,轻松搞定表单,支持多端适配(附源码)
  • 被低估的SQL