Guest User

msgbox.c

a guest
Mar 13th, 2022
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 73.92 KB | None | 0 0
  1. /****************************** Module Header ******************************\
  2. * Module Name: msgbox.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains the MessageBox API and related functions.
  7. *
  8. * History:
  9. * 10-23-90 DarrinM     Created.
  10. * 02-08-91 IanJa       HWND revalidation added
  11. \***************************************************************************/
  12.  
  13. #include "precomp.h"
  14. #pragma hdrstop
  15.  
  16. //
  17. // Dimension constants  --  D.U. == dialog units
  18. //
  19. #define DU_OUTERMARGIN    7
  20. #define DU_INNERMARGIN    10
  21.  
  22. #define DU_BTNGAP         4   // D.U. of space between buttons
  23. #define DU_BTNHEIGHT      14  // D.U. of button height
  24. // This is used only in kernel\inctlpan.c, so move it there
  25. //
  26. // #define DU_BTNWIDTH       50  // D.U. of button width, minimum
  27. //
  28.  
  29. LPBYTE MB_UpdateDlgHdr(LPDLGTEMPLATE lpDlgTmp, long lStyle, long lExtendedStyle, BYTE bItemCount,
  30.            int iX, int iY, int iCX, int iCY, LPWSTR lpszCaption, int iCaptionLen);
  31. LPBYTE MB_UpdateDlgItem(LPDLGITEMTEMPLATE lpDlgItem, int iCtrlId, long lStyle, long lExtendedStyle,
  32.            int iX, int iY, int iCX, int iCY, LPWSTR lpszText, UINT wTextLen,
  33.            int iControlClass);
  34. UINT   MB_GetIconOrdNum(UINT rgBits);
  35. LPBYTE MB_AddPushButtons(
  36.     LPDLGITEMTEMPLATE lpDlgTmp,
  37.     LPMSGBOXDATA      lpmb,
  38.     UINT wLEdge,
  39.     UINT wBEdge);
  40. UINT MB_FindDlgTemplateSize( LPMSGBOXDATA lpmb );
  41. int MessageBoxWorker(LPMSGBOXDATA pMsgBoxParams);
  42. VOID EndTaskModalDialog(HWND hwndDlg);
  43. VOID StartTaskModalDialog(HWND hwndDlg);
  44.  
  45. #ifdef _JANUS_
  46.  
  47. #include "strid.h"
  48. #include <imagehlp.h>
  49.  
  50. // constant strings
  51. CONST WCHAR szEMIKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Error Message Instrument\\";
  52. CONST WCHAR szEMIEnable[] = L"EnableLogging";
  53. CONST WCHAR szEMISeverity[] = L"LogSeverity";
  54. CONST WCHAR szDMREnable[] = L"EnableDefaultReply";
  55. CONST WCHAR szEventKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\EventLog\\Application\\Error Instrument\\";
  56. CONST WCHAR szEventMsgFile[] = L"EventMessageFile";
  57. CONST WCHAR szEventType[] = L"TypesSupported";
  58.  
  59. #define TITLE_SIZE          64
  60. #define DATETIME_SIZE       32
  61.  
  62. #define EMI_SEVERITY_ALL          0
  63. #define EMI_SEVERITY_USER         1
  64. #define EMI_SEVERITY_INFORMATION  2
  65. #define EMI_SEVERITY_QUESTION     3
  66. #define EMI_SEVERITY_WARNING      4
  67. #define EMI_SEVERITY_ERROR        5
  68. #define EMI_SEVERITY_MAX_VALUE    5
  69.  
  70. // element of error message
  71. PVOID gpReturnAddr = 0;
  72. HANDLE gdwEMIThreadID = 0;
  73. typedef struct _ERROR_ELEMENT {
  74.     WCHAR       ProcessName[MAX_PATH];
  75.     WCHAR       WindowTitle[TITLE_SIZE];
  76.     DWORD       dwStyle;
  77.     DWORD       dwErrorCode;
  78.     WCHAR       CallerModuleName[MAX_PATH];
  79.     PVOID       BaseAddr;
  80.     DWORD       dwImageSize;
  81.     PVOID       ReturnAddr;
  82.     LPWSTR      lpszCaption;
  83.     LPWSTR      lpszText;
  84. } ERROR_ELEMENT, *LPERROR_ELEMENT;
  85.  
  86. BOOL ErrorMessageInst(LPMSGBOXDATA pMsgBoxParams);
  87. BOOL InitInstrument(LPDWORD lpEMIControl);
  88.  
  89. // eventlog stuff
  90. HANDLE gEventSource;
  91. NTSTATUS CreateLogSource();
  92. BOOL LogMessageBox(LPERROR_ELEMENT lpErrEle);
  93.  
  94. #define EMIGETRETURNADDRESS()                                    \
  95. {                                                                \
  96.     if (gfEMIEnable) {                                           \
  97.         if (InterlockedCompareExchangePointer(&gdwEMIThreadID,   \
  98.                                               GETTHREADID(),     \
  99.                                               0)                 \
  100.              == 0) {                                             \
  101.             gpReturnAddr = (PVOID) 1; \
  102.         }                                                        \
  103.     }                                                            \
  104. }
  105.  
  106. // _ReturnAddress();
  107. #else
  108. #define EMIGETRETURNADDRESS()
  109. #endif //_JANUS_
  110.  
  111.  
  112.  
  113. #define MB_MASKSHIFT    4
  114.  
  115. static CONST WCHAR szEmpty[] = L"";
  116. WCHAR szERROR[10];
  117.  
  118. /***************************************************************************\
  119. * SendHelpMessage
  120. *
  121. *
  122. \***************************************************************************/
  123. VOID
  124. SendHelpMessage(
  125.     HWND   hwnd,
  126.     int    iType,
  127.     int    iCtrlId,
  128.     HANDLE hItemHandle,
  129.     DWORD  dwContextId,
  130.     MSGBOXCALLBACK lpfnCallback)
  131. {
  132.     HELPINFO    HelpInfo;
  133.     long        lValue;
  134.  
  135.     HelpInfo.cbSize = sizeof(HELPINFO);
  136.     HelpInfo.iContextType = iType;
  137.     HelpInfo.iCtrlId = iCtrlId;
  138.     HelpInfo.hItemHandle = hItemHandle;
  139.     HelpInfo.dwContextId = dwContextId;
  140.  
  141.     lValue = NtUserGetMessagePos();
  142.     HelpInfo.MousePos.x = GET_X_LPARAM(lValue);
  143.     HelpInfo.MousePos.y = GET_Y_LPARAM(lValue);
  144.  
  145.     // Check if there is an app supplied callback.
  146.     if (lpfnCallback != NULL) {
  147.         if (IsWOWProc(lpfnCallback)) {
  148.             (*pfnWowMsgBoxIndirectCallback)(PtrToUlong(lpfnCallback), &HelpInfo);
  149.         } else {
  150.             (*lpfnCallback)(&HelpInfo);
  151.         }
  152.     } else {
  153.         SendMessage(hwnd, WM_HELP, 0, (LPARAM)&HelpInfo);
  154.     }
  155. }
  156.  
  157.  
  158. /***************************************************************************\
  159. * ServiceMessageBox
  160. *
  161. *
  162. \***************************************************************************/
  163.  
  164. CONST int aidReturn[] = { 0, 0, IDABORT, IDCANCEL, IDIGNORE, IDNO, IDOK, IDRETRY, IDYES };
  165.  
  166. int ServiceMessageBox(
  167.     LPCWSTR pText,
  168.     LPCWSTR pCaption,
  169.     UINT wType,
  170.     DWORD dwTimeout)
  171. {
  172.     NTSTATUS Status;
  173.     ULONG_PTR Parameters[4];
  174.     ULONG Response = ResponseNotHandled;
  175.     UNICODE_STRING Text, Caption;
  176.  
  177.     /*
  178.      * For Terminal Services we must decided the session in which this message
  179.      * box should be displayed.  We do this by looking at the impersonation token
  180.      * and use the session on which the client is running.
  181.      */
  182.     if (ISTS()) {
  183.         HANDLE      TokenHandle;
  184.         ULONG       ClientSessionId;
  185.         ULONG       ProcessSessionId;
  186.         ULONG       ReturnLength;
  187.         BOOLEAN     bResult;
  188.  
  189.         /*
  190.          * Obtain access to the impersonation token if it's present.
  191.          */
  192.         Status = NtOpenThreadToken (
  193.             GetCurrentThread(),
  194.             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  195.             TRUE,
  196.             &TokenHandle
  197.             );
  198.         if (NT_SUCCESS(Status)) {
  199.             /*
  200.              * Query the Session ID out of the Token
  201.              */
  202.             Status = NtQueryInformationToken (
  203.                 TokenHandle,
  204.                 TokenSessionId,
  205.                 (PVOID)&ClientSessionId,
  206.                 sizeof(ClientSessionId),
  207.                 &ReturnLength
  208.                 );
  209.             CloseHandle(TokenHandle);
  210.             if (NT_SUCCESS(Status)) {
  211.                 /*
  212.                  * Get the process session Id.  Use the Kernel32 API first because
  213.                  * the PEB is writable in case someone is hacking it.
  214.                  */
  215.                 if (!ProcessIdToSessionId(GetCurrentProcessId(), &ProcessSessionId)) {
  216.                     ProcessSessionId = NtCurrentPeb()->SessionId;
  217.                 }
  218.  
  219.                 if (ClientSessionId != ProcessSessionId) {
  220.                     /*
  221.                      * This message box was intended for session other than the
  222.                      * one on which this process is running.  Forward it to the
  223.                      * right session with WinStationSendMessage().
  224.                      */
  225.                     /*
  226.                      * Handle case where Caption or Title is NULL
  227.                      */
  228.                     if (pCaption == NULL) {
  229.                         pCaption = szEmpty;
  230.                     }
  231.                     if (pText == NULL) {
  232.                         pText = szEmpty;
  233.                     }
  234.  
  235.                     /*
  236.                      * MessageBoxTimeout assumes the timeout value is in milliseconds,
  237.                      * but WinStationSendMessageW uses seconds.
  238.                      */
  239.                     if (dwTimeout != INFINITE) {
  240.                         dwTimeout /= 1000;
  241.                     }
  242.                     bResult = WinStationSendMessageW(SERVERNAME_CURRENT,
  243.                                                      ClientSessionId,
  244.                                                      (LPWSTR)pCaption,
  245.                                                      wcslen(pCaption) * sizeof(WCHAR),
  246.                                                      (LPWSTR)pText,
  247.                                                      wcslen(pText) * sizeof(WCHAR),
  248.                                                      wType,
  249.                                                      dwTimeout,
  250.                                                      &Response,
  251.                                                      FALSE         // always wait
  252.                                                     );
  253.                     if (bResult != TRUE) {
  254.                         Response = aidReturn[ResponseNotHandled];
  255.                     } else {
  256.                         if (Response == IDTIMEOUT || Response == IDERROR) {
  257.                             Response = aidReturn[ResponseNotHandled];
  258.                         }
  259.                     }
  260.  
  261.                     return (int)Response;
  262.                 }
  263.             }
  264.         }
  265.     }
  266.  
  267.     /*
  268.      * MessageBox is for this session, go call CSR.
  269.      */
  270.     RtlInitUnicodeString(&Text, pText);
  271.     RtlInitUnicodeString(&Caption, pCaption);
  272.     Parameters[0] = (ULONG_PTR)&Text;
  273.     Parameters[1] = (ULONG_PTR)&Caption;
  274.     Parameters[2] = wType;
  275.     Parameters[3] = dwTimeout;
  276.  
  277.     /*
  278.      * Compatibility: Pass the override bit to make sure this box always shows
  279.      */
  280.     Status = NtRaiseHardError(STATUS_SERVICE_NOTIFICATION | HARDERROR_OVERRIDE_ERRORMODE,
  281.                               ARRAY_SIZE(Parameters),
  282.                               3,
  283.                               Parameters,
  284.                               OptionOk,
  285.                               &Response);
  286.  
  287.     if (!NT_SUCCESS(Status)) {
  288.         RIPNTERR0(Status, RIP_VERBOSE, "");
  289.     }
  290.  
  291.     return aidReturn[Response];
  292. }
  293.  
  294.  
  295. /***************************************************************************\
  296. * MessageBox (API)
  297. *
  298. * History:
  299. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  300. \***************************************************************************/
  301. int MessageBoxA(
  302.     HWND hwndOwner,
  303.     LPCSTR lpszText,
  304.     LPCSTR lpszCaption,
  305.     UINT wStyle)
  306. {
  307.     EMIGETRETURNADDRESS();
  308.     return MessageBoxExA(hwndOwner, lpszText, lpszCaption, wStyle, 0);
  309. }
  310.  
  311.  
  312. int MessageBoxW(
  313.     HWND hwndOwner,
  314.     LPCWSTR lpszText,
  315.     LPCWSTR lpszCaption,
  316.     UINT wStyle)
  317. {
  318.     EMIGETRETURNADDRESS();
  319.     return MessageBoxExW(hwndOwner, lpszText, lpszCaption, wStyle, 0);
  320. }
  321.  
  322.  
  323. /***************************************************************************\
  324. * MessageBoxEx (API)
  325. *
  326. * History:
  327. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  328. \***************************************************************************/
  329. int MessageBoxExA(
  330.     HWND hwndOwner,
  331.     LPCSTR lpszText,
  332.     LPCSTR lpszCaption,
  333.     UINT wStyle,
  334.     WORD wLanguageId)
  335. {
  336.     return MessageBoxTimeoutA(hwndOwner,
  337.                               lpszText,
  338.                               lpszCaption,
  339.                               wStyle,
  340.                               wLanguageId,
  341.                               INFINITE);
  342. }
  343.  
  344.  
  345. int MessageBoxExW(
  346.     HWND hwndOwner,
  347.     LPCWSTR lpszText,
  348.     LPCWSTR lpszCaption,
  349.     UINT wStyle,
  350.     WORD wLanguageId)
  351. {
  352.     return MessageBoxTimeoutW(hwndOwner,
  353.                               lpszText,
  354.                               lpszCaption,
  355.                               wStyle,
  356.                               wLanguageId,
  357.                               INFINITE);
  358. }
  359.  
  360. /***************************************************************************\
  361. * MessageBoxTimeout (API)
  362. *
  363. * History:
  364. * 04-28-2001 JasonSch   Wrote it.
  365. \***************************************************************************/
  366. int MessageBoxTimeoutW(
  367.     HWND hwndOwner,
  368.     LPCWSTR lpszText,
  369.     LPCWSTR lpszCaption,
  370.     UINT wStyle,
  371.     WORD wLanguageId,
  372.     DWORD dwTimeout)
  373. {
  374.     MSGBOXDATA  MsgBoxParams;
  375.  
  376. #if DBG
  377.     /*
  378.      * MB_USERICON is valid for MessageBoxIndirect only.
  379.      * MessageBoxWorker validates the other style bits
  380.      */
  381.     if (wStyle & MB_USERICON) {
  382.         RIPMSG0(RIP_WARNING, "MessageBoxExW: Invalid flag: MB_USERICON");
  383.     }
  384. #endif
  385.  
  386.     RtlZeroMemory(&MsgBoxParams, sizeof(MsgBoxParams));
  387.     MsgBoxParams.cbSize           = sizeof(MSGBOXPARAMS);
  388.     MsgBoxParams.hwndOwner        = hwndOwner;
  389.     MsgBoxParams.hInstance        = NULL;
  390.     MsgBoxParams.lpszText         = lpszText;
  391.     MsgBoxParams.lpszCaption      = lpszCaption;
  392.     MsgBoxParams.dwStyle          = wStyle;
  393.     MsgBoxParams.wLanguageId      = wLanguageId;
  394.     MsgBoxParams.dwTimeout        = dwTimeout;
  395.  
  396.     EMIGETRETURNADDRESS();
  397.     return MessageBoxWorker(&MsgBoxParams);
  398. }
  399.  
  400. int MessageBoxTimeoutA(
  401.     HWND hwndOwner,
  402.     LPCSTR lpszText,
  403.     LPCSTR lpszCaption,
  404.     UINT wStyle,
  405.     WORD wLanguageId,
  406.     DWORD dwTimeout)
  407. {
  408.     int retval;
  409.     LPWSTR lpwszText = NULL;
  410.     LPWSTR lpwszCaption = NULL;
  411.  
  412.     if (lpszText) {
  413.         if (!MBToWCS(lpszText, -1, &lpwszText, -1, TRUE))
  414.             return 0;
  415.     }
  416.  
  417.     if (lpszCaption) {
  418.         if (!MBToWCS(lpszCaption, -1, &lpwszCaption, -1, TRUE)) {
  419.             UserLocalFree(lpwszText);
  420.             return 0;
  421.         }
  422.     }
  423.  
  424.     EMIGETRETURNADDRESS();
  425.     retval = MessageBoxTimeoutW(hwndOwner,
  426.                                 lpwszText,
  427.                                 lpwszCaption,
  428.                                 wStyle,
  429.                                 wLanguageId,
  430.                                 dwTimeout);
  431.  
  432.     UserLocalFree(lpwszText);
  433.     if (lpwszCaption) {
  434.         UserLocalFree(lpwszCaption);
  435.     }
  436.  
  437.     return retval;
  438. }
  439.  
  440. #define MessageBoxIndirectInit(MsgBoxParams, lpmbp)                             \
  441.     do {                                                                        \
  442.         if (lpmbp->cbSize != sizeof(MSGBOXPARAMS)) {                            \
  443.             RIPMSG1(RIP_WARNING,                                                \
  444.                     "MessageBoxIndirect: Invalid cbSize 0x%x",                  \
  445.                     lpmbp->cbSize);                                             \
  446.         }                                                                       \
  447.                                                                                 \
  448.         RtlZeroMemory(&MsgBoxParams, sizeof(MSGBOXDATA));                       \
  449.         RtlCopyMemory(&MsgBoxParams, lpmbp, sizeof(MSGBOXPARAMS));              \
  450.     } while (FALSE);
  451.  
  452. /**************************************************************************\
  453. * MessageBoxIndirect (API)
  454. *
  455. * 09-30-1994 FritzS      Created.
  456. \**************************************************************************/
  457. int MessageBoxIndirectA(
  458.     CONST MSGBOXPARAMSA *lpmbp)
  459. {
  460.     int retval;
  461.     MSGBOXDATA  MsgBoxParams;
  462.     LPWSTR lpwszText = NULL;
  463.     LPWSTR lpwszCaption = NULL;
  464.  
  465.     MessageBoxIndirectInit(MsgBoxParams, lpmbp);
  466.  
  467.     if (IS_PTR(MsgBoxParams.lpszText)) {
  468.         if (!MBToWCS((LPSTR)MsgBoxParams.lpszText, -1, &lpwszText, -1, TRUE)) {
  469.             return 0;
  470.         }
  471.         MsgBoxParams.lpszText = lpwszText;
  472.     }
  473.     if (IS_PTR(MsgBoxParams.lpszCaption)) {
  474.         if (!MBToWCS((LPSTR)MsgBoxParams.lpszCaption, -1, &lpwszCaption, -1, TRUE)) {
  475.             UserLocalFree(lpwszText);
  476.             return 0;
  477.         }
  478.         MsgBoxParams.lpszCaption = lpwszCaption;
  479.     }
  480.  
  481.     EMIGETRETURNADDRESS();
  482.     retval = MessageBoxWorker(&MsgBoxParams);
  483.  
  484.     if (lpwszText) {
  485.         UserLocalFree(lpwszText);
  486.     }
  487.     if (lpwszCaption) {
  488.         UserLocalFree(lpwszCaption);
  489.     }
  490.  
  491.     return retval;
  492. }
  493.  
  494. int MessageBoxIndirectW(
  495.     CONST MSGBOXPARAMSW *lpmbp)
  496. {
  497.     MSGBOXDATA  MsgBoxParams;
  498.  
  499.     MessageBoxIndirectInit(MsgBoxParams, lpmbp);
  500.  
  501.     EMIGETRETURNADDRESS();
  502.     return MessageBoxWorker(&MsgBoxParams);
  503. }
  504.  
  505. /***************************************************************************\
  506. * MessageBoxWorker (API)
  507. *
  508. * History:
  509. * 03-10-93 JohnL      Created
  510. \***************************************************************************/
  511.  
  512. int MessageBoxWorker(
  513.     LPMSGBOXDATA pMsgBoxParams)
  514. {
  515.     DWORD  dwStyle = pMsgBoxParams->dwStyle;
  516.     UINT   wBtnCnt;
  517.     UINT   wDefButton;
  518.     UINT   i;
  519.     UINT   wBtnBeg;
  520.     WCHAR  szErrorBuf[64];
  521.     LPWSTR apstrButton[4];
  522.     int    aidButton[4];
  523.     BOOL   fCancel = FALSE;
  524.     int    retValue;
  525.     PMBSTRING pMBString;
  526.  
  527. #if DBG
  528.     if (dwStyle & ~MB_VALID) {
  529.         RIPMSG2(RIP_WARNING, "MessageBoxWorker: Invalid flags, %#lx & ~%#lx != 0",
  530.               dwStyle, MB_VALID);
  531.     }
  532. #endif
  533.  
  534.     /*
  535.      * dwTimeout == 0 means wait forever. This is mostly for compat reasons.
  536.      */
  537.     if (pMsgBoxParams->dwTimeout == 0) {
  538.         pMsgBoxParams->dwTimeout = INFINITE;
  539.     }
  540.  
  541.     /*
  542.      * Be sure that MBStrings are already loaded.
  543.      */
  544.     UserAssert(gpsi->MBStrings[0].szName[0] != TEXT('\0'));
  545.  
  546. #ifdef _JANUS_
  547.     /*
  548.      * Error message instrument start here
  549.      * Check EMI enable
  550.      */
  551.  
  552.     if (gfEMIEnable) {
  553.         if (!ErrorMessageInst(pMsgBoxParams))
  554.             RIPMSG0(RIP_WARNING, "MessageBoxWorker: Fail to instrument error msg");
  555.     };
  556.  
  557.     /*
  558.      * Default Message Return: on unattended systems the default button
  559.      * can be returned automatically without putting up the message box
  560.      */
  561.  
  562.     if (gfDMREnable) {
  563.         /*
  564.          * validate the style and default button as in the main code path
  565.          */
  566.  
  567.         /*
  568.          * Validate the "type" of message box requested.
  569.          */
  570.         if ((dwStyle & MB_TYPEMASK) > MB_LASTVALIDTYPE) {
  571.             RIPERR0(ERROR_INVALID_MSGBOX_STYLE, RIP_VERBOSE, "");
  572.             return 0;
  573.         }
  574.  
  575.         wBtnCnt = mpTypeCcmd[dwStyle & MB_TYPEMASK] +
  576.                                 ((dwStyle & MB_HELP) ? 1 : 0);
  577.  
  578.         /*
  579.          * Set the default button value
  580.          */
  581.         wDefButton = (dwStyle & (UINT)MB_DEFMASK) / (UINT)(MB_DEFMASK & (MB_DEFMASK >> 3));
  582.  
  583.         if (wDefButton >= wBtnCnt)   /* Check if valid */
  584.             wDefButton = 0;          /* Set the first button if error */
  585.  
  586.         /*
  587.          * return the default button
  588.          */
  589.  
  590.         wBtnBeg = mpTypeIich[dwStyle & (UINT)MB_TYPEMASK];
  591.         pMBString = &gpsi->MBStrings[ SEBbuttons[wBtnBeg + wDefButton] ];
  592.         return pMBString->uID;
  593.     }
  594. #endif // _JANUS_
  595.  
  596.     /*
  597.      * If lpszCaption is NULL, then use "Error!" string as the caption
  598.      * string.
  599.      * LATER: IanJa localize according to wLanguageId
  600.      */
  601.     if (pMsgBoxParams->lpszCaption == NULL) {
  602.         /*
  603.          * Load the default error string if we haven't done it yet
  604.          */
  605.         if (*szERROR == 0) {
  606.             LoadStringW(hmodUser, STR_ERROR, szERROR, ARRAY_SIZE(szERROR));
  607.         }
  608.         if (pMsgBoxParams->wLanguageId == 0) {
  609.             pMsgBoxParams->lpszCaption = szERROR;
  610.         } else {
  611.             LoadStringOrError(hmodUser,
  612.                                  STR_ERROR,
  613.                                  szErrorBuf,
  614.                                  sizeof(szErrorBuf)/sizeof(WCHAR),
  615.                                  pMsgBoxParams->wLanguageId);
  616.  
  617.             /*
  618.              *  If it didn't find the string, use the default language
  619.              */
  620.             if (*szErrorBuf) {
  621.                pMsgBoxParams->lpszCaption = szErrorBuf;
  622.             } else {
  623.                pMsgBoxParams->lpszCaption = szERROR;
  624.  
  625.                RIPMSG1(RIP_WARNING, "MessageBoxWorker: STR_ERROR string resource for language %#lx not found",
  626.                       pMsgBoxParams->wLanguageId);
  627.             }
  628.         }
  629.     }
  630.  
  631.     /*
  632.      * MB_SERVICE_NOTIFICATION had to be redefined because
  633.      * Win95 defined MB_TOPMOST using the same value.
  634.      * So for old apps, we map it to the new value
  635.      */
  636.  
  637.     if ((dwStyle & MB_TOPMOST) && !Is400Compat(GetClientInfo()->dwExpWinVer)) {
  638.         dwStyle &= ~MB_TOPMOST;
  639.         dwStyle |= MB_SERVICE_NOTIFICATION;
  640.         pMsgBoxParams->dwStyle = dwStyle;
  641.  
  642.         RIPMSG1(RIP_WARNING, "MessageBoxWorker: MB_SERVICE_NOTIFICATION flag mapped. New dwStyle:%#lx", dwStyle);
  643.     }
  644.  
  645.     /*
  646.      * For backward compatiblity, use MB_SERVICE_NOTIFICATION if
  647.      * it's going to the default desktop.
  648.      */
  649.     if (dwStyle & (MB_DEFAULT_DESKTOP_ONLY | MB_SERVICE_NOTIFICATION)) {
  650.  
  651.         /*
  652.          * Allow services to put up popups without getting
  653.          * access to the current desktop.
  654.          */
  655.         if (pMsgBoxParams->hwndOwner != NULL) {
  656.             RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
  657.             return 0;
  658.         }
  659.  
  660.         return ServiceMessageBox(pMsgBoxParams->lpszText,
  661.                                  pMsgBoxParams->lpszCaption,
  662.                                  dwStyle & ~MB_SERVICE_NOTIFICATION,
  663.                                  pMsgBoxParams->dwTimeout);
  664.     }
  665.  
  666.     /*
  667.      * Make sure we have a valid window handle.
  668.      */
  669.     if (pMsgBoxParams->hwndOwner && !IsWindow(pMsgBoxParams->hwndOwner)) {
  670.         RIPERR0(ERROR_INVALID_WINDOW_HANDLE, RIP_VERBOSE, "");
  671.         return 0;
  672.     }
  673.  
  674.     /*
  675.      * Validate the "type" of message box requested.
  676.      */
  677.     if ((dwStyle & MB_TYPEMASK) > MB_LASTVALIDTYPE) {
  678.         RIPERR0(ERROR_INVALID_MSGBOX_STYLE, RIP_VERBOSE, "");
  679.         return 0;
  680.     }
  681.  
  682.     wBtnCnt = mpTypeCcmd[dwStyle & MB_TYPEMASK] +
  683.                             ((dwStyle & MB_HELP) ? 1 : 0);
  684.  
  685.     /*
  686.      * Set the default button value
  687.      */
  688.     wDefButton = (dwStyle & (UINT)MB_DEFMASK) / (UINT)(MB_DEFMASK & (MB_DEFMASK >> 3));
  689.  
  690.     if (wDefButton >= wBtnCnt)   /* Check if valid */
  691.         wDefButton = 0;          /* Set the first button if error */
  692.  
  693.     /*
  694.      * Calculate the strings to use in the message box
  695.      */
  696.     wBtnBeg = mpTypeIich[dwStyle & (UINT)MB_TYPEMASK];
  697.     for (i=0; i<wBtnCnt; i++) {
  698.  
  699.         pMBString = &gpsi->MBStrings[SEBbuttons[wBtnBeg + i]];
  700.         /*
  701.          * Pick up the string for the button.
  702.          */
  703.         if (pMsgBoxParams->wLanguageId == 0) {
  704.             apstrButton[i] = KPWSTR_TO_PWSTR(pMBString->szName);
  705.         } else {
  706.             WCHAR szButtonBuf[64];
  707.             // LATER is it possible to have button text greater than 64 chars
  708.  
  709.            /*
  710.             *  BUG: gpsi->wMaxBtnSize might be too short for the length of this string...
  711.             */
  712.             LoadStringOrError(hmodUser,
  713.                     pMBString->uStr,
  714.                     szButtonBuf,
  715.                     ARRAY_SIZE(szButtonBuf),
  716.                     pMsgBoxParams->wLanguageId);
  717.  
  718.             /*
  719.              *  If it didn't find the string, use the default language.
  720.              */
  721.             if (*szButtonBuf) {
  722.                apstrButton[i] = TextAlloc(szButtonBuf);
  723.             } else {
  724.                apstrButton[i] = TextAlloc(KPWSTR_TO_PWSTR(pMBString->szName));
  725.  
  726.                RIPMSG2(RIP_WARNING, "MessageBoxWorker: string resource %#lx for language %#lx not found",
  727.                       pMBString->uStr,
  728.                       pMsgBoxParams->wLanguageId);
  729.             }
  730.         }
  731.         aidButton[i] = pMBString->uID;
  732.         if (aidButton[i] == IDCANCEL) {
  733.             fCancel = TRUE;
  734.         }
  735.     }
  736.  
  737.     /*
  738.      * Hackery: There are some apps that use MessageBox as initial error
  739.      * indicators, such as mplay32, and we want this messagebox to be
  740.      * visible regardless of waht was specified in the StartupInfo->wShowWindow
  741.      * field.  ccMail for instance starts all of its embedded objects hidden
  742.      * but on win 3.1 the error message would show because they don't have
  743.      * the startup info.
  744.      */
  745.     NtUserModifyUserStartupInfoFlags(STARTF_USESHOWWINDOW, 0);
  746.  
  747.     pMsgBoxParams->pidButton      = aidButton;
  748.     pMsgBoxParams->ppszButtonText = apstrButton;
  749.     pMsgBoxParams->DefButton      = wDefButton;
  750.     pMsgBoxParams->cButtons       = wBtnCnt;
  751.     pMsgBoxParams->CancelId      = ((dwStyle & MB_TYPEMASK) == 0) ? IDOK : (fCancel ? IDCANCEL : 0);
  752.     retValue = SoftModalMessageBox(pMsgBoxParams);
  753.  
  754.     if (pMsgBoxParams->wLanguageId != 0) {
  755.         for (i = 0; i < wBtnCnt; i++) {
  756.            UserLocalFree(apstrButton[i]);
  757.         }
  758.     }
  759.  
  760.     return retValue;
  761. }
  762.  
  763. #define MAX_RES_STRING  256
  764.  
  765. /***************************************************************************\
  766. * SoftModalMessageBox
  767. \***************************************************************************/
  768. int SoftModalMessageBox(
  769.     LPMSGBOXDATA lpmb)
  770. {
  771.     LPBYTE              lpDlgTmp;
  772.     int                 cyIcon, cxIcon;
  773.     int                 cxButtons;
  774.     int                 cxMBMax;
  775.     int                 cxText, cyText, xText;
  776.     int                 cxBox, cyBox;
  777.     int                 cxFoo, cxCaption;
  778.     int                 xMB, yMB;
  779.     HDC                 hdc;
  780.     DWORD               wIconOrdNum;
  781.     DWORD               wCaptionLen;
  782.     DWORD               wTextLen;
  783.     WORD                OrdNum[2];  // Must be an array or WORDs
  784.     RECT                rc;
  785.     RECT                rcWork;
  786.     HCURSOR             hcurOld;
  787.     DWORD               dwStyleMsg, dwStyleText;
  788.     DWORD               dwExStyleMsg = 0;
  789.     DWORD               dwStyleDlg;
  790.     HWND                hwndOwner;
  791.     LPWSTR              lpsz;
  792.     int                 iRetVal     = 0;
  793.     HICON               hIcon;
  794.     HGLOBAL             hTemplate   = NULL;
  795.     HGLOBAL             hCaption    = NULL;
  796.     HGLOBAL             hText       = NULL;
  797.     HINSTANCE           hInstMsg    = lpmb->hInstance;
  798.     SIZE                size;
  799.     HFONT               hFontOld    = NULL;
  800.     int                 cntMBox;
  801.     PMONITOR            pMonitor;
  802.  
  803.     ConnectIfNecessary(0);
  804.  
  805.     dwStyleMsg = lpmb->dwStyle;
  806.  
  807.     if (dwStyleMsg & MB_RIGHT) {
  808.         dwExStyleMsg |= WS_EX_RIGHT;
  809.     }
  810.  
  811.     if (!IS_PTR(lpmb->lpszCaption)) {
  812.         /*
  813.          * Won't ever be NULL because MessageBox sticks "Error!" on error.
  814.          */
  815.         if (hInstMsg && (hCaption = UserLocalAlloc(HEAP_ZERO_MEMORY, MAX_RES_STRING * sizeof(WCHAR)))) {
  816.             lpsz = (LPWSTR)hCaption;
  817.             LoadString(hInstMsg, PTR_TO_ID(lpmb->lpszCaption), lpsz, MAX_RES_STRING);
  818.         } else {
  819.             lpsz = NULL;
  820.         }
  821.  
  822.         lpmb->lpszCaption = lpsz ? lpsz : szEmpty;
  823.     }
  824.  
  825.     if (!IS_PTR(lpmb->lpszText)) {
  826.         // NULL not allowed
  827.         if (hInstMsg && (hText = UserLocalAlloc(HEAP_ZERO_MEMORY, MAX_RES_STRING * sizeof(WCHAR)))) {
  828.             lpsz = (LPWSTR)hText;
  829.             LoadString(hInstMsg, PTR_TO_ID(lpmb->lpszText), lpsz, MAX_RES_STRING);
  830.         } else {
  831.             lpsz = NULL;
  832.         }
  833.  
  834.         lpmb->lpszText = lpsz ? lpsz : szEmpty;
  835.     }
  836.  
  837.     //
  838.     // Mirroring of MessageBox'es is only enabled if :-
  839.     //
  840.     // * MB_RTLREADING style has been specified in the MessageBox styles OR
  841.     // * The first two code points of the MessageBox text are Right-To-Left
  842.     //   marks (RLMs = U+200f).
  843.     // The feature of enable RTL mirroring if two consecutive RLMs are found
  844.     // in the MB text is to acheive a no-code-change for localization of
  845.     // of MessageBoxes for BiDi Apps.  [samera]
  846.     //
  847.     if ((dwStyleMsg & MB_RTLREADING) ||
  848.             (lpmb->lpszText != NULL && (lpmb->lpszText[0] == UNICODE_RLM) &&
  849.             (lpmb->lpszText[1] == UNICODE_RLM))) {
  850.         //
  851.         // Set Mirroring so that MessageBox and its child controls
  852.         // get mirrored. Otherwise, the message box and its child controls
  853.         // are Left-To-Right.
  854.         //
  855.         dwExStyleMsg |= WS_EX_LAYOUTRTL;
  856.  
  857.         //
  858.         // And turn off any conflicting flags.
  859.         //
  860.         dwExStyleMsg &= ~WS_EX_RIGHT;
  861.         if (dwStyleMsg & MB_RTLREADING) {
  862.             dwStyleMsg &= ~MB_RTLREADING;
  863.             dwStyleMsg ^= MB_RIGHT;
  864.         }
  865.     }
  866.  
  867.     if ((dwStyleMsg & MB_ICONMASK) == MB_USERICON)
  868.         hIcon = LoadIcon(hInstMsg, lpmb->lpszIcon);
  869.     else
  870.         hIcon = NULL;
  871.  
  872.     // For compatibility reasons, we still allow the message box to come up.
  873.     hwndOwner = lpmb->hwndOwner;
  874.  
  875.     // For PowerBuilder4.0, we must make their messageboxes owned popups. Or, else
  876.     // they get WM_ACTIVATEAPP and they install multiple keyboard hooks and get into
  877.     // infinite loop later.
  878.     // Bug #15896 -- WIN95B -- 2/17/95 -- SANKAR --
  879.     if (!hwndOwner)
  880.       {
  881.         WCHAR pwszLibFileName[MAX_PATH];
  882.         static WCHAR szPB040[] = L"PB040";  // Module name of PowerBuilder4.0
  883.         WCHAR *pw1;
  884.  
  885.         //Is this a win3.1 or older app?
  886.         if (!Is400Compat(GETAPPVER())) {
  887.             if (GetModuleFileName(NULL, pwszLibFileName, sizeof(pwszLibFileName)/sizeof(WCHAR)) == 0) goto getthedc;
  888.             pw1 = pwszLibFileName + wcslen(pwszLibFileName) - 1;
  889.             while (pw1 > pwszLibFileName) {
  890.                 if (*pw1 == TEXT('.')) *pw1-- = 0;
  891.                 else if (*pw1 == TEXT(':')) {pw1++; break;}
  892.                 else if (*pw1 == TEXT('\\')) {pw1++; break;}
  893.                 else pw1--;
  894.             }
  895.             // Is this the PowerBuilder 4.0 module?
  896.             if (!_wcsicmp(pw1, szPB040))
  897.                 hwndOwner = NtUserGetForegroundWindow(); // Make the MsgBox owned.
  898.           }
  899.       }
  900. getthedc:
  901.     // Check if we're out of cache DCs until robustness...
  902.     if (!(hdc = NtUserGetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE))) {
  903.  
  904.         /*
  905.          * The above call might fail for TIF_RESTRICTED processes
  906.          * so check for the DC from the owner window
  907.          */
  908.         if (!(hdc = NtUserGetDCEx(hwndOwner, NULL, DCX_WINDOW | DCX_CACHE)))
  909.             goto SMB_Exit;
  910.     }
  911.  
  912.     // Figure out the types and dimensions of buttons
  913.  
  914.     cxButtons = (lpmb->cButtons * gpsi->wMaxBtnSize) + ((lpmb->cButtons - 1) * XPixFromXDU(DU_BTNGAP, gpsi->cxMsgFontChar));
  915.  
  916.     // Ditto for the icon, if there is one.  If not, cxIcon & cyIcon are 0.
  917.  
  918.     if (wIconOrdNum = MB_GetIconOrdNum(dwStyleMsg)) {
  919.         cxIcon = SYSMET(CXICON) + XPixFromXDU(DU_INNERMARGIN, gpsi->cxMsgFontChar);
  920.         cyIcon = SYSMET(CYICON);
  921.     } else
  922.         cxIcon = cyIcon = 0;
  923.  
  924.     hFontOld = SelectObject(hdc, KHFONT_TO_HFONT(gpsi->hCaptionFont));
  925.  
  926.     // Find the max between the caption text and the buttons
  927.     wCaptionLen = wcslen(lpmb->lpszCaption);
  928.     GetTextExtentPoint(hdc, lpmb->lpszCaption, wCaptionLen, &size);
  929.     cxCaption = size.cx + 2*SYSMET(CXSIZE);
  930.  
  931.     //
  932.     // The max width of the message box is 5/8 of the work area for most
  933.     // countries.  We will then try 6/8 and 7/8 if it won't fit.  Then
  934.     // we will use whole screen.
  935.     //
  936.     pMonitor = GetDialogMonitor(hwndOwner, MONITOR_DEFAULTTOPRIMARY);
  937.     CopyRect(&rcWork, KPRECT_TO_PRECT(&pMonitor->rcWork));
  938.     cxMBMax = MultDiv(rcWork.right - rcWork.left, 5, 8);
  939.  
  940.     cxFoo = 2*XPixFromXDU(DU_OUTERMARGIN, gpsi->cxMsgFontChar);
  941.  
  942.     SelectObject(hdc, KHFONT_TO_HFONT(gpsi->hMsgFont));
  943.  
  944.     //
  945.     // If the text doesn't fit in 5/8, try 7/8 of the screen
  946.     //
  947. ReSize:
  948.     //
  949.     // The message box is as big as needed to hold the caption/text/buttons,
  950.     // but not bigger than the maximum width.
  951.     //
  952.  
  953.     cxBox = cxMBMax - 2*SYSMET(CXFIXEDFRAME);
  954.  
  955.     // Ask DrawText for the right cx and cy
  956.     rc.left     = 0;
  957.     rc.top      = 0;
  958.     rc.right    = cxBox - cxFoo - cxIcon;
  959.     rc.bottom   = rcWork.bottom - rcWork.top;
  960.     cyText = DrawTextExW(hdc, (LPWSTR)lpmb->lpszText, -1, &rc,
  961.                 DT_CALCRECT | DT_WORDBREAK | DT_EXPANDTABS |
  962.                 DT_NOPREFIX | DT_EXTERNALLEADING | DT_EDITCONTROL, NULL);
  963.     //
  964.     // Make sure we have enough width to hold the buttons, in addition to
  965.     // the icon+text.  Always force the buttons.  If they don't fit, it's
  966.     // because the working area is small.
  967.     //
  968.     //
  969.     // The buttons are centered underneath the icon/text.
  970.     //
  971.     cxText = rc.right - rc.left + cxIcon + cxFoo;
  972.     cxBox = min(cxBox, max(cxText, cxCaption));
  973.     cxBox = max(cxBox, cxButtons + cxFoo);
  974.     cxText = cxBox - cxFoo - cxIcon;
  975.  
  976.     //
  977.     // Now we know the text width for sure.  Really calculate how high the
  978.     // text will be.
  979.     //
  980.     rc.left     = 0;
  981.     rc.top      = 0;
  982.     rc.right    = cxText;
  983.     rc.bottom   = rcWork.bottom - rcWork.top;
  984.     cyText      = DrawTextExW(hdc, (LPWSTR)lpmb->lpszText, -1, &rc, DT_CALCRECT | DT_WORDBREAK
  985.         | DT_EXPANDTABS | DT_NOPREFIX | DT_EXTERNALLEADING | DT_EDITCONTROL, NULL);
  986.  
  987.     // Find the window size.
  988.     cxBox += 2*SYSMET(CXFIXEDFRAME);
  989.     cyBox = 2*SYSMET(CYFIXEDFRAME) + SYSMET(CYCAPTION) + YPixFromYDU(2*DU_OUTERMARGIN +
  990.         DU_INNERMARGIN + DU_BTNHEIGHT, gpsi->cyMsgFontChar);
  991.  
  992.     cyBox += max(cyIcon, cyText);
  993.  
  994.     //
  995.     // If the message box doesn't fit on the working area, we'll try wider
  996.     // sizes successively:  6/8 of work then 7/8 of screen.
  997.     //
  998.     if (cyBox > rcWork.bottom - rcWork.top) {
  999.         int cxTemp;
  1000.  
  1001.         cxTemp = MultDiv(rcWork.right - rcWork.left, 6, 8);
  1002.  
  1003.         if (cxMBMax == MultDiv(rcWork.right - rcWork.left, 5, 8)) {
  1004.             cxMBMax = cxTemp;
  1005.             goto ReSize;
  1006.         } else if (cxMBMax == cxTemp) {
  1007.             // then let's try with rcMonitor
  1008.             CopyRect(&rcWork, KPRECT_TO_PRECT(&pMonitor->rcMonitor));
  1009.             cxMBMax = MultDiv(rcWork.right - rcWork.left, 7, 8);
  1010.             goto ReSize;
  1011.         }
  1012.     }
  1013.  
  1014.     if (hFontOld) {
  1015.         SelectFont(hdc, hFontOld);
  1016.     }
  1017.     NtUserReleaseDC(NULL, hdc);
  1018.  
  1019.     // Find the window position
  1020.     cntMBox = GetClientInfo()->pDeskInfo->cntMBox;
  1021.  
  1022.     xMB = (rcWork.left + rcWork.right - cxBox) / 2 + (cntMBox * SYSMET(CXSIZE));
  1023.     xMB = max(xMB, rcWork.left);
  1024.     yMB = (rcWork.top + rcWork.bottom - cyBox) / 2 + (cntMBox * SYSMET(CYSIZE));
  1025.     yMB = max(yMB, rcWork.top);
  1026.  
  1027.     //
  1028.     // Bottom, right justify if we're going off the screen--but leave a
  1029.     // little gap.
  1030.     //
  1031.     if (xMB + cxBox > rcWork.right) {
  1032.         xMB = rcWork.right - SYSMET(CXEDGE) - cxBox;
  1033.     }
  1034.  
  1035.     //
  1036.     // Pin to the working area.  If it won't fit, then pin to the screen
  1037.     // height.  Bottom justify it at least if too big even for that, so
  1038.     // that the buttons are visible.
  1039.     //
  1040.     if (yMB + cyBox > rcWork.bottom) {
  1041.         yMB = rcWork.bottom - SYSMET(CYEDGE) - cyBox;
  1042.         if (yMB < rcWork.top) {
  1043.             yMB = pMonitor->rcMonitor.bottom - SYSMET(CYEDGE) - cyBox;
  1044.         }
  1045.     }
  1046.  
  1047.     wTextLen = wcslen(lpmb->lpszText);
  1048.  
  1049.     // Find out the memory required for the Dlg template and try to alloc it
  1050.     hTemplate = UserLocalAlloc(HEAP_ZERO_MEMORY, MB_FindDlgTemplateSize(lpmb));
  1051.     if (!hTemplate) {
  1052.         goto SMB_Exit;
  1053.     }
  1054.  
  1055.     lpDlgTmp = (LPBYTE)hTemplate;
  1056.  
  1057.     //
  1058.     // Setup the dialog style for the message box
  1059.     //
  1060.     dwStyleDlg = WS_POPUPWINDOW | WS_CAPTION | DS_ABSALIGN | DS_NOIDLEMSG |
  1061.                  DS_SETFONT | DS_3DLOOK;
  1062.  
  1063.     if ((dwStyleMsg & MB_MODEMASK) == MB_SYSTEMMODAL) {
  1064.         dwStyleDlg |= DS_SYSMODAL | DS_SETFOREGROUND;
  1065.     } else {
  1066.         dwStyleDlg |= DS_MODALFRAME | WS_SYSMENU;
  1067.     }
  1068.  
  1069.     if (dwStyleMsg & MB_SETFOREGROUND) {
  1070.         dwStyleDlg |= DS_SETFOREGROUND;
  1071.     }
  1072.  
  1073.     // Add the Header of the Dlg Template
  1074.     // BOGUS !!!  don't ADD bools
  1075.     lpDlgTmp = MB_UpdateDlgHdr((LPDLGTEMPLATE) lpDlgTmp, dwStyleDlg, dwExStyleMsg,
  1076.         (BYTE) (lpmb->cButtons + (wIconOrdNum != 0) + (lpmb->lpszText != NULL)),
  1077.         xMB, yMB, cxBox, cyBox, (LPWSTR)lpmb->lpszCaption, wCaptionLen);
  1078.  
  1079.     //
  1080.     // Center the buttons
  1081.     //
  1082.  
  1083.     cxFoo = (cxBox - 2*SYSMET(CXFIXEDFRAME) - cxButtons) / 2;
  1084.  
  1085.     lpDlgTmp = MB_AddPushButtons((LPDLGITEMTEMPLATE)lpDlgTmp, lpmb, cxFoo,
  1086.         cyBox - SYSMET(CYCAPTION) - (2 * SYSMET(CYFIXEDFRAME)) -
  1087.         YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar));
  1088.  
  1089.     // Add Icon, if any, to the Dlg template
  1090.     //
  1091.     // The icon is always top justified.  If the text is shorter than the
  1092.     // height of the icon, we center it.  Otherwise the text will start at
  1093.     // the top.
  1094.     //
  1095.     if (wIconOrdNum) {
  1096.         OrdNum[0] = 0xFFFF;  // To indicate that an Ordinal number follows
  1097.         OrdNum[1] = (WORD) wIconOrdNum;
  1098.  
  1099.         lpDlgTmp = MB_UpdateDlgItem((LPDLGITEMTEMPLATE)lpDlgTmp, IDUSERICON,        // Control Id
  1100.             SS_ICON | WS_GROUP | WS_CHILD | WS_VISIBLE, 0,
  1101.             XPixFromXDU(DU_OUTERMARGIN, gpsi->cxMsgFontChar),   // X co-ordinate
  1102.             YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar),   // Y co-ordinate
  1103.             0,  0,          // For Icons, CX and CY are ignored, can be zero
  1104.             OrdNum,         // Ordinal number of Icon
  1105.             ARRAY_SIZE(OrdNum), // Length of OrdNum
  1106.             STATICCODE);
  1107.     }
  1108.  
  1109.     // Add the Text of the Message to the Dlg Template
  1110.     if (lpmb->lpszText) {
  1111.         //
  1112.         // Center the text if shorter than the icon.
  1113.         //
  1114.         if (cyText >= cyIcon)
  1115.             cxFoo = 0;
  1116.         else
  1117.             cxFoo = (cyIcon - cyText) / 2;
  1118.  
  1119.         dwStyleText = SS_NOPREFIX | WS_GROUP | WS_CHILD | WS_VISIBLE | SS_EDITCONTROL;
  1120.         if (dwStyleMsg & MB_RIGHT) {
  1121.             dwStyleText |= SS_RIGHT;
  1122.             xText = cxBox - (SYSMET(CXSIZE) + cxText);
  1123.         } else {
  1124.             dwStyleText |= SS_LEFT;
  1125.             xText = cxIcon + XPixFromXDU(DU_INNERMARGIN, gpsi->cxMsgFontChar);
  1126.         }
  1127.  
  1128.         MB_UpdateDlgItem((LPDLGITEMTEMPLATE)lpDlgTmp, -1, dwStyleText, dwExStyleMsg, xText,
  1129.             YPixFromYDU(DU_OUTERMARGIN, gpsi->cyMsgFontChar) + cxFoo,
  1130.             cxText, cyText,
  1131.             (LPWSTR)lpmb->lpszText, wTextLen, STATICCODE);
  1132.     }
  1133.  
  1134.     // The dialog template is ready
  1135.  
  1136.     //
  1137.     // Set the normal cursor
  1138.     //
  1139.     hcurOld = NtUserSetCursor(LoadCursor(NULL, IDC_ARROW));
  1140.  
  1141.     lpmb->lpszIcon = (LPWSTR) hIcon;
  1142.  
  1143.     if (!(lpmb->dwStyle & MB_USERICON))
  1144.     {
  1145.         int wBeep = (LOWORD(lpmb->dwStyle & MB_ICONMASK)) >> MB_MASKSHIFT;
  1146.         if (wBeep < USER_SOUND_MAX) {
  1147.             NtUserCallOneParam(wBeep, SFI_PLAYEVENTSOUND);
  1148.         }
  1149.     }
  1150.  
  1151.     iRetVal = (int)InternalDialogBox(hmodUser, hTemplate, hwndOwner,
  1152.         MB_DlgProc, (LPARAM) lpmb, FALSE);
  1153.  
  1154.     //
  1155.     // Fix up return value
  1156.     if (iRetVal == -1)
  1157.         iRetVal = 0;                /* Messagebox should also return error */
  1158.  
  1159.      //
  1160.      // If the messagebox contains only OK button, then its ID is changed as
  1161.      // IDCANCEL in MB_DlgProc; So, we must change it back to IDOK irrespective
  1162.      // of whether ESC is pressed or Carriage return is pressed;
  1163.      //
  1164.     if (((dwStyleMsg & MB_TYPEMASK) == MB_OK) && iRetVal)
  1165.         iRetVal = IDOK;
  1166.  
  1167.  
  1168.     //
  1169.     // Restore the previous cursor
  1170.     //
  1171.     if (hcurOld)
  1172.         NtUserSetCursor(hcurOld);
  1173.  
  1174. SMB_Exit:
  1175.     if (hTemplate) {
  1176.         UserLocalFree(hTemplate);
  1177.     }
  1178.  
  1179.     if (hCaption) {
  1180.         UserLocalFree(hCaption);
  1181.     }
  1182.  
  1183.     if (hText) {
  1184.         UserLocalFree(hText);
  1185.     }
  1186.  
  1187.     return iRetVal;
  1188. }
  1189.  
  1190. /***************************************************************************\
  1191. * MB_CopyToClipboard
  1192. *
  1193. * Called in response to WM_COPY, it will save the title, message and button's
  1194. * texts to the clipboard in CF_UNICODETEXT format.
  1195. *
  1196. *   ---------------------------
  1197. *   Caption
  1198. *   ---------------------------
  1199. *   Text
  1200. *   ---------------------------
  1201. *   Button1   ...   ButtonN
  1202. *   ---------------------------
  1203. *
  1204. *
  1205. * History:
  1206. * 08-03-97 MCostea      Created
  1207. \***************************************************************************/
  1208. VOID
  1209. MB_CopyToClipboard(
  1210.     HWND hwndDlg)
  1211. {
  1212.     LPCWSTR lpszRead;
  1213.     LPWSTR lpszAll, lpszWrite;
  1214.     HANDLE hData;
  1215.     static  CONST WCHAR   szLine[] = L"---------------------------\r\n";
  1216.     UINT cBufSize, i, cWrote;
  1217.     LPMSGBOXDATA lpmb;
  1218.  
  1219.     if (!(lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA))) {
  1220.         return;
  1221.     }
  1222.  
  1223.     if (!OpenClipboard(hwndDlg)) {
  1224.         return;
  1225.     }
  1226.  
  1227.     /*
  1228.      * Calculate the buffer size:
  1229.      *      - the message text can be all \n, that will become \r\n
  1230.      *      - there are a few extra \r\n (that's why 8)
  1231.      */
  1232.     cBufSize =  (lpmb->lpszCaption ? wcslen(lpmb->lpszCaption) : 0) +
  1233.                 (lpmb->lpszText ? 2*wcslen(lpmb->lpszText) : 0) +
  1234.                 4*sizeof(szLine) +
  1235.                 lpmb->cButtons * gpsi->wMaxBtnSize +
  1236.                 8;
  1237.  
  1238.     cBufSize *= sizeof(WCHAR);
  1239.  
  1240.     if (!(hData = UserGlobalAlloc(LHND, (LONG)(cBufSize))) ) {
  1241.         goto CloseClip;
  1242.     }
  1243.  
  1244.     USERGLOBALLOCK(hData, lpszAll);
  1245.     UserAssert(lpszAll);
  1246.  
  1247.     cWrote = wsprintf(lpszAll, L"%s%s\r\n%s",
  1248.                                 szLine,
  1249.                                 lpmb->lpszCaption ? lpmb->lpszCaption : L"",
  1250.                                 szLine);
  1251.  
  1252.     lpszWrite = lpszAll + cWrote;
  1253.     lpszRead = lpmb->lpszText;
  1254.     /*
  1255.      * Change \n to \r\n in the text
  1256.      */
  1257.     for (i = 0; *lpszRead; i++) {
  1258.  
  1259.         if (*lpszRead == L'\n')
  1260.             *lpszWrite++ = L'\r';
  1261.  
  1262.         *lpszWrite++ = *lpszRead++;
  1263.     }
  1264.  
  1265.     cWrote = wsprintf(lpszWrite, L"\r\n%s", szLine);
  1266.     lpszWrite += cWrote;
  1267.  
  1268.     /*
  1269.      * Remove & from the button texts
  1270.      */
  1271.     for (i = 0; i<lpmb->cButtons; i++) {
  1272.  
  1273.         lpszRead = lpmb->ppszButtonText[i];
  1274.         while (*lpszRead) {
  1275.             if (*lpszRead != L'&') {
  1276.                 *lpszWrite++ = *lpszRead;
  1277.             }
  1278.             lpszRead++;
  1279.         }
  1280.         *lpszWrite++ = L' ';
  1281.         *lpszWrite++ = L' ';
  1282.         *lpszWrite++ = L' ';
  1283.     }
  1284.     wsprintf(lpszWrite, L"\r\n%s\0", szLine);
  1285.  
  1286.     USERGLOBALUNLOCK(hData);
  1287.  
  1288.     NtUserEmptyClipboard();
  1289.     /*
  1290.      * If we just called EmptyClipboard in the context of a 16 bit
  1291.      * app then we also have to tell WOW to nix its 16 handle copy of
  1292.      * clipboard data.  WOW does its own clipboard caching because
  1293.      * some 16 bit apps use clipboard data even after the clipboard
  1294.      * has been emptied.  See the note in the server code.
  1295.      *
  1296.      * Note: this is another place (besides client\editec.c) where
  1297.      * EmptyClipboard is called* for a 16 bit app not going through WOW.
  1298.      * If we added others we might want to move this into EmptyClipboard
  1299.      * and have two versions.
  1300.      */
  1301.     if (GetClientInfo()->CI_flags & CI_16BIT) {
  1302.         pfnWowEmptyClipBoard();
  1303.     }
  1304.  
  1305.     SetClipboardData(CF_UNICODETEXT, hData);
  1306.  
  1307. CloseClip:
  1308.     NtUserCloseClipboard();
  1309.  
  1310. }
  1311.  
  1312. /***************************************************************************\
  1313. * MB_UpdateDlgHdr
  1314. *
  1315. * History:
  1316. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1317. \***************************************************************************/
  1318.  
  1319. LPBYTE MB_UpdateDlgHdr(
  1320.     LPDLGTEMPLATE lpDlgTmp,
  1321.     long lStyle,
  1322.     long lExtendedStyle,
  1323.     BYTE bItemCount,
  1324.     int iX,
  1325.     int iY,
  1326.     int iCX,
  1327.     int iCY,
  1328.     LPWSTR lpszCaption,
  1329.     int cchCaptionLen)
  1330. {
  1331.     LPTSTR lpStr;
  1332.     RECT rc;
  1333.  
  1334.     /*
  1335.      * Adjust the rectangle dimensions.
  1336.      */
  1337.     rc.left     = iX + SYSMET(CXFIXEDFRAME);
  1338.     rc.top      = iY + SYSMET(CYFIXEDFRAME);
  1339.     rc.right    = iX + iCX - SYSMET(CXFIXEDFRAME);
  1340.     rc.bottom   = iY + iCY - SYSMET(CYFIXEDFRAME);
  1341.  
  1342.  
  1343.     /*
  1344.      * Adjust for the caption.
  1345.      */
  1346.     rc.top += SYSMET(CYCAPTION);
  1347.  
  1348.     lpDlgTmp->style = lStyle;
  1349.     lpDlgTmp->dwExtendedStyle = lExtendedStyle;
  1350.     lpDlgTmp->cdit = bItemCount;
  1351.     lpDlgTmp->x  = XDUFromXPix(rc.left, gpsi->cxMsgFontChar);
  1352.     lpDlgTmp->y  = YDUFromYPix(rc.top, gpsi->cyMsgFontChar);
  1353.     lpDlgTmp->cx = XDUFromXPix(rc.right - rc.left, gpsi->cxMsgFontChar);
  1354.     lpDlgTmp->cy = YDUFromYPix(rc.bottom - rc.top, gpsi->cyMsgFontChar);
  1355.  
  1356.     /*
  1357.      * Move pointer to variable length fields.  No menu resource for
  1358.      * message box, a zero window class (means dialog box class).
  1359.      */
  1360.     lpStr = (LPWSTR)(lpDlgTmp + 1);
  1361.     *lpStr++ = 0;                           // Menu
  1362.     lpStr = (LPWSTR)NextWordBoundary(lpStr);
  1363.     *lpStr++ = 0;                           // Class
  1364.     lpStr = (LPWSTR)NextWordBoundary(lpStr);
  1365.  
  1366.     /*
  1367.      * NOTE: iCaptionLen may be less than the length of the Caption string;
  1368.      * So, DO NOT USE lstrcpy();
  1369.      */
  1370.     RtlCopyMemory(lpStr, lpszCaption, cchCaptionLen*sizeof(WCHAR));
  1371.     lpStr += cchCaptionLen;
  1372.     *lpStr++ = TEXT('\0');                // Null terminate the caption str
  1373.  
  1374.     /*
  1375.      * Font height of 0x7FFF means use the message box font
  1376.      */
  1377.     *lpStr++ = 0x7FFF;
  1378.  
  1379.     return NextDWordBoundary(lpStr);
  1380. }
  1381.  
  1382. /***************************************************************************\
  1383. * MB_AddPushButtons
  1384. *
  1385. * History:
  1386. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1387. \***************************************************************************/
  1388.  
  1389. LPBYTE MB_AddPushButtons(
  1390.     LPDLGITEMTEMPLATE  lpDlgTmp,
  1391.     LPMSGBOXDATA       lpmb,
  1392.     UINT               wLEdge,
  1393.     UINT               wBEdge)
  1394. {
  1395.     UINT   wYValue;
  1396.     UINT   i;
  1397.     UINT   wHeight;
  1398.     UINT   wCount = lpmb->cButtons;
  1399.  
  1400.     wHeight = YPixFromYDU(DU_BTNHEIGHT, gpsi->cyMsgFontChar);
  1401.  
  1402.     wYValue = wBEdge - wHeight;         // Y co-ordinate for push buttons
  1403.  
  1404.     for (i = 0; i < wCount; i++) {
  1405.  
  1406.         lpDlgTmp = (LPDLGITEMTEMPLATE)MB_UpdateDlgItem(
  1407.                 lpDlgTmp,                       /* Ptr to template */
  1408.                 lpmb->pidButton[i],             /* Control Id */
  1409.                 WS_TABSTOP | WS_CHILD | WS_VISIBLE | (i == 0 ? WS_GROUP : 0) |
  1410.                 ((UINT)i == lpmb->DefButton ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON),
  1411.                 0,
  1412.                 wLEdge,                         /* X co-ordinate */
  1413.                 wYValue,                        /* Y co-ordinate */
  1414.                 gpsi->wMaxBtnSize,              /* CX */
  1415.                 wHeight,                        /* CY */
  1416.                 lpmb->ppszButtonText[i],        /* String for button */
  1417.                 (UINT)wcslen(lpmb->ppszButtonText[i]),/* Length */
  1418.                 BUTTONCODE);
  1419.  
  1420.         /*
  1421.          * Get the X co-ordinate for the next Push button
  1422.          */
  1423.         wLEdge += gpsi->wMaxBtnSize + XPixFromXDU(DU_BTNGAP, gpsi->cxMsgFontChar);
  1424.     }
  1425.  
  1426.     return (LPBYTE)lpDlgTmp;
  1427. }
  1428.  
  1429. /***************************************************************************\
  1430. * MB_UpdateDlgItem
  1431. *
  1432. * History:
  1433. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1434. \***************************************************************************/
  1435.  
  1436. LPBYTE MB_UpdateDlgItem(
  1437.     LPDLGITEMTEMPLATE lpDlgItem,
  1438.     int iCtrlId,
  1439.     long lStyle,
  1440.     long lExtendedStyle,
  1441.     int iX,
  1442.     int iY,
  1443.     int iCX,
  1444.     int iCY,
  1445.     LPWSTR lpszText,
  1446.     UINT cchTextLen,
  1447.     int iControlClass)
  1448. {
  1449.     LPWSTR lpStr;
  1450.     BOOL fIsOrdNum;
  1451.  
  1452.  
  1453.     lpDlgItem->x        = XDUFromXPix(iX, gpsi->cxMsgFontChar);
  1454.     lpDlgItem->y        = YDUFromYPix(iY, gpsi->cyMsgFontChar);
  1455.     lpDlgItem->cx       = XDUFromXPix(iCX,gpsi->cxMsgFontChar);
  1456.     lpDlgItem->cy       = YDUFromYPix(iCY,gpsi->cyMsgFontChar);
  1457.     lpDlgItem->id       = (WORD)iCtrlId;
  1458.     lpDlgItem->style    = lStyle;
  1459.     lpDlgItem->dwExtendedStyle = lExtendedStyle;
  1460.  
  1461.     /*
  1462.      * We have to avoid the following nasty rounding off problem:
  1463.      * (e.g) If iCX=192 and cxSysFontChar=9, then cx becomes 85; When the
  1464.      * static text is drawn, from 85 dlg units we get 191 pixels; So, the text
  1465.      * is truncated;
  1466.      * So, to avoid this, check if this is a static text and if so,
  1467.      * add one more dialog unit to cx and cy;
  1468.      * --Fix for Bug #4481 --SANKAR-- 09-29-89--
  1469.      */
  1470.  
  1471.     /*
  1472.      * Also, make sure we only do this to static text items.  davidds
  1473.      */
  1474.  
  1475.     /*
  1476.      * Now static text uses SS_NOPREFIX = 0x80;
  1477.      * So, test the lStyle field only with 0x0F instead of 0xFF;
  1478.      * Fix for Bugs #5933 and 5935 --SANKAR-- 11-28-89
  1479.      */
  1480.     if (iControlClass == STATICCODE &&
  1481.          (((lStyle & 0x0F) == SS_LEFT) || ((lStyle & 0x0F) == SS_RIGHT))) {
  1482.  
  1483.         /*
  1484.          * This is static text
  1485.          */
  1486.         lpDlgItem->cx++;
  1487.         lpDlgItem->cy++;
  1488.     }
  1489.  
  1490.     /*
  1491.      * Move ptr to the variable fields
  1492.      */
  1493.     lpStr = (LPWSTR)(lpDlgItem + 1);
  1494.  
  1495.     /*
  1496.      * Store the Control Class value
  1497.      */
  1498.     *lpStr++ = 0xFFFF;
  1499.     *lpStr++ = (BYTE)iControlClass;
  1500.     lpStr = (LPWSTR)NextWordBoundary(lpStr);        // WORD-align lpszText
  1501.  
  1502.     /*
  1503.      * Check if the String contains Ordinal number or not
  1504.      */
  1505.     fIsOrdNum = ((*lpszText == 0xFFFF) && (cchTextLen == sizeof(DWORD)/sizeof(WCHAR)));
  1506.  
  1507.     /*
  1508.      * NOTE: cchTextLen may be less than the length of lpszText.  So,
  1509.      * DO NOT USE lstrcpy() for the copy.
  1510.      */
  1511.     RtlCopyMemory(lpStr, lpszText, cchTextLen*sizeof(WCHAR));
  1512.     lpStr = lpStr + cchTextLen;
  1513.     if (!fIsOrdNum) {
  1514.         *lpStr = TEXT('\0');    // NULL terminate the string
  1515.         lpStr = (LPWSTR)NextWordBoundary(lpStr + 1);
  1516.     }
  1517.  
  1518.     *lpStr++ = 0;           // sizeof control data (there is none)
  1519.  
  1520.     return NextDWordBoundary(lpStr);
  1521. }
  1522.  
  1523.  
  1524. /***************************************************************************\
  1525. * MB_FindDlgTemplateSize
  1526. *
  1527. * This routine computes the amount of memory that will be needed for the
  1528. * messagebox's dialog template structure.  The dialog template has several
  1529. * required and optional records.  The dialog manager expects each record to
  1530. * be DWORD aligned so any necessary padding is also accounted for.
  1531. *
  1532. * (header - required)
  1533. * DLGTEMPLATE (header) + 1 menu byte + 1 pad + 1 class byte + 1 pad
  1534. * szCaption + 0 term + DWORD alignment
  1535. *
  1536. * (static icon control - optional)
  1537. * DLGITEMTEMPLATE + 1 class byte + 1 pad + (0xFF00 + icon ordinal # [szText]) +
  1538. * UINT alignment + 1 control data length byte (0) + DWORD alignment
  1539. *
  1540. * (pushbutton controls - variable, but at least one required)
  1541. * DLGITEMTEMPLATE + 1 class byte + 1 pad + length of button text +
  1542. * UINT alignment + 1 control data length byte (0) + DWORD alignment
  1543. *
  1544. * (static text control - optional)
  1545. * DLGITEMTEMPLATE + 1 class byte + 1 pad + length of text +
  1546. * UINT alignment + 1 control data length byte (0) + DWORD alignment
  1547. *
  1548. * History:
  1549. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1550. \***************************************************************************/
  1551. UINT
  1552. MB_FindDlgTemplateSize(
  1553.     LPMSGBOXDATA lpmb)
  1554. {
  1555.     ULONG_PTR cbLen;
  1556.     UINT cbT;
  1557.     UINT i;
  1558.     UINT wCount;
  1559.  
  1560.     wCount = lpmb->cButtons;
  1561.  
  1562.     /*
  1563.      * Start with dialog header's size.
  1564.      */
  1565.     cbLen = (ULONG_PTR)NextWordBoundary(sizeof(DLGTEMPLATE) + sizeof(WCHAR));
  1566.     cbLen = (ULONG_PTR)NextWordBoundary(cbLen + sizeof(WCHAR));
  1567.     cbLen += wcslen(lpmb->lpszCaption) * sizeof(WCHAR) + sizeof(WCHAR);
  1568.     cbLen += sizeof(WORD);                   // Font height
  1569.     cbLen = (ULONG_PTR)NextDWordBoundary(cbLen);
  1570.  
  1571.     /*
  1572.      * Check if an Icon is present.
  1573.      */
  1574.     if (lpmb->dwStyle & MB_ICONMASK)
  1575.         cbLen += (ULONG_PTR)NextDWordBoundary(sizeof(DLGITEMTEMPLATE) + 7 * sizeof(WCHAR));
  1576.  
  1577.     /*
  1578.      * Find the number of buttons in the msg box.
  1579.      */
  1580.     for (i = 0; i < wCount; i++) {
  1581.         cbLen = (ULONG_PTR)NextWordBoundary(cbLen + sizeof(DLGITEMTEMPLATE) +
  1582.                 (2 * sizeof(WCHAR)));
  1583.         cbT = (wcslen(lpmb->ppszButtonText[i]) + 1) * sizeof(WCHAR);
  1584.         cbLen = (ULONG_PTR)NextWordBoundary(cbLen + cbT);
  1585.         cbLen += sizeof(WCHAR);
  1586.         cbLen = (ULONG_PTR)NextDWordBoundary(cbLen);
  1587.     }
  1588.  
  1589.     /*
  1590.      * Add in the space required for the text message (if there is one).
  1591.      */
  1592.     if (lpmb->lpszText != NULL) {
  1593.         cbLen = (ULONG_PTR)NextWordBoundary(cbLen + sizeof(DLGITEMTEMPLATE) +
  1594.                 (2 * sizeof(WCHAR)));
  1595.         cbT = (wcslen(lpmb->lpszText) + 1) * sizeof(WCHAR);
  1596.         cbLen = (ULONG_PTR)NextWordBoundary(cbLen + cbT);
  1597.         cbLen += sizeof(WCHAR);
  1598.         cbLen = (ULONG_PTR)NextDWordBoundary(cbLen);
  1599.     }
  1600.  
  1601.     return (UINT)cbLen;
  1602. }
  1603.  
  1604. /***************************************************************************\
  1605. * MB_GetIconOrdNum
  1606. *
  1607. * History:
  1608. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1609. \***************************************************************************/
  1610.  
  1611. UINT MB_GetIconOrdNum(
  1612.     UINT rgBits)
  1613. {
  1614.     switch (rgBits & MB_ICONMASK) {
  1615.     case MB_USERICON:
  1616.     case MB_ICONHAND:
  1617.         return PtrToUlong(IDI_HAND);
  1618.  
  1619.     case MB_ICONQUESTION:
  1620.         return PtrToUlong(IDI_QUESTION);
  1621.  
  1622.     case MB_ICONEXCLAMATION:
  1623.         return PtrToUlong(IDI_EXCLAMATION);
  1624.  
  1625.     case MB_ICONASTERISK:
  1626.         return PtrToUlong(IDI_ASTERISK);
  1627.     }
  1628.  
  1629.     return 0;
  1630. }
  1631.  
  1632. /***************************************************************************\
  1633. * MB_GetString
  1634. *
  1635. * History:
  1636. *  1-24-95 JerrySh      Created.
  1637. \***************************************************************************/
  1638. LPWSTR MB_GetString(
  1639.     UINT wBtn)
  1640. {
  1641.     if (wBtn < MAX_SEB_STYLES)
  1642.         return GETGPSIMBPSTR(wBtn);
  1643.  
  1644.     RIPMSG1(RIP_ERROR, "Invalid wBtn: %d", wBtn);
  1645.  
  1646.     return NULL;
  1647. }
  1648.  
  1649. /***************************************************************************\
  1650. * MB_DlgProc
  1651. *
  1652. * Returns: TRUE  - message processed
  1653. *          FALSE - message not processed
  1654. *
  1655. * History:
  1656. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1657. \***************************************************************************/
  1658. INT_PTR MB_DlgProc(
  1659.     HWND hwndDlg,
  1660.     UINT wMsg,
  1661.     WPARAM wParam,
  1662.     LPARAM lParam)
  1663. {
  1664.     HWND hwndT;
  1665.     int iCount;
  1666.     LPMSGBOXDATA lpmb;
  1667.     HWND hwndOwner;
  1668.     PVOID lpfnCallback;
  1669.     PWND pwnd;
  1670.     BOOL bTimedOut = FALSE;
  1671.  
  1672.     switch (wMsg) {
  1673.     case WM_CTLCOLORDLG:
  1674.     case WM_CTLCOLORSTATIC:
  1675.         if ((pwnd = ValidateHwnd(hwndDlg)) == NULL)
  1676.             return 0L;
  1677.         return DefWindowProcWorker(pwnd, WM_CTLCOLORMSGBOX,
  1678.                                    wParam, lParam, FALSE);
  1679.  
  1680.     case WM_TIMER:
  1681.         if (!bTimedOut) {
  1682.             bTimedOut = TRUE;
  1683.             EndTaskModalDialog(hwndDlg);
  1684.             EndDialog(hwndDlg, IDTIMEOUT);
  1685.         }
  1686.         break;
  1687.  
  1688.     case WM_NCDESTROY:
  1689.         if ((lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA))) {
  1690.             if (lpmb->dwTimeout != INFINITE) {
  1691.                 NtUserKillTimer(hwndDlg, 0);
  1692.                 lpmb->dwTimeout = INFINITE;
  1693.             }
  1694.         }
  1695.         if ((pwnd = ValidateHwnd(hwndDlg)) == NULL) {
  1696.             return 0L;
  1697.         }
  1698.         return DefWindowProcWorker(pwnd, wMsg,
  1699.                                    wParam, lParam, FALSE);
  1700.  
  1701.  
  1702.     case WM_INITDIALOG:
  1703.  
  1704.         lpmb = (LPMSGBOXDATA)lParam;
  1705.         SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (ULONG_PTR)lParam);
  1706.  
  1707.         NtUserCallHwnd(hwndDlg, SFI_SETMSGBOX);
  1708.  
  1709.         if (lpmb->dwStyle & MB_HELP) {
  1710.             NtUserSetWindowContextHelpId(hwndDlg, lpmb->dwContextHelpId);
  1711.         }
  1712.  
  1713.         if (lpmb->dwStyle & MB_TOPMOST) {
  1714.             NtUserSetWindowPos(hwndDlg,
  1715.                                HWND_TOPMOST,
  1716.                                0, 0, 0, 0,
  1717.                                SWP_NOMOVE | SWP_NOSIZE);
  1718.         }
  1719.  
  1720.         if (lpmb->dwStyle & MB_USERICON) {
  1721.             SendDlgItemMessage(hwndDlg, IDUSERICON, STM_SETICON, (WPARAM)(lpmb->lpszIcon), 0);
  1722.             iCount = ALERT_SYSTEM_WARNING;
  1723.         } else {
  1724.             /*
  1725.              * Generate an alert notification
  1726.              */
  1727.             switch (lpmb->dwStyle & MB_ICONMASK) {
  1728.             case MB_ICONWARNING:
  1729.                 iCount = ALERT_SYSTEM_WARNING;
  1730.                 break;
  1731.  
  1732.             case MB_ICONQUESTION:
  1733.                 iCount = ALERT_SYSTEM_QUERY;
  1734.                 break;
  1735.  
  1736.             case MB_ICONERROR:
  1737.                 iCount = ALERT_SYSTEM_ERROR;
  1738.                 break;
  1739.  
  1740.             case MB_ICONINFORMATION:
  1741.             default:
  1742.                 iCount = ALERT_SYSTEM_INFORMATIONAL;
  1743.                 break;
  1744.             }
  1745.         }
  1746.  
  1747.         NotifyWinEvent(EVENT_SYSTEM_ALERT, hwndDlg, OBJID_ALERT, iCount);
  1748.  
  1749.         if (lpmb->hwndOwner == NULL &&
  1750.             (lpmb->dwStyle & MB_MODEMASK) == MB_TASKMODAL) {
  1751.             StartTaskModalDialog(hwndDlg);
  1752.         }
  1753.  
  1754.         /*
  1755.          * Set focus on the default button
  1756.          */
  1757.         hwndT = GetWindow(hwndDlg, GW_CHILD);
  1758.         iCount = lpmb->DefButton;
  1759.         while (iCount--)
  1760.             hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  1761.  
  1762.         NtUserSetFocus(hwndT);
  1763.  
  1764.         //
  1765.         // Need the dialog's HWND later, but we reuse hwndDlg.
  1766.         //
  1767.         hwndT = hwndDlg;
  1768.  
  1769.         //
  1770.         // If this dialogbox does not contain a IDCANCEL button, then
  1771.         // remove the CLOSE command from the system menu.
  1772.         // Bug #4445, --SANKAR-- 09-13-89 --
  1773.         //
  1774.         if (lpmb->CancelId == 0) {
  1775.             HMENU hMenu;
  1776.  
  1777.             if (hMenu = NtUserGetSystemMenu(hwndDlg, FALSE)) {
  1778.                 NtUserDeleteMenu(hMenu, SC_CLOSE, (UINT)MF_BYCOMMAND);
  1779.             }
  1780.         }
  1781.  
  1782.         if ((lpmb->dwStyle & MB_TYPEMASK) == MB_OK) {
  1783.             //
  1784.             // Make the ID of OK button to be CANCEL, because we want
  1785.             // the ESC to terminate the dialogbox; GetDlgItem32() will
  1786.             // not fail, because this is MB_OK messagebox!
  1787.             //
  1788.  
  1789.             hwndDlg = GetDlgItem(hwndDlg, IDOK);
  1790.  
  1791.             if (hwndDlg != NULL) {
  1792.             //    hwndDlg->hMenu = (HMENU)IDCANCEL;
  1793.                 SetWindowLongPtr(hwndDlg, GWLP_ID, IDCANCEL);
  1794.             } else {
  1795.                 RIPMSG0(RIP_WARNING, "MB_DlgProc- IDOK control not found");
  1796.             }
  1797.         }
  1798.  
  1799.         if (lpmb->dwTimeout != INFINITE) {
  1800.             if (NtUserSetTimer(hwndT, 0, lpmb->dwTimeout, NULL) == 0) {
  1801.                 /*
  1802.                  * Couldn't create the timer, so "clear" out the timeout value
  1803.                  * for future reference.
  1804.                  */
  1805.                 lpmb->dwTimeout = INFINITE;
  1806.             }
  1807.         }
  1808.  
  1809.         /*
  1810.          * We have changed the input focus
  1811.          */
  1812.         return FALSE;
  1813.  
  1814.     case WM_HELP:
  1815.         // When user hits an F1 key, it results in this message.
  1816.         // It is possible that this MsgBox has a callback instead of a
  1817.         // parent. So, we must behave as if the user hit the HELP button.
  1818.  
  1819.         goto  MB_GenerateHelp;
  1820.  
  1821.     case WM_COMMAND:
  1822.         switch (LOWORD(wParam)) {
  1823.         case IDOK:
  1824.         case IDCANCEL:
  1825.            //
  1826.            // Check if a control exists with the given ID; This
  1827.            // check is needed because DlgManager returns IDCANCEL
  1828.            // blindly when ESC is pressed even if a button with
  1829.            // IDCANCEL is not present.
  1830.            // Bug #4445 --SANKAR--09-13-1989--
  1831.            //
  1832.            if (!GetDlgItem(hwndDlg, LOWORD(wParam)))
  1833.               return FALSE;
  1834.  
  1835.  
  1836.            // else FALL THRO....This is intentional.
  1837.         case IDABORT:
  1838.         case IDIGNORE:
  1839.         case IDNO:
  1840.         case IDRETRY:
  1841.         case IDYES:
  1842.         case IDTRYAGAIN:
  1843.         case IDCONTINUE:
  1844.            EndTaskModalDialog(hwndDlg);
  1845.            EndDialog(hwndDlg, LOWORD(wParam));
  1846.              break;
  1847.         case IDHELP:
  1848. MB_GenerateHelp:
  1849.                 // Generate the WM_HELP message and send it to owner or callback
  1850.            hwndOwner = NULL;
  1851.  
  1852.            // Check if there is an app supplied callback for this MsgBox
  1853.            lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1854.            if ((lpfnCallback = lpmb->lpfnMsgBoxCallback) == NULL) {
  1855.                // If not, see if we need to inform the parent.
  1856.                hwndOwner = GetWindow(hwndDlg, GW_OWNER);
  1857.            }
  1858.  
  1859.            /*
  1860.             * See if we need to generate the Help message or call back.
  1861.             */
  1862.            if (hwndOwner || lpfnCallback) {
  1863.                SendHelpMessage(hwndOwner,
  1864.                                HELPINFO_WINDOW,
  1865.                                IDHELP,
  1866.                                hwndDlg,
  1867.                                NtUserGetWindowContextHelpId(hwndDlg),
  1868.                                lpfnCallback);
  1869.            }
  1870.            break;
  1871.  
  1872.         default:
  1873.             return FALSE;
  1874.             break;
  1875.         }
  1876.         break;
  1877.  
  1878.     case WM_COPY:
  1879.         MB_CopyToClipboard(hwndDlg);
  1880.         break;
  1881.  
  1882.     default:
  1883.         return FALSE;
  1884.     }
  1885.  
  1886.     return TRUE;
  1887. }
  1888.  
  1889.  
  1890. /***************************************************************************\
  1891. * StartTaskModalDialog
  1892. *
  1893. * History:
  1894. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1895. \***************************************************************************/
  1896. VOID
  1897. StartTaskModalDialog(
  1898.     HWND hwndDlg)
  1899. {
  1900.     int cHwnd;
  1901.     HWND *phwnd;
  1902.     HWND *phwndList, *phwndEnd;
  1903.     HWND hwnd;
  1904.     PWND pwnd;
  1905.     LPMSGBOXDATA lpmb;
  1906.  
  1907.     /*
  1908.      * Get the hwnd list. It is returned in a block of memory allocated with
  1909.      * UserLocalAlloc.
  1910.      */
  1911.     if ((cHwnd = BuildHwndList(NULL, NULL, FALSE, GetCurrentThreadId(), &phwndList)) == 0) {
  1912.         return;
  1913.     }
  1914.  
  1915.     lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1916.     lpmb->phwndList = phwndList;
  1917.  
  1918.     phwndEnd = phwndList + cHwnd;
  1919.     for (phwnd = phwndList; phwnd < phwndEnd; phwnd++) {
  1920.         if ((hwnd = *phwnd) == NULL || (pwnd = RevalidateHwnd(hwnd)) == NULL)
  1921.             continue;
  1922.  
  1923.         /*
  1924.          * if the window belongs to the current task and is enabled, disable
  1925.          * it.  All other windows are NULL'd out, to prevent their being
  1926.          * enabled later
  1927.          */
  1928.         if (!TestWF(pwnd, WFDISABLED) && DIFFWOWHANDLE(hwnd, hwndDlg)) {
  1929.             NtUserEnableWindow(hwnd, FALSE);
  1930.         } else {
  1931.             *phwnd = NULL;
  1932.         }
  1933.     }
  1934. }
  1935.  
  1936.  
  1937. /***************************************************************************\
  1938. * EndTaskModalDialog
  1939. *
  1940. * History:
  1941. * 11-20-90 DarrinM      Ported from Win 3.0 sources.
  1942. \***************************************************************************/
  1943. VOID
  1944. EndTaskModalDialog(
  1945.     HWND hwndDlg)
  1946. {
  1947.     HWND *phwnd;
  1948.     HWND *phwndList;
  1949.     HWND hwnd;
  1950.     LPMSGBOXDATA lpmb;
  1951.  
  1952.     lpmb = (LPMSGBOXDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1953.     phwndList = lpmb->phwndList;
  1954.     if (phwndList == NULL) {
  1955.         return;
  1956.     }
  1957.  
  1958.     lpmb->phwndList = NULL;
  1959.  
  1960.     for (phwnd = phwndList; *phwnd != (HWND)1; phwnd++) {
  1961.         if ((hwnd = *phwnd) != NULL) {
  1962.             NtUserEnableWindow(hwnd, TRUE);
  1963.         }
  1964.     }
  1965.  
  1966.     UserLocalFree(phwndList);
  1967. }
  1968.  
  1969. #ifdef _JANUS_
  1970. /***************************************************************************\
  1971. * ErrorMessageInst
  1972. *
  1973. * Instrument routine for recording error msg
  1974. *
  1975. * Returns: TRUE  - Instrument error msg Success
  1976. *          FALSE - Fail
  1977. *
  1978. * History:
  1979. *   8-5-98 Chienho      Created
  1980. \***************************************************************************/
  1981.  
  1982. BOOL ErrorMessageInst(
  1983.      LPMSGBOXDATA pMsgBoxParams)
  1984. {
  1985.     ERROR_ELEMENT ErrEle;
  1986.     WCHAR *pwcs;
  1987.     PVOID ImageBase;
  1988.     PIMAGE_NT_HEADERS NtHeaders;
  1989.     BOOL rc;
  1990.     WCHAR szUnknown[32];
  1991.  
  1992.     /*
  1993.      * Check if the MessageBox style is within the logged severity level
  1994.      */
  1995.     switch (pMsgBoxParams->dwStyle & MB_ICONMASK) {
  1996.     case MB_ICONHAND:
  1997.         /*
  1998.          * when EMI is enabled, we at least log error messages
  1999.          */
  2000.         break;
  2001.     case MB_ICONEXCLAMATION:
  2002.         if (gdwEMIControl > EMI_SEVERITY_WARNING) {
  2003.             rc = TRUE;
  2004.             goto End;
  2005.         }
  2006.         break;
  2007.     case MB_ICONQUESTION:
  2008.         if (gdwEMIControl > EMI_SEVERITY_QUESTION) {
  2009.             rc = TRUE;
  2010.             goto End;
  2011.         }
  2012.         break;
  2013.     case MB_ICONASTERISK:
  2014.         if (gdwEMIControl > EMI_SEVERITY_INFORMATION) {
  2015.             rc = TRUE;
  2016.             goto End;
  2017.         }
  2018.         break;
  2019.     case MB_USERICON:
  2020.         if (gdwEMIControl > EMI_SEVERITY_USER) {
  2021.             rc = TRUE;
  2022.             goto End;
  2023.         }
  2024.         break;
  2025.     default:
  2026.         if (gdwEMIControl > EMI_SEVERITY_ALL) {
  2027.             rc = TRUE;
  2028.             goto End;
  2029.         }
  2030.         break;
  2031.     }
  2032.  
  2033.     if (gdwEMIThreadID != GETTHREADID()) {
  2034.         rc = FALSE;
  2035.         goto End;
  2036.     }
  2037.     RtlZeroMemory(&ErrEle, sizeof(ErrEle));
  2038.  
  2039.     /*
  2040.      * get last error first, check with FormatMessage???
  2041.      */
  2042.     ErrEle.dwErrorCode = GetLastError();
  2043.  
  2044.     /*
  2045.      * get return address
  2046.      */
  2047.  
  2048.     ErrEle.ReturnAddr = gpReturnAddr;
  2049.  
  2050.     /*
  2051.      * get the process image name
  2052.      */
  2053.     GetCurrentProcessName(ErrEle.ProcessName, ARRAY_SIZE(ErrEle.ProcessName));
  2054.  
  2055.     /*
  2056.      * Load the "unknown" string
  2057.      */
  2058.     LoadString(hmodUser, STR_UNKNOWN, szUnknown, ARRAYSIZE(szUnknown));
  2059.  
  2060.     /*
  2061.      * get the window title
  2062.      */
  2063.     GetWindowTextW(pMsgBoxParams->hwndOwner, ErrEle.WindowTitle, TITLE_SIZE);
  2064.     if (!(*(ErrEle.WindowTitle))) {
  2065.         lstrcpy(ErrEle.WindowTitle, szUnknown);
  2066.     }
  2067.  
  2068.     /*
  2069.      * get messagebox data
  2070.      */
  2071.     ErrEle.lpszText = (LPWSTR)pMsgBoxParams->lpszText;
  2072.     ErrEle.lpszCaption = (LPWSTR)pMsgBoxParams->lpszCaption;
  2073.     ErrEle.dwStyle = pMsgBoxParams->dwStyle;
  2074.  
  2075.     /*
  2076.      * resolve the module name of caller
  2077.      */
  2078.     if (!RtlPcToFileHeader((PVOID)ErrEle.ReturnAddr, &ImageBase)) {
  2079.         RIPMSG0(RIP_WARNING, "ErrorMessageInst: Can't find Caller");
  2080.         ErrEle.BaseAddr = (PVOID)-1;
  2081.         ErrEle.dwImageSize = -1;
  2082.         lstrcpy(ErrEle.CallerModuleName, szUnknown);
  2083.     } else {
  2084.         ErrEle.BaseAddr = ImageBase;
  2085.         if (GetModuleFileName((HMODULE)ImageBase, ErrEle.CallerModuleName, MAX_PATH)) {
  2086.             pwcs = wcsrchr(ErrEle.CallerModuleName, TEXT('\\'));
  2087.             if (pwcs) {
  2088.                 pwcs++;
  2089.                 lstrcpy(ErrEle.CallerModuleName, pwcs);
  2090.             }
  2091.         } else {
  2092.             lstrcpy(ErrEle.CallerModuleName, szUnknown);
  2093.         }
  2094.         NtHeaders = RtlImageNtHeader(ImageBase);
  2095.         if (NtHeaders == NULL) {
  2096.             ErrEle.dwImageSize = -1;
  2097.         } else {
  2098.             ErrEle.dwImageSize = NtHeaders->OptionalHeader.SizeOfImage;
  2099.         }
  2100.     }
  2101.     /*
  2102.      * Register the event if we haven't done so already.
  2103.      * Since RegisterEventSource is supported by a service, we must not hold
  2104.      * any locks while making this call. Hence we might have several threads
  2105.      * registering the event simultaneously.
  2106.      */
  2107.  
  2108.     if (!gEventSource) {
  2109.         gEventSource = RegisterEventSourceW(NULL, L"Error Instrument");
  2110.         if (!gEventSource) {
  2111.             ErrEle.dwErrorCode = GetLastError();
  2112.             rc = FALSE;
  2113.         }
  2114.     }
  2115.  
  2116.     /*
  2117.      * report event
  2118.      */
  2119.     if (gEventSource) {
  2120.        rc = LogMessageBox(&ErrEle);
  2121.     }
  2122.  
  2123.     /*
  2124.      * allow to process another event log again
  2125.      */
  2126.  
  2127.     InterlockedExchangePointer(&gdwEMIThreadID, 0);
  2128.  
  2129. End:
  2130.     return rc;
  2131. }
  2132.  
  2133. /***************************************************************************\
  2134. * InitInstrument
  2135.  *
  2136. * Returns: TRUE  - Initialization Success
  2137. *          FALSE - Initialization Fail
  2138. *
  2139. \***************************************************************************/
  2140. BOOL InitInstrument(
  2141.     LPDWORD lpEMIControl)
  2142. {
  2143.     NTSTATUS Status;
  2144.     HKEY hKeyEMI = NULL;
  2145.     UNICODE_STRING UnicodeStringEMIKey;
  2146.     UNICODE_STRING UnicodeStringEnable;
  2147.     UNICODE_STRING UnicodeStringStyle;
  2148.     OBJECT_ATTRIBUTES ObjA;
  2149.     DWORD EMIEnable = 0; //means disable
  2150.     DWORD EMISeverity;
  2151.     struct {
  2152.         KEY_VALUE_PARTIAL_INFORMATION;
  2153.         LARGE_INTEGER;
  2154.     } EMIValueInfo;
  2155.     DWORD dwDisposition;
  2156.  
  2157.     RtlInitUnicodeString(&UnicodeStringEMIKey, szEMIKey);
  2158.     InitializeObjectAttributes(&ObjA, &UnicodeStringEMIKey, OBJ_CASE_INSENSITIVE, NULL, NULL);
  2159.  
  2160.     Status = NtOpenKey(&hKeyEMI, KEY_READ, &ObjA);
  2161.     if (!NT_SUCCESS(Status)) {
  2162.         /*
  2163.          * Key doesn't exist, assume disable
  2164.          */
  2165.         return FALSE;
  2166.     }
  2167.  
  2168.     /*
  2169.      * read the logging enable and setting
  2170.      */
  2171.     RtlInitUnicodeString(&UnicodeStringEnable, szEMIEnable);
  2172.     Status = NtQueryValueKey(hKeyEMI,
  2173.                      &UnicodeStringEnable,
  2174.                      KeyValuePartialInformation,
  2175.                      &EMIValueInfo,
  2176.                      sizeof(EMIValueInfo),
  2177.                      &dwDisposition);
  2178.  
  2179.     if (NT_SUCCESS(Status)) {
  2180.  
  2181.         RtlCopyMemory(&EMIEnable, &EMIValueInfo.Data, sizeof(EMIEnable));
  2182.  
  2183.         RtlInitUnicodeString(&UnicodeStringStyle, szEMISeverity);
  2184.         Status = NtQueryValueKey(hKeyEMI,
  2185.                          &UnicodeStringStyle,
  2186.                          KeyValuePartialInformation,
  2187.                          &EMIValueInfo,
  2188.                          sizeof(EMIValueInfo),
  2189.                          &dwDisposition);
  2190.  
  2191.         if (NT_SUCCESS(Status)) {
  2192.             RtlCopyMemory(&EMISeverity, &EMIValueInfo.Data, sizeof(EMISeverity));
  2193.             /*
  2194.              * Validate data
  2195.              */
  2196.             if (EMISeverity > EMI_SEVERITY_MAX_VALUE) {
  2197.                 EMISeverity = EMI_SEVERITY_MAX_VALUE;
  2198.             }
  2199.         } else {
  2200.             /*
  2201.              * default severity for instrument
  2202.              */
  2203.             EMISeverity = EMI_SEVERITY_WARNING;
  2204.         }
  2205.         *lpEMIControl = EMISeverity;
  2206.     }
  2207.  
  2208.     /*
  2209.      * read default message reply enable
  2210.      */
  2211.     RtlInitUnicodeString(&UnicodeStringEnable, szDMREnable);
  2212.     Status = NtQueryValueKey(hKeyEMI,
  2213.                      &UnicodeStringEnable,
  2214.                      KeyValuePartialInformation,
  2215.                      &EMIValueInfo,
  2216.                      sizeof(EMIValueInfo),
  2217.                      &dwDisposition);
  2218.  
  2219.     if (NT_SUCCESS(Status)) {
  2220.         RtlCopyMemory(&gfDMREnable, &EMIValueInfo.Data, sizeof(gfDMREnable));
  2221.     }
  2222.  
  2223.     NtClose(hKeyEMI);
  2224.  
  2225.     if (EMIEnable) {
  2226.  
  2227.           /*
  2228.            * add eventlog file
  2229.            */
  2230.           if (NT_SUCCESS(CreateLogSource())) {
  2231.               return TRUE;
  2232.           }
  2233.     }
  2234.     return FALSE;
  2235. }
  2236.  
  2237. /***************************************************************************\
  2238. * CreateLogSource
  2239. *
  2240. * Create the event source for eventlog
  2241. * Return : NTSTATUS
  2242. *
  2243. \***************************************************************************/
  2244. NTSTATUS CreateLogSource()
  2245. {
  2246.     NTSTATUS Status;
  2247.     UNICODE_STRING UnicodeStringEventKey;
  2248.     OBJECT_ATTRIBUTES ObjA;
  2249.     HKEY hKeyEvent = NULL;
  2250.     UNICODE_STRING UnicodeString;
  2251.     DWORD dwDisposition;
  2252.  
  2253.  
  2254.     RtlInitUnicodeString(&UnicodeStringEventKey, szEventKey);
  2255.     InitializeObjectAttributes(&ObjA, &UnicodeStringEventKey, OBJ_CASE_INSENSITIVE, NULL, NULL);
  2256.  
  2257.     if (NT_SUCCESS(Status = NtOpenKey(&hKeyEvent, KEY_READ, &ObjA))) {
  2258.  
  2259.         struct {
  2260.             KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
  2261.             WCHAR awchMsgFileName[256];
  2262.         } MsgFile;
  2263.  
  2264.         RtlInitUnicodeString(&UnicodeString, szEventMsgFile);
  2265.  
  2266.         Status = NtQueryValueKey(hKeyEvent,
  2267.                                  &UnicodeString,
  2268.                                  KeyValuePartialInformation,
  2269.                                  &MsgFile,
  2270.                                  sizeof MsgFile,
  2271.                                  &dwDisposition);
  2272.         if (NT_SUCCESS(Status)) {
  2273.             Status = lstrcmpi((LPWSTR)MsgFile.KeyInfo.Data, L"%SystemRoot%\\System32\\user32.dll");
  2274.         }
  2275.         NtClose(hKeyEvent);
  2276.     }
  2277.  
  2278.     return Status;
  2279. }
  2280.  
  2281. /***************************************************************************\
  2282. * LogMessageBox
  2283. *
  2284. * Output error message record into eventlog
  2285. *
  2286. \***************************************************************************/
  2287. BOOL LogMessageBox(
  2288.     LPERROR_ELEMENT lpErrEle)
  2289. {
  2290.     LPWSTR lps[8];
  2291.     DWORD dwData[2];
  2292.     WCHAR BaseAddress[19];
  2293.     WCHAR ImageSize[19];
  2294.     WCHAR ReturnAddress[19];
  2295.     PTOKEN_USER pTokenUser = NULL;
  2296.     PSID pSid = NULL;
  2297.     BOOL rc;
  2298.  
  2299.     lps[0] = lpErrEle->ProcessName;
  2300.     lps[1] = lpErrEle->WindowTitle;
  2301.     lps[2] = lpErrEle->lpszCaption;
  2302.     lps[3] = lpErrEle->lpszText;
  2303.     lps[4] = lpErrEle->CallerModuleName;
  2304.     wsprintf(BaseAddress, L"%-#16p", lpErrEle->BaseAddr);
  2305.     lps[5] = BaseAddress;
  2306.     wsprintf(ImageSize, L"%-#16lX", lpErrEle->dwImageSize);
  2307.     lps[6] = ImageSize;
  2308.     wsprintf(ReturnAddress, L"%-#16p", lpErrEle->ReturnAddr);
  2309.     lps[7] = ReturnAddress;
  2310.  
  2311.     dwData[0] = lpErrEle->dwStyle;
  2312.     dwData[1] = lpErrEle->dwErrorCode;
  2313.  
  2314.     if (GetUserSid(&pTokenUser)) {
  2315.         pSid = pTokenUser->User.Sid;
  2316.     }
  2317.  
  2318.     UserAssert(gEventSource != NULL);
  2319.     rc = ReportEventW(gEventSource,
  2320.                       EVENTLOG_INFORMATION_TYPE,
  2321.                       0,
  2322.                       STATUS_LOG_ERROR_MSG,
  2323.                       pSid,
  2324.                       ARRAY_SIZE(lps),
  2325.                       sizeof(dwData),
  2326.                       lps,
  2327.                       dwData);
  2328.  
  2329.     if (pTokenUser) {
  2330.         VirtualFree(pTokenUser, 0, MEM_RELEASE);
  2331.     }
  2332.  
  2333.     return rc;
  2334. }
  2335. #endif
  2336.  
Advertisement
Add Comment
Please, Sign In to add comment