Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2335 lines
72 KiB

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