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.

3393 lines
113 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: sendmsg.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Contains SendMessage, xxxSendNotifyMessage, ReplyMessage, InSendMessage,
  7. * RegisterWindowMessage and a few closely related functions.
  8. *
  9. * History:
  10. * 10-19-90 darrinm Created.
  11. * 02-04-91 IanJa Window handle revalidation added
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #include <dbt.h>
  15. #pragma hdrstop
  16. #define IsASwitchWnd( pw ) \
  17. (gpsi->atomSysClass[ICLS_SWITCH] == pw->pcls->atomClassName)
  18. #define IsOleMainThreadWnd( pw ) \
  19. (gaOleMainThreadWndClass == pw->pcls->atomClassName)
  20. VOID UnlinkSendListSms(PSMS, PSMS *);
  21. VOID ReceiverDied(PSMS, PSMS *);
  22. VOID SenderDied(PSMS, PSMS *);
  23. NTSTATUS InitSMSLookaside(VOID);
  24. #pragma alloc_text(INIT, InitSMSLookaside)
  25. /*
  26. * Globals local to this file only
  27. */
  28. PPAGED_LOOKASIDE_LIST SMSLookaside;
  29. /***************************************************************************\
  30. * BroadcastProc
  31. *
  32. * Some windows need to be insulated from Broadcast messages.
  33. * These include icon title windows, the switch window, all
  34. * menu windows, etc. Before stuffing the message in the task's
  35. * queue, check to see if it is one we want to trash.
  36. *
  37. * Notes: this procedure does not do exactly the same thing it does in
  38. * windows 3.1. There it actually posts/Sends the message. For NT, it
  39. * just returns TRUE if we SHOULD post the message, or FALSE other wise
  40. *
  41. * History:
  42. * 25-Jun-1992 JonPa Ported from Windows 3.1 sources
  43. \***************************************************************************/
  44. #define fBroadcastProc(pwnd) \
  45. (!(ISAMENU(pwnd) || IsASwitchWnd(pwnd) || IsOleMainThreadWnd(pwnd)))
  46. /***************************************************************************\
  47. * StubAllocSMS / StubFreeSMS
  48. *
  49. * These are stub routines for SMS allocations. We need these to call
  50. * our debug UserAlloc routines
  51. *
  52. * Dec-16-97 clupu Created.
  53. \***************************************************************************/
  54. PVOID StubAllocSMS(
  55. POOL_TYPE PoolType,
  56. SIZE_T uBytes,
  57. ULONG iTag)
  58. {
  59. return UserAllocPool(uBytes, iTag);
  60. UNREFERENCED_PARAMETER(PoolType);
  61. }
  62. VOID StubFreeSMS(
  63. PVOID p)
  64. {
  65. UserFreePool(p);
  66. }
  67. /***************************************************************************\
  68. * InitSMSLookaside
  69. *
  70. * Initializes the SMS entry lookaside list. This improves SMS entry locality
  71. * by keeping SMS entries in a single page
  72. *
  73. * 09-09-93 Markl Created.
  74. \***************************************************************************/
  75. NTSTATUS
  76. InitSMSLookaside()
  77. {
  78. SMSLookaside = Win32AllocPoolNonPagedNS(sizeof(PAGED_LOOKASIDE_LIST),
  79. TAG_LOOKASIDE);
  80. if (SMSLookaside == NULL) {
  81. return STATUS_NO_MEMORY;
  82. }
  83. ExInitializePagedLookasideList(SMSLookaside,
  84. StubAllocSMS,
  85. StubFreeSMS,
  86. POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
  87. sizeof(SMS),
  88. TAG_SMS,
  89. 8);
  90. return STATUS_SUCCESS;
  91. }
  92. /***************************************************************************\
  93. * AllocSMS
  94. *
  95. * Allocates a message on a message list. DelSMS deletes a message
  96. * on a message list.
  97. *
  98. * 10-22-92 ScottLu Created.
  99. \***************************************************************************/
  100. PSMS AllocSMS(
  101. VOID)
  102. {
  103. return ExAllocateFromPagedLookasideList(SMSLookaside);
  104. }
  105. /***************************************************************************\
  106. * FreeSMS
  107. *
  108. * Returns a qmsg to the lookaside buffer or free the memory.
  109. *
  110. * 10-26-93 JimA Created.
  111. \***************************************************************************/
  112. void FreeSMS(
  113. PSMS psms)
  114. {
  115. ExFreeToPagedLookasideList(SMSLookaside, psms);
  116. }
  117. /***************************************************************************\
  118. * _ReplyMessage (API)
  119. *
  120. * This function replies to a message sent from one thread to another, using
  121. * the provided lRet value.
  122. *
  123. * The return value is TRUE if the calling thread is processing a SendMessage()
  124. * and FALSE otherwise.
  125. *
  126. * History:
  127. * 01-13-91 DavidPe Ported.
  128. * 01-24-91 DavidPe Rewrote for Windows.
  129. \***************************************************************************/
  130. BOOL _ReplyMessage(
  131. LRESULT lRet)
  132. {
  133. PTHREADINFO ptiCurrent;
  134. PSMS psms;
  135. CheckCritIn();
  136. ptiCurrent = PtiCurrent();
  137. /*
  138. * Are we processing a SendMessage?
  139. */
  140. psms = ptiCurrent->psmsCurrent;
  141. if (psms == NULL)
  142. return FALSE;
  143. /*
  144. * See if the reply has been made already.
  145. */
  146. if (psms->flags & SMF_REPLY)
  147. return FALSE;
  148. /*
  149. * Blow off the rest of the call if the SMS came
  150. * from xxxSendNotifyMessage(). Obviously there's
  151. * no one around to reply to in the case.
  152. */
  153. if (psms->ptiSender != NULL) {
  154. /*
  155. * Reply to this message. The sender should not free the SMS
  156. * because the receiver still considers it valid. Thus we
  157. * mark it with a special bit indicating it has been replied
  158. * to. We wait until both the sender and receiver are done
  159. * with the sms before we free it.
  160. */
  161. psms->lRet = lRet;
  162. psms->flags |= SMF_REPLY;
  163. /*
  164. * Wake up the sender.
  165. * ??? why don't we test that psms == ptiSender->psmsSent?
  166. */
  167. SetWakeBit(psms->ptiSender, QS_SMSREPLY);
  168. } else if (psms->flags & SMF_CB_REQUEST) {
  169. /*
  170. * From SendMessageCallback REQUEST callback. Send the message
  171. * back with a the REPLY value.
  172. */
  173. TL tlpwnd;
  174. INTRSENDMSGEX ism;
  175. psms->flags |= SMF_REPLY;
  176. if (!(psms->flags & SMF_SENDERDIED)) {
  177. ism.fuCall = ISM_CALLBACK | ISM_REPLY;
  178. if (psms->flags & SMF_CB_CLIENT)
  179. ism.fuCall |= ISM_CB_CLIENT;
  180. ism.lpResultCallBack = psms->lpResultCallBack;
  181. ism.dwData = psms->dwData;
  182. ism.lRet = lRet;
  183. ThreadLockWithPti(ptiCurrent, psms->spwnd, &tlpwnd);
  184. xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L,
  185. NULL, psms->ptiCallBackSender, &ism );
  186. ThreadUnlock(&tlpwnd);
  187. }
  188. }
  189. /*
  190. * We have 4 conditions to satisfy:
  191. *
  192. * 16 - 16 : receiver yields if sender is waiting for this reply
  193. * 32 - 16 : receiver yields if sender is waiting for this reply
  194. * 16 - 32 : no yield required
  195. * 32 - 32 : No yielding required.
  196. */
  197. if (psms->ptiSender &&
  198. (psms->ptiSender->TIF_flags & TIF_16BIT || ptiCurrent->TIF_flags & TIF_16BIT)) {
  199. DirectedScheduleTask(ptiCurrent, psms->ptiSender, FALSE, psms);
  200. if (ptiCurrent->TIF_flags & TIF_16BIT && psms->ptiSender->psmsSent == psms) {
  201. xxxSleepTask(TRUE, NULL);
  202. }
  203. }
  204. return TRUE;
  205. }
  206. VOID
  207. UserLogError(
  208. PCWSTR pwszError,
  209. ULONG cbError,
  210. NTSTATUS ErrorCode)
  211. {
  212. PIO_ERROR_LOG_PACKET perrLogEntry;
  213. /*
  214. * Allocate an error packet, fill it out, and write it to the log.
  215. */
  216. perrLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(gpWin32kDriverObject,
  217. (UCHAR)(cbError + sizeof(IO_ERROR_LOG_PACKET)));
  218. if (perrLogEntry) {
  219. perrLogEntry->ErrorCode = ErrorCode;
  220. if (cbError) {
  221. perrLogEntry->NumberOfStrings = 1;
  222. perrLogEntry->StringOffset = FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData);
  223. RtlCopyMemory(perrLogEntry->DumpData, pwszError, cbError);
  224. }
  225. IoWriteErrorLogEntry(perrLogEntry);
  226. }
  227. }
  228. NTSTATUS
  229. GetWindowLuid(
  230. PWND pwnd,
  231. PLUID pluidWnd
  232. )
  233. {
  234. PACCESS_TOKEN pUserToken = NULL;
  235. BOOLEAN fCopyOnOpen;
  236. BOOLEAN fEffectiveOnly;
  237. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  238. NTSTATUS Status;
  239. PTHREADINFO pti = GETPTI(pwnd);
  240. //
  241. // Get the window's thread token
  242. //
  243. pUserToken = PsReferenceImpersonationToken(pti->pEThread,
  244. &fCopyOnOpen, &fEffectiveOnly, &ImpersonationLevel);
  245. if (pUserToken == NULL) {
  246. //
  247. // No thread token, go to the process
  248. //
  249. pUserToken = PsReferencePrimaryToken(pti->ppi->Process);
  250. if (pUserToken == NULL)
  251. return STATUS_NO_TOKEN;
  252. }
  253. Status = SeQueryAuthenticationIdToken(pUserToken, pluidWnd);
  254. //
  255. // We're finished with the token
  256. //
  257. ObDereferenceObject(pUserToken);
  258. return Status;
  259. }
  260. BOOL xxxSendBSMtoDesktop(
  261. PWND pwndDesk,
  262. UINT message,
  263. WPARAM wParam,
  264. LPARAM lParam,
  265. LPBROADCASTSYSTEMMSGPARAMS pbsmParams)
  266. {
  267. PBWL pbwl;
  268. HWND *phwnd;
  269. PWND pwnd;
  270. TL tlpwnd;
  271. BOOL fReturnValue = TRUE;
  272. BOOL fFilterDriveMsg = FALSE;
  273. PTHREADINFO ptiCurrent = PtiCurrent();
  274. BOOL fPrivateMessage = (message >= WM_USER) && (message < MAXINTATOM);
  275. DEV_BROADCAST_VOLUME dbv;
  276. if (fPrivateMessage) {
  277. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to broadcast a private message");
  278. }
  279. pbwl = BuildHwndList(pwndDesk->spwndChild, BWL_ENUMLIST, NULL);
  280. if (pbwl == NULL)
  281. return 0;
  282. if (!(pbsmParams->dwFlags & BSF_POSTMESSAGE)) {
  283. /*
  284. * Does the caller want to allow the receivers to take the foreground
  285. * while processing the notification?
  286. */
  287. /*
  288. * Bug 412159. In order to allow the AppsHelp window to come to the
  289. * foreground we set ptiLastWoken to NULL, which will allow any window
  290. * to come to the foreground after a CD's been inserted.
  291. */
  292. if ((pbsmParams->dwFlags & BSF_ALLOWSFW) &&
  293. (GETPDESK(pwndDesk) == grpdeskRitInput) &&
  294. ((ptiCurrent->TIF_flags & TIF_CSRSSTHREAD)
  295. || CanForceForeground(ptiCurrent->ppi FG_HOOKLOCK_PARAM(ptiCurrent)))) {
  296. glinp.ptiLastWoken = NULL;
  297. }
  298. }
  299. /*
  300. * Determine if we need to filter the Drive Letter mask in fnINDEVICECHANGE
  301. * WM_DEVICECHANGE message are sent synchronously
  302. * LUID DosDevices maps must be enabled
  303. */
  304. if ((gLUIDDeviceMapsEnabled == TRUE) &&
  305. (message == WM_DEVICECHANGE) &&
  306. ((wParam == DBT_DEVICEREMOVECOMPLETE) || (wParam == DBT_DEVICEARRIVAL)) &&
  307. (((struct _DEV_BROADCAST_HEADER *)lParam)->dbcd_devicetype == DBT_DEVTYP_VOLUME)
  308. ) {
  309. LUID luidClient;
  310. NTSTATUS Status;
  311. if( ((DEV_BROADCAST_VOLUME *)lParam)->dbcv_unitmask & DBV_FILTER_MSG ) {
  312. return 0;
  313. }
  314. else {
  315. dbv = *((DEV_BROADCAST_VOLUME *)lParam);
  316. dbv.dbcv_unitmask |= DBV_FILTER_MSG;
  317. }
  318. /*
  319. * Caller must be LocalSystem and BSF_LUID is not specified
  320. */
  321. if (!(pbsmParams->dwFlags & BSF_LUID)) {
  322. Status = GetProcessLuid(NULL, &luidClient);
  323. if (NT_SUCCESS(Status) &&
  324. RtlEqualLuid(&luidClient, &luidSystem)) {
  325. fFilterDriveMsg = TRUE;
  326. }
  327. }
  328. }
  329. for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
  330. BOOL UseFilterLparam = FALSE;
  331. /*
  332. * Make sure this hwnd is still around.
  333. */
  334. if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
  335. continue;
  336. if (pbsmParams->dwFlags & BSF_IGNORECURRENTTASK) {
  337. // Don't deal with windows in the current task.
  338. if (GETPTI(pwnd)->pq == ptiCurrent->pq)
  339. continue;
  340. }
  341. if (pbsmParams->dwFlags & BSF_LUID) {
  342. LUID luidWnd;
  343. luidWnd.LowPart = luidWnd.HighPart = 0;
  344. /*
  345. * Now we have the window Luid LuidWindow
  346. * Check to see if it is equal to the callers Luid or not
  347. */
  348. if (!NT_SUCCESS(GetWindowLuid(pwnd, &luidWnd)) ||
  349. !RtlEqualLuid(&pbsmParams->luid, &luidWnd)) {
  350. continue;
  351. }
  352. }
  353. if (fFilterDriveMsg == TRUE) {
  354. LUID luidWnd;
  355. if (!NT_SUCCESS(GetWindowLuid(pwnd, &luidWnd))) {
  356. continue;
  357. }
  358. /*
  359. * Since LocalSystem uses the Global DosDevices,
  360. * don't filter for windows owned by LocalSystem
  361. */
  362. if(!RtlEqualLuid(&luidSystem, &luidWnd)) {
  363. UseFilterLparam = TRUE;
  364. }
  365. }
  366. /*
  367. * Make sure this window can handle broadcast messages
  368. */
  369. if (!fBroadcastProc(pwnd)) {
  370. continue;
  371. }
  372. if (fPrivateMessage && TestWF(pwnd, WFWIN40COMPAT)) { // Don't broadcast
  373. continue; // private message
  374. } // to 4.0 apps.
  375. ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
  376. // Now, send message; This could be a query; so, remember the return value.
  377. if (pbsmParams->dwFlags & BSF_POSTMESSAGE) {
  378. _PostMessage(pwnd, message, wParam, lParam);
  379. } else if (pbsmParams->dwFlags & BSF_SENDNOTIFYMESSAGE) {
  380. /*
  381. * We don't want to wait for an answer, but we don't want to use
  382. * PostMessage either. This is useful if you need to maintain the
  383. * order in which messages are delivered, but you only want to
  384. * wait for some of them. See WM_POWERBROADCAST for an example.
  385. */
  386. xxxSendNotifyMessage(pwnd, message, wParam, lParam);
  387. } else if (pbsmParams->dwFlags & BSF_QUEUENOTIFYMESSAGE) {
  388. /*
  389. * We don't want to wait for an answer, but we don't want to use
  390. * PostMessage either. This is useful if you need to maintain the
  391. * order in which messages are delivered, but you only want to
  392. * wait for some of them. See WM_POWERBROADCAST for an example.
  393. */
  394. QueueNotifyMessage(pwnd, message, wParam, lParam);
  395. } else {
  396. /*
  397. * pbsmParams->dwFlags can be changed while we loop here
  398. * so we need to check it in every iteration.
  399. */
  400. BOOL fNoHang = (BOOL)pbsmParams->dwFlags & BSF_NOHANG;
  401. BOOL fForce = (BOOL)pbsmParams->dwFlags & BSF_FORCEIFHUNG;
  402. DWORD dwTimeout;
  403. ULONG_PTR dwResult = 0;
  404. if (fNoHang)
  405. dwTimeout = CMSWAITTOKILLTIMEOUT;
  406. else
  407. dwTimeout = 0;
  408. if (xxxSendMessageTimeout(pwnd, message, wParam,
  409. (UseFilterLparam ? (LPARAM)&dbv : lParam),
  410. (fNoHang ? SMTO_ABORTIFHUNG : SMTO_NORMAL) |
  411. ((pbsmParams->dwFlags & BSF_NOTIMEOUTIFNOTHUNG) ? SMTO_NOTIMEOUTIFNOTHUNG : 0),
  412. dwTimeout, &dwResult)) {
  413. if (pbsmParams->dwFlags & BSF_QUERY) {
  414. // For old messages, returning 0 means a deny
  415. if(message == WM_QUERYENDSESSION)
  416. fReturnValue = (dwResult != 0);
  417. else
  418. // For all new messages, returning BROADCAST_QUERY_DENY is
  419. // the way to deny a query.
  420. fReturnValue = (dwResult != BROADCAST_QUERY_DENY);
  421. }
  422. } else {
  423. fReturnValue = fForce;
  424. }
  425. /*
  426. * If our query was denied, return immediately.
  427. */
  428. if (fReturnValue == 0) {
  429. // Store who denied the query.
  430. pbsmParams->hwnd = HWq(pwnd);
  431. if (pbsmParams->dwFlags & BSF_RETURNHDESK) {
  432. NTSTATUS Status;
  433. HDESK hdesk = NULL;
  434. if (pwnd->head.rpdesk) {
  435. Status = ObOpenObjectByPointer(pwnd->head.rpdesk,
  436. 0,
  437. NULL,
  438. EVENT_ALL_ACCESS,
  439. NULL,
  440. UserMode,
  441. &hdesk);
  442. if (!NT_SUCCESS(Status)) {
  443. RIPMSG2(RIP_WARNING, "Could not get a handle for pdesk %#p Status %x",
  444. pwnd->head.rpdesk, Status);
  445. }
  446. }
  447. pbsmParams->hdesk = hdesk;
  448. }
  449. if (message == WM_POWERBROADCAST && wParam == PBT_APMQUERYSUSPEND) {
  450. WCHAR wchTask[40];
  451. ULONG cbTask;
  452. /*
  453. * Get the application name and log an error.
  454. */
  455. cbTask = GetTaskName(GETPTI(pwnd), wchTask, sizeof(wchTask));
  456. UserLogError(wchTask, cbTask, WARNING_POWER_QUERYSUSPEND_CANCELLED);
  457. }
  458. ThreadUnlock(&tlpwnd);
  459. break;
  460. }
  461. }
  462. ThreadUnlock(&tlpwnd);
  463. }
  464. FreeHwndList(pbwl);
  465. return fReturnValue;
  466. }
  467. LONG xxxSendMessageBSM(
  468. PWND pwnd,
  469. UINT message,
  470. WPARAM wParam,
  471. LPARAM lParam,
  472. LPBROADCASTSYSTEMMSGPARAMS pbsmParams)
  473. {
  474. PTHREADINFO ptiCurrent = PtiCurrent();
  475. LONG lRet;
  476. if (pbsmParams->dwRecipients & BSM_ALLDESKTOPS) {
  477. PWINDOWSTATION pwinsta;
  478. PDESKTOP pdesk;
  479. TL tlpwinsta;
  480. TL tlpdesk;
  481. /*
  482. * Walk through all windowstations and desktop looking for
  483. * top-level windows.
  484. */
  485. ThreadLockWinSta(ptiCurrent, NULL, &tlpwinsta);
  486. ThreadLockDesktop(ptiCurrent, NULL, &tlpdesk, LDLT_FN_SENDMESSAGEBSM);
  487. for (pwinsta = grpWinStaList; pwinsta != NULL; ) {
  488. ThreadLockExchangeWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  489. for (pdesk = pwinsta->rpdeskList; pdesk != NULL; ) {
  490. ThreadLockExchangeDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_SENDMESSAGEBSM);
  491. lRet = xxxSendBSMtoDesktop(pdesk->pDeskInfo->spwnd,
  492. message, wParam, lParam, pbsmParams);
  493. /*
  494. * If our query was denied, return immediately.
  495. */
  496. if ((lRet == 0) && (pbsmParams->dwFlags & BSF_QUERY)) {
  497. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SENDMESSAGEBSM1);
  498. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  499. return 0;
  500. }
  501. pdesk = pdesk->rpdeskNext;
  502. }
  503. pwinsta = pwinsta->rpwinstaNext;
  504. }
  505. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SENDMESSAGEBSM2);
  506. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  507. } else {
  508. lRet = xxxSendBSMtoDesktop(pwnd, message, wParam, lParam,
  509. pbsmParams);
  510. }
  511. return lRet;
  512. }
  513. /***************************************************************************\
  514. * xxxSendMessageFF
  515. *
  516. * We can't check for -1 in the thunks because that would allow all message
  517. * thunk apis to take -1 erroneously. Since all message apis need to go through
  518. * the message thunks, the message thunks can only do least-common-denominator
  519. * hwnd validation (can't allow -1). So I made a special thunk that gets called
  520. * when SendMessage(-1) gets called. This means the client side will do the
  521. * special stuff to make sure the pwnd passed goes through thunk validation
  522. * ok. I do it this way rather than doing validation in all message apis and
  523. * not in the thunks (if I did it this way the code would be larger and
  524. * inefficient in the common cases).
  525. *
  526. * 03-20-92 ScottLu Created.
  527. \***************************************************************************/
  528. LRESULT xxxSendMessageFF(
  529. PWND pwnd,
  530. UINT message,
  531. WPARAM wParam,
  532. LPARAM lParam,
  533. ULONG_PTR xParam)
  534. {
  535. UNREFERENCED_PARAMETER(pwnd);
  536. /*
  537. * Call xxxSendMessage() to do broadcasting rather than calling
  538. * broadcast from here in case any internal code that calls
  539. * sendmessage passes a -1 (that way the internal code doesn't
  540. * need to know about this weird routine).
  541. */
  542. if (xParam != 0L) {
  543. /*
  544. * SendMessageTimeout call
  545. */
  546. return xxxSendMessageEx(PWND_BROADCAST, message, wParam, lParam, xParam);
  547. } else {
  548. /*
  549. * Normal SendMessage call
  550. */
  551. return xxxSendMessageTimeout(PWND_BROADCAST, message, wParam,
  552. lParam, SMTO_NORMAL, 0, NULL );
  553. }
  554. }
  555. /***************************************************************************\
  556. * xxxSendMessageEx
  557. *
  558. * The SendMessageTimeOut sends a pointer to struct that holds the extra
  559. * params needed for the timeout call. Instead of chaning a bunch of things,
  560. * we use the xParam to hold a ptr to a struct. So we change the client/srv
  561. * entry point to hear so we can check for the extra param and extract the
  562. * stuff we need if it's there.
  563. *
  564. *
  565. * WARNING!!!! RETURN VALUE SWAPPED
  566. *
  567. * Only call this function from the thunks!
  568. *
  569. * our thunks are written for SendMessage where it returns the value of
  570. * the message. This routine is used to dispatch SendMessageTimeout calls.
  571. * SendMessageTimeout returns only TRUE or FALSE and returns the retval of
  572. * the function in lpdwResult. So here the meanings are swapped and fixed
  573. * up again in Client side SendMessageTimeout
  574. *
  575. *
  576. * 08-10-92 ChrisBl Created.
  577. \***************************************************************************/
  578. LRESULT xxxSendMessageEx(
  579. PWND pwnd,
  580. UINT message,
  581. WPARAM wParam,
  582. LPARAM lParam,
  583. ULONG_PTR xParam)
  584. {
  585. /*
  586. * extract values from the xParam if from TimeOut call
  587. * This should be the only way this function is ever
  588. * called, but check it just in case...
  589. */
  590. if (xParam != 0L) {
  591. LRESULT lRet;
  592. LRESULT lResult;
  593. NTSTATUS Status;
  594. SNDMSGTIMEOUT smto;
  595. PETHREAD Thread = PsGetCurrentThread();
  596. if (Thread == NULL)
  597. return FALSE;
  598. /*
  599. * Probe all read arguments
  600. */
  601. try {
  602. ProbeForWrite((PVOID)xParam, sizeof(smto), sizeof(ULONG));
  603. smto = *(SNDMSGTIMEOUT *)xParam;
  604. Status = STATUS_SUCCESS;
  605. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  606. Status = GetExceptionCode();
  607. }
  608. if ( !NT_SUCCESS(Status) ) {
  609. return FALSE;
  610. }
  611. lRet = xxxSendMessageTimeout(pwnd, message, wParam, lParam,
  612. smto.fuFlags, smto.uTimeout, &lResult);
  613. /*
  614. * put the result back into the client
  615. */
  616. smto.lSMTOResult = lResult;
  617. smto.lSMTOReturn = lRet;
  618. try {
  619. *(SNDMSGTIMEOUT *)xParam = smto;
  620. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  621. lResult = FALSE;
  622. }
  623. /*
  624. * Return the lResult so our thunks are happy.
  625. */
  626. return lResult;
  627. }
  628. return xxxSendMessageTimeout(pwnd, message, wParam,
  629. lParam, SMTO_NORMAL, 0, NULL);
  630. }
  631. /***********************************************************************\
  632. * xxxSendMessage (API)
  633. *
  634. * This function synchronously sends a message to a window. The four
  635. * parameters hwnd, message, wParam, and lParam are passed to the window
  636. * procedure of the receiving window. If the window receiving the message
  637. * belongs to the same queue as the current thread, the window proc is called
  638. * directly. Otherwise, we set up an sms structure, wake the appropriate
  639. * thread to receive the message and wait for a reply.
  640. *
  641. * Returns:
  642. * the value returned by the window procedure, or NULL if there is an error
  643. *
  644. * History:
  645. * 01-13-91 DavidPe Ported.
  646. \***********************************************************************/
  647. LRESULT xxxSendMessage(
  648. PWND pwnd,
  649. UINT message,
  650. WPARAM wParam,
  651. LPARAM lParam)
  652. {
  653. return xxxSendMessageTimeout(pwnd, message, wParam, lParam,
  654. SMTO_NORMAL, 0, NULL);
  655. }
  656. /***********************************************************************\
  657. * xxxSendMessageToClient
  658. *
  659. * History:
  660. * 04-22-98 GerardoB Extracted from xxxSendMessageTimeout, xxxSendMesageCallback
  661. * and xxxReceiveMessage
  662. * 05-12-00 JStall Changed from macro to inline function.
  663. \***********************************************************************/
  664. __inline void
  665. xxxSendMessageToClient(
  666. PWND pwnd,
  667. UINT message,
  668. WPARAM wParam,
  669. LPARAM lParam,
  670. PSMS psms,
  671. BOOL fLock,
  672. LRESULT * plRet)
  673. {
  674. DWORD dwSCMSFlags;
  675. WORD fnid;
  676. /*
  677. * If the window has a client side worker proc and has
  678. * not been subclassed, dispatch the message directly
  679. * to the worker proc. Otherwise, dispatch it normally.
  680. */
  681. dwSCMSFlags = TestWF((pwnd), WFANSIPROC) ? SCMS_FLAGS_ANSI : 0;
  682. if (gihmodUserApiHook >= 0) {
  683. /*
  684. * UserApiHooks are installed, so we can't optimize the sending because
  685. * the OverrideWndProc's needs to get the message.
  686. */
  687. goto StandardSend;
  688. }
  689. fnid = GETFNID((pwnd));
  690. if ((fnid >= FNID_CONTROLSTART && fnid <= FNID_CONTROLEND) &&
  691. ((ULONG_PTR)(pwnd)->lpfnWndProc == FNID_TO_CLIENT_PFNW(fnid) ||
  692. (ULONG_PTR)(pwnd)->lpfnWndProc == FNID_TO_CLIENT_PFNA(fnid))) {
  693. PWNDMSG pwm = &gSharedInfo.awmControl[fnid - FNID_START] ;
  694. /*
  695. * If this message is not processed by the control, call
  696. * xxxDefWindowProc
  697. */
  698. if (pwm->abMsgs && (((message) > pwm->maxMsgs) ||
  699. !((pwm->abMsgs)[(message) / 8] & (1 << ((message) & 7))))) {
  700. /*
  701. * If this is a dialog window, we need to call the client because
  702. * the app might want this message (eventhough DefDlgProc doesn't
  703. * want it).
  704. * If the dialog hasn't been marked as such, the app's DlgProc is
  705. * not yet available so it's OK to ignore the message.
  706. */
  707. if (TestWF((pwnd), WFDIALOGWINDOW)) {
  708. *plRet = ScSendMessageSMS((pwnd), (message), (wParam), (lParam),
  709. dwSCMSFlags, (PROC)(FNID_TO_CLIENT_PFNWORKER(fnid)),
  710. dwSCMSFlags, (psms));
  711. } else {
  712. TL tlpwnd;
  713. if (fLock) {
  714. ThreadLock((pwnd), &tlpwnd);
  715. }
  716. *plRet = xxxDefWindowProc((pwnd), (message), (wParam), (lParam));
  717. if (fLock) {
  718. ThreadUnlock(&tlpwnd);
  719. }
  720. }
  721. } else {
  722. *plRet = ScSendMessageSMS((pwnd), (message), (wParam), (lParam),
  723. dwSCMSFlags, (PROC)(FNID_TO_CLIENT_PFNWORKER(fnid)),
  724. dwSCMSFlags, (psms));
  725. }
  726. } else {
  727. StandardSend:
  728. *plRet = ScSendMessageSMS((pwnd), (message), (wParam), (lParam),
  729. (ULONG_PTR)(pwnd)->lpfnWndProc,
  730. gpsi->apfnClientW.pfnDispatchMessage, dwSCMSFlags, (psms));
  731. }
  732. }
  733. /***********************************************************************\
  734. * xxxSendMessageTimeout (API)
  735. *
  736. * This function synchronously sends a message to a window. The four
  737. * parameters hwnd, message, wParam, and lParam are passed to the window
  738. * procedure of the receiving window. If the window receiving the message
  739. * belongs to the same queue as the current thread, the window proc is called
  740. * directly. Otherwise, we set up an sms structure, wake the appropriate
  741. * thread to receive the message and wait for a reply.
  742. * If the thread is 'hung' or if the time-out value is exceeded, we will
  743. * fail the request.
  744. *
  745. * lpdwResult = NULL if normal sendmessage, if !NULL then it's a timeout call
  746. *
  747. * Returns:
  748. * the value returned by the window procedure, or NULL if there is an error
  749. *
  750. * History:
  751. * 07-13-92 ChrisBl Created/extended from SendMessage
  752. \***********************************************************************/
  753. LRESULT xxxSendMessageTimeout(
  754. PWND pwnd,
  755. UINT message,
  756. WPARAM wParam,
  757. LPARAM lParam,
  758. UINT fuFlags,
  759. UINT uTimeout,
  760. PLONG_PTR lpdwResult)
  761. {
  762. LRESULT lRet;
  763. PTHREADINFO ptiCurrent;
  764. ULONG_PTR uResult; // holder for DDE_INITIATE case
  765. CheckCritIn();
  766. /*
  767. * The timeout value is only respected if lpdwResult is non-NULL. This,
  768. * however, is not obvious, and has caused multiple, hard to track down
  769. * bugs. So let's assert that the call makes sense.
  770. */
  771. UserAssert(uTimeout == 0 || lpdwResult != NULL);
  772. if (lpdwResult != NULL) {
  773. *lpdwResult = 0L;
  774. }
  775. /*
  776. * Is this a BroadcastMsg()?
  777. */
  778. if (pwnd == PWND_BROADCAST) {
  779. BROADCASTMSG bcm;
  780. PBROADCASTMSG pbcm = NULL;
  781. UINT uCmd = BMSG_SENDMSG;
  782. if (lpdwResult != NULL) {
  783. uCmd = BMSG_SENDMSGTIMEOUT;
  784. bcm.to.fuFlags = fuFlags;
  785. bcm.to.uTimeout = uTimeout;
  786. bcm.to.lpdwResult = lpdwResult;
  787. pbcm = &bcm;
  788. }
  789. return xxxBroadcastMessage(NULL, message, wParam, lParam, uCmd, pbcm );
  790. }
  791. CheckLock(pwnd);
  792. if (message >= WM_DDE_FIRST && message <= WM_DDE_LAST) {
  793. /*
  794. * Even though apps should only send WM_DDE_INITIATE or WM_DDE_ACK
  795. * messages, we hook them all so DDESPY can monitor them.
  796. */
  797. if (!xxxDDETrackSendHook(pwnd, message, wParam, lParam)) {
  798. return 0;
  799. }
  800. if (message == WM_DDE_INITIATE && guDdeSendTimeout) {
  801. /*
  802. * This hack prevents DDE apps from locking up because some
  803. * one in the system has a top level window and is not
  804. * processing messages. guDdeSendTimeout is registry set.
  805. */
  806. if (lpdwResult == NULL) {
  807. lpdwResult = &uResult;
  808. }
  809. fuFlags |= SMTO_ABORTIFHUNG;
  810. uTimeout = guDdeSendTimeout;
  811. }
  812. }
  813. ptiCurrent = PtiCurrent();
  814. /*
  815. * Do inter-thread call if window queue differs from current queue
  816. */
  817. if (ptiCurrent != GETPTI(pwnd)) {
  818. INTRSENDMSGEX ism;
  819. PINTRSENDMSGEX pism = NULL;
  820. /*
  821. * If this window is a zombie, don't allow inter-thread send messages
  822. * to it.
  823. */
  824. if (HMIsMarkDestroy(pwnd))
  825. return xxxDefWindowProc(pwnd, message, wParam, lParam);
  826. if ( lpdwResult != NULL ) {
  827. /*
  828. * fail if we think the thread is hung
  829. */
  830. if ((fuFlags & SMTO_ABORTIFHUNG) && FHungApp(GETPTI(pwnd), CMSWAITTOKILLTIMEOUT))
  831. return 0;
  832. /*
  833. * Setup for a InterSend time-out call
  834. */
  835. ism.fuCall = ISM_TIMEOUT;
  836. ism.fuSend = fuFlags;
  837. ism.uTimeout = uTimeout;
  838. ism.lpdwResult = lpdwResult;
  839. pism = &ism;
  840. }
  841. lRet = xxxInterSendMsgEx(pwnd, message, wParam, lParam,
  842. ptiCurrent, GETPTI(pwnd), pism );
  843. return lRet;
  844. }
  845. /*
  846. * Call WH_CALLWNDPROC if it's installed and the window is not marked
  847. * as destroyed.
  848. */
  849. if (IsHooked(ptiCurrent, WHF_CALLWNDPROC)) {
  850. CWPSTRUCTEX cwps;
  851. cwps.hwnd = HWq(pwnd);
  852. cwps.message = message;
  853. cwps.wParam = wParam;
  854. cwps.lParam = lParam;
  855. cwps.psmsSender = NULL;
  856. /*
  857. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  858. * to the CWPSTRUCT contents.
  859. */
  860. xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROC);
  861. /*
  862. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  863. * to the CWPSTRUCT contents. If this behavior reverts to
  864. * Win3.1 semantics, we will need to copy the new parameters
  865. * from cwps.
  866. */
  867. }
  868. /*
  869. * If this window's proc is meant to be executed from the server side
  870. * we'll just stay inside the semaphore and call it directly. Note
  871. * how we don't convert the pwnd into an hwnd before calling the proc.
  872. */
  873. if (TestWF(pwnd, WFSERVERSIDEPROC)) {
  874. /*
  875. * We have a number of places where we do recursion in User. This often goes
  876. * through SendMessage (when we send a message to the parent for example) which
  877. * can eat the amount of stack we have
  878. */
  879. if ((IoGetRemainingStackSize() < KERNEL_STACK_MINIMUM_RESERVE)
  880. #if defined(_IA64_)
  881. || (GET_CURRENT_BSTORE() < KERNEL_BSTORE_MINIMUM_RESERVE)
  882. #endif
  883. ) {
  884. RIPMSG1(RIP_ERROR, "SendMessage: Thread recursing in User with message %lX; failing", message);
  885. return FALSE;
  886. }
  887. lRet = pwnd->lpfnWndProc(pwnd, message, wParam, lParam);
  888. if ( lpdwResult == NULL ) {
  889. return lRet;
  890. } else { /* time-out call */
  891. *lpdwResult = lRet;
  892. return TRUE;
  893. }
  894. }
  895. /*
  896. * Call the client or xxxDefWindowProc. pwnd is already locked.
  897. */
  898. xxxSendMessageToClient(pwnd, message, wParam, lParam, NULL, FALSE, &lRet);
  899. /*
  900. * Call WH_CALLWNDPROCRET if it's installed.
  901. */
  902. if (IsHooked(ptiCurrent, WHF_CALLWNDPROCRET)) {
  903. CWPRETSTRUCTEX cwps;
  904. cwps.hwnd = HWq(pwnd);
  905. cwps.message = message;
  906. cwps.wParam = wParam;
  907. cwps.lParam = lParam;
  908. cwps.lResult = lRet;
  909. cwps.psmsSender = NULL;
  910. /*
  911. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  912. * to the CWPSTRUCT contents.
  913. */
  914. xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROCRET);
  915. /*
  916. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  917. * to the CWPSTRUCT contents. If this behavior reverts to
  918. * Win3.1 semantics, we will need to copy the new parameters
  919. * from cwps.
  920. */
  921. }
  922. if ( lpdwResult != NULL ) { /* time-out call */
  923. *lpdwResult = lRet;
  924. return TRUE;
  925. }
  926. return lRet;
  927. }
  928. /***************************************************************************\
  929. * QueueNotifyMessage
  930. *
  931. * This routine queues up a notify message *only*, and does NOT do any callbacks
  932. * or any waits. This is for certain code that cannot do a callback for
  933. * compatibility reasons, but still needs to send notify messages (normal
  934. * notify messages actually do a callback if the calling thread created the
  935. * pwnd. Also this will NOT callback any hooks (sorry!)
  936. *
  937. * 04-13-93 ScottLu Created.
  938. \***************************************************************************/
  939. void QueueNotifyMessage(
  940. PWND pwnd,
  941. UINT message,
  942. WPARAM wParam,
  943. LPARAM lParam)
  944. {
  945. TL tlpwnd;
  946. BEGINATOMICCHECK();
  947. /*
  948. * We have to thread lock the window even though we don't leave
  949. * the critical section or else xxxSendMessageCallback complains.
  950. */
  951. ThreadLock(pwnd, &tlpwnd);
  952. xxxSendMessageCallback(pwnd, message, wParam, lParam, NULL, 1L, 0);
  953. ThreadUnlock(&tlpwnd);
  954. ENDATOMICCHECK();
  955. }
  956. /***************************************************************************\
  957. * xxxSystemBroadcastMessage
  958. *
  959. * Sends a message to all top-level windows in the system. To do this
  960. * for messages with parameters that point to data structures in a way
  961. * that won't block on a hung app, post an event message for
  962. * each window that is to receive the real message. The real message
  963. * will be sent when the event message is processed.
  964. *
  965. * History:
  966. * 05-12-94 JimA Created.
  967. \***************************************************************************/
  968. VOID xxxSystemBroadcastMessage(
  969. UINT message,
  970. WPARAM wParam,
  971. LPARAM lParam,
  972. UINT wCmd,
  973. PBROADCASTMSG pbcm)
  974. {
  975. PTHREADINFO ptiCurrent = PtiCurrent();
  976. PWINDOWSTATION pwinsta;
  977. PDESKTOP pdesk;
  978. TL tlpwinsta;
  979. TL tlpdesk;
  980. /*
  981. * Walk through all windowstations and desktop looking for
  982. * top-level windows.
  983. */
  984. ThreadLockWinSta(ptiCurrent, NULL, &tlpwinsta);
  985. ThreadLockDesktop(ptiCurrent, NULL, &tlpdesk, LDLT_FN_SYSTEMBROADCASTMESSAGE);
  986. for (pwinsta = grpWinStaList; pwinsta != NULL; ) {
  987. UINT wCmd1;
  988. if ((wCmd == BMSG_SENDMSG) && (pwinsta != ptiCurrent->rpdesk->rpwinstaParent))
  989. wCmd1 = BMSG_SENDNOTIFYMSG;
  990. else
  991. wCmd1 = wCmd;
  992. ThreadLockExchangeWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  993. for (pdesk = pwinsta->rpdeskList; pdesk != NULL; ) {
  994. ThreadLockExchangeDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_SYSTEMBROADCASTMESSAGE);
  995. /*
  996. * Bug 276814. Don't recurse calling again xxxBroadcastMessage if there
  997. * is no window on this desktop.
  998. */
  999. if (pdesk->pDeskInfo->spwnd != NULL) {
  1000. xxxBroadcastMessage(pdesk->pDeskInfo->spwnd, message, wParam, lParam,
  1001. wCmd1, pbcm);
  1002. }
  1003. pdesk = pdesk->rpdeskNext;
  1004. }
  1005. pwinsta = pwinsta->rpwinstaNext;
  1006. }
  1007. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SYSTEMBROADCASTMESSAGE);
  1008. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  1009. }
  1010. /***********************************************************************\
  1011. * xxxSendNotifyMessage (API)
  1012. *
  1013. * This function sends a message to the window proc associated with pwnd.
  1014. * The window proc is executed in the context of the thread which created
  1015. * pwnd. The function is identical to SendMessage() except that in the
  1016. * case of an inter-thread call, the send does not wait for a reply from
  1017. * the receiver, it simply returns a BOOL indicating success or failure.
  1018. * If the message is sent to a window on the current thread, then the
  1019. * function behaves just like SendMessage() and essentially does a
  1020. * subroutine call to pwnd's window procedure.
  1021. *
  1022. * History:
  1023. * 01-23-91 DavidPe Created.
  1024. * 07-14-92 ChrisBl Will return T/F if in same thread, as documented
  1025. \***********************************************************************/
  1026. BOOL xxxSendNotifyMessage(
  1027. PWND pwnd,
  1028. UINT message,
  1029. WPARAM wParam,
  1030. LPARAM lParam)
  1031. {
  1032. /*
  1033. * If this is a broadcast of one of the system
  1034. * notification messages, send it to all top-level
  1035. * windows in the system.
  1036. */
  1037. if (pwnd == PWND_BROADCAST) {
  1038. switch (message) {
  1039. case WM_WININICHANGE:
  1040. case WM_DEVMODECHANGE:
  1041. case WM_SPOOLERSTATUS:
  1042. xxxSystemBroadcastMessage(message, wParam, lParam,
  1043. BMSG_SENDNOTIFYMSG, NULL);
  1044. return 1;
  1045. default:
  1046. break;
  1047. }
  1048. }
  1049. return xxxSendMessageCallback( pwnd, message, wParam, lParam,
  1050. NULL, 0L, 0 );
  1051. }
  1052. /***********************************************************************\
  1053. * xxxSendMessageCallback (API)
  1054. *
  1055. * This function synchronously sends a message to a window. The four
  1056. * parameters hwnd, message, wParam, and lParam are passed to the window
  1057. * procedure of the receiving window. If the window receiving the message
  1058. * belongs to the same queue as the current thread, the window proc is called
  1059. * directly. Otherwise, we set up an sms structure, wake the appropriate
  1060. * thread to receive the message and give him a call back function to send
  1061. * the result to.
  1062. *
  1063. * History:
  1064. * 07-13-92 ChrisBl Created/extended from SendNotifyMessage
  1065. \***********************************************************************/
  1066. BOOL xxxSendMessageCallback(
  1067. PWND pwnd,
  1068. UINT message,
  1069. WPARAM wParam,
  1070. LPARAM lParam,
  1071. SENDASYNCPROC lpResultCallBack,
  1072. ULONG_PTR dwData,
  1073. BOOL fClientRequest)
  1074. {
  1075. LRESULT lRet;
  1076. PTHREADINFO ptiCurrent;
  1077. BOOL fQueuedNotify;
  1078. /*
  1079. * See if this is a queued notify message.
  1080. */
  1081. fQueuedNotify = FALSE;
  1082. if (lpResultCallBack == NULL && dwData == 1L)
  1083. fQueuedNotify = TRUE;
  1084. /*
  1085. * First check to see if this message takes DWORDs only. If it does not,
  1086. * fail the call. Cannot allow an app to post a message with pointers or
  1087. * handles in it - this can cause the server to fault and cause other
  1088. * problems - such as causing apps in separate address spaces to fault.
  1089. * (or even an app in the same address space to fault!)
  1090. */
  1091. if (TESTSYNCONLYMESSAGE(message, wParam)) {
  1092. RIPERR1(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING,
  1093. "Trying to non-synchronously send a structure msg=%lX", message);
  1094. return FALSE;
  1095. }
  1096. CheckCritIn();
  1097. /*
  1098. * Is this a BroadcastMsg()?
  1099. */
  1100. if (pwnd == PWND_BROADCAST) {
  1101. BROADCASTMSG bcm;
  1102. PBROADCASTMSG pbcm = NULL;
  1103. UINT uCmd = BMSG_SENDNOTIFYMSG;
  1104. if (lpResultCallBack != NULL) {
  1105. uCmd = BMSG_SENDMSGCALLBACK;
  1106. bcm.cb.lpResultCallBack = lpResultCallBack;
  1107. bcm.cb.dwData = dwData;
  1108. bcm.cb.bClientRequest = fClientRequest;
  1109. pbcm = &bcm;
  1110. }
  1111. return xxxBroadcastMessage(NULL, message, wParam, lParam, uCmd, pbcm );
  1112. }
  1113. CheckLock(pwnd);
  1114. ptiCurrent = PtiCurrent();
  1115. /*
  1116. * Do inter-thread call if window thead differs from current thread.
  1117. * We pass NULL for ptiSender to tell xxxInterSendMsgEx() that this is
  1118. * a xxxSendNotifyMessage() and that there's no need for a reply.
  1119. *
  1120. * If this is a queued notify, always call InterSendMsgEx() so that
  1121. * we queue it up and return - we don't do callbacks here with queued
  1122. * notifies.
  1123. */
  1124. if (fQueuedNotify || ptiCurrent != GETPTI(pwnd)) {
  1125. INTRSENDMSGEX ism;
  1126. PINTRSENDMSGEX pism = NULL;
  1127. if (lpResultCallBack != NULL) { /* CallBack request */
  1128. ism.fuCall = ISM_CALLBACK | (fClientRequest ? ISM_CB_CLIENT : 0);
  1129. ism.lpResultCallBack = lpResultCallBack;
  1130. ism.dwData = dwData;
  1131. pism = &ism;
  1132. }
  1133. return (BOOL)xxxInterSendMsgEx(pwnd, message, wParam, lParam,
  1134. NULL, GETPTI(pwnd), pism );
  1135. }
  1136. /*
  1137. * Call WH_CALLWNDPROC if it's installed.
  1138. */
  1139. if (!fQueuedNotify && IsHooked(ptiCurrent, WHF_CALLWNDPROC)) {
  1140. CWPSTRUCTEX cwps;
  1141. cwps.hwnd = HWq(pwnd);
  1142. cwps.message = message;
  1143. cwps.wParam = wParam;
  1144. cwps.lParam = lParam;
  1145. cwps.psmsSender = NULL;
  1146. /*
  1147. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  1148. * to the CWPSTRUCT contents.
  1149. */
  1150. xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROC);
  1151. /*
  1152. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  1153. * to the CWPSTRUCT contents. If this behavior reverts to
  1154. * Win3.1 semantics, we will need to copy the new parameters
  1155. * from cwps.
  1156. */
  1157. }
  1158. /*
  1159. * If this window's proc is meant to be executed from the server side
  1160. * we'll just stay inside the semaphore and call it directly. Note
  1161. * how we don't convert the pwnd into an hwnd before calling the proc.
  1162. */
  1163. if (TestWF(pwnd, WFSERVERSIDEPROC)) {
  1164. lRet = pwnd->lpfnWndProc(pwnd, message, wParam, lParam);
  1165. } else {
  1166. /*
  1167. * Call the client or xxxDefWindowProc. pwnd is already locked
  1168. */
  1169. xxxSendMessageToClient(pwnd, message, wParam, lParam, NULL, FALSE, &lRet);
  1170. }
  1171. if (lpResultCallBack != NULL) {
  1172. /*
  1173. * Call the callback funtion for the return value
  1174. */
  1175. if (fClientRequest) {
  1176. /*
  1177. * The application-defined callback proc is neither Unicode/ANSI
  1178. */
  1179. SET_FLAG(ptiCurrent->pcti->CTIF_flags, CTIF_INCALLBACKMESSAGE);
  1180. CallClientProcA(pwnd, message, dwData, lRet,
  1181. (ULONG_PTR)lpResultCallBack);
  1182. CLEAR_FLAG(ptiCurrent->pcti->CTIF_flags, CTIF_INCALLBACKMESSAGE);
  1183. } else {
  1184. (*lpResultCallBack)((HWND)pwnd, message, dwData, lRet);
  1185. }
  1186. }
  1187. /*
  1188. * Call WH_CALLWNDPROCRET if it's installed.
  1189. */
  1190. if (!fQueuedNotify && IsHooked(ptiCurrent, WHF_CALLWNDPROCRET)) {
  1191. CWPRETSTRUCTEX cwps;
  1192. cwps.hwnd = HWq(pwnd);
  1193. cwps.message = message;
  1194. cwps.wParam = wParam;
  1195. cwps.lParam = lParam;
  1196. cwps.lResult = lRet;
  1197. cwps.psmsSender = NULL;
  1198. /*
  1199. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  1200. * to the CWPSTRUCT contents.
  1201. */
  1202. xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROCRET);
  1203. /*
  1204. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  1205. * to the CWPSTRUCT contents. If this behavior reverts to
  1206. * Win3.1 semantics, we will need to copy the new parameters
  1207. * from cwps.
  1208. */
  1209. }
  1210. return TRUE;
  1211. }
  1212. /***********************************************************************\
  1213. * xxxInterSendMsgEx
  1214. *
  1215. * This function does an inter-thread send message. If ptiSender is NULL,
  1216. * that means we're called from xxxSendNotifyMessage() and should act
  1217. * accordingly.
  1218. *
  1219. * History:
  1220. * 07-13-92 ChrisBl Created/extended from xxxInterSendMsg
  1221. \***********************************************************************/
  1222. #define NoString 0
  1223. #define IsAnsiString 1
  1224. #define IsUnicodeString 2
  1225. /*
  1226. * We will capture the an address in two cases
  1227. * 1- If the address is a user mode address or
  1228. * 2- The call is a SendNotifyMessafe or SendMessageCallback.
  1229. *
  1230. * #2 is true if ptiSender is NULL see xxxSendMessageCallback implementation.
  1231. * Why we do that?
  1232. * if we are in SendNotifyMessafe or SendMessageCallback then force capture.
  1233. * because these two APIs will not wait till the receiver thread handles the
  1234. * message, then any kernel stack memory will be invalid once we return from
  1235. * these two APIs.
  1236. */
  1237. #define FORCE_CAPTURE(Addr) (!IS_SYSTEM_ADDRESS(Addr) || (ptiSender == NULL))
  1238. LRESULT xxxInterSendMsgEx(
  1239. PWND pwnd,
  1240. UINT message,
  1241. WPARAM wParam,
  1242. LPARAM lParam,
  1243. PTHREADINFO ptiSender,
  1244. PTHREADINFO ptiReceiver,
  1245. PINTRSENDMSGEX pism)
  1246. {
  1247. PSMS psms, *ppsms;
  1248. PSMS psmsSentSave;
  1249. LRESULT lRet = 0;
  1250. DWORD cbCapture, cbOutput;
  1251. PBYTE lpCapture;
  1252. PCOPYDATASTRUCT pcds;
  1253. PMDICREATESTRUCTEX pmdics;
  1254. LPHLP phlp;
  1255. LPHELPINFO phelpinfo;
  1256. LARGE_STRING str;
  1257. LPARAM lParamSave;
  1258. UINT fString = NoString;
  1259. BOOLEAN bWasSwapEnabled;
  1260. CheckCritIn();
  1261. /*
  1262. * If the sender is dying, fail the call
  1263. */
  1264. if ((ptiSender != NULL) && (ptiSender->TIF_flags & TIF_INCLEANUP))
  1265. return 0;
  1266. /*
  1267. * Some messages cannot be sent across process because we don't know how to thunk them
  1268. * Fail attempts to read passwords across processes.
  1269. */
  1270. if (pwnd && GETPTI(pwnd)->ppi != PpiCurrent()) {
  1271. switch (message) {
  1272. case EM_SETWORDBREAKPROC:
  1273. if (!RtlEqualLuid(&(GETPTI(pwnd)->ppi->luidSession), &(PpiCurrent()->luidSession))) {
  1274. RIPMSGF3(RIP_WARNING,
  1275. "Message cannot be sent across different LUID, pwnd: %p, message: 0x%x, target ppi: %p.",
  1276. pwnd,
  1277. message,
  1278. GETPTI(pwnd)->ppi);
  1279. return 0;
  1280. }
  1281. break;
  1282. case WM_INITDIALOG:
  1283. case WM_NOTIFY:
  1284. RIPMSG0(RIP_WARNING | RIP_THERESMORE, "xxxInterSendMsgEx: message cannot be sent across processes");
  1285. RIPMSG4(RIP_WARNING | RIP_THERESMORE, " pwnd:%#p message:%#x wParam:%#p lParam:%#p", pwnd, message, wParam, lParam);
  1286. return 0;
  1287. /*
  1288. * A change was introduced here to check with IS_EDIT macro instead of directly
  1289. * accessing FNID. The reason is to maintain conformity and not break
  1290. * comctl32 v6 password edits which can't set fnid field in pwnd.
  1291. */
  1292. case WM_GETTEXT:
  1293. case EM_GETLINE:
  1294. case EM_SETPASSWORDCHAR:
  1295. if (IS_EDIT(pwnd) && TestWF(pwnd, EFPASSWORD)) {
  1296. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Can't access protected edit control");
  1297. return 0;
  1298. }
  1299. break;
  1300. }
  1301. }
  1302. /*
  1303. * Alloc SMS structure.
  1304. */
  1305. psms = AllocSMS();
  1306. if (psms == NULL) {
  1307. /*
  1308. * Set to zero so xxxSendNotifyMessage would return FALSE.
  1309. */
  1310. return 0;
  1311. }
  1312. /*
  1313. * Prepare to capture variable length data from client
  1314. * space. Addresses have already been probed. Fixed-length
  1315. * data is probed and captured in the message thunk.
  1316. */
  1317. psms->pvCapture = NULL;
  1318. cbCapture = cbOutput = 0;
  1319. lpCapture = (LPBYTE)lParam;
  1320. /*
  1321. * If this is a reply message then wParam and lParam is equal NULL.
  1322. * No need to capture anything.
  1323. */
  1324. if ((pism != NULL) && (pism->fuCall == (ISM_CALLBACK | ISM_REPLY))) {
  1325. goto REPLY_MSG;
  1326. }
  1327. /*
  1328. * For messages with indirect data, set cbCapture and lpCapture
  1329. * (if not lParam) as approp.
  1330. */
  1331. try {
  1332. switch (message) {
  1333. case WM_COPYGLOBALDATA: // fnCOPYGLOBALDATA
  1334. cbCapture = (DWORD)wParam;
  1335. break;
  1336. case WM_COPYDATA: // fnCOPYDATA
  1337. pcds = (PCOPYDATASTRUCT)lParam;
  1338. if (pcds->lpData) {
  1339. cbCapture = sizeof(COPYDATASTRUCT) + pcds->cbData;
  1340. } else {
  1341. cbCapture = sizeof(COPYDATASTRUCT);
  1342. }
  1343. break;
  1344. case WM_CREATE: // fnINLPCREATESTRUCT
  1345. case WM_NCCREATE: // fnINLPCREATESTRUCT
  1346. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Can't Intersend WM_CREATE or WM_NCCREATE message");
  1347. FreeSMS(psms);
  1348. return 0;
  1349. case WM_HELP: // fnINLPHELPINFOSTRUCT
  1350. phelpinfo = (LPHELPINFO)lParam;
  1351. cbCapture = phelpinfo->cbSize;
  1352. break;
  1353. case WM_WINHELP: // fnINLPHLPSTRUCT
  1354. phlp = (LPHLP)lParam;
  1355. cbCapture = phlp->cbData;
  1356. break;
  1357. case WM_MDICREATE: // fnINLPMDICREATESTRUCT
  1358. pmdics = (PMDICREATESTRUCTEX)lParam;
  1359. cbCapture = pmdics->strTitle.MaximumLength +
  1360. pmdics->strClass.MaximumLength;
  1361. UserAssert(pmdics->strClass.Buffer == NULL || pmdics->strClass.Buffer == pmdics->mdics.szClass);
  1362. if (pmdics->strTitle.Buffer)
  1363. UserAssert(pmdics->strTitle.Buffer == pmdics->mdics.szTitle);
  1364. break;
  1365. case LB_ADDSTRING: // INLBOXSTRING calls fnINSTRING
  1366. case LB_INSERTSTRING: // INLBOXSTRING calls fnINSTRING
  1367. case LB_SELECTSTRING: // INLBOXSTRING calls fnINSTRING
  1368. case LB_FINDSTRING: // INLBOXSTRING calls fnINSTRING
  1369. case LB_FINDSTRINGEXACT: // INLBOXSTRING calls fnINSTRING
  1370. /*
  1371. * See if the control is ownerdraw and does not have the LBS_HASSTRINGS
  1372. * style. If so, treat lParam as a DWORD.
  1373. */
  1374. if (pwnd && !(pwnd->style & LBS_HASSTRINGS) &&
  1375. (pwnd->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))) {
  1376. /*
  1377. * Treat lParam as a dword.
  1378. */
  1379. break;
  1380. } else {
  1381. goto fnINSTRINGThunk;
  1382. }
  1383. break;
  1384. case CB_ADDSTRING: // INCBOXSTRING calls fnINSTRING
  1385. case CB_INSERTSTRING: // INCBOXSTRING calls fnINSTRING
  1386. case CB_SELECTSTRING: // INCBOXSTRING calls fnINSTRING
  1387. case CB_FINDSTRING: // INCBOXSTRING calls fnINSTRING
  1388. case CB_FINDSTRINGEXACT: // INCBOXSTRING calls fnINSTRING
  1389. /*
  1390. * See if the control is ownerdraw and does not have the CBS_HASSTRINGS
  1391. * style. If so, treat lParam as a DWORD.
  1392. */
  1393. if (pwnd && !(pwnd->style & CBS_HASSTRINGS) &&
  1394. (pwnd->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))) {
  1395. /*
  1396. * Treat lParam as a dword.
  1397. */
  1398. break;
  1399. } else {
  1400. goto fnINSTRINGThunk;
  1401. }
  1402. break;
  1403. case EM_REPLACESEL: // fnINSTRINGNULL
  1404. case WM_SETTEXT: // fnINSTRINGNULL
  1405. case WM_WININICHANGE: // fnINSTRINGNULL
  1406. if (lParam == 0)
  1407. break;
  1408. /*
  1409. * Fall through
  1410. */
  1411. case CB_DIR: // fnINSTRING
  1412. case LB_ADDFILE: // fnINSTRING
  1413. case LB_DIR: // fnINSTRING
  1414. case WM_DEVMODECHANGE: // fnINSTRING
  1415. fnINSTRINGThunk:
  1416. /*
  1417. * Only capture strings if they are not in system space or ptiSender
  1418. * is NULL (see FORCE_CAPTURE definition).
  1419. *
  1420. * Also we are going to capture the LARGE_STRING structure itself because
  1421. * it is (lParam) a stack memory.
  1422. */
  1423. str = *(PLARGE_STRING)lParam;
  1424. if (FORCE_CAPTURE(str.Buffer))
  1425. cbCapture = str.Length + sizeof(WCHAR) + sizeof(LARGE_STRING);
  1426. break;
  1427. case WM_DEVICECHANGE:
  1428. if (lParam == 0)
  1429. break;
  1430. /*
  1431. * Only capture data if lParam is a pointer and
  1432. * the data is not in system space
  1433. */
  1434. if ((wParam & 0x8000) != 0x8000)
  1435. break;
  1436. if (FORCE_CAPTURE((LPVOID)lParam)) {
  1437. cbCapture = *((DWORD *)lpCapture);
  1438. UserAssert(FALSE);
  1439. }
  1440. break;
  1441. case EM_SETTABSTOPS: // fnPOPTINLPUINT
  1442. case LB_SETTABSTOPS: // fnPOPTINLPUINT
  1443. case LB_GETSELITEMS: // fnPOUTLPINT
  1444. cbCapture = (UINT)wParam * sizeof(INT);
  1445. break;
  1446. case EM_GETLINE: // fnINCNTOUTSTRING
  1447. case WM_ASKCBFORMATNAME: // fnINCNTOUTSTRINGNULL
  1448. case WM_GETTEXT: // fnOUTSTRING
  1449. case LB_GETTEXT: // fnOUTLBOXSTRING
  1450. case CB_GETLBTEXT: // fnOUTCBOXSTRING
  1451. /*
  1452. * Only allocate output buffer if the real one is not in system space
  1453. */
  1454. str = *(PLARGE_STRING)lParam;
  1455. /*
  1456. * Bug 18108. For WM_GETTEXT only copy the actual string and not the
  1457. * the maximum size into the output buffer
  1458. */
  1459. if(str.bAnsi) {
  1460. fString = IsAnsiString ;
  1461. } else {
  1462. fString = IsUnicodeString ;
  1463. }
  1464. lParam = (LPARAM)&str;
  1465. if (FORCE_CAPTURE(str.Buffer))
  1466. cbCapture = str.MaximumLength;
  1467. break;
  1468. }
  1469. if (cbCapture &&
  1470. (psms->pvCapture = UserAllocPoolWithQuota(cbCapture, TAG_SMS_CAPTURE)) != NULL) {
  1471. lParamSave = lParam;
  1472. /*
  1473. * now actually copy memory from lpCapture to psms->pvCapture
  1474. * and fixup any references to the indirect data to point to
  1475. * psms->pvCapture.
  1476. */
  1477. switch (message) {
  1478. case WM_COPYDATA: // fnCOPYDATA
  1479. {
  1480. PCOPYDATASTRUCT pcdsNew = (PCOPYDATASTRUCT)psms->pvCapture;
  1481. lParam = (LPARAM)pcdsNew;
  1482. RtlCopyMemory(pcdsNew, pcds, sizeof(COPYDATASTRUCT));
  1483. if (pcds->lpData) {
  1484. pcdsNew->lpData = (PVOID)((PBYTE)pcdsNew + sizeof(COPYDATASTRUCT));
  1485. RtlCopyMemory(pcdsNew->lpData, pcds->lpData, pcds->cbData);
  1486. }
  1487. }
  1488. break;
  1489. case WM_MDICREATE: // fnINLPMDICREATESTRUCT
  1490. if (pmdics->strClass.Buffer) {
  1491. RtlCopyMemory(psms->pvCapture, pmdics->strClass.Buffer,
  1492. pmdics->strClass.MaximumLength);
  1493. pmdics->mdics.szClass = (LPWSTR)psms->pvCapture;
  1494. }
  1495. if (pmdics->strTitle.Length) {
  1496. lpCapture = (PBYTE)psms->pvCapture + pmdics->strClass.MaximumLength;
  1497. RtlCopyMemory(lpCapture, pmdics->strTitle.Buffer,
  1498. pmdics->strTitle.MaximumLength);
  1499. pmdics->mdics.szTitle = (LPWSTR)lpCapture;
  1500. }
  1501. break;
  1502. case CB_DIR: // fnINSTRING
  1503. case LB_FINDSTRING: // INLBOXSTRING calls fnINSTRING
  1504. case LB_FINDSTRINGEXACT: // INLBOXSTRING calls fnINSTRING
  1505. case CB_FINDSTRING: // INCBOXSTRING calls fnINSTRING
  1506. case CB_FINDSTRINGEXACT: // INCBOXSTRING calls fnINSTRING
  1507. case LB_ADDFILE: // fnINSTRING
  1508. case LB_ADDSTRING: // INLBOXSTRING calls fnINSTRING
  1509. case LB_INSERTSTRING: // INLBOXSTRING calls fnINSTRING
  1510. case LB_SELECTSTRING: // INLBOXSTRING calls fnINSTRING
  1511. case CB_ADDSTRING: // INCBOXSTRING calls fnINSTRING
  1512. case CB_INSERTSTRING: // INCBOXSTRING calls fnINSTRING
  1513. case CB_SELECTSTRING: // INCBOXSTRING calls fnINSTRING
  1514. case LB_DIR: // fnINSTRING
  1515. case WM_DEVMODECHANGE: // fnINSTRING
  1516. case EM_REPLACESEL: // fnINSTRINGNULL
  1517. case WM_SETTEXT: // fnINSTRINGNULL
  1518. case WM_WININICHANGE: // fnINSTRINGNULL
  1519. {
  1520. PLARGE_STRING pstr = psms->pvCapture;
  1521. lParam = (LPARAM)pstr;
  1522. pstr->bAnsi = str.bAnsi;
  1523. pstr->Length = str.Length;
  1524. pstr->Buffer = (LPBYTE)pstr + sizeof(LARGE_STRING);
  1525. pstr->MaximumLength = cbCapture - sizeof(LARGE_STRING);
  1526. UserAssert(pstr->MaximumLength == pstr->Length + sizeof(WCHAR));
  1527. RtlCopyMemory(pstr->Buffer, str.Buffer, pstr->MaximumLength);
  1528. }
  1529. break;
  1530. case LB_GETSELITEMS:
  1531. cbOutput = cbCapture;
  1532. RtlCopyMemory(psms->pvCapture, lpCapture, cbCapture);
  1533. lParam = (LPARAM)psms->pvCapture;
  1534. break;
  1535. case EM_GETLINE: // fnINCNTOUTSTRING
  1536. *(WORD *)psms->pvCapture = *(WORD *)str.Buffer;
  1537. /*
  1538. * Fall through
  1539. */
  1540. case WM_ASKCBFORMATNAME: // fnINCNTOUTSTRINGNULL
  1541. case WM_GETTEXT: // fnOUTSTRING
  1542. case LB_GETTEXT: // fnOUTLBOXSTRING
  1543. case CB_GETLBTEXT: // fnOUTCBOXSTRING
  1544. cbOutput = cbCapture;
  1545. lParamSave = (LPARAM)str.Buffer;
  1546. str.Buffer = psms->pvCapture;
  1547. break;
  1548. default:
  1549. RtlCopyMemory(psms->pvCapture, lpCapture, cbCapture);
  1550. lParam = (LPARAM)psms->pvCapture;
  1551. break;
  1552. }
  1553. }
  1554. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1555. if (psms->pvCapture != NULL)
  1556. UserFreePool(psms->pvCapture);
  1557. FreeSMS(psms);
  1558. return 0;
  1559. }
  1560. if (cbCapture && psms->pvCapture == NULL) {
  1561. FreeSMS(psms);
  1562. return 0;
  1563. }
  1564. REPLY_MSG:
  1565. /*
  1566. * Copy message parms
  1567. */
  1568. psms->spwnd = NULL;
  1569. psms->psmsReceiveNext = NULL;
  1570. #if DBG
  1571. psms->psmsSendList = NULL;
  1572. psms->psmsSendNext = NULL;
  1573. #endif
  1574. Lock(&(psms->spwnd), pwnd);
  1575. psms->message = message;
  1576. psms->wParam = wParam;
  1577. psms->lParam = lParam;
  1578. psms->flags = 0;
  1579. /*
  1580. * Link into gpsmsList
  1581. */
  1582. psms->psmsNext = gpsmsList;
  1583. gpsmsList = psms;
  1584. /*
  1585. * Time stamp message
  1586. */
  1587. psms->tSent = NtGetTickCount();
  1588. /*
  1589. * Set queue fields
  1590. */
  1591. psms->ptiReceiver = ptiReceiver;
  1592. psms->ptiSender = ptiSender;
  1593. psms->ptiCallBackSender = NULL;
  1594. if ((pism != NULL) && (pism->fuCall & ISM_CALLBACK)) {
  1595. /*
  1596. * Setup for a SendMessageCallback
  1597. */
  1598. psms->flags |= (pism->fuCall & ISM_CB_CLIENT) ? SMF_CB_CLIENT : SMF_CB_SERVER;
  1599. psms->lpResultCallBack = pism->lpResultCallBack;
  1600. psms->dwData = pism->dwData;
  1601. if (pism->fuCall & ISM_REPLY) {
  1602. psms->flags |= SMF_CB_REPLY;
  1603. psms->lRet = pism->lRet;
  1604. } else { /* REQUEST */
  1605. psms->flags |= SMF_CB_REQUEST;
  1606. psms->ptiCallBackSender = PtiCurrent();
  1607. }
  1608. }
  1609. /*
  1610. * Add SMS to the end of the ptiReceiver's receive list
  1611. */
  1612. ppsms = &ptiReceiver->psmsReceiveList;
  1613. while (*ppsms != NULL) {
  1614. ppsms = &((*ppsms)->psmsReceiveNext);
  1615. }
  1616. *ppsms = psms;
  1617. /*
  1618. * Link this SMS into the SendMsg chain. Of course only do this if
  1619. * it's not from a xxxSendNotifyMessage() call.
  1620. *
  1621. * The psmsSendNext field implements a chain of messages being
  1622. * processed because of an initial SendMsg call. For example, if
  1623. * thread A sends message M1 to thread B, which causes B to send
  1624. * message M2 to thread C, the SendMsg chain is M1->M2. If the
  1625. * system hangs in this situation, the chain is traversed to find
  1626. * the offending thread (C).
  1627. *
  1628. * psms->psmsSendList always points to the head of this list so
  1629. * we can tell where to begin a list traversal.
  1630. *
  1631. * ptiSender->psmsCurrent is the last SMS in the chain.
  1632. */
  1633. #if DBG
  1634. if (ptiSender != NULL && ptiSender->psmsCurrent != NULL) {
  1635. /*
  1636. * sending queue is currently processing a message sent to it,
  1637. * so append SMS to the chain. Link in the new sms because
  1638. * psmsSendNext may be pointing to a replied-to message.
  1639. */
  1640. psms->psmsSendNext = ptiSender->psmsCurrent->psmsSendNext;
  1641. ptiSender->psmsCurrent->psmsSendNext = psms;
  1642. psms->psmsSendList = ptiSender->psmsCurrent->psmsSendList;
  1643. } else {
  1644. /*
  1645. * sending queue is initiating a send sequence, so put sms at
  1646. * the head of the chain
  1647. */
  1648. psms->psmsSendList = psms;
  1649. }
  1650. #endif
  1651. if (ptiSender != NULL) {
  1652. /*
  1653. * ptiSender->psmsSent marks the most recent message sent from this
  1654. * thread that has not yet been replied to. Save the previous value
  1655. * on the stack so it can be restored when we get the reply.
  1656. *
  1657. * This way when an "older" SMS for this thread gets a reply before
  1658. * the "current" one does, the thread does get woken up.
  1659. */
  1660. psmsSentSave = ptiSender->psmsSent;
  1661. ptiSender->psmsSent = psms;
  1662. } else {
  1663. /*
  1664. * Set SMF_RECEIVERFREE since we'll be returning to
  1665. * xxxSendNotifyMessage() right away and won't get a
  1666. * chance to free it.
  1667. */
  1668. psms->flags |= SMF_RECEIVERFREE;
  1669. }
  1670. #ifdef DEBUG_SMS
  1671. ValidateSmsSendLists(psms);
  1672. #endif
  1673. /*
  1674. * If we're not being called from xxxSendNotifyMessage() or
  1675. * SendMessageCallback(), then sleep while we wait for the reply.
  1676. */
  1677. if (ptiSender == NULL) {
  1678. /*
  1679. * Wake receiver for the sent message
  1680. */
  1681. SetWakeBit(ptiReceiver, QS_SENDMESSAGE);
  1682. return (LONG)TRUE;
  1683. } else {
  1684. BOOL fTimeOut = FALSE;
  1685. UINT uTimeout = 0;
  1686. UINT uWakeMask = QS_SMSREPLY;
  1687. /*
  1688. * Wake up the receiver thread.
  1689. */
  1690. SetWakeBit(ptiReceiver, QS_SENDMESSAGE);
  1691. /*
  1692. * We have 4 sending cases:
  1693. *
  1694. * 16 - 16 : yield to the 16 bit receiver
  1695. * 32 - 16 : no yielding required
  1696. * 16 - 32 : sender yields while receiver processes the message
  1697. * 32 - 32 : no yielding required.
  1698. */
  1699. if (ptiSender->TIF_flags & TIF_16BIT || ptiReceiver->TIF_flags & TIF_16BIT) {
  1700. DirectedScheduleTask(ptiSender, ptiReceiver, TRUE, psms);
  1701. }
  1702. /*
  1703. * Put this thread to sleep until the reply arrives. First clear
  1704. * the QS_SMSREPLY bit, then leave the semaphore and go to sleep.
  1705. *
  1706. * IMPORTANT: The QS_SMSREPLY bit is not cleared once we get a
  1707. * reply because of the following case:
  1708. *
  1709. * We've recursed a second level into SendMessage() when the first level
  1710. * receiver thread dies, causing exit list processing to simulate
  1711. * a reply to the first message. When the second level send returns,
  1712. * SleepThread() is called again to get the first reply.
  1713. *
  1714. * Keeping QS_SMSREPLY set causes this call to SleepThread()
  1715. * to return without going to sleep to wait for the reply that has
  1716. * already happened.
  1717. */
  1718. if ( pism != NULL ) {
  1719. if (pism->fuSend & SMTO_BLOCK) {
  1720. /*
  1721. * only wait for a return, all other events will
  1722. * be ignored until timeout or return
  1723. */
  1724. uWakeMask |= QS_EXCLUSIVE;
  1725. }
  1726. uTimeout = pism->uTimeout;
  1727. }
  1728. /*
  1729. * Don't swap this guys stack while sleeping during a sendmessage
  1730. */
  1731. if (ptiSender->cEnterCount == 0) {
  1732. bWasSwapEnabled = KeSetKernelStackSwapEnable(FALSE);
  1733. } else {
  1734. UserAssert(ptiSender->cEnterCount > 0);
  1735. }
  1736. ptiSender->cEnterCount++;
  1737. while ((psms->flags & SMF_REPLY) == 0 && !fTimeOut) {
  1738. PHOOK phk = NULL;
  1739. TL tl;
  1740. BOOLEAN fRememberTimeout = FALSE;
  1741. ptiSender->pcti->fsChangeBits &= ~QS_SMSREPLY;
  1742. if (message == WM_HOOKMSG && lParam && GetAppCompatFlags2ForPti(ptiReceiver, VER51)) {
  1743. phk = ((PHOOKMSGSTRUCT)lParam)->phk;
  1744. switch (phk->iHook) {
  1745. case WH_KEYBOARD_LL:
  1746. case WH_MOUSE_LL:
  1747. ThreadLock(phk, &tl);
  1748. fRememberTimeout = TRUE;
  1749. break;
  1750. }
  1751. }
  1752. /*
  1753. * If SendMessageTimeout, sleep for timeout amount, else wait
  1754. * forever. Since this is not technically a transition to an
  1755. * idle condition, indicate that this sleep is not going "idle".
  1756. */
  1757. fTimeOut = !xxxSleepThread(uWakeMask, uTimeout, FALSE);
  1758. /*
  1759. * Windows bug 307738: EverQuest LL hook is virtually
  1760. * hung, blocking the DirectInput thread.
  1761. */
  1762. if (fRememberTimeout) {
  1763. phk->fLastHookHung = fTimeOut;
  1764. ThreadUnlock(&tl);
  1765. }
  1766. /*
  1767. * If a timeout occurs, and the SMTO_NOTIMEOUTIFNOTHUNG bit is set,
  1768. * and the app is still calling GetMessage(), then just try again.
  1769. * This probably means that the receiver has put up some UI in
  1770. * response to this message but the user hasn't completed the
  1771. * interaction yet.
  1772. */
  1773. if (fTimeOut && pism && (pism->fuSend & SMTO_NOTIMEOUTIFNOTHUNG) &&
  1774. !FHungApp(ptiReceiver, CMSHUNGAPPTIMEOUT)) {
  1775. fTimeOut = FALSE;
  1776. }
  1777. }
  1778. UserAssert(ptiSender->cEnterCount > 0);
  1779. if (--ptiSender->cEnterCount == 0) {
  1780. KeSetKernelStackSwapEnable(bWasSwapEnabled);
  1781. }
  1782. /*
  1783. * The reply bit should always be set! (even if we timed out). That
  1784. * is because if we're recursed into intersendmsg, we're going to
  1785. * return to the first intersendmsg's call to SleepThread() - and
  1786. * it needs to return back to intersendmsgex to see if its sms
  1787. * has been replied to.
  1788. */
  1789. SetWakeBit(ptiSender, QS_SMSREPLY);
  1790. /*
  1791. * Copy out captured data. If cbOutput != 0 we know
  1792. * that the output buffer is in user-mode address
  1793. * space.
  1794. */
  1795. if (!fTimeOut && cbOutput) {
  1796. PBYTE pbOutput;
  1797. INT len;
  1798. /*
  1799. * Probe output buffer if it is in the user's address space
  1800. */
  1801. pbOutput = (PBYTE)lParamSave;
  1802. try {
  1803. if(fString == NoString) {
  1804. RtlCopyMemory((PBYTE)pbOutput, psms->pvCapture,
  1805. cbOutput);
  1806. } else if(fString == IsAnsiString) {
  1807. len = strncpycch((LPSTR)pbOutput,(LPCSTR)psms->pvCapture,
  1808. cbOutput);
  1809. #if DBG
  1810. len--; //Length includes terminating NULL char
  1811. if(len != psms->lRet) {
  1812. RIPMSG0(RIP_WARNING,
  1813. "Length of the copied string being returned is diffrent from the actual string length");
  1814. }
  1815. #endif
  1816. } else { //IsUnicodeString
  1817. len = wcsncpycch((LPWSTR)pbOutput,(LPCWSTR)psms->pvCapture,
  1818. cbOutput/sizeof(WCHAR));
  1819. #if DBG
  1820. len--;
  1821. if(len != psms->lRet) {
  1822. RIPMSG0(RIP_WARNING,
  1823. "Length of the copied string being returned is diffrent from the actual string length");
  1824. }
  1825. #endif
  1826. }
  1827. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1828. /*
  1829. * Return 0 to indicate an error.
  1830. */
  1831. psms->lRet = 0;
  1832. }
  1833. }
  1834. /*
  1835. * we now have the reply -- restore psmsSent and save the return value
  1836. */
  1837. ptiSender->psmsSent = psmsSentSave;
  1838. if (pism == NULL) {
  1839. lRet = psms->lRet;
  1840. } else {
  1841. /*
  1842. * save the values off for a SendMesssageTimeOut
  1843. */
  1844. *pism->lpdwResult = psms->lRet;
  1845. lRet = (!fTimeOut) ? TRUE : FALSE; /* do this to ensure ret is T or F... */
  1846. /*
  1847. * If we did timeout and no reply was received, rely on
  1848. * the receiver to free the sms.
  1849. */
  1850. if (!(psms->flags & SMF_REPLY))
  1851. psms->flags |= SMF_REPLY | SMF_RECEIVERFREE;
  1852. }
  1853. /*
  1854. * If the reply came while the receiver is still processing
  1855. * the sms, force the receiver to free the sms. This can occur
  1856. * via timeout, ReplyMessage or journal cancel.
  1857. */
  1858. if ((psms->flags & (SMF_RECEIVERBUSY | SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE) {
  1859. psms->flags |= SMF_RECEIVERFREE;
  1860. }
  1861. /*
  1862. * Unlink the SMS structure from both the SendMsg chain and gpsmsList
  1863. * list and free it. This sms could be anywhere in the chain.
  1864. *
  1865. * If the SMS was replied to by a thread other than the receiver
  1866. * (ie. through ReplyMessage()), we don't free the SMS because the
  1867. * receiver is still processing it and will free it when done.
  1868. */
  1869. if ((psms->flags & SMF_RECEIVERFREE) == 0) {
  1870. UnlinkSendListSms(psms, NULL);
  1871. }
  1872. }
  1873. return lRet;
  1874. }
  1875. /***********************************************************************\
  1876. * xxxReceiveMessage
  1877. *
  1878. * This function receives a message sent from another thread. Physically,
  1879. * it gets the message, calls the window proc and then cleans up the
  1880. * fsWakeBits and sms stuctures.
  1881. *
  1882. * History:
  1883. * 01-13-91 DavidPe Ported.
  1884. * 01-23-91 DavidPe Add xxxSendNotifyMessage() support.
  1885. * 07-14-92 ChrisBl Added xxxSendMessageCallback support.
  1886. \***********************************************************************/
  1887. VOID xxxReceiveMessage(
  1888. PTHREADINFO ptiReceiver)
  1889. {
  1890. PSMS psms;
  1891. PSMS psmsCurrentSave;
  1892. PTHREADINFO ptiSender;
  1893. LRESULT lRet = 0;
  1894. TL tlpwnd;
  1895. CheckCritIn();
  1896. /*
  1897. * Get the SMS and unlink it from the list of SMSs we've received
  1898. */
  1899. psms = ptiReceiver->psmsReceiveList;
  1900. /*
  1901. * This can be NULL because an SMS can be removed in our cleanup
  1902. * code without clearing the QS_SENDMESSAGE bit.
  1903. */
  1904. if (psms == NULL) {
  1905. ptiReceiver->pcti->fsWakeBits &= ~QS_SENDMESSAGE;
  1906. ptiReceiver->pcti->fsChangeBits &= ~QS_SENDMESSAGE;
  1907. return;
  1908. }
  1909. ptiReceiver->psmsReceiveList = psms->psmsReceiveNext;
  1910. psms->psmsReceiveNext = NULL;
  1911. /*
  1912. * We've taken the SMS off the receive list - mark the SMS with this
  1913. * information - used during cleanup.
  1914. */
  1915. psms->flags |= SMF_RECEIVERBUSY | SMF_RECEIVEDMESSAGE;
  1916. /*
  1917. * Clear QS_SENDMESSAGE wakebit if list is now empty
  1918. */
  1919. if (ptiReceiver->psmsReceiveList == NULL) {
  1920. ptiReceiver->pcti->fsWakeBits &= ~QS_SENDMESSAGE;
  1921. ptiReceiver->pcti->fsChangeBits &= ~QS_SENDMESSAGE;
  1922. }
  1923. ptiSender = psms->ptiSender;
  1924. if (psms->flags & SMF_CB_REPLY) {
  1925. /*
  1926. * From SendMessageCallback REPLY to callback. We need to call
  1927. * the call back function to give the return value.
  1928. * Don't process any this message, just mechanism for notification
  1929. * the sender's thread lock is already gone, so we need to re-lock here.
  1930. */
  1931. if (ptiSender == NULL) {
  1932. ThreadLock(psms->spwnd, &tlpwnd);
  1933. }
  1934. if (psms->flags & SMF_CB_CLIENT) {
  1935. PTHREADINFO ptiCurrent = PtiCurrent();
  1936. /*
  1937. * Application-defined callback proc is neither Unicode nor ANSI
  1938. */
  1939. SET_FLAG(ptiCurrent->pcti->CTIF_flags, CTIF_INCALLBACKMESSAGE);
  1940. CallClientProcA(psms->spwnd, psms->message, psms->dwData,
  1941. psms->lRet, (ULONG_PTR)psms->lpResultCallBack);
  1942. CLEAR_FLAG(ptiCurrent->pcti->CTIF_flags, CTIF_INCALLBACKMESSAGE);
  1943. } else {
  1944. psms->lpResultCallBack(HW(psms->spwnd), psms->message,
  1945. psms->dwData, psms->lRet);
  1946. }
  1947. if (ptiSender == NULL) {
  1948. ThreadUnlock(&tlpwnd);
  1949. }
  1950. } else if (!(psms->flags & (SMF_REPLY | SMF_SENDERDIED | SMF_RECEIVERDIED))) {
  1951. /*
  1952. * Don't process message if it has been replied to already or
  1953. * if the sending or receiving thread has died
  1954. */
  1955. /*
  1956. * Set new psmsCurrent for this queue, saving the current one
  1957. */
  1958. psmsCurrentSave = ptiReceiver->psmsCurrent;
  1959. ptiReceiver->psmsCurrent = psms;
  1960. SET_FLAG(ptiReceiver->pcti->CTIF_flags, CTIF_INSENDMESSAGE);
  1961. /*
  1962. * If this SMS originated from a xxxSendNotifyMessage() or a
  1963. * xxxSendMessageCallback() call, the sender's thread lock is
  1964. * already gone, so we need to re-lock here.
  1965. */
  1966. if (ptiSender == NULL) {
  1967. ThreadLock(psms->spwnd, &tlpwnd);
  1968. }
  1969. if (psms->message == WM_HOOKMSG) {
  1970. union {
  1971. EVENTMSG emsg; // WH_JOURNALRECORD/PLAYBACK
  1972. MOUSEHOOKSTRUCTEX mhs; // WH_MOUSE
  1973. KBDLLHOOKSTRUCT kbds; // WH_KEYBORD_LL
  1974. MSLLHOOKSTRUCT mslls;// WH_MOUSE_LL
  1975. #ifdef REDIRECTION
  1976. HTHOOKSTRUCT ht; // WH_HITTEST
  1977. #endif // REDIRECTION
  1978. } LocalData;
  1979. PVOID pSendersData;
  1980. PHOOKMSGSTRUCT phkmp;
  1981. int iHook;
  1982. BOOL bAnsiHook;
  1983. /*
  1984. * Some hook types (eg: WH_JOURNALPLAYBACK) pass pointers to
  1985. * data in the calling thread's stack. We must copy this to our
  1986. * own (called thread's) stack for safety because of the way this
  1987. * "message" is handled and in case the calling thread dies. #13577
  1988. *
  1989. * Originally only WH_JOURNALRECORD and WH_JOURNALPLAYBACK went
  1990. * through this code, but now all sorts of hooks do.
  1991. */
  1992. phkmp = (PHOOKMSGSTRUCT)psms->lParam;
  1993. pSendersData = (PVOID)(phkmp->lParam);
  1994. iHook = phkmp->phk->iHook;
  1995. switch (iHook) {
  1996. case WH_JOURNALRECORD:
  1997. case WH_JOURNALPLAYBACK:
  1998. if (pSendersData)
  1999. LocalData.emsg = *(PEVENTMSG)pSendersData;
  2000. break;
  2001. case WH_MOUSE:
  2002. if (pSendersData)
  2003. LocalData.mhs = *(LPMOUSEHOOKSTRUCTEX)pSendersData;
  2004. break;
  2005. case WH_KEYBOARD_LL:
  2006. if (pSendersData)
  2007. LocalData.kbds = *(LPKBDLLHOOKSTRUCT)pSendersData;
  2008. break;
  2009. case WH_MOUSE_LL:
  2010. if (pSendersData)
  2011. LocalData.mslls = *(LPMSLLHOOKSTRUCT)pSendersData;
  2012. break;
  2013. #ifdef REDIRECTION
  2014. case WH_HITTEST:
  2015. if (pSendersData)
  2016. LocalData.ht = *(LPHTHOOKSTRUCT)pSendersData;
  2017. break;
  2018. #endif // REDIRECTION
  2019. case WH_KEYBOARD:
  2020. case WH_SHELL:
  2021. /*
  2022. * Fall thru...
  2023. */
  2024. pSendersData = NULL;
  2025. break;
  2026. default:
  2027. /*
  2028. * No pointers: wParam & lParam can be sent as is.
  2029. */
  2030. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Receive hook %d", iHook);
  2031. pSendersData = NULL;
  2032. break;
  2033. }
  2034. lRet = xxxCallHook2(phkmp->phk, phkmp->nCode, psms->wParam,
  2035. pSendersData ? (LPARAM)&LocalData : phkmp->lParam, &bAnsiHook);
  2036. /*
  2037. * Copy back data only if the sender hasn't died or timed out
  2038. * (timed out messages are marked SMF_REPLY by the sending thread)
  2039. */
  2040. if (!(psms->flags & (SMF_SENDERDIED|SMF_REPLY)) && pSendersData) {
  2041. switch (iHook) {
  2042. case WH_JOURNALRECORD:
  2043. case WH_JOURNALPLAYBACK:
  2044. *(PEVENTMSG)pSendersData = LocalData.emsg;
  2045. break;
  2046. case WH_KEYBOARD_LL:
  2047. *(LPKBDLLHOOKSTRUCT)pSendersData = LocalData.kbds;
  2048. break;
  2049. case WH_MOUSE_LL:
  2050. *(LPMSLLHOOKSTRUCT)pSendersData = LocalData.mslls;
  2051. break;
  2052. case WH_MOUSE:
  2053. *(LPMOUSEHOOKSTRUCTEX)pSendersData = LocalData.mhs;
  2054. break;
  2055. #ifdef REDIRECTION
  2056. case WH_HITTEST:
  2057. *(LPHTHOOKSTRUCT)pSendersData = LocalData.ht;
  2058. break;
  2059. #endif // REDIRECTION
  2060. }
  2061. }
  2062. } else {
  2063. /*
  2064. * Call WH_CALLWNDPROC if it's installed and the window is not marked
  2065. * as destroyed.
  2066. */
  2067. if (IsHooked(ptiReceiver, WHF_CALLWNDPROC)) {
  2068. CWPSTRUCTEX cwps;
  2069. cwps.hwnd = HW(psms->spwnd);
  2070. cwps.message = psms->message;
  2071. cwps.wParam = psms->wParam;
  2072. cwps.lParam = psms->lParam;
  2073. cwps.psmsSender = psms;
  2074. xxxCallHook(HC_ACTION, TRUE, (LPARAM)&cwps, WH_CALLWNDPROC);
  2075. /*
  2076. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  2077. * to the CWPSTRUCT contents. If this behavior reverts to
  2078. * Win3.1 semantics, we will need to copy the new parameters
  2079. * from cwps.
  2080. */
  2081. }
  2082. if (!(psms->flags & (SMF_REPLY | SMF_SENDERDIED | SMF_RECEIVERDIED)) &&
  2083. psms->spwnd != NULL) {
  2084. if (TestWF(psms->spwnd, WFSERVERSIDEPROC)) {
  2085. TL tlpwndKernel;
  2086. ThreadLock(psms->spwnd, &tlpwndKernel);
  2087. /*
  2088. * If this window's proc is meant to be executed from the server side
  2089. * we'll just stay inside the semaphore and call it directly. Note
  2090. * how we don't convert the pwnd into an hwnd before calling the proc.
  2091. */
  2092. lRet = psms->spwnd->lpfnWndProc(psms->spwnd, psms->message,
  2093. psms->wParam, psms->lParam);
  2094. ThreadUnlock(&tlpwndKernel);
  2095. } else {
  2096. /*
  2097. * Call the client or xxxDefWindowProc.
  2098. */
  2099. xxxSendMessageToClient(psms->spwnd, psms->message, psms->wParam, psms->lParam,
  2100. psms, TRUE, &lRet);
  2101. }
  2102. /*
  2103. * Call WH_CALLWNDPROCRET if it's installed.
  2104. */
  2105. if (IsHooked(ptiReceiver, WHF_CALLWNDPROCRET) &&
  2106. !(psms->flags & SMF_SENDERDIED)) {
  2107. CWPRETSTRUCTEX cwps;
  2108. cwps.hwnd = HW(psms->spwnd);
  2109. cwps.message = psms->message;
  2110. cwps.wParam = psms->wParam;
  2111. cwps.lParam = psms->lParam;
  2112. cwps.lResult = lRet;
  2113. cwps.psmsSender = psms;
  2114. /*
  2115. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  2116. * to the CWPSTRUCT contents.
  2117. */
  2118. xxxCallHook(HC_ACTION, TRUE, (LPARAM)&cwps, WH_CALLWNDPROCRET);
  2119. /*
  2120. * Unlike Win3.1, NT and Win95 ignore any changes the app makes
  2121. * to the CWPSTRUCT contents. If this behavior reverts to
  2122. * Win3.1 semantics, we will need to copy the new parameters
  2123. * from cwps.
  2124. */
  2125. }
  2126. }
  2127. }
  2128. if ((psms->flags & (SMF_CB_REQUEST | SMF_REPLY)) == SMF_CB_REQUEST) {
  2129. /*
  2130. * From SendMessageCallback REQUEST callback. Send the message
  2131. * back with a the REPLY value.
  2132. */
  2133. INTRSENDMSGEX ism;
  2134. psms->flags |= SMF_REPLY;
  2135. if (!(psms->flags & SMF_SENDERDIED)) {
  2136. ism.fuCall = ISM_CALLBACK | ISM_REPLY;
  2137. if (psms->flags & SMF_CB_CLIENT)
  2138. ism.fuCall |= ISM_CB_CLIENT;
  2139. ism.lpResultCallBack = psms->lpResultCallBack;
  2140. ism.dwData = psms->dwData;
  2141. ism.lRet = lRet;
  2142. xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L,
  2143. NULL, psms->ptiCallBackSender, &ism );
  2144. }
  2145. }
  2146. if (ptiSender == NULL) {
  2147. ThreadUnlock(&tlpwnd);
  2148. }
  2149. /*
  2150. * Restore receiver's original psmsCurrent.
  2151. */
  2152. ptiReceiver->psmsCurrent = psmsCurrentSave;
  2153. SET_OR_CLEAR_FLAG(ptiReceiver->pcti->CTIF_flags,
  2154. CTIF_INSENDMESSAGE,
  2155. ptiReceiver->psmsCurrent);
  2156. #ifdef DEBUG_SMS
  2157. ValidateSmsSendLists(psmsCurrentSave);
  2158. #endif
  2159. }
  2160. /*
  2161. * We're done with this sms, so the appropriate thread
  2162. * can now free it.
  2163. */
  2164. psms->flags &= ~SMF_RECEIVERBUSY;
  2165. /*
  2166. * Free the sms and return without reply if the
  2167. * SMF_RECEIVERFREE bit is set. Handily, this does just what we
  2168. * want for xxxSendNotifyMessage() since we set SMF_RECEIVERFREE
  2169. * in that case.
  2170. */
  2171. if (psms->flags & SMF_RECEIVERFREE) {
  2172. UnlinkSendListSms(psms, NULL);
  2173. return;
  2174. }
  2175. /*
  2176. * Set reply flag and return value if this message has not already
  2177. * been replied to with ReplyMessage().
  2178. */
  2179. if (!(psms->flags & SMF_REPLY)) {
  2180. psms->lRet = lRet;
  2181. psms->flags |= SMF_REPLY;
  2182. /*
  2183. * Tell the sender, the reply is done
  2184. */
  2185. if (ptiSender != NULL) {
  2186. /*
  2187. * Wake up the sender thread.
  2188. */
  2189. SetWakeBit(ptiSender, QS_SMSREPLY);
  2190. /*
  2191. * We have 4 conditions to satisfy:
  2192. *
  2193. * 16 - 16 : yielding required, if sender is waiting for this reply
  2194. * 32 - 16 : yielding required, if sender is waiting for this reply
  2195. * 16 - 32 : no yielding required
  2196. * 32 - 32 : No yielding required.
  2197. */
  2198. if (ptiSender->TIF_flags & TIF_16BIT || ptiReceiver->TIF_flags & TIF_16BIT) {
  2199. DirectedScheduleTask(ptiReceiver, ptiSender, FALSE, psms);
  2200. if (ptiReceiver->TIF_flags & TIF_16BIT &&
  2201. ptiSender->psmsSent == psms)
  2202. {
  2203. xxxSleepTask(TRUE, NULL);
  2204. }
  2205. }
  2206. }
  2207. }
  2208. }
  2209. /***********************************************************************\
  2210. * SendMsgCleanup
  2211. *
  2212. * This function cleans up sendmessage structures when the thread associated
  2213. * with a queue terminates. In the following, S is the sending thread,
  2214. * R the receiving thread.
  2215. *
  2216. * Case Table:
  2217. *
  2218. * single death:
  2219. * R no reply, S dies: mark that S died, R will free sms
  2220. * R no reply, R dies: fake reply for S
  2221. * R replied, S dies: free sms
  2222. * R replied, R dies: no problem
  2223. *
  2224. * double death:
  2225. * R no reply, S dies, R dies: free sms
  2226. * R no reply, R dies, S dies: free sms
  2227. * R replied, S dies, R dies: sms freed when S dies, as in single death
  2228. * R replied, R dies, S dies: sms freed when S dies, as in single death
  2229. *
  2230. * History:
  2231. * 01-13-91 DavidPe Ported.
  2232. \***********************************************************************/
  2233. VOID SendMsgCleanup(
  2234. PTHREADINFO ptiCurrent)
  2235. {
  2236. PSMS *ppsms;
  2237. PSMS psmsNext;
  2238. CheckCritIn();
  2239. for (ppsms = &gpsmsList; *ppsms; ) {
  2240. psmsNext = (*ppsms)->psmsNext;
  2241. if ((*ppsms)->ptiSender == ptiCurrent ||
  2242. (*ppsms)->ptiCallBackSender == ptiCurrent) {
  2243. SenderDied(*ppsms, ppsms);
  2244. } else if ((*ppsms)->ptiReceiver == ptiCurrent) {
  2245. ReceiverDied(*ppsms, ppsms);
  2246. }
  2247. /*
  2248. * If the message was not unlinked, go to the next one.
  2249. */
  2250. if (*ppsms != psmsNext)
  2251. ppsms = &(*ppsms)->psmsNext;
  2252. }
  2253. }
  2254. /***********************************************************************\
  2255. * ClearSendMessages
  2256. *
  2257. * This function marks messages destined for a given window as invalid.
  2258. *
  2259. * History:
  2260. * 01-13-91 DavidPe Ported.
  2261. \***********************************************************************/
  2262. VOID ClearSendMessages(
  2263. PWND pwnd)
  2264. {
  2265. PSMS psms, psmsNext;
  2266. PSMS *ppsms;
  2267. CheckCritIn();
  2268. psms = gpsmsList;
  2269. while (psms != NULL) {
  2270. /*
  2271. * Grab the next one beforehand in case we free the current one.
  2272. */
  2273. psmsNext = psms->psmsNext;
  2274. if (psms->spwnd == pwnd) {
  2275. /*
  2276. * If the sender has died, then mark this receiver free so the
  2277. * receiver will destroy it in its processing.
  2278. */
  2279. if (psms->flags & SMF_SENDERDIED) {
  2280. psms->flags |= SMF_REPLY | SMF_RECEIVERFREE;
  2281. } else {
  2282. /*
  2283. * The sender is alive. If the receiver hasn't replied to
  2284. * this yet, make a reply so the sender gets it. Make sure
  2285. * the receiver is the one free it so we don't have a race
  2286. * condition.
  2287. */
  2288. if (!(psms->flags & SMF_REPLY)) {
  2289. /*
  2290. * The sms is either still on the receive list
  2291. * or is currently being received. Since the sender
  2292. * is alive, we want the sender to get the reply
  2293. * to this SMS. If it hasn't been received, take
  2294. * it off the receive list and reply to it. If it
  2295. * has been received, then just leave it alone:
  2296. * it'll get replied to normally.
  2297. */
  2298. if (psms->flags & SMF_CB_REQUEST) {
  2299. /*
  2300. * From SendMessageCallback REQUEST callback. Send the
  2301. * message back with a the REPLY value.
  2302. */
  2303. TL tlpwnd;
  2304. INTRSENDMSGEX ism;
  2305. psms->flags |= SMF_REPLY;
  2306. ism.fuCall = ISM_CALLBACK | ISM_REPLY;
  2307. if (psms->flags & SMF_CB_CLIENT)
  2308. ism.fuCall |= ISM_CB_CLIENT;
  2309. ism.lpResultCallBack = psms->lpResultCallBack;
  2310. ism.dwData = psms->dwData;
  2311. ism.lRet = 0L; /* null return */
  2312. ThreadLock(psms->spwnd, &tlpwnd);
  2313. xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L,
  2314. NULL, psms->ptiCallBackSender, &ism );
  2315. ThreadUnlock(&tlpwnd);
  2316. } else if (!(psms->flags & SMF_RECEIVERBUSY)) {
  2317. /*
  2318. * If there is no sender, this is a notification
  2319. * message (nobody to reply to). In this case,
  2320. * just set the SMF_REPLY bit (SMF_RECEIVERFREE
  2321. * is already set) and this'll cause ReceiveMessage
  2322. * to just free this SMS and return.
  2323. */
  2324. if (psms->ptiSender == NULL) {
  2325. psms->flags |= SMF_REPLY;
  2326. } else {
  2327. /*
  2328. * There is a sender, and it wants a reply: take
  2329. * this SMS off the receive list, and reply
  2330. * to the sender.
  2331. */
  2332. for (ppsms = &(psms->ptiReceiver->psmsReceiveList);
  2333. *ppsms != NULL;
  2334. ppsms = &((*ppsms)->psmsReceiveNext)) {
  2335. if (*ppsms == psms) {
  2336. *ppsms = psms->psmsReceiveNext;
  2337. break;
  2338. }
  2339. }
  2340. /*
  2341. * Reply to this message so the sender
  2342. * wakes up.
  2343. */
  2344. psms->flags |= SMF_REPLY;
  2345. psms->lRet = 0;
  2346. psms->psmsReceiveNext = NULL;
  2347. SetWakeBit(psms->ptiSender, QS_SMSREPLY);
  2348. /*
  2349. * 16 bit senders need to be notifed that sends completed
  2350. * otherwise it may wait for a very long time for the reply.
  2351. */
  2352. if (psms->ptiSender->TIF_flags & TIF_16BIT) {
  2353. DirectedScheduleTask(psms->ptiReceiver, psms->ptiSender, FALSE, psms);
  2354. }
  2355. }
  2356. }
  2357. }
  2358. }
  2359. /*
  2360. * Unlock the pwnd from the SMS structure.
  2361. */
  2362. Unlock(&psms->spwnd);
  2363. }
  2364. psms = psmsNext;
  2365. }
  2366. }
  2367. /***********************************************************************\
  2368. * ReceiverDied
  2369. *
  2370. * This function cleans up the send message structures after a message
  2371. * receiver window or queue has died. It fakes a reply if one has not
  2372. * already been sent and the sender has not died. It frees the sms if
  2373. * the sender has died.
  2374. *
  2375. * History:
  2376. * 01-13-91 DavidPe Ported.
  2377. \***********************************************************************/
  2378. VOID ReceiverDied(
  2379. PSMS psms,
  2380. PSMS *ppsmsUnlink)
  2381. {
  2382. PSMS *ppsms;
  2383. PTHREADINFO ptiReceiver;
  2384. PTHREADINFO ptiSender;
  2385. /*
  2386. * mark that the receiver died
  2387. */
  2388. ptiReceiver = psms->ptiReceiver;
  2389. psms->ptiReceiver = NULL;
  2390. psms->flags |= SMF_RECEIVERDIED;
  2391. /*
  2392. * Unlink sms from thread if it is not dying. We need to do
  2393. * this for journal cleanup.
  2394. */
  2395. if (!(ptiReceiver->TIF_flags & TIF_INCLEANUP)) {
  2396. /*
  2397. * unlink sms from the receiver's receive list
  2398. */
  2399. for (ppsms = &(ptiReceiver->psmsReceiveList); *ppsms != NULL;
  2400. ppsms = &((*ppsms)->psmsReceiveNext)) {
  2401. if (*ppsms == psms) {
  2402. *ppsms = psms->psmsReceiveNext;
  2403. break;
  2404. }
  2405. }
  2406. /*
  2407. * clear the QS_SENDMESSAGE bit if there are no more messages
  2408. */
  2409. if (ptiReceiver->psmsReceiveList == NULL) {
  2410. ptiReceiver->pcti->fsWakeBits &= ~QS_SENDMESSAGE;
  2411. ptiReceiver->pcti->fsChangeBits &= ~QS_SENDMESSAGE;
  2412. }
  2413. } else {
  2414. /*
  2415. * The receiver thread is dying. Clear the received flag
  2416. * so that if there is a sender, it will free the sms.
  2417. */
  2418. psms->flags &= ~SMF_RECEIVERBUSY;
  2419. }
  2420. psms->psmsReceiveNext = NULL;
  2421. /*
  2422. * Check if the sender died or if the receiver was marked to
  2423. * free the sms.
  2424. */
  2425. if (psms->ptiSender == NULL) {
  2426. if (!(psms->flags & SMF_SENDERDIED) &&
  2427. (psms->flags & (SMF_CB_REQUEST | SMF_REPLY)) == SMF_CB_REQUEST) {
  2428. /*
  2429. * From SendMessageCallback REQUEST callback. Send the message
  2430. * back with a the REPLY value.
  2431. */
  2432. TL tlpwnd;
  2433. INTRSENDMSGEX ism;
  2434. psms->flags |= SMF_REPLY;
  2435. ism.fuCall = ISM_CALLBACK | ISM_REPLY;
  2436. if (psms->flags & SMF_CB_CLIENT)
  2437. ism.fuCall |= ISM_CB_CLIENT;
  2438. ism.lpResultCallBack = psms->lpResultCallBack;
  2439. ism.dwData = psms->dwData;
  2440. ism.lRet = 0L; /* null return */
  2441. ThreadLock(psms->spwnd, &tlpwnd);
  2442. xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L,
  2443. NULL, psms->ptiCallBackSender, &ism );
  2444. ThreadUnlock(&tlpwnd);
  2445. }
  2446. /*
  2447. * If the receiver is not processing the message, free it.
  2448. */
  2449. if (!(psms->flags & SMF_RECEIVERBUSY))
  2450. UnlinkSendListSms(psms, ppsmsUnlink);
  2451. return;
  2452. } else if (!(psms->flags & SMF_REPLY)) {
  2453. /*
  2454. * fake a reply
  2455. */
  2456. psms->flags |= SMF_REPLY;
  2457. psms->lRet = 0;
  2458. psms->ptiReceiver = NULL;
  2459. /*
  2460. * wake the sender if he was waiting for us
  2461. */
  2462. SetWakeBit(psms->ptiSender, QS_SMSREPLY);
  2463. } else {
  2464. /*
  2465. * There is a reply. We know the receiver is dying, so clear the
  2466. * SMF_RECEIVERFREE bit or the sender won't free this SMS!
  2467. * Although the sender's wake bit has already been set by the
  2468. * call to ClearSendMessages() earlier in the cleanup code,
  2469. * set it here again for safety.
  2470. *
  2471. * ??? Why would SMF_RECEIVERFREE be set?
  2472. */
  2473. psms->flags &= ~SMF_RECEIVERFREE;
  2474. SetWakeBit(psms->ptiSender, QS_SMSREPLY);
  2475. }
  2476. /*
  2477. * If the sender is a WOW task, that task is now blocked in the non-
  2478. * preemptive scheduler waiting for a reply. DestroyTask will
  2479. * clean this up (even if ptiReceiver is 32-bit).
  2480. */
  2481. ptiSender = psms->ptiSender;
  2482. if (ptiSender->TIF_flags & TIF_16BIT) {
  2483. DirectedScheduleTask(ptiReceiver, ptiSender, FALSE, psms);
  2484. }
  2485. /*
  2486. * Unlock this window from the sms: it is no longer needed, and will get
  2487. * rid of lock warnings.
  2488. */
  2489. Unlock(&psms->spwnd);
  2490. }
  2491. /***********************************************************************\
  2492. * SenderDied
  2493. *
  2494. * This function cleans up the send message structures after a message
  2495. * sender has died.
  2496. *
  2497. * History:
  2498. * 01-13-91 DavidPe Ported.
  2499. \***********************************************************************/
  2500. VOID SenderDied(
  2501. PSMS psms,
  2502. PSMS *ppsmsUnlink)
  2503. {
  2504. PTHREADINFO ptiSender;
  2505. BOOL fReply = FALSE;
  2506. /*
  2507. * mark the death
  2508. */
  2509. if (psms->ptiSender != NULL)
  2510. ptiSender = psms->ptiSender;
  2511. else
  2512. ptiSender = psms->ptiCallBackSender;
  2513. psms->ptiSender = NULL;
  2514. psms->flags |= SMF_SENDERDIED;
  2515. /*
  2516. * There are two cases where we leave the sms alone so the receiver
  2517. * can handle the message and then free the sms itself.
  2518. *
  2519. * 1. When the receiver is processing the message.
  2520. *
  2521. * 2. When the message has not yet been received.
  2522. */
  2523. /*
  2524. * If the receiver is processing the message, make it free the sms.
  2525. * Fake a reply for journal cancel.
  2526. */
  2527. if (psms->flags & SMF_RECEIVERBUSY) {
  2528. psms->flags |= SMF_RECEIVERFREE;
  2529. fReply = TRUE;
  2530. }
  2531. /*
  2532. * This sms may be in the process of being sent, but has not yet
  2533. * been received. In so, fake a reply and wake the sender.
  2534. * The last thread to touch the sms, either the sender or
  2535. * receiver, will free the sms.
  2536. */
  2537. if (ptiSender->psmsSent == psms)
  2538. fReply = TRUE;
  2539. /*
  2540. * If journalling is being cancelled and reply needs to be made,
  2541. * fake a reply and return.
  2542. */
  2543. if (!(ptiSender->TIF_flags & TIF_INCLEANUP) && fReply) {
  2544. /*
  2545. * fake a reply
  2546. */
  2547. psms->flags |= SMF_REPLY;
  2548. psms->lRet = 0;
  2549. /*
  2550. * wake the sender if he was waiting for us
  2551. */
  2552. SetWakeBit(ptiSender, QS_SMSREPLY);
  2553. return;
  2554. }
  2555. /*
  2556. * If the receiver isn't dead, check to see if it has honestly replied to
  2557. * this SMS. If it has not replied, leave it alone so the receiver can
  2558. * reply to it (it'll then clean it up). If it has replied, then it's
  2559. * ok to free it.
  2560. *
  2561. * It is also ok to free it if the receiver is dead.
  2562. */
  2563. if ((psms->flags & SMF_RECEIVERDIED) ||
  2564. (psms->flags & (SMF_REPLY | SMF_RECEIVERFREE)) == SMF_REPLY) {
  2565. UnlinkSendListSms(psms, ppsmsUnlink);
  2566. } else {
  2567. psms->flags |= SMF_RECEIVERFREE;
  2568. }
  2569. }
  2570. /***********************************************************************\
  2571. * UnlinkSendListSms
  2572. *
  2573. * This function unlinks an sms structure from both its SendMsg chain and
  2574. * the global gpsmsList and frees it.
  2575. *
  2576. * History:
  2577. * 01-13-91 DavidPe Ported.
  2578. \***********************************************************************/
  2579. VOID UnlinkSendListSms(
  2580. PSMS psms,
  2581. PSMS *ppsmsUnlink)
  2582. {
  2583. #if DBG
  2584. PSMS psmsT;
  2585. BOOL fUpdateSendList;
  2586. PSMS *ppsms;
  2587. #endif
  2588. CheckCritIn();
  2589. #ifdef DEBUG_SMS
  2590. ValidateSmsSendLists(psms);
  2591. #endif
  2592. UserAssert(psms->psmsReceiveNext == NULL);
  2593. #if DBG
  2594. /*
  2595. * Remember ahead of time if the psms we're unlinking is also the
  2596. * head of the sms send list (so we know if we need to update this field
  2597. * member in every SMS in this list).
  2598. */
  2599. fUpdateSendList = (psms == psms->psmsSendList);
  2600. /*
  2601. * Unlink sms from the sendlist chain. This effectively unlinks the SMS
  2602. * and updates psms->psmsSendList with the right head....
  2603. */
  2604. ppsms = &(psms->psmsSendList);
  2605. while (*ppsms != NULL) {
  2606. if (*ppsms == psms) {
  2607. *ppsms = psms->psmsSendNext;
  2608. break;
  2609. }
  2610. ppsms = &(*ppsms)->psmsSendNext;
  2611. }
  2612. /*
  2613. * Update psmsSendList if necessary. psms->psmsSendList has been updated
  2614. * with the right sms send list head... distribute this head to all other
  2615. * sms's in this chain if this sms we're removing the current head.
  2616. */
  2617. if (fUpdateSendList) {
  2618. for (psmsT = psms->psmsSendList; psmsT != NULL;
  2619. psmsT = psmsT->psmsSendNext) {
  2620. psmsT->psmsSendList = psms->psmsSendList;
  2621. }
  2622. }
  2623. psms->psmsSendList = NULL;
  2624. #endif
  2625. /*
  2626. * This unlinks an sms structure from the global gpsmsList and frees it.
  2627. */
  2628. if (ppsmsUnlink == NULL) {
  2629. ppsmsUnlink = &gpsmsList;
  2630. while (*ppsmsUnlink && (*ppsmsUnlink != psms)) {
  2631. ppsmsUnlink = &((*ppsmsUnlink)->psmsNext);
  2632. }
  2633. }
  2634. UserAssert(*ppsmsUnlink);
  2635. *ppsmsUnlink = psms->psmsNext;
  2636. Unlock(&psms->spwnd);
  2637. #if DBG
  2638. UserAssert(!(psms == psms->psmsSendList && psms->psmsSendNext != NULL));
  2639. #endif
  2640. if (psms->pvCapture)
  2641. UserFreePool(psms->pvCapture);
  2642. FreeSMS(psms);
  2643. }
  2644. /***************************************************************************\
  2645. * xxxSendSizeMessages
  2646. *
  2647. *
  2648. *
  2649. * History:
  2650. * 10-19-90 darrinm Ported from Win 3.0 sources.
  2651. \***************************************************************************/
  2652. void xxxSendSizeMessage(
  2653. PWND pwnd,
  2654. UINT cmdSize)
  2655. {
  2656. RECT rc;
  2657. CheckLock(pwnd);
  2658. // Added by Chicago: HACK ALERT:
  2659. // If the window is minimized then the real client width and height are
  2660. // zero. But, in win3.1 they were non-zero. Under Chicago, PrintShop
  2661. // Deluxe ver 1.2 hits a divide by zero. To fix this we fake the width
  2662. // and height for old apps to be non-zero values.
  2663. // GetClientRect does that job for us.
  2664. _GetClientRect(pwnd, &rc);
  2665. xxxSendMessage(pwnd, WM_SIZE, cmdSize,
  2666. MAKELONG(rc.right - rc.left, rc.bottom - rc.top));
  2667. }
  2668. /***************************************************************************\
  2669. * xxxProcessAsyncSendMessage
  2670. *
  2671. * Processes an event message posted by xxxSystemBroadcastMessage by
  2672. * sending a message to the window stored in the event.
  2673. *
  2674. * History:
  2675. * 05-12-94 JimA Created.
  2676. \***************************************************************************/
  2677. VOID xxxProcessAsyncSendMessage(
  2678. PASYNCSENDMSG pmsg)
  2679. {
  2680. PWND pwnd;
  2681. TL tlpwndT;
  2682. WCHAR awchString[MAX_PATH];
  2683. ATOM Atom = 0;
  2684. LARGE_UNICODE_STRING str;
  2685. pwnd = RevalidateHwnd(pmsg->hwnd);
  2686. if (pwnd != NULL) {
  2687. ThreadLockAlways(pwnd, &tlpwndT);
  2688. switch (pmsg->message) {
  2689. case WM_WININICHANGE:
  2690. case WM_DEVMODECHANGE:
  2691. if (pmsg->lParam) {
  2692. if (UserGetAtomName((ATOM)pmsg->lParam, awchString, sizeof(awchString))) {
  2693. Atom = (ATOM)pmsg->lParam;
  2694. RtlInitLargeUnicodeString(&str, awchString, (UINT)-1);
  2695. pmsg->lParam = (LPARAM)&str;
  2696. } else {
  2697. UserAssert(FALSE);
  2698. pmsg->lParam = 0;
  2699. }
  2700. }
  2701. break;
  2702. }
  2703. xxxSendMessage(pwnd, pmsg->message, pmsg->wParam, pmsg->lParam);
  2704. ThreadUnlock(&tlpwndT);
  2705. }
  2706. if (Atom) {
  2707. UserDeleteAtom(Atom);
  2708. }
  2709. UserFreePool(pmsg);
  2710. }
  2711. /***************************************************************************\
  2712. * xxxBroadcastMessage
  2713. *
  2714. *
  2715. *
  2716. * History:
  2717. * 02-21-91 DavidPe Created.
  2718. \***************************************************************************/
  2719. LONG xxxBroadcastMessage(
  2720. PWND pwnd,
  2721. UINT message,
  2722. WPARAM wParam,
  2723. LPARAM lParam,
  2724. UINT wCmd,
  2725. PBROADCASTMSG pbcm)
  2726. {
  2727. PBWL pbwl;
  2728. HWND *phwnd;
  2729. TL tlpwnd;
  2730. PASYNCSENDMSG pmsg;
  2731. PPROCESSINFO ppiCurrent;
  2732. LONG lRet = TRUE;
  2733. TL tlPool;
  2734. PTHREADINFO ptiCurrent = PtiCurrent();
  2735. BOOL fPrivateMessage = (message >= WM_USER) && (message < MAXINTATOM);
  2736. if (fPrivateMessage) {
  2737. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to broadcast a private message");
  2738. }
  2739. if (pwnd == NULL) {
  2740. LARGE_UNICODE_STRING str;
  2741. PLARGE_STRING pstr;
  2742. /*
  2743. * Handle special system-wide broadcasts.
  2744. */
  2745. switch (message) {
  2746. case WM_SPOOLERSTATUS:
  2747. xxxSystemBroadcastMessage(message, wParam, lParam, wCmd, pbcm);
  2748. return 1;
  2749. case WM_WININICHANGE:
  2750. case WM_DEVMODECHANGE:
  2751. /*
  2752. * Probe and capture the string.
  2753. */
  2754. if (lParam) {
  2755. UINT cbAlloc;
  2756. NTSTATUS Status;
  2757. /*
  2758. * Allocate a temp buffer and convert
  2759. * the string to Unicode
  2760. */
  2761. pstr = ((PLARGE_STRING)lParam);
  2762. if (pstr->bAnsi)
  2763. cbAlloc = (pstr->Length + 1) * sizeof(WCHAR);
  2764. else
  2765. cbAlloc = pstr->Length + sizeof(WCHAR);
  2766. str.Buffer = UserAllocPoolWithQuota(cbAlloc, TAG_SMS_STRING);
  2767. if (str.Buffer == NULL) {
  2768. return 0;
  2769. }
  2770. str.MaximumLength = cbAlloc;
  2771. str.bAnsi = FALSE;
  2772. try {
  2773. if (pstr->bAnsi) {
  2774. Status = RtlMultiByteToUnicodeN(
  2775. (PWCH)str.Buffer,
  2776. cbAlloc,
  2777. &cbAlloc,
  2778. (PCH)pstr->Buffer,
  2779. pstr->Length
  2780. );
  2781. str.Length = cbAlloc;
  2782. } else {
  2783. str.Length = pstr->Length;
  2784. RtlCopyMemory(str.Buffer, pstr->Buffer, str.Length);
  2785. Status = STATUS_SUCCESS;
  2786. }
  2787. str.Buffer[str.Length / sizeof(WCHAR)] = 0;
  2788. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  2789. Status = GetExceptionCode();
  2790. }
  2791. if (!NT_SUCCESS(Status)) {
  2792. UserFreePool(str.Buffer);
  2793. return 0;
  2794. }
  2795. pstr->Buffer = str.Buffer;
  2796. }
  2797. if (lParam) {
  2798. ThreadLockPool(ptiCurrent, str.Buffer, &tlPool);
  2799. }
  2800. xxxSystemBroadcastMessage(message, wParam,
  2801. lParam ? (LPARAM)&str : 0, wCmd, pbcm);
  2802. if (lParam)
  2803. ThreadUnlockAndFreePool(ptiCurrent, &tlPool);
  2804. return 1;
  2805. case WM_TIMECHANGE:
  2806. /*
  2807. * We automatically broadcast a WM_TIMECHANGE message whenever the
  2808. * kernel tells us the time has changed, so blow off any apps who
  2809. * are trying to do the same thing.
  2810. */
  2811. if (!(ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD)) {
  2812. RIPMSG0(RIP_WARNING, "Only system should broadcast WM_TIMECHANGE");
  2813. return 0;
  2814. }
  2815. break;
  2816. }
  2817. UserAssert(ptiCurrent->rpdesk);
  2818. pwnd = ptiCurrent->rpdesk->pDeskInfo->spwnd;
  2819. if (pwnd == NULL) {
  2820. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "sender must have an associated desktop");
  2821. return 0;
  2822. }
  2823. }
  2824. pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL);
  2825. if (pbwl == NULL)
  2826. return 0;
  2827. ppiCurrent = PpiCurrent();
  2828. for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
  2829. /*
  2830. * Make sure this hwnd is still around.
  2831. */
  2832. if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
  2833. continue;
  2834. /*
  2835. * Make sure this window can handle broadcast messages
  2836. */
  2837. if (!fBroadcastProc(pwnd))
  2838. continue;
  2839. if (fPrivateMessage && TestWF(pwnd, WFWIN40COMPAT)) { // Don't broadcast
  2840. continue; // private message
  2841. } // to 4.0 apps.
  2842. /*
  2843. * Don't bother sending palette messages to windows that are not
  2844. * visible on threads that are not palette aware.
  2845. */
  2846. if ((message == WM_PALETTEISCHANGING || message == WM_PALETTECHANGED) &&
  2847. !TestWF(pwnd, WFVISIBLE) &&
  2848. !(GETPTI(pwnd)->TIF_flags & TIF_PALETTEAWARE)) {
  2849. continue;
  2850. }
  2851. ThreadLockAlways(pwnd, &tlpwnd);
  2852. switch (wCmd) {
  2853. case BMSG_SENDMSG:
  2854. xxxSendMessage(pwnd, message, wParam, lParam);
  2855. break;
  2856. case BMSG_SENDNOTIFYMSG:
  2857. {
  2858. ATOM Atom = 0;
  2859. switch (message) {
  2860. case WM_WININICHANGE:
  2861. case WM_DEVMODECHANGE:
  2862. if (lParam) {
  2863. PLARGE_STRING pstr = (PLARGE_STRING)lParam;
  2864. /*
  2865. * Convert strings to atoms for the post.
  2866. */
  2867. if (pstr)
  2868. Atom = UserAddAtom(pstr->Buffer, FALSE);
  2869. if (!Atom) {
  2870. lRet = FALSE;
  2871. break;
  2872. }
  2873. }
  2874. /*
  2875. * These messages need to be able to cross
  2876. * desktops so PostEvent 'em.
  2877. */
  2878. pmsg = UserAllocPool(sizeof(ASYNCSENDMSG),
  2879. TAG_SMS_ASYNC);
  2880. if (pmsg == NULL) {
  2881. goto CleanupAtom;
  2882. }
  2883. pmsg->hwnd = *phwnd;
  2884. pmsg->message = message;
  2885. pmsg->wParam = wParam;
  2886. pmsg->lParam = Atom;
  2887. if (!PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq,
  2888. QEVENT_ASYNCSENDMSG,NULL, 0,
  2889. (WPARAM)pmsg, 0)) {
  2890. UserFreePool(pmsg);
  2891. CleanupAtom:
  2892. if (Atom) {
  2893. UserDeleteAtom(Atom);
  2894. }
  2895. lRet = FALSE;
  2896. }
  2897. break;
  2898. default:
  2899. /*
  2900. * A regular kind of guy. No desktop crossing.
  2901. */
  2902. xxxSendNotifyMessage(pwnd, message, wParam, lParam);
  2903. break;
  2904. }
  2905. }
  2906. break;
  2907. case BMSG_SENDNOTIFYMSGPROCESS:
  2908. UserAssert(message != WM_WININICHANGE && message != WM_DEVMODECHANGE);
  2909. /*
  2910. * Intra-process messages are synchronous; 22238.
  2911. * WM_PALETTECHANGED was being sent after the WM_DESTROY
  2912. * but console thread must not be synchronous.
  2913. */
  2914. if ((GETPTI(pwnd)->ppi == ppiCurrent) && !(GETPTI(pwnd)->TIF_flags & TIF_CSRSSTHREAD)) {
  2915. xxxSendMessage(pwnd, message, wParam, lParam);
  2916. } else {
  2917. xxxSendNotifyMessage(pwnd, message, wParam, lParam);
  2918. }
  2919. break;
  2920. case BMSG_POSTMSG:
  2921. /*
  2922. * Don't broadcast-post to owned windows (Win3.1 compatiblilty)
  2923. */
  2924. if (pwnd->spwndOwner == NULL)
  2925. _PostMessage(pwnd, message, wParam, lParam);
  2926. break;
  2927. case BMSG_SENDMSGCALLBACK:
  2928. xxxSendMessageCallback(pwnd, message, wParam, lParam,
  2929. pbcm->cb.lpResultCallBack, pbcm->cb.dwData, pbcm->cb.bClientRequest);
  2930. break;
  2931. case BMSG_SENDMSGTIMEOUT:
  2932. xxxSendMessageTimeout(pwnd, message, wParam, lParam,
  2933. pbcm->to.fuFlags, pbcm->to.uTimeout, pbcm->to.lpdwResult);
  2934. break;
  2935. }
  2936. ThreadUnlock(&tlpwnd);
  2937. }
  2938. FreeHwndList(pbwl);
  2939. /*
  2940. * Excel-Solver 3.0 expects a non-zero return value from a
  2941. * SendMessage(-1,WM_DDE_INITIATE,....); Because, we had
  2942. * FFFE_FARFRAME in 3.0, the DX register at this point always had
  2943. * a value of 0x102; But, because we removed it under Win3.1, we get
  2944. * a zero value in ax and dx; This makes solver think that the DDE has
  2945. * failed. So, to support the existing SOLVER, we make dx nonzero.
  2946. * Fix for Bug #6005 -- SANKAR -- 05-16-91 --
  2947. */
  2948. return 1;
  2949. }