Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

sendmsg.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: sendmsg.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Contains SendMessage, xxxSendNotifyMessage, ReplyMessage, InSendMessage, 00007 * RegisterWindowMessage and a few closely related functions. 00008 * 00009 * History: 00010 * 10-19-90 darrinm Created. 00011 * 02-04-91 IanJa Window handle revalidation added 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #include "pnp.h" 00016 #pragma hdrstop 00017 00018 #define IsASwitchWnd( pw ) \ 00019 (gpsi->atomSysClass[ICLS_SWITCH] == pw->pcls->atomClassName) 00020 00021 #define IsOleMainThreadWnd( pw ) \ 00022 (gaOleMainThreadWndClass == pw->pcls->atomClassName) 00023 00024 VOID UnlinkSendListSms(PSMS, PSMS *); 00025 VOID ReceiverDied(PSMS, PSMS *); 00026 VOID SenderDied(PSMS, PSMS *); 00027 NTSTATUS InitSMSLookaside(VOID); 00028 00029 #pragma alloc_text(INIT, InitSMSLookaside) 00030 00031 /* 00032 * Globals local to this file only 00033 */ 00034 PPAGED_LOOKASIDE_LIST SMSLookaside; 00035 00036 #ifdef DEBUG_SMS 00037 00038 /* 00039 * JimA - 08-24-94 00040 * In addition to doing no useful work, the psmsSendList/psmsSendNext 00041 * stuff is broken and therefore should be removed. It works fine as 00042 * long as straight SendMessage is used. The list will be broken if 00043 * a thread calls SendMessage while processing a message sent with 00044 * SentNotifyMessage or SendMessageCallback. 00045 */ 00046 void ValidateSmsSendLists(PSMS psms) 00047 { 00048 PSMS psmsT2; 00049 PSMS psmsT3; 00050 00051 /* 00052 * First try to find this SMS. 00053 */ 00054 if (psms != NULL) { 00055 for (psmsT2 = gpsmsList; psmsT2 != NULL; psmsT2 = psmsT2->psmsNext) { 00056 if (psmsT2 == psms) 00057 break; 00058 } 00059 00060 UserAssertMsg1(psmsT2 != NULL, "sms %x is not on global sms list\n", psms); 00061 } 00062 00063 /* 00064 * Validate every SMS's send list. 00065 */ 00066 for (psmsT2 = gpsmsList; psmsT2 != NULL; psmsT2 = psmsT2->psmsNext) { 00067 if (psmsT2->ptiSender != NULL) { 00068 for (psmsT3 = psmsT2->psmsSendList; psmsT3 != NULL; 00069 psmsT3 = psmsT3->psmsSendNext) { 00070 if (psmsT3 == psmsT2) 00071 break; 00072 } 00073 00074 UserAssertMsg2(psmsT3 != NULL, 00075 "sms %x is not on send list %x\n", 00076 psmsT2, 00077 psmsT2->psmsSendList); 00078 } 00079 } 00080 } 00081 #endif 00082 00083 /***************************************************************************\ 00084 * BroadcastProc 00085 * 00086 * Some windows need to be insulated from Broadcast messages. 00087 * These include icon title windows, the switch window, all 00088 * menu windows, etc. Before stuffing the message in the task's 00089 * queue, check to see if it is one we want to trash. 00090 * 00091 * Notes: this procedure does not do exactly the same thing it does in 00092 * windows 3.1. There it actually posts/Sends the message. For NT, it 00093 * just returns TRUE if we SHOULD post the message, or FALSE other wise 00094 * 00095 * History: 00096 * 25-Jun-1992 JonPa Ported from Windows 3.1 sources 00097 \***************************************************************************/ 00098 #define fBroadcastProc( pwnd ) \ 00099 (!(ISAMENU(pwnd) || IsASwitchWnd(pwnd) || IsOleMainThreadWnd(pwnd))) 00100 00101 00102 00103 /***************************************************************************\ 00104 * StubAllocSMS / StubFreeSMS 00105 * 00106 * These are stub routines for SMS allocations. We need these to call 00107 * our debug UserAlloc routines 00108 * 00109 * Dec-16-97 clupu Created. 00110 \***************************************************************************/ 00111 PVOID StubAllocSMS( 00112 POOL_TYPE PoolType, 00113 SIZE_T uBytes, 00114 ULONG iTag) 00115 { 00116 return UserAllocPool(uBytes, iTag); 00117 00118 UNREFERENCED_PARAMETER(PoolType); 00119 } 00120 00121 VOID StubFreeSMS( 00122 PVOID p) 00123 { 00124 UserFreePool(p); 00125 } 00126 00127 /***************************************************************************\ 00128 * InitSMSLookaside 00129 * 00130 * Initializes the SMS entry lookaside list. This improves SMS entry locality 00131 * by keeping SMS entries in a single page 00132 * 00133 * 09-09-93 Markl Created. 00134 \***************************************************************************/ 00135 00136 NTSTATUS 00137 InitSMSLookaside() 00138 { 00139 SMSLookaside = UserAllocPoolNonPaged(sizeof(PAGED_LOOKASIDE_LIST), TAG_LOOKASIDE); 00140 if (SMSLookaside == NULL) { 00141 return STATUS_NO_MEMORY; 00142 } 00143 00144 ExInitializePagedLookasideList(SMSLookaside, 00145 StubAllocSMS, 00146 StubFreeSMS, 00147 POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 00148 sizeof(SMS), 00149 TAG_SMS, 00150 8); 00151 00152 return STATUS_SUCCESS; 00153 } 00154 00155 /***************************************************************************\ 00156 * AllocSMS 00157 * 00158 * Allocates a message on a message list. DelSMS deletes a message 00159 * on a message list. 00160 * 00161 * 10-22-92 ScottLu Created. 00162 \***************************************************************************/ 00163 00164 PSMS AllocSMS( 00165 VOID) 00166 { 00167 return ExAllocateFromPagedLookasideList(SMSLookaside); 00168 } 00169 00170 /***************************************************************************\ 00171 * FreeSMS 00172 * 00173 * Returns a qmsg to the lookaside buffer or free the memory. 00174 * 00175 * 10-26-93 JimA Created. 00176 \***************************************************************************/ 00177 00178 void FreeSMS( 00179 PSMS psms) 00180 { 00181 ExFreeToPagedLookasideList(SMSLookaside, psms); 00182 } 00183 00184 /***************************************************************************\ 00185 * _ReplyMessage (API) 00186 * 00187 * This function replies to a message sent from one thread to another, using 00188 * the provided lRet value. 00189 * 00190 * The return value is TRUE if the calling thread is processing a SendMessage() 00191 * and FALSE otherwise. 00192 * 00193 * History: 00194 * 01-13-91 DavidPe Ported. 00195 * 01-24-91 DavidPe Rewrote for Windows. 00196 \***************************************************************************/ 00197 00198 BOOL _ReplyMessage( 00199 LRESULT lRet) 00200 { 00201 PTHREADINFO ptiCurrent; 00202 PSMS psms; 00203 00204 CheckCritIn(); 00205 00206 ptiCurrent = PtiCurrent(); 00207 00208 /* 00209 * Are we processing a SendMessage? 00210 */ 00211 psms = ptiCurrent->psmsCurrent; 00212 if (psms == NULL) 00213 return FALSE; 00214 00215 /* 00216 * See if the reply has been made already. 00217 */ 00218 if (psms->flags & SMF_REPLY) 00219 return FALSE; 00220 00221 /* 00222 * Blow off the rest of the call if the SMS came 00223 * from xxxSendNotifyMessage(). Obviously there's 00224 * no one around to reply to in the case. 00225 */ 00226 if (psms->ptiSender != NULL) { 00227 00228 /* 00229 * Reply to this message. The sender should not free the SMS 00230 * because the receiver still considers it valid. Thus we 00231 * mark it with a special bit indicating it has been replied 00232 * to. We wait until both the sender and receiver are done 00233 * with the sms before we free it. 00234 */ 00235 psms->lRet = lRet; 00236 psms->flags |= SMF_REPLY; 00237 00238 /* 00239 * Wake up the sender. 00240 * ??? why don't we test that psms == ptiSender->psmsSent? 00241 */ 00242 SetWakeBit(psms->ptiSender, QS_SMSREPLY); 00243 } else if (psms->flags & SMF_CB_REQUEST) { 00244 00245 /* 00246 * From SendMessageCallback REQUEST callback. Send the message 00247 * back with a the REPLY value. 00248 */ 00249 TL tlpwnd; 00250 INTRSENDMSGEX ism; 00251 00252 psms->flags |= SMF_REPLY; 00253 00254 if (!(psms->flags & SMF_SENDERDIED)) { 00255 ism.fuCall = ISM_CALLBACK | ISM_REPLY; 00256 if (psms->flags & SMF_CB_CLIENT) 00257 ism.fuCall |= ISM_CB_CLIENT; 00258 ism.lpResultCallBack = psms->lpResultCallBack; 00259 ism.dwData = psms->dwData; 00260 ism.lRet = lRet; 00261 00262 ThreadLockWithPti(ptiCurrent, psms->spwnd, &tlpwnd); 00263 00264 xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L, 00265 NULL, psms->ptiCallBackSender, &ism ); 00266 00267 ThreadUnlock(&tlpwnd); 00268 } 00269 } 00270 00271 /* 00272 * We have 4 conditions to satisfy: 00273 * 00274 * 16 - 16 : receiver yields if sender is waiting for this reply 00275 * 32 - 16 : receiver yields if sender is waiting for this reply 00276 * 16 - 32 : no yield required 00277 * 32 - 32 : No yielding required. 00278 */ 00279 if (psms->ptiSender && 00280 (psms->ptiSender->TIF_flags & TIF_16BIT || ptiCurrent->TIF_flags & TIF_16BIT)) { 00281 00282 DirectedScheduleTask(ptiCurrent, psms->ptiSender, FALSE, psms); 00283 if (ptiCurrent->TIF_flags & TIF_16BIT && psms->ptiSender->psmsSent == psms) { 00284 xxxSleepTask(TRUE, NULL); 00285 } 00286 } 00287 00288 return TRUE; 00289 } 00290 00291 VOID 00292 UserLogError( 00293 PCWSTR pwszError, 00294 ULONG cbError, 00295 NTSTATUS ErrorCode) 00296 { 00297 PIO_ERROR_LOG_PACKET perrLogEntry; 00298 00299 /* 00300 * Allocate an error packet, fill it out, and write it to the log. 00301 */ 00302 perrLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(gpWin32kDriverObject, 00303 (UCHAR)(cbError + sizeof(IO_ERROR_LOG_PACKET))); 00304 if (perrLogEntry) { 00305 perrLogEntry->ErrorCode = ErrorCode; 00306 if (cbError) { 00307 perrLogEntry->NumberOfStrings = 1; 00308 perrLogEntry->StringOffset = FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData); 00309 RtlCopyMemory(perrLogEntry->DumpData, pwszError, cbError); 00310 } 00311 IoWriteErrorLogEntry(perrLogEntry); 00312 } 00313 } 00314 00315 BOOL xxxSendBSMtoDesktop( 00316 PWND pwndDesk, 00317 UINT message, 00318 WPARAM wParam, 00319 LPARAM lParam, 00320 LPBROADCASTSYSTEMMSGPARAMS pbsmParams) 00321 { 00322 PBWL pbwl; 00323 HWND *phwnd; 00324 PWND pwnd; 00325 TL tlpwnd; 00326 BOOL fReturnValue = TRUE; 00327 PTHREADINFO ptiCurrent = PtiCurrent(); 00328 BOOL fPrivateMessage = (message >= WM_USER) && (message < MAXINTATOM); 00329 00330 00331 if (fPrivateMessage) { 00332 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to broadcast a private message"); 00333 } 00334 00335 pbwl = BuildHwndList(pwndDesk->spwndChild, BWL_ENUMLIST, NULL); 00336 00337 if (pbwl == NULL) 00338 return 0; 00339 00340 if (!(pbsmParams->dwFlags & BSF_POSTMESSAGE)) { 00341 /* 00342 * Does the caller want to allow the receivers to take the foreground 00343 * while processing the notification? 00344 */ 00345 /* 00346 * Bug 412159. In order to allow the AppsHelp window to come to the 00347 * foreground we set ptiLastWoken to NULL, which will allow any window 00348 * to come to the foreground after a CD's been inserted. 00349 */ 00350 if((pbsmParams->dwFlags & BSF_ALLOWSFW) && 00351 (GETPDESK(pwndDesk) == grpdeskRitInput) && 00352 ((ptiCurrent->TIF_flags & TIF_CSRSSTHREAD) 00353 || CanForceForeground(ptiCurrent->ppi))) { 00354 glinp.ptiLastWoken = NULL; 00355 } 00356 00357 } 00358 00359 for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { 00360 00361 /* 00362 * Make sure this hwnd is still around. 00363 */ 00364 if ((pwnd = RevalidateHwnd(*phwnd)) == NULL) 00365 continue; 00366 00367 if (pbsmParams->dwFlags & BSF_IGNORECURRENTTASK) { 00368 // Don't deal with windows in the current task. 00369 if (GETPTI(pwnd)->pq == ptiCurrent->pq) 00370 continue; 00371 } 00372 00373 00374 /* 00375 * Make sure this window can handle broadcast messages 00376 */ 00377 00378 if (!fBroadcastProc(pwnd)) { 00379 continue; 00380 } 00381 00382 if (fPrivateMessage && TestWF(pwnd, WFWIN40COMPAT)) { // Don't broadcast 00383 continue; // private message 00384 } // to 4.0 apps. 00385 00386 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 00387 00388 // Now, send message; This could be a query; so, remember the return value. 00389 if (pbsmParams->dwFlags & BSF_POSTMESSAGE) { 00390 _PostMessage(pwnd, message, wParam, lParam); 00391 } else if (pbsmParams->dwFlags & BSF_SENDNOTIFYMESSAGE) { 00392 /* 00393 * We don't want to wait for an answer, but we don't want to use 00394 * PostMessage either. This is useful if you need to maintain the 00395 * order in which messages are delivered, but you only want to 00396 * wait for some of them. See WM_POWERBROADCAST for an example. 00397 */ 00398 xxxSendNotifyMessage(pwnd, message, wParam, lParam); 00399 } else if (pbsmParams->dwFlags & BSF_QUEUENOTIFYMESSAGE) { 00400 /* 00401 * We don't want to wait for an answer, but we don't want to use 00402 * PostMessage either. This is useful if you need to maintain the 00403 * order in which messages are delivered, but you only want to 00404 * wait for some of them. See WM_POWERBROADCAST for an example. 00405 */ 00406 QueueNotifyMessage(pwnd, message, wParam, lParam); 00407 } else { 00408 /* 00409 * pbsmParams->dwFlags can be changed while we loop here 00410 * so we need to check it in every iteration. 00411 */ 00412 BOOL fNoHang = (BOOL)pbsmParams->dwFlags & BSF_NOHANG; 00413 BOOL fForce = (BOOL)pbsmParams->dwFlags & BSF_FORCEIFHUNG; 00414 DWORD dwTimeout; 00415 ULONG_PTR dwResult = 0; 00416 00417 if (fNoHang) 00418 dwTimeout = CMSWAITTOKILLTIMEOUT; 00419 else 00420 dwTimeout = 0; 00421 00422 if (xxxSendMessageTimeout(pwnd, message, wParam, lParam, 00423 (fNoHang ? SMTO_ABORTIFHUNG : SMTO_NORMAL) | 00424 ((pbsmParams->dwFlags & BSF_NOTIMEOUTIFNOTHUNG) ? SMTO_NOTIMEOUTIFNOTHUNG : 0), 00425 dwTimeout, &dwResult)) { 00426 00427 if (pbsmParams->dwFlags & BSF_QUERY) { 00428 // For old messages, returning 0 means a deny 00429 if(message == WM_QUERYENDSESSION) 00430 fReturnValue = (dwResult != 0); 00431 else 00432 // For all new messages, returning BROADCAST_QUERY_DENY is 00433 // the way to deny a query. 00434 fReturnValue = (dwResult != BROADCAST_QUERY_DENY); 00435 } 00436 } else { 00437 fReturnValue = fForce; 00438 } 00439 00440 /* 00441 * If our query was denied, return immediately. 00442 */ 00443 if (fReturnValue == 0) { 00444 if (message == WM_POWERBROADCAST && wParam == PBT_APMQUERYSUSPEND) { 00445 WCHAR wchTask[40]; 00446 ULONG cbTask; 00447 00448 /* 00449 * Get the application name and log an error. 00450 */ 00451 cbTask = GetTaskName(GETPTI(pwnd), wchTask, sizeof(wchTask)); 00452 UserLogError(wchTask, cbTask, WARNING_POWER_QUERYSUSPEND_CANCELLED); 00453 } 00454 ThreadUnlock(&tlpwnd); 00455 break; 00456 } 00457 } 00458 ThreadUnlock(&tlpwnd); 00459 } 00460 00461 FreeHwndList(pbwl); 00462 00463 return fReturnValue; 00464 } 00465 00466 LONG xxxSendMessageBSM( 00467 PWND pwnd, 00468 UINT message, 00469 WPARAM wParam, 00470 LPARAM lParam, 00471 LPBROADCASTSYSTEMMSGPARAMS pbsmParams) 00472 00473 { 00474 PTHREADINFO ptiCurrent = PtiCurrent(); 00475 LONG lRet; 00476 00477 if (pbsmParams->dwRecipients & BSM_ALLDESKTOPS) { 00478 PWINDOWSTATION pwinsta; 00479 PDESKTOP pdesk; 00480 TL tlpwinsta; 00481 TL tlpdesk; 00482 00483 /* 00484 * Walk through all windowstations and desktop looking for 00485 * top-level windows. 00486 */ 00487 ThreadLockWinSta(ptiCurrent, NULL, &tlpwinsta); 00488 ThreadLockDesktop(ptiCurrent, NULL, &tlpdesk, LDLT_FN_SENDMESSAGEBSM); 00489 for (pwinsta = grpWinStaList; pwinsta != NULL; ) { 00490 ThreadLockExchangeWinSta(ptiCurrent, pwinsta, &tlpwinsta); 00491 for (pdesk = pwinsta->rpdeskList; pdesk != NULL; ) { 00492 ThreadLockExchangeDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_SENDMESSAGEBSM); 00493 00494 lRet = xxxSendBSMtoDesktop(pdesk->pDeskInfo->spwnd, 00495 message, wParam, lParam, pbsmParams); 00496 00497 /* 00498 * If our query was denied, return immediately. 00499 */ 00500 if ((lRet == 0) && (pbsmParams->dwFlags & BSF_QUERY)) { 00501 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SENDMESSAGEBSM1); 00502 ThreadUnlockWinSta(ptiCurrent, &tlpwinsta); 00503 return 0; 00504 } 00505 pdesk = pdesk->rpdeskNext; 00506 } 00507 pwinsta = pwinsta->rpwinstaNext; 00508 } 00509 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SENDMESSAGEBSM2); 00510 ThreadUnlockWinSta(ptiCurrent, &tlpwinsta); 00511 00512 /* 00513 * If this is a power broadcast, inform any service that cares. 00514 */ 00515 if (message == WM_POWERBROADCAST && !gbRemoteSession) { 00516 LeaveCrit(); 00517 00518 /* 00519 * If it's a query, deliver it synchronously to pickup the return code 00520 */ 00521 if ((wParam == PBT_APMQUERYSUSPEND) || 00522 (wParam == PBT_APMQUERYSTANDBY)) { 00523 lRet = IoPnPDeliverServicePowerNotification((ULONG)wParam,TRUE); 00524 }else { 00525 lRet = IoPnPDeliverServicePowerNotification((ULONG)wParam,FALSE); 00526 00527 } 00528 EnterCrit(); 00529 } 00530 00531 } else { 00532 lRet = xxxSendBSMtoDesktop(pwnd, message, wParam, lParam, 00533 pbsmParams); 00534 } 00535 00536 return lRet; 00537 } 00538 00539 00540 /***************************************************************************\ 00541 * xxxSendMessageFF 00542 * 00543 * We can't check for -1 in the thunks because that would allow all message 00544 * thunk apis to take -1 erroneously. Since all message apis need to go through 00545 * the message thunks, the message thunks can only do least-common-denominator 00546 * hwnd validation (can't allow -1). So I made a special thunk that gets called 00547 * when SendMessage(-1) gets called. This means the client side will do the 00548 * special stuff to make sure the pwnd passed goes through thunk validation 00549 * ok. I do it this way rather than doing validation in all message apis and 00550 * not in the thunks (if I did it this way the code would be larger and 00551 * inefficient in the common cases). 00552 * 00553 * 03-20-92 ScottLu Created. 00554 \***************************************************************************/ 00555 00556 LRESULT xxxSendMessageFF( 00557 PWND pwnd, 00558 UINT message, 00559 WPARAM wParam, 00560 LPARAM lParam, 00561 ULONG_PTR xParam) 00562 { 00563 DBG_UNREFERENCED_PARAMETER(pwnd); 00564 00565 /* 00566 * Call xxxSendMessage() to do broadcasting rather than calling 00567 * broadcast from here in case any internal code that calls 00568 * sendmessage passes a -1 (that way the internal code doesn't 00569 * need to know about this weird routine). 00570 */ 00571 if (xParam != 0L) { 00572 /* 00573 * SendMessageTimeout call 00574 */ 00575 return xxxSendMessageEx(PWND_BROADCAST, message, wParam, lParam, xParam); 00576 } else { 00577 /* 00578 * Normal SendMessage call 00579 */ 00580 return xxxSendMessageTimeout(PWND_BROADCAST, message, wParam, 00581 lParam, SMTO_NORMAL, 0, NULL ); 00582 } 00583 } 00584 00585 /***************************************************************************\ 00586 * xxxSendMessageEx 00587 * 00588 * The SendMessageTimeOut sends a pointer to struct that holds the extra 00589 * params needed for the timeout call. Instead of chaning a bunch of things, 00590 * we use the xParam to hold a ptr to a struct. So we change the client/srv 00591 * entry point to hear so we can check for the extra param and extract the 00592 * stuff we need if it's there. 00593 * 00594 * 00595 * WARNING!!!! RETURN VALUE SWAPPED 00596 * 00597 * Only call this function from the thunks! 00598 * 00599 * our thunks are written for SendMessage where it returns the value of 00600 * the message. This routine is used to dispatch SendMessageTimeout calls. 00601 * SendMessageTimeout returns only TRUE or FALSE and returns the retval of 00602 * the function in lpdwResult. So here the meanings are swapped and fixed 00603 * up again in Client side SendMessageTimeout 00604 * 00605 * 00606 * 08-10-92 ChrisBl Created. 00607 \***************************************************************************/ 00608 00609 LRESULT xxxSendMessageEx( 00610 PWND pwnd, 00611 UINT message, 00612 WPARAM wParam, 00613 LPARAM lParam, 00614 ULONG_PTR xParam) 00615 { 00616 /* 00617 * extract values from the xParam if from TimeOut call 00618 * This should be the only way this function is ever 00619 * called, but check it just in case... 00620 */ 00621 if (xParam != 0L) { 00622 LRESULT lRet; 00623 LRESULT lResult; 00624 NTSTATUS Status; 00625 SNDMSGTIMEOUT smto; 00626 PETHREAD Thread = PsGetCurrentThread(); 00627 00628 if (Thread == NULL) 00629 return FALSE; 00630 00631 /* 00632 * Probe all read arguments 00633 */ 00634 try { 00635 ProbeForWrite((PVOID)xParam, sizeof(smto), sizeof(ULONG)); 00636 smto = *(SNDMSGTIMEOUT *)xParam; 00637 Status = STATUS_SUCCESS; 00638 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00639 Status = GetExceptionCode(); 00640 } 00641 if ( !NT_SUCCESS(Status) ) { 00642 return FALSE; 00643 } 00644 00645 lRet = xxxSendMessageTimeout(pwnd, message, wParam, lParam, 00646 smto.fuFlags, smto.uTimeout, &lResult ); 00647 00648 /* 00649 * put the result back into the client 00650 */ 00651 smto.lSMTOResult = lResult; 00652 smto.lSMTOReturn = lRet; 00653 00654 try { 00655 *(SNDMSGTIMEOUT *)xParam = smto; 00656 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00657 lResult = FALSE; 00658 } 00659 00660 /* 00661 * Return the lResult so our thunks are happy. 00662 */ 00663 return lResult; 00664 } 00665 00666 return xxxSendMessageTimeout(pwnd, message, wParam, 00667 lParam, SMTO_NORMAL, 0, NULL ); 00668 } 00669 00670 00671 /***********************************************************************\ 00672 * xxxSendMessage (API) 00673 * 00674 * This function synchronously sends a message to a window. The four 00675 * parameters hwnd, message, wParam, and lParam are passed to the window 00676 * procedure of the receiving window. If the window receiving the message 00677 * belongs to the same queue as the current thread, the window proc is called 00678 * directly. Otherwise, we set up an sms structure, wake the appropriate 00679 * thread to receive the message and wait for a reply. 00680 * 00681 * Returns: 00682 * the value returned by the window procedure, or NULL if there is an error 00683 * 00684 * History: 00685 * 01-13-91 DavidPe Ported. 00686 \***********************************************************************/ 00687 00688 LRESULT xxxSendMessage( 00689 PWND pwnd, 00690 UINT message, 00691 WPARAM wParam, 00692 LPARAM lParam) 00693 { 00694 return xxxSendMessageTimeout( pwnd, message, wParam, lParam, 00695 SMTO_NORMAL, 0, NULL ); 00696 } 00697 00698 /***********************************************************************\ 00699 * XXXSENDMESSAGETOCLIENT 00700 * 00701 * History: 00702 * 04-22-98 GerardoB Extracted from xxxSendMessageTimeout, xxxSendMesageCallback 00703 * and xxxReceiveMessage 00704 \***********************************************************************/ 00705 #define XXXSENDMESSAGETOCLIENT(pwnd, message, wParam, lParam, psms, fLock) \ 00706 { \ 00707 /* \ 00708 * If the window has a client side worker proc and has \ 00709 * not been subclassed, dispatch the message directly \ 00710 * to the worker proc. Otherwise, dispatch it normally \. 00711 */ \ 00712 DWORD dwSCMSFlags = TestWF((pwnd), WFANSIPROC) ? SCMS_FLAGS_ANSI : 0; \ 00713 WORD fnid = GETFNID((pwnd)); \ 00714 if ((fnid >= FNID_CONTROLSTART && fnid <= FNID_CONTROLEND) && \ 00715 ((ULONG_PTR)(pwnd)->lpfnWndProc == FNID_TO_CLIENT_PFNW(fnid) || \ 00716 (ULONG_PTR)(pwnd)->lpfnWndProc == FNID_TO_CLIENT_PFNA(fnid))) { \ 00717 PWNDMSG pwm = &gSharedInfo.awmControl[fnid - FNID_START] ; \ 00718 /* \ 00719 * If this message is not processed by the control, call \ 00720 * xxxDefWindowProc \ 00721 */ \ 00722 if (pwm->abMsgs && (((message) > pwm->maxMsgs) || \ 00723 !((pwm->abMsgs)[(message) / 8] & (1 << ((message) & 7))))) { \ 00724 /* \ 00725 * If this is a dialog window, we need to call the client because \ 00726 * the app might want this message (eventhough DefDlgProc doesn't \ 00727 * want it). \ 00728 * If the dialog hasn't been marked as such, the app's DlgProc is \ 00729 * not yet available so it's OK to ignore the message. \ 00730 */ \ 00731 if (TestWF((pwnd), WFDIALOGWINDOW)) { \ 00732 lRet = ScSendMessageSMS((pwnd), (message), (wParam), (lParam), \ 00733 dwSCMSFlags, (PROC)(FNID_TO_CLIENT_PFNWORKER(fnid)), \ 00734 dwSCMSFlags, (psms)); \ 00735 } else { \ 00736 TL tlpwnd; \ 00737 if (fLock) { \ 00738 ThreadLock((pwnd), &tlpwnd); \ 00739 } \ 00740 lRet = xxxDefWindowProc((pwnd), (message), (wParam), (lParam)); \ 00741 if (fLock) { \ 00742 ThreadUnlock(&tlpwnd); \ 00743 } \ 00744 } \ 00745 } else { \ 00746 lRet = ScSendMessageSMS((pwnd), (message), (wParam), (lParam), \ 00747 dwSCMSFlags, (PROC)(FNID_TO_CLIENT_PFNWORKER(fnid)), \ 00748 dwSCMSFlags, (psms)); \ 00749 } \ 00750 } else { \ 00751 lRet = ScSendMessageSMS((pwnd), (message), (wParam), (lParam), \ 00752 (ULONG_PTR)(pwnd)->lpfnWndProc, \ 00753 gpsi->apfnClientW.pfnDispatchMessage, dwSCMSFlags, (psms)); \ 00754 } \ 00755 } 00756 /***********************************************************************\ 00757 * xxxSendMessageTimeout (API) 00758 * 00759 * This function synchronously sends a message to a window. The four 00760 * parameters hwnd, message, wParam, and lParam are passed to the window 00761 * procedure of the receiving window. If the window receiving the message 00762 * belongs to the same queue as the current thread, the window proc is called 00763 * directly. Otherwise, we set up an sms structure, wake the appropriate 00764 * thread to receive the message and wait for a reply. 00765 * If the thread is 'hung' or if the time-out value is exceeded, we will 00766 * fail the request. 00767 * 00768 * lpdwResult = NULL if normal sendmessage, if !NULL then it's a timeout call 00769 * 00770 * Returns: 00771 * the value returned by the window procedure, or NULL if there is an error 00772 * 00773 * History: 00774 * 07-13-92 ChrisBl Created/extended from SendMessage 00775 \***********************************************************************/ 00776 00777 LRESULT xxxSendMessageTimeout( 00778 PWND pwnd, 00779 UINT message, 00780 WPARAM wParam, 00781 LPARAM lParam, 00782 UINT fuFlags, 00783 UINT uTimeout, 00784 PLONG_PTR lpdwResult) 00785 { 00786 LRESULT lRet; 00787 PTHREADINFO ptiCurrent; 00788 ULONG_PTR uResult; // holder for DDE_INITIATE case 00789 00790 CheckCritIn(); 00791 00792 if (lpdwResult != NULL) 00793 *lpdwResult = 0L; 00794 00795 /* 00796 * Is this a BroadcastMsg()? 00797 */ 00798 if (pwnd == PWND_BROADCAST) { 00799 BROADCASTMSG bcm; 00800 PBROADCASTMSG pbcm = NULL; 00801 UINT uCmd = BMSG_SENDMSG; 00802 00803 if (lpdwResult != NULL) { 00804 uCmd = BMSG_SENDMSGTIMEOUT; 00805 bcm.to.fuFlags = fuFlags; 00806 bcm.to.uTimeout = uTimeout; 00807 bcm.to.lpdwResult = lpdwResult; 00808 pbcm = &bcm; 00809 } 00810 00811 return xxxBroadcastMessage(NULL, message, wParam, lParam, uCmd, pbcm ); 00812 } 00813 00814 CheckLock(pwnd); 00815 00816 if (message >= WM_DDE_FIRST && message <= WM_DDE_LAST) { 00817 /* 00818 * Even though apps should only send WM_DDE_INITIATE or WM_DDE_ACK 00819 * messages, we hook them all so DDESPY can monitor them. 00820 */ 00821 if (!xxxDDETrackSendHook(pwnd, message, wParam, lParam)) { 00822 return 0; 00823 } 00824 if (message == WM_DDE_INITIATE && guDdeSendTimeout) { 00825 /* 00826 * This hack prevents DDE apps from locking up because some 00827 * bozo in the system has a top level window and is not 00828 * processing messages. guDdeSendTimeout is registry set. 00829 */ 00830 if (lpdwResult == NULL) { 00831 lpdwResult = &uResult; 00832 } 00833 fuFlags |= SMTO_ABORTIFHUNG; 00834 uTimeout = guDdeSendTimeout; 00835 } 00836 } 00837 00838 ptiCurrent = PtiCurrent(); 00839 00840 /* 00841 * Do inter-thread call if window queue differs from current queue 00842 */ 00843 if (ptiCurrent != GETPTI(pwnd)) { 00844 INTRSENDMSGEX ism; 00845 PINTRSENDMSGEX pism = NULL; 00846 00847 /* 00848 * If this window is a zombie, don't allow inter-thread send messages 00849 * to it. 00850 */ 00851 if (HMIsMarkDestroy(pwnd)) 00852 return xxxDefWindowProc(pwnd, message, wParam, lParam); 00853 00854 if ( lpdwResult != NULL ) { 00855 /* 00856 * fail if we think the thread is hung 00857 */ 00858 if ((fuFlags & SMTO_ABORTIFHUNG) && FHungApp(GETPTI(pwnd), CMSWAITTOKILLTIMEOUT)) 00859 return 0; 00860 00861 /* 00862 * Setup for a InterSend time-out call 00863 */ 00864 ism.fuCall = ISM_TIMEOUT; 00865 ism.fuSend = fuFlags; 00866 ism.uTimeout = uTimeout; 00867 ism.lpdwResult = lpdwResult; 00868 pism = &ism; 00869 } 00870 00871 lRet = xxxInterSendMsgEx(pwnd, message, wParam, lParam, 00872 ptiCurrent, GETPTI(pwnd), pism ); 00873 00874 return lRet; 00875 } 00876 00877 /* 00878 * Call WH_CALLWNDPROC if it's installed and the window is not marked 00879 * as destroyed. 00880 */ 00881 if (IsHooked(ptiCurrent, WHF_CALLWNDPROC)) { 00882 CWPSTRUCTEX cwps; 00883 00884 cwps.hwnd = HWq(pwnd); 00885 cwps.message = message; 00886 cwps.wParam = wParam; 00887 cwps.lParam = lParam; 00888 cwps.psmsSender = NULL; 00889 00890 /* 00891 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 00892 * to the CWPSTRUCT contents. 00893 */ 00894 xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROC); 00895 00896 /* 00897 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 00898 * to the CWPSTRUCT contents. If this behavior reverts to 00899 * Win3.1 semantics, we will need to copy the new parameters 00900 * from cwps. 00901 */ 00902 } 00903 00904 /* 00905 * If this window's proc is meant to be executed from the server side 00906 * we'll just stay inside the semaphore and call it directly. Note 00907 * how we don't convert the pwnd into an hwnd before calling the proc. 00908 */ 00909 if (TestWF(pwnd, WFSERVERSIDEPROC)) { 00910 00911 /* 00912 * We have a number of places where we do recursion in User. This often goes 00913 * through SendMessage (when we send a message to the parent for example) which 00914 * can eat the amount of stack we have 00915 */ 00916 if (((ULONG_PTR)&uResult - (ULONG_PTR)KeGetCurrentThread()->StackLimit) < KERNEL_STACK_MINIMUM_RESERVE) { 00917 RIPMSG1(RIP_ERROR, "SendMessage: Thread recursing in User with message %lX; failing", message); 00918 return FALSE; 00919 } 00920 00921 lRet = pwnd->lpfnWndProc(pwnd, message, wParam, lParam); 00922 00923 if ( lpdwResult == NULL ) { 00924 return lRet; 00925 } else { /* time-out call */ 00926 *lpdwResult = lRet; 00927 return TRUE; 00928 } 00929 } 00930 00931 /* 00932 * Call the client or xxxDefWindowProc. pwnd is already locked. 00933 */ 00934 XXXSENDMESSAGETOCLIENT(pwnd, message, wParam, lParam, NULL, FALSE); 00935 00936 /* 00937 * Call WH_CALLWNDPROCRET if it's installed. 00938 */ 00939 if (IsHooked(ptiCurrent, WHF_CALLWNDPROCRET)) { 00940 CWPRETSTRUCTEX cwps; 00941 00942 cwps.hwnd = HWq(pwnd); 00943 cwps.message = message; 00944 cwps.wParam = wParam; 00945 cwps.lParam = lParam; 00946 cwps.lResult = lRet; 00947 cwps.psmsSender = NULL; 00948 00949 /* 00950 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 00951 * to the CWPSTRUCT contents. 00952 */ 00953 xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROCRET); 00954 00955 /* 00956 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 00957 * to the CWPSTRUCT contents. If this behavior reverts to 00958 * Win3.1 semantics, we will need to copy the new parameters 00959 * from cwps. 00960 */ 00961 } 00962 00963 if ( lpdwResult != NULL ) { /* time-out call */ 00964 *lpdwResult = lRet; 00965 return TRUE; 00966 } 00967 00968 return lRet; 00969 } 00970 /***************************************************************************\ 00971 * QueueNotifyMessage 00972 * 00973 * This routine queues up a notify message *only*, and does NOT do any callbacks 00974 * or any waits. This is for certain code that cannot do a callback for 00975 * compatibility reasons, but still needs to send notify messages (normal 00976 * notify messages actually do a callback if the calling thread created the 00977 * pwnd. Also this will NOT callback any hooks (sorry!) 00978 * 00979 * 04-13-93 ScottLu Created. 00980 \***************************************************************************/ 00981 00982 void QueueNotifyMessage( 00983 PWND pwnd, 00984 UINT message, 00985 WPARAM wParam, 00986 LPARAM lParam) 00987 { 00988 TL tlpwnd; 00989 BEGINATOMICCHECK(); 00990 00991 /* 00992 * We have to thread lock the window even though we don't leave 00993 * the semaphore or else xxxSendMessageCallback complains 00994 */ 00995 ThreadLock(pwnd, &tlpwnd); 00996 xxxSendMessageCallback(pwnd, message, wParam, lParam, NULL, 1L, 0); 00997 ThreadUnlock(&tlpwnd); 00998 ENDATOMICCHECK(); 00999 } 01000 01001 01002 /***************************************************************************\ 01003 * xxxSystemBroadcastMessage 01004 * 01005 * Sends a message to all top-level windows in the system. To do this 01006 * for messages with parameters that point to data structures in a way 01007 * that won't block on a hung app, post an event message for 01008 * each window that is to receive the real message. The real message 01009 * will be sent when the event message is processed. 01010 * 01011 * History: 01012 * 05-12-94 JimA Created. 01013 \***************************************************************************/ 01014 01015 VOID xxxSystemBroadcastMessage( 01016 UINT message, 01017 WPARAM wParam, 01018 LPARAM lParam, 01019 UINT wCmd, 01020 PBROADCASTMSG pbcm) 01021 { 01022 PTHREADINFO ptiCurrent = PtiCurrent(); 01023 PWINDOWSTATION pwinsta; 01024 PDESKTOP pdesk; 01025 TL tlpwinsta; 01026 TL tlpdesk; 01027 01028 /* 01029 * Walk through all windowstations and desktop looking for 01030 * top-level windows. 01031 */ 01032 ThreadLockWinSta(ptiCurrent, NULL, &tlpwinsta); 01033 ThreadLockDesktop(ptiCurrent, NULL, &tlpdesk, LDLT_FN_SYSTEMBROADCASTMESSAGE); 01034 for (pwinsta = grpWinStaList; pwinsta != NULL; ) { 01035 UINT wCmd1; 01036 01037 if ((wCmd == BMSG_SENDMSG) && (pwinsta != ptiCurrent->rpdesk->rpwinstaParent)) 01038 wCmd1 = BMSG_SENDNOTIFYMSG; 01039 else 01040 wCmd1 = wCmd; 01041 01042 ThreadLockExchangeWinSta(ptiCurrent, pwinsta, &tlpwinsta); 01043 for (pdesk = pwinsta->rpdeskList; pdesk != NULL; ) { 01044 01045 ThreadLockExchangeDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_SYSTEMBROADCASTMESSAGE); 01046 01047 /* 01048 * Bug 276814. Don't recurse calling again xxxBroadcastMessage if there 01049 * is no window on this desktop. 01050 */ 01051 if (pdesk->pDeskInfo->spwnd != NULL) { 01052 xxxBroadcastMessage(pdesk->pDeskInfo->spwnd, message, wParam, lParam, 01053 wCmd1, pbcm); 01054 } 01055 01056 pdesk = pdesk->rpdeskNext; 01057 } 01058 pwinsta = pwinsta->rpwinstaNext; 01059 } 01060 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SYSTEMBROADCASTMESSAGE); 01061 ThreadUnlockWinSta(ptiCurrent, &tlpwinsta); 01062 } 01063 01064 01065 /***********************************************************************\ 01066 * xxxSendNotifyMessage (API) 01067 * 01068 * This function sends a message to the window proc associated with pwnd. 01069 * The window proc is executed in the context of the thread which created 01070 * pwnd. The function is identical to SendMessage() except that in the 01071 * case of an inter-thread call, the send does not wait for a reply from 01072 * the receiver, it simply returns a BOOL indicating success or failure. 01073 * If the message is sent to a window on the current thread, then the 01074 * function behaves just like SendMessage() and essentially does a 01075 * subroutine call to pwnd's window procedure. 01076 * 01077 * History: 01078 * 01-23-91 DavidPe Created. 01079 * 07-14-92 ChrisBl Will return T/F if in same thread, as documented 01080 \***********************************************************************/ 01081 01082 BOOL xxxSendNotifyMessage( 01083 PWND pwnd, 01084 UINT message, 01085 WPARAM wParam, 01086 LPARAM lParam) 01087 { 01088 /* 01089 * If this is a broadcast of one of the system 01090 * notification messages, send it to all top-level 01091 * windows in the system. 01092 */ 01093 if (pwnd == PWND_BROADCAST) { 01094 switch (message) { 01095 case WM_WININICHANGE: 01096 case WM_DEVMODECHANGE: 01097 case WM_SPOOLERSTATUS: 01098 xxxSystemBroadcastMessage(message, wParam, lParam, 01099 BMSG_SENDNOTIFYMSG, NULL); 01100 return 1; 01101 01102 default: 01103 break; 01104 } 01105 } 01106 01107 return xxxSendMessageCallback( pwnd, message, wParam, lParam, 01108 NULL, 0L, 0 ); 01109 } 01110 01111 01112 /***********************************************************************\ 01113 * xxxSendMessageCallback (API) 01114 * 01115 * This function synchronously sends a message to a window. The four 01116 * parameters hwnd, message, wParam, and lParam are passed to the window 01117 * procedure of the receiving window. If the window receiving the message 01118 * belongs to the same queue as the current thread, the window proc is called 01119 * directly. Otherwise, we set up an sms structure, wake the appropriate 01120 * thread to receive the message and give him a call back function to send 01121 * the result to. 01122 * 01123 * History: 01124 * 07-13-92 ChrisBl Created/extended from SendNotifyMessage 01125 \***********************************************************************/ 01126 01127 BOOL xxxSendMessageCallback( 01128 PWND pwnd, 01129 UINT message, 01130 WPARAM wParam, 01131 LPARAM lParam, 01132 SENDASYNCPROC lpResultCallBack, 01133 ULONG_PTR dwData, 01134 BOOL fClientRequest) 01135 { 01136 LRESULT lRet; 01137 PTHREADINFO ptiCurrent; 01138 BOOL fQueuedNotify; 01139 01140 /* 01141 * See if this is a queued notify message. 01142 */ 01143 fQueuedNotify = FALSE; 01144 if (lpResultCallBack == NULL && dwData == 1L) 01145 fQueuedNotify = TRUE; 01146 01147 /* 01148 * First check to see if this message takes DWORDs only. If it does not, 01149 * fail the call. Cannot allow an app to post a message with pointers or 01150 * handles in it - this can cause the server to fault and cause other 01151 * problems - such as causing apps in separate address spaces to fault. 01152 * (or even an app in the same address space to fault!) 01153 */ 01154 if (TESTSYNCONLYMESSAGE(message, wParam)) { 01155 RIPERR1(ERROR_MESSAGE_SYNC_ONLY, RIP_WARNING, 01156 "Trying to non-synchronously send a structure msg=%lX", message); 01157 return FALSE; 01158 } 01159 01160 CheckCritIn(); 01161 01162 /* 01163 * Is this a BroadcastMsg()? 01164 */ 01165 if (pwnd == PWND_BROADCAST) { 01166 BROADCASTMSG bcm; 01167 PBROADCASTMSG pbcm = NULL; 01168 UINT uCmd = BMSG_SENDNOTIFYMSG; 01169 01170 if (lpResultCallBack != NULL) { 01171 uCmd = BMSG_SENDMSGCALLBACK; 01172 bcm.cb.lpResultCallBack = lpResultCallBack; 01173 bcm.cb.dwData = dwData; 01174 bcm.cb.bClientRequest = fClientRequest; 01175 pbcm = &bcm; 01176 } 01177 01178 return xxxBroadcastMessage(NULL, message, wParam, lParam, uCmd, pbcm ); 01179 } 01180 01181 CheckLock(pwnd); 01182 01183 ptiCurrent = PtiCurrent(); 01184 01185 /* 01186 * Do inter-thread call if window thead differs from current thread. 01187 * We pass NULL for ptiSender to tell xxxInterSendMsgEx() that this is 01188 * a xxxSendNotifyMessage() and that there's no need for a reply. 01189 * 01190 * If this is a queued notify, always call InterSendMsgEx() so that 01191 * we queue it up and return - we don't do callbacks here with queued 01192 * notifies. 01193 */ 01194 if (fQueuedNotify || ptiCurrent != GETPTI(pwnd)) { 01195 INTRSENDMSGEX ism; 01196 PINTRSENDMSGEX pism = NULL; 01197 01198 if (lpResultCallBack != NULL) { /* CallBack request */ 01199 ism.fuCall = ISM_CALLBACK | (fClientRequest ? ISM_CB_CLIENT : 0); 01200 ism.lpResultCallBack = lpResultCallBack; 01201 ism.dwData = dwData; 01202 pism = &ism; 01203 } 01204 return (BOOL)xxxInterSendMsgEx(pwnd, message, wParam, lParam, 01205 NULL, GETPTI(pwnd), pism ); 01206 } 01207 01208 /* 01209 * Call WH_CALLWNDPROC if it's installed. 01210 */ 01211 if (!fQueuedNotify && IsHooked(ptiCurrent, WHF_CALLWNDPROC)) { 01212 CWPSTRUCTEX cwps; 01213 01214 cwps.hwnd = HWq(pwnd); 01215 cwps.message = message; 01216 cwps.wParam = wParam; 01217 cwps.lParam = lParam; 01218 cwps.psmsSender = NULL; 01219 01220 /* 01221 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 01222 * to the CWPSTRUCT contents. 01223 */ 01224 xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROC); 01225 01226 /* 01227 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 01228 * to the CWPSTRUCT contents. If this behavior reverts to 01229 * Win3.1 semantics, we will need to copy the new parameters 01230 * from cwps. 01231 */ 01232 } 01233 01234 /* 01235 * If this window's proc is meant to be executed from the server side 01236 * we'll just stay inside the semaphore and call it directly. Note 01237 * how we don't convert the pwnd into an hwnd before calling the proc. 01238 */ 01239 if (TestWF(pwnd, WFSERVERSIDEPROC)) { 01240 lRet = pwnd->lpfnWndProc(pwnd, message, wParam, lParam); 01241 } else { 01242 /* 01243 * Call the client or xxxDefWindowProc. pwnd is already locked 01244 */ 01245 XXXSENDMESSAGETOCLIENT(pwnd, message, wParam, lParam, NULL, FALSE); 01246 } 01247 01248 if (lpResultCallBack != NULL) { 01249 /* 01250 * Call the callback funtion for the return value 01251 */ 01252 if (fClientRequest) { 01253 /* 01254 * The application-defined callback proc is neither Unicode/ANSI 01255 */ 01256 CallClientProcA(pwnd, message, dwData, lRet, 01257 (ULONG_PTR)lpResultCallBack); 01258 } else { 01259 (*lpResultCallBack)((HWND)pwnd, message, dwData, lRet); 01260 } 01261 } 01262 01263 /* 01264 * Call WH_CALLWNDPROCRET if it's installed. 01265 */ 01266 if (!fQueuedNotify && IsHooked(ptiCurrent, WHF_CALLWNDPROCRET)) { 01267 CWPRETSTRUCTEX cwps; 01268 01269 cwps.hwnd = HWq(pwnd); 01270 cwps.message = message; 01271 cwps.wParam = wParam; 01272 cwps.lParam = lParam; 01273 cwps.lResult = lRet; 01274 cwps.psmsSender = NULL; 01275 01276 /* 01277 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 01278 * to the CWPSTRUCT contents. 01279 */ 01280 xxxCallHook(HC_ACTION, FALSE, (LPARAM)&cwps, WH_CALLWNDPROCRET); 01281 01282 /* 01283 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 01284 * to the CWPSTRUCT contents. If this behavior reverts to 01285 * Win3.1 semantics, we will need to copy the new parameters 01286 * from cwps. 01287 */ 01288 } 01289 01290 return TRUE; 01291 } 01292 01293 01294 /***********************************************************************\ 01295 * xxxInterSendMsgEx 01296 * 01297 * This function does an inter-thread send message. If ptiSender is NULL, 01298 * that means we're called from xxxSendNotifyMessage() and should act 01299 * accordingly. 01300 * 01301 * History: 01302 * 07-13-92 ChrisBl Created/extended from xxxInterSendMsg 01303 \***********************************************************************/ 01304 01305 #define NoString 0 01306 #define IsAnsiString 1 01307 #define IsUnicodeString 2 01308 01309 LRESULT xxxInterSendMsgEx( 01310 PWND pwnd, 01311 UINT message, 01312 WPARAM wParam, 01313 LPARAM lParam, 01314 PTHREADINFO ptiSender, 01315 PTHREADINFO ptiReceiver, 01316 PINTRSENDMSGEX pism) 01317 { 01318 PSMS psms, *ppsms; 01319 PSMS psmsSentSave; 01320 LRESULT lRet = 0; 01321 DWORD cbCapture, cbOutput; 01322 PBYTE lpCapture; 01323 PCOPYDATASTRUCT pcds; 01324 PMDICREATESTRUCTEX pmdics; 01325 LPHLP phlp; 01326 LPHELPINFO phelpinfo; 01327 LARGE_STRING str; 01328 LPARAM lParamSave; 01329 UINT fString = NoString; 01330 BOOLEAN bWasSwapEnabled; 01331 01332 CheckCritIn(); 01333 01334 01335 /* 01336 * If the sender is dying, fail the call 01337 */ 01338 if ((ptiSender != NULL) && (ptiSender->TIF_flags & TIF_INCLEANUP)) 01339 return 0; 01340 01341 /* 01342 * Some messages cannot be sent across process because we don't know how to thunk them 01343 * Fail attempts to read passwords across processes. 01344 */ 01345 if (pwnd && GETPTI(pwnd)->ppi != PpiCurrent()) { 01346 switch (message) { 01347 case WM_NOTIFY: 01348 RIPMSG0(RIP_WARNING | RIP_THERESMORE, "xxxInterSendMsgEx: message cannot be sent across processes"); 01349 RIPMSG4(RIP_WARNING | RIP_THERESMORE, " pwnd:%#p message:%#x wParam:%#p lParam:%#p", pwnd, message, wParam, lParam); 01350 return 0; 01351 01352 case WM_GETTEXT: 01353 case EM_GETLINE: 01354 case EM_SETPASSWORDCHAR: 01355 if ((GETFNID(pwnd) == FNID_EDIT) && TestWF(pwnd, EFPASSWORD)) { 01356 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Can't access protected edit control"); 01357 return 0; 01358 } 01359 break; 01360 } 01361 } 01362 01363 /* 01364 * Alloc SMS structure. 01365 */ 01366 psms = AllocSMS(); 01367 if (psms == NULL) { 01368 01369 /* 01370 * Set to zero so xxxSendNotifyMessage would return FALSE. 01371 */ 01372 return 0; 01373 } 01374 01375 /* 01376 * Prepare to capture variable length data from client 01377 * space. Addresses have already been probed. Fixed-length 01378 * data is probed and captured in the message thunk. 01379 */ 01380 psms->pvCapture = NULL; 01381 cbCapture = cbOutput = 0; 01382 lpCapture = (LPBYTE)lParam; 01383 01384 /* 01385 * For messages with indirect data, set cbCapture and lpCapture 01386 * (if not lParam) as approp. 01387 */ 01388 try { 01389 switch (message) { 01390 case WM_COPYGLOBALDATA: // fnCOPYGLOBALDATA 01391 cbCapture = (DWORD)wParam; 01392 break; 01393 01394 case WM_COPYDATA: // fnCOPYDATA 01395 pcds = (PCOPYDATASTRUCT)lParam; 01396 if (pcds->lpData) { 01397 cbCapture = sizeof(COPYDATASTRUCT) + pcds->cbData; 01398 } else { 01399 cbCapture = sizeof(COPYDATASTRUCT); 01400 } 01401 break; 01402 01403 case WM_CREATE: // fnINLPCREATESTRUCT 01404 case WM_NCCREATE: // fnINLPCREATESTRUCT 01405 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Can't Intersend WM_CREATE or WM_NCCREATE message"); 01406 FreeSMS(psms); 01407 return 0; 01408 01409 case WM_HELP: // fnINLPHELPINFOSTRUCT 01410 phelpinfo = (LPHELPINFO)lParam; 01411 cbCapture = phelpinfo->cbSize; 01412 break; 01413 01414 case WM_WINHELP: // fnINLPHLPSTRUCT 01415 phlp = (LPHLP)lParam; 01416 cbCapture = phlp->cbData; 01417 break; 01418 01419 case WM_MDICREATE: // fnINLPMDICREATESTRUCT 01420 pmdics = (PMDICREATESTRUCTEX)lParam; 01421 cbCapture = pmdics->strTitle.MaximumLength + 01422 pmdics->strClass.MaximumLength; 01423 UserAssert(pmdics->strClass.Buffer == NULL || pmdics->strClass.Buffer == pmdics->mdics.szClass); 01424 if (pmdics->strTitle.Buffer) 01425 UserAssert(pmdics->strTitle.Buffer == pmdics->mdics.szTitle); 01426 break; 01427 01428 case LB_ADDSTRING: // INLBOXSTRING calls fnINSTRING 01429 case LB_INSERTSTRING: // INLBOXSTRING calls fnINSTRING 01430 case LB_SELECTSTRING: // INLBOXSTRING calls fnINSTRING 01431 case LB_FINDSTRING: // INLBOXSTRING calls fnINSTRING 01432 case LB_FINDSTRINGEXACT: // INLBOXSTRING calls fnINSTRING 01433 /* 01434 * See if the control is ownerdraw and does not have the LBS_HASSTRINGS 01435 * style. If so, treat lParam as a DWORD. 01436 */ 01437 if (pwnd && !(pwnd->style & LBS_HASSTRINGS) && 01438 (pwnd->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))) { 01439 /* 01440 * Treat lParam as a dword. 01441 */ 01442 break; 01443 } else { 01444 goto fnINSTRINGThunk; 01445 } 01446 break; 01447 01448 case CB_ADDSTRING: // INCBOXSTRING calls fnINSTRING 01449 case CB_INSERTSTRING: // INCBOXSTRING calls fnINSTRING 01450 case CB_SELECTSTRING: // INCBOXSTRING calls fnINSTRING 01451 case CB_FINDSTRING: // INCBOXSTRING calls fnINSTRING 01452 case CB_FINDSTRINGEXACT: // INCBOXSTRING calls fnINSTRING 01453 /* 01454 * See if the control is ownerdraw and does not have the CBS_HASSTRINGS 01455 * style. If so, treat lParam as a DWORD. 01456 */ 01457 if (pwnd && !(pwnd->style & CBS_HASSTRINGS) && 01458 (pwnd->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))) { 01459 01460 /* 01461 * Treat lParam as a dword. 01462 */ 01463 break; 01464 } else { 01465 goto fnINSTRINGThunk; 01466 } 01467 break; 01468 01469 case EM_REPLACESEL: // fnINSTRINGNULL 01470 case WM_SETTEXT: // fnINSTRINGNULL 01471 case WM_WININICHANGE: // fnINSTRINGNULL 01472 if (lParam == 0) 01473 break; 01474 01475 /* 01476 * Fall through 01477 */ 01478 01479 case CB_DIR: // fnINSTRING 01480 case LB_ADDFILE: // fnINSTRING 01481 case LB_DIR: // fnINSTRING 01482 case WM_DEVMODECHANGE: // fnINSTRING 01483 fnINSTRINGThunk: 01484 01485 /* 01486 * Only capture strings if they are not in system space 01487 */ 01488 str = *(PLARGE_STRING)lParam; 01489 lParam = (LPARAM)&str; 01490 01491 if (!IS_SYSTEM_ADDRESS(str.Buffer)) 01492 cbCapture = str.Length + sizeof(WCHAR); 01493 break; 01494 01495 case WM_DEVICECHANGE: 01496 if (lParam == 0) 01497 break; 01498 01499 /* 01500 * Only capture data if lParam is a pointer and 01501 * the data is not in system space 01502 */ 01503 if ((wParam & 0x8000) != 0x8000) 01504 break; 01505 01506 if (!IS_SYSTEM_ADDRESS((LPVOID)lParam)) { 01507 cbCapture = *((DWORD *)lpCapture); 01508 UserAssert(FALSE); 01509 } 01510 break; 01511 01512 case EM_SETTABSTOPS: // fnPOPTINLPUINT 01513 case LB_SETTABSTOPS: // fnPOPTINLPUINT 01514 case LB_GETSELITEMS: // fnPOUTLPINT 01515 cbCapture = (UINT)wParam * sizeof(INT); 01516 break; 01517 01518 case EM_GETLINE: // fnINCNTOUTSTRING 01519 case WM_ASKCBFORMATNAME: // fnINCNTOUTSTRINGNULL 01520 case WM_GETTEXT: // fnOUTSTRING 01521 case LB_GETTEXT: // fnOUTLBOXSTRING 01522 case CB_GETLBTEXT: // fnOUTCBOXSTRING 01523 01524 /* 01525 * Only allocate output buffer if the real one is not in system space 01526 */ 01527 str = *(PLARGE_STRING)lParam; 01528 /* 01529 * Bug 18108. For WM_GETTEXT only copy the actual string and not the 01530 * the maximum size into the output buffer 01531 */ 01532 if(str.bAnsi) { 01533 fString = IsAnsiString ; 01534 } else { 01535 fString = IsUnicodeString ; 01536 } 01537 lParam = (LPARAM)&str; 01538 if (!IS_SYSTEM_ADDRESS(str.Buffer)) 01539 cbCapture = str.MaximumLength; 01540 break; 01541 } 01542 if (cbCapture && 01543 (psms->pvCapture = UserAllocPoolWithQuota(cbCapture, TAG_SMS_CAPTURE)) != NULL) { 01544 01545 lParamSave = lParam; 01546 01547 /* 01548 * now actually copy memory from lpCapture to psms->pvCapture 01549 * and fixup any references to the indirect data to point to 01550 * psms->pvCapture. 01551 */ 01552 switch (message) { 01553 case WM_COPYDATA: // fnCOPYDATA 01554 { 01555 PCOPYDATASTRUCT pcdsNew = (PCOPYDATASTRUCT)psms->pvCapture; 01556 lParam = (LPARAM)pcdsNew; 01557 RtlCopyMemory(pcdsNew, pcds, sizeof(COPYDATASTRUCT)); 01558 if (pcds->lpData) { 01559 pcdsNew->lpData = (PVOID)((PBYTE)pcdsNew + sizeof(COPYDATASTRUCT)); 01560 RtlCopyMemory(pcdsNew->lpData, pcds->lpData, pcds->cbData); 01561 } 01562 } 01563 break; 01564 case WM_MDICREATE: // fnINLPMDICREATESTRUCT 01565 if (pmdics->strClass.Buffer) { 01566 RtlCopyMemory(psms->pvCapture, pmdics->strClass.Buffer, 01567 pmdics->strClass.MaximumLength); 01568 pmdics->mdics.szClass = (LPWSTR)psms->pvCapture; 01569 } 01570 if (pmdics->strTitle.Length) { 01571 lpCapture = (PBYTE)psms->pvCapture + pmdics->strClass.MaximumLength; 01572 RtlCopyMemory(lpCapture, pmdics->strTitle.Buffer, 01573 pmdics->strTitle.MaximumLength); 01574 pmdics->mdics.szTitle = (LPWSTR)lpCapture; 01575 } 01576 break; 01577 01578 case CB_DIR: // fnINSTRING 01579 case LB_FINDSTRING: // INLBOXSTRING calls fnINSTRING 01580 case LB_FINDSTRINGEXACT: // INLBOXSTRING calls fnINSTRING 01581 case CB_FINDSTRING: // INCBOXSTRING calls fnINSTRING 01582 case CB_FINDSTRINGEXACT: // INCBOXSTRING calls fnINSTRING 01583 case LB_ADDFILE: // fnINSTRING 01584 case LB_ADDSTRING: // INLBOXSTRING calls fnINSTRING 01585 case LB_INSERTSTRING: // INLBOXSTRING calls fnINSTRING 01586 case LB_SELECTSTRING: // INLBOXSTRING calls fnINSTRING 01587 case CB_ADDSTRING: // INCBOXSTRING calls fnINSTRING 01588 case CB_INSERTSTRING: // INCBOXSTRING calls fnINSTRING 01589 case CB_SELECTSTRING: // INCBOXSTRING calls fnINSTRING 01590 case LB_DIR: // fnINSTRING 01591 case WM_DEVMODECHANGE: // fnINSTRING 01592 case EM_REPLACESEL: // fnINSTRINGNULL 01593 case WM_SETTEXT: // fnINSTRINGNULL 01594 case WM_WININICHANGE: // fnINSTRINGNULL 01595 RtlCopyMemory(psms->pvCapture, str.Buffer, cbCapture); 01596 str.Buffer = psms->pvCapture; 01597 break; 01598 01599 case LB_GETSELITEMS: 01600 cbOutput = cbCapture; 01601 RtlCopyMemory(psms->pvCapture, lpCapture, cbCapture); 01602 lParam = (LPARAM)psms->pvCapture; 01603 break; 01604 01605 case EM_GETLINE: // fnINCNTOUTSTRING 01606 *(WORD *)psms->pvCapture = *(WORD *)str.Buffer; 01607 01608 /* 01609 * Fall through 01610 */ 01611 case WM_ASKCBFORMATNAME: // fnINCNTOUTSTRINGNULL 01612 case WM_GETTEXT: // fnOUTSTRING 01613 case LB_GETTEXT: // fnOUTLBOXSTRING 01614 case CB_GETLBTEXT: // fnOUTCBOXSTRING 01615 cbOutput = cbCapture; 01616 lParamSave = (LPARAM)str.Buffer; 01617 str.Buffer = psms->pvCapture; 01618 break; 01619 01620 default: 01621 RtlCopyMemory(psms->pvCapture, lpCapture, cbCapture); 01622 lParam = (LPARAM)psms->pvCapture; 01623 break; 01624 } 01625 } 01626 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01627 if (psms->pvCapture != NULL) 01628 UserFreePool(psms->pvCapture); 01629 FreeSMS(psms); 01630 return 0; 01631 } 01632 01633 if (cbCapture && psms->pvCapture == NULL) { 01634 FreeSMS(psms); 01635 return 0; 01636 } 01637 01638 /* 01639 * Copy message parms 01640 */ 01641 psms->spwnd = NULL; 01642 psms->psmsReceiveNext = NULL; 01643 #if DBG 01644 psms->psmsSendList = NULL; 01645 psms->psmsSendNext = NULL; 01646 #endif 01647 Lock(&(psms->spwnd), pwnd); 01648 psms->message = message; 01649 psms->wParam = wParam; 01650 psms->lParam = lParam; 01651 psms->flags = 0; 01652 01653 /* 01654 * Link into gpsmsList 01655 */ 01656 psms->psmsNext = gpsmsList; 01657 gpsmsList = psms; 01658 01659 /* 01660 * Time stamp message 01661 */ 01662 psms->tSent = NtGetTickCount(); 01663 01664 /* 01665 * Set queue fields 01666 */ 01667 psms->ptiReceiver = ptiReceiver; 01668 psms->ptiSender = ptiSender; 01669 psms->ptiCallBackSender = NULL; 01670 01671 if ((pism != NULL) && (pism->fuCall & ISM_CALLBACK)) { 01672 /* 01673 * Setup for a SendMessageCallback 01674 */ 01675 psms->flags |= (pism->fuCall & ISM_CB_CLIENT) ? SMF_CB_CLIENT : SMF_CB_SERVER; 01676 psms->lpResultCallBack = pism->lpResultCallBack; 01677 psms->dwData = pism->dwData; 01678 01679 if (pism->fuCall & ISM_REPLY) { 01680 psms->flags |= SMF_CB_REPLY; 01681 psms->lRet = pism->lRet; 01682 } else { /* REQUEST */ 01683 psms->flags |= SMF_CB_REQUEST; 01684 psms->ptiCallBackSender = PtiCurrent(); 01685 } 01686 } 01687 01688 /* 01689 * Add SMS to the end of the ptiReceiver's receive list 01690 */ 01691 ppsms = &ptiReceiver->psmsReceiveList; 01692 while (*ppsms != NULL) { 01693 ppsms = &((*ppsms)->psmsReceiveNext); 01694 } 01695 *ppsms = psms; 01696 01697 /* 01698 * Link this SMS into the SendMsg chain. Of course only do this if 01699 * it's not from a xxxSendNotifyMessage() call. 01700 * 01701 * The psmsSendNext field implements a chain of messages being 01702 * processed because of an initial SendMsg call. For example, if 01703 * thread A sends message M1 to thread B, which causes B to send 01704 * message M2 to thread C, the SendMsg chain is M1->M2. If the 01705 * system hangs in this situation, the chain is traversed to find 01706 * the offending thread (C). 01707 * 01708 * psms->psmsSendList always points to the head of this list so 01709 * we can tell where to begin a list traversal. 01710 * 01711 * ptiSender->psmsCurrent is the last SMS in the chain. 01712 */ 01713 #if DBG 01714 if (ptiSender != NULL && ptiSender->psmsCurrent != NULL) { 01715 /* 01716 * sending queue is currently processing a message sent to it, 01717 * so append SMS to the chain. Link in the new sms because 01718 * psmsSendNext may be pointing to a replied-to message. 01719 */ 01720 psms->psmsSendNext = ptiSender->psmsCurrent->psmsSendNext; 01721 ptiSender->psmsCurrent->psmsSendNext = psms; 01722 psms->psmsSendList = ptiSender->psmsCurrent->psmsSendList; 01723 01724 } else { 01725 /* 01726 * sending queue is initiating a send sequence, so put sms at 01727 * the head of the chain 01728 */ 01729 psms->psmsSendList = psms; 01730 } 01731 #endif 01732 01733 if (ptiSender != NULL) { 01734 /* 01735 * ptiSender->psmsSent marks the most recent message sent from this 01736 * thread that has not yet been replied to. Save the previous value 01737 * on the stack so it can be restored when we get the reply. 01738 * 01739 * This way when an "older" SMS for this thread gets a reply before 01740 * the "current" one does, the thread does get woken up. 01741 */ 01742 psmsSentSave = ptiSender->psmsSent; 01743 ptiSender->psmsSent = psms; 01744 } else { 01745 01746 /* 01747 * Set SMF_RECEIVERFREE since we'll be returning to 01748 * xxxSendNotifyMessage() right away and won't get a 01749 * chance to free it. 01750 */ 01751 psms->flags |= SMF_RECEIVERFREE; 01752 } 01753 01754 #ifdef DEBUG_SMS 01755 ValidateSmsSendLists(psms); 01756 #endif 01757 01758 /* 01759 * If we're not being called from xxxSendNotifyMessage() or 01760 * SendMessageCallback(), then sleep while we wait for the reply. 01761 */ 01762 if (ptiSender == NULL) { 01763 /* 01764 * Wake receiver for the sent message 01765 */ 01766 SetWakeBit(ptiReceiver, QS_SENDMESSAGE); 01767 01768 return (LONG)TRUE; 01769 } else { 01770 BOOL fTimeOut = FALSE; 01771 UINT uTimeout = 0; 01772 UINT uWakeMask = QS_SMSREPLY; 01773 01774 /* 01775 * Wake up the receiver thread. 01776 */ 01777 SetWakeBit(ptiReceiver, QS_SENDMESSAGE); 01778 01779 /* 01780 * We have 4 sending cases: 01781 * 01782 * 16 - 16 : yield to the 16 bit receiver 01783 * 32 - 16 : no yielding required 01784 * 16 - 32 : sender yields while receiver processes the message 01785 * 32 - 32 : no yielding required. 01786 */ 01787 if (ptiSender->TIF_flags & TIF_16BIT || ptiReceiver->TIF_flags & TIF_16BIT) { 01788 DirectedScheduleTask(ptiSender, ptiReceiver, TRUE, psms); 01789 } 01790 01791 /* 01792 * Put this thread to sleep until the reply arrives. First clear 01793 * the QS_SMSREPLY bit, then leave the semaphore and go to sleep. 01794 * 01795 * IMPORTANT: The QS_SMSREPLY bit is not cleared once we get a 01796 * reply because of the following case: 01797 * 01798 * We've recursed a second level into SendMessage() when the first level 01799 * receiver thread dies, causing exit list processing to simulate 01800 * a reply to the first message. When the second level send returns, 01801 * SleepThread() is called again to get the first reply. 01802 * 01803 * Keeping QS_SMSREPLY set causes this call to SleepThread() 01804 * to return without going to sleep to wait for the reply that has 01805 * already happened. 01806 */ 01807 if ( pism != NULL ) { 01808 if (pism->fuSend & SMTO_BLOCK) { 01809 /* 01810 * only wait for a return, all other events will 01811 * be ignored until timeout or return 01812 */ 01813 uWakeMask |= QS_EXCLUSIVE; 01814 } 01815 01816 uTimeout = pism->uTimeout; 01817 } 01818 01819 01820 /* 01821 * Don't swap this guys stack while sleeping during a sendmessage 01822 */ 01823 if (ptiSender->cEnterCount == 0) { 01824 bWasSwapEnabled = KeSetKernelStackSwapEnable(FALSE); 01825 } else { 01826 UserAssert(ptiSender->cEnterCount > 0); 01827 } 01828 ptiSender->cEnterCount++; 01829 01830 01831 while (!(psms->flags & SMF_REPLY) && !fTimeOut) { 01832 ptiSender->pcti->fsChangeBits &= ~QS_SMSREPLY; 01833 01834 /* 01835 * If SendMessageTimeout, sleep for timeout amount, else wait 01836 * forever. Since this is not technically a transition to an 01837 * idle condition, indicate that this sleep is not going "idle". 01838 */ 01839 fTimeOut = !xxxSleepThread(uWakeMask, uTimeout, FALSE); 01840 /* 01841 * If a timeout occurs, and the SMTO_NOTIMEOUTIFNOTHUNG bit is set, 01842 * and the app is still calling GetMessage(), then just try again. 01843 * This probably means that the receiver has put up some UI in 01844 * response to this message but the user hasn't completed the 01845 * interaction yet. 01846 */ 01847 if (fTimeOut && pism && (pism->fuSend & SMTO_NOTIMEOUTIFNOTHUNG) && 01848 !FHungApp(ptiReceiver, CMSHUNGAPPTIMEOUT)) { 01849 fTimeOut = FALSE; 01850 } 01851 } 01852 01853 UserAssert(ptiSender->cEnterCount > 0); 01854 if (--ptiSender->cEnterCount == 0) { 01855 KeSetKernelStackSwapEnable(bWasSwapEnabled); 01856 } 01857 01858 /* 01859 * The reply bit should always be set! (even if we timed out). That 01860 * is because if we're recursed into intersendmsg, we're going to 01861 * return to the first intersendmsg's call to SleepThread() - and 01862 * it needs to return back to intersendmsgex to see if its sms 01863 * has been replied to. 01864 */ 01865 SetWakeBit(ptiSender, QS_SMSREPLY); 01866 01867 /* 01868 * Copy out captured data. If cbOutput != 0 we know 01869 * that the output buffer is in user-mode address 01870 * space. 01871 */ 01872 if (!fTimeOut && cbOutput) { 01873 PBYTE pbOutput; 01874 INT len; 01875 01876 /* 01877 * Probe output buffer if it is in the user's address space 01878 */ 01879 01880 pbOutput = (PBYTE)lParamSave; 01881 try { 01882 if(fString == NoString) { 01883 RtlCopyMemory((PBYTE)pbOutput, psms->pvCapture, 01884 cbOutput); 01885 } else if(fString == IsAnsiString) { 01886 len = strncpycch((LPSTR)pbOutput,(LPCSTR)psms->pvCapture, 01887 cbOutput); 01888 #if DBG 01889 len--; //Length includes terminating NULL char 01890 if(len != psms->lRet) { 01891 RIPMSG0(RIP_WARNING, 01892 "Length of the copied string being returned is diffrent from the actual string length"); 01893 } 01894 #endif 01895 } else { //IsUnicodeString 01896 len = wcsncpycch((LPWSTR)pbOutput,(LPCWSTR)psms->pvCapture, 01897 cbOutput/sizeof(WCHAR)); 01898 #if DBG 01899 len--; 01900 if(len != psms->lRet) { 01901 RIPMSG0(RIP_WARNING, 01902 "Length of the copied string being returned is diffrent from the actual string length"); 01903 } 01904 #endif 01905 } 01906 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01907 01908 /* 01909 * Return 0 to indicate an error. 01910 */ 01911 psms->lRet = 0; 01912 } 01913 } 01914 01915 /* 01916 * we now have the reply -- restore psmsSent and save the return value 01917 */ 01918 ptiSender->psmsSent = psmsSentSave; 01919 01920 if (pism == NULL) { 01921 lRet = psms->lRet; 01922 } else { 01923 /* 01924 * save the values off for a SendMesssageTimeOut 01925 */ 01926 *pism->lpdwResult = psms->lRet; 01927 lRet = (!fTimeOut) ? TRUE : FALSE; /* do this to ensure ret is T or F... */ 01928 01929 /* 01930 * If we did timeout and no reply was received, rely on 01931 * the receiver to free the sms. 01932 */ 01933 if (!(psms->flags & SMF_REPLY)) 01934 psms->flags |= SMF_REPLY | SMF_RECEIVERFREE; 01935 } 01936 01937 /* 01938 * If the reply came while the receiver is still processing 01939 * the sms, force the receiver to free the sms. This can occur 01940 * via timeout, ReplyMessage or journal cancel. 01941 */ 01942 if ((psms->flags & (SMF_RECEIVERBUSY | SMF_RECEIVEDMESSAGE)) != 01943 SMF_RECEIVEDMESSAGE) { 01944 psms->flags |= SMF_RECEIVERFREE; 01945 } 01946 01947 /* 01948 * Unlink the SMS structure from both the SendMsg chain and gpsmsList 01949 * list and free it. This sms could be anywhere in the chain. 01950 * 01951 * If the SMS was replied to by a thread other than the receiver 01952 * (ie. through ReplyMessage()), we don't free the SMS because the 01953 * receiver is still processing it and will free it when done. 01954 */ 01955 if (!(psms->flags & SMF_RECEIVERFREE)) { 01956 UnlinkSendListSms(psms, NULL); 01957 } 01958 } 01959 01960 return lRet; 01961 } 01962 01963 01964 /***********************************************************************\ 01965 * xxxReceiveMessage 01966 * 01967 * This function receives a message sent from another thread. Physically, 01968 * it gets the message, calls the window proc and then cleans up the 01969 * fsWakeBits and sms stuctures. 01970 * 01971 * History: 01972 * 01-13-91 DavidPe Ported. 01973 * 01-23-91 DavidPe Add xxxSendNotifyMessage() support. 01974 * 07-14-92 ChrisBl Added xxxSendMessageCallback support. 01975 \***********************************************************************/ 01976 01977 VOID xxxReceiveMessage( 01978 PTHREADINFO ptiReceiver) 01979 { 01980 PSMS psms; 01981 PSMS psmsCurrentSave; 01982 PTHREADINFO ptiSender; 01983 LRESULT lRet = 0; 01984 TL tlpwnd; 01985 01986 CheckCritIn(); 01987 01988 /* 01989 * Get the SMS and unlink it from the list of SMSs we've received 01990 */ 01991 psms = ptiReceiver->psmsReceiveList; 01992 01993 /* 01994 * This can be NULL because an SMS can be removed in our cleanup 01995 * code without clearing the QS_SENDMESSAGE bit. 01996 */ 01997 if (psms == NULL) { 01998 ptiReceiver->pcti->fsWakeBits &= ~QS_SENDMESSAGE; 01999 ptiReceiver->pcti->fsChangeBits &= ~QS_SENDMESSAGE; 02000 return; 02001 } 02002 02003 ptiReceiver->psmsReceiveList = psms->psmsReceiveNext; 02004 psms->psmsReceiveNext = NULL; 02005 02006 /* 02007 * We've taken the SMS off the receive list - mark the SMS with this 02008 * information - used during cleanup. 02009 */ 02010 psms->flags |= SMF_RECEIVERBUSY | SMF_RECEIVEDMESSAGE; 02011 02012 /* 02013 * Clear QS_SENDMESSAGE wakebit if list is now empty 02014 */ 02015 if (ptiReceiver->psmsReceiveList == NULL) { 02016 ptiReceiver->pcti->fsWakeBits &= ~QS_SENDMESSAGE; 02017 ptiReceiver->pcti->fsChangeBits &= ~QS_SENDMESSAGE; 02018 } 02019 02020 ptiSender = psms->ptiSender; 02021 02022 if (psms->flags & SMF_CB_REPLY) { 02023 /* 02024 * From SendMessageCallback REPLY to callback. We need to call 02025 * the call back function to give the return value. 02026 * Don't process any this message, just mechanism for notification 02027 * the sender's thread lock is already gone, so we need to re-lock here. 02028 */ 02029 if (ptiSender == NULL) { 02030 ThreadLock(psms->spwnd, &tlpwnd); 02031 } 02032 02033 if (psms->flags & SMF_CB_CLIENT) { 02034 /* 02035 * Application-defined callback proc is neither Unicode nor ANSI 02036 */ 02037 CallClientProcA(psms->spwnd, psms->message, psms->dwData, 02038 psms->lRet, (ULONG_PTR)psms->lpResultCallBack); 02039 } else { 02040 psms->lpResultCallBack(HW(psms->spwnd), psms->message, 02041 psms->dwData, psms->lRet); 02042 } 02043 02044 if (ptiSender == NULL) { 02045 ThreadUnlock(&tlpwnd); 02046 } 02047 } else if (!(psms->flags & (SMF_REPLY | SMF_SENDERDIED | SMF_RECEIVERDIED))) { 02048 /* 02049 * Don't process message if it has been replied to already or 02050 * if the sending or receiving thread has died 02051 */ 02052 02053 /* 02054 * Set new psmsCurrent for this queue, saving the current one 02055 */ 02056 psmsCurrentSave = ptiReceiver->psmsCurrent; 02057 ptiReceiver->psmsCurrent = psms; 02058 SET_FLAG(ptiReceiver->pcti->CTIF_flags, CTIF_INSENDMESSAGE); 02059 02060 /* 02061 * If this SMS originated from a xxxSendNotifyMessage() or a 02062 * xxxSendMessageCallback() call, the sender's thread lock is 02063 * already gone, so we need to re-lock here. 02064 */ 02065 if (ptiSender == NULL) { 02066 ThreadLock(psms->spwnd, &tlpwnd); 02067 } 02068 02069 if (psms->message == WM_HOOKMSG) { 02070 union { 02071 EVENTMSG emsg; // WH_JOURNALRECORD/PLAYBACK 02072 MOUSEHOOKSTRUCTEX mhs; // WH_MOUSE 02073 KBDLLHOOKSTRUCT kbds; // WH_KEYBORD_LL 02074 MSLLHOOKSTRUCT mslls;// WH_MOUSE_LL 02075 #ifdef REDIRECTION 02076 HTHOOKSTRUCT ht; // WH_HITTEST 02077 #endif // REDIRECTION 02078 } LocalData; 02079 PVOID pSendersData; 02080 PHOOKMSGSTRUCT phkmp; 02081 int iHook; 02082 BOOL bAnsiHook; 02083 02084 /* 02085 * Some hook types (eg: WH_JOURNALPLAYBACK) pass pointers to 02086 * data in the calling thread's stack. We must copy this to our 02087 * own (called thread's) stack for safety because of the way this 02088 * "message" is handled and in case the calling thread dies. #13577 02089 * 02090 * Originally only WH_JOURNALRECORD and WH_JOURNALPLAYBACK went 02091 * through this code, but now all sorts of hooks do. 02092 */ 02093 phkmp = (PHOOKMSGSTRUCT)psms->lParam; 02094 pSendersData = (PVOID)(phkmp->lParam); 02095 iHook = phkmp->phk->iHook; 02096 02097 switch (iHook) { 02098 case WH_JOURNALRECORD: 02099 case WH_JOURNALPLAYBACK: 02100 if (pSendersData) 02101 LocalData.emsg = *(PEVENTMSG)pSendersData; 02102 break; 02103 02104 case WH_MOUSE: 02105 if (pSendersData) 02106 LocalData.mhs = *(LPMOUSEHOOKSTRUCTEX)pSendersData; 02107 break; 02108 02109 case WH_KEYBOARD_LL: 02110 if (pSendersData) 02111 LocalData.kbds = *(LPKBDLLHOOKSTRUCT)pSendersData; 02112 break; 02113 02114 case WH_MOUSE_LL: 02115 if (pSendersData) 02116 LocalData.mslls = *(LPMSLLHOOKSTRUCT)pSendersData; 02117 break; 02118 02119 #ifdef REDIRECTION 02120 case WH_HITTEST: 02121 if (pSendersData) 02122 LocalData.ht = *(LPHTHOOKSTRUCT)pSendersData; 02123 break; 02124 #endif // REDIRECTION 02125 02126 case WH_KEYBOARD: 02127 case WH_SHELL: 02128 /* 02129 * Fall thru... 02130 */ 02131 pSendersData = NULL; 02132 break; 02133 02134 default: 02135 /* 02136 * No pointers: wParam & lParam can be sent as is. 02137 */ 02138 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Receive hook %d", iHook); 02139 pSendersData = NULL; 02140 break; 02141 } 02142 02143 02144 lRet = xxxCallHook2(phkmp->phk, phkmp->nCode, psms->wParam, 02145 pSendersData ? (LPARAM)&LocalData : phkmp->lParam, &bAnsiHook); 02146 02147 /* 02148 * Copy back data only if the sender hasn't died or timed out 02149 * (timed out messages are marked SMF_REPLY by the sending thread) 02150 */ 02151 if (!(psms->flags & (SMF_SENDERDIED|SMF_REPLY)) && pSendersData) { 02152 switch (iHook) { 02153 case WH_JOURNALRECORD: 02154 case WH_JOURNALPLAYBACK: 02155 *(PEVENTMSG)pSendersData = LocalData.emsg; 02156 break; 02157 02158 case WH_KEYBOARD_LL: 02159 *(LPKBDLLHOOKSTRUCT)pSendersData = LocalData.kbds; 02160 break; 02161 02162 case WH_MOUSE_LL: 02163 *(LPMSLLHOOKSTRUCT)pSendersData = LocalData.mslls; 02164 break; 02165 02166 case WH_MOUSE: 02167 *(LPMOUSEHOOKSTRUCTEX)pSendersData = LocalData.mhs; 02168 break; 02169 02170 #ifdef REDIRECTION 02171 case WH_HITTEST: 02172 *(LPHTHOOKSTRUCT)pSendersData = LocalData.ht; 02173 break; 02174 #endif // REDIRECTION 02175 } 02176 } 02177 02178 } else { 02179 /* 02180 * Call WH_CALLWNDPROC if it's installed and the window is not marked 02181 * as destroyed. 02182 */ 02183 if (IsHooked(ptiReceiver, WHF_CALLWNDPROC)) { 02184 CWPSTRUCTEX cwps; 02185 02186 cwps.hwnd = HW(psms->spwnd); 02187 cwps.message = psms->message; 02188 cwps.wParam = psms->wParam; 02189 cwps.lParam = psms->lParam; 02190 cwps.psmsSender = psms; 02191 02192 xxxCallHook(HC_ACTION, TRUE, (LPARAM)&cwps, WH_CALLWNDPROC); 02193 02194 /* 02195 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 02196 * to the CWPSTRUCT contents. If this behavior reverts to 02197 * Win3.1 semantics, we will need to copy the new parameters 02198 * from cwps. 02199 */ 02200 } 02201 02202 if (!(psms->flags & (SMF_REPLY | SMF_SENDERDIED | SMF_RECEIVERDIED)) && 02203 psms->spwnd != NULL) { 02204 if (TestWF(psms->spwnd, WFSERVERSIDEPROC)) { 02205 TL tlpwndKernel; 02206 02207 ThreadLock(psms->spwnd, &tlpwndKernel); 02208 /* 02209 * If this window's proc is meant to be executed from the server side 02210 * we'll just stay inside the semaphore and call it directly. Note 02211 * how we don't convert the pwnd into an hwnd before calling the proc. 02212 */ 02213 lRet = psms->spwnd->lpfnWndProc(psms->spwnd, psms->message, 02214 psms->wParam, psms->lParam); 02215 02216 ThreadUnlock(&tlpwndKernel); 02217 } else { 02218 /* 02219 * Call the client or xxxDefWindowProc. 02220 */ 02221 XXXSENDMESSAGETOCLIENT(psms->spwnd, psms->message, psms->wParam, psms->lParam, 02222 psms, TRUE); 02223 } 02224 02225 /* 02226 * Call WH_CALLWNDPROCRET if it's installed. 02227 */ 02228 if (IsHooked(ptiReceiver, WHF_CALLWNDPROCRET) && 02229 !(psms->flags & SMF_SENDERDIED)) { 02230 CWPRETSTRUCTEX cwps; 02231 02232 cwps.hwnd = HW(psms->spwnd); 02233 cwps.message = psms->message; 02234 cwps.wParam = psms->wParam; 02235 cwps.lParam = psms->lParam; 02236 cwps.lResult = lRet; 02237 cwps.psmsSender = psms; 02238 02239 /* 02240 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 02241 * to the CWPSTRUCT contents. 02242 */ 02243 xxxCallHook(HC_ACTION, TRUE, (LPARAM)&cwps, WH_CALLWNDPROCRET); 02244 02245 /* 02246 * Unlike Win3.1, NT and Win95 ignore any changes the app makes 02247 * to the CWPSTRUCT contents. If this behavior reverts to 02248 * Win3.1 semantics, we will need to copy the new parameters 02249 * from cwps. 02250 */ 02251 } 02252 } 02253 } 02254 02255 if ((psms->flags & (SMF_CB_REQUEST | SMF_REPLY)) == SMF_CB_REQUEST) { 02256 02257 /* 02258 * From SendMessageCallback REQUEST callback. Send the message 02259 * back with a the REPLY value. 02260 */ 02261 INTRSENDMSGEX ism; 02262 02263 psms->flags |= SMF_REPLY; 02264 02265 if (!(psms->flags & SMF_SENDERDIED)) { 02266 ism.fuCall = ISM_CALLBACK | ISM_REPLY; 02267 if (psms->flags & SMF_CB_CLIENT) 02268 ism.fuCall |= ISM_CB_CLIENT; 02269 ism.lpResultCallBack = psms->lpResultCallBack; 02270 ism.dwData = psms->dwData; 02271 ism.lRet = lRet; 02272 02273 xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L, 02274 NULL, psms->ptiCallBackSender, &ism ); 02275 } 02276 } 02277 02278 if (ptiSender == NULL) { 02279 ThreadUnlock(&tlpwnd); 02280 } 02281 02282 /* 02283 * Restore receiver's original psmsCurrent. 02284 */ 02285 ptiReceiver->psmsCurrent = psmsCurrentSave; 02286 SET_OR_CLEAR_FLAG(ptiReceiver->pcti->CTIF_flags, 02287 CTIF_INSENDMESSAGE, 02288 ptiReceiver->psmsCurrent); 02289 02290 #ifdef DEBUG_SMS 02291 ValidateSmsSendLists(psmsCurrentSave); 02292 #endif 02293 } 02294 02295 /* 02296 * We're done with this sms, so the appropriate thread 02297 * can now free it. 02298 */ 02299 psms->flags &= ~SMF_RECEIVERBUSY; 02300 02301 /* 02302 * Free the sms and return without reply if the 02303 * SMF_RECEIVERFREE bit is set. Handily, this does just what we 02304 * want for xxxSendNotifyMessage() since we set SMF_RECEIVERFREE 02305 * in that case. 02306 */ 02307 if (psms->flags & SMF_RECEIVERFREE) { 02308 UnlinkSendListSms(psms, NULL); 02309 return; 02310 } 02311 02312 /* 02313 * Set reply flag and return value if this message has not already 02314 * been replied to with ReplyMessage(). 02315 */ 02316 if (!(psms->flags & SMF_REPLY)) { 02317 psms->lRet = lRet; 02318 psms->flags |= SMF_REPLY; 02319 02320 /* 02321 * Tell the sender, the reply is done 02322 */ 02323 if (ptiSender != NULL) { 02324 /* 02325 * Wake up the sender thread. 02326 */ 02327 SetWakeBit(ptiSender, QS_SMSREPLY); 02328 02329 /* 02330 * We have 4 conditions to satisfy: 02331 * 02332 * 16 - 16 : yielding required, if sender is waiting for this reply 02333 * 32 - 16 : yielding required, if sender is waiting for this reply 02334 * 16 - 32 : no yielding required 02335 * 32 - 32 : No yielding required. 02336 */ 02337 02338 if (ptiSender->TIF_flags & TIF_16BIT || ptiReceiver->TIF_flags & TIF_16BIT) { 02339 DirectedScheduleTask(ptiReceiver, ptiSender, FALSE, psms); 02340 if (ptiReceiver->TIF_flags & TIF_16BIT && 02341 ptiSender->psmsSent == psms) 02342 { 02343 xxxSleepTask(TRUE, NULL); 02344 } 02345 } 02346 } 02347 } 02348 02349 } 02350 02351 02352 /***********************************************************************\ 02353 * SendMsgCleanup 02354 * 02355 * This function cleans up sendmessage structures when the thread associated 02356 * with a queue terminates. In the following, S is the sending thread, 02357 * R the receiving thread. 02358 * 02359 * Case Table: 02360 * 02361 * single death: 02362 * R no reply, S dies: mark that S died, R will free sms 02363 * R no reply, R dies: fake reply for S 02364 * R replied, S dies: free sms 02365 * R replied, R dies: no problem 02366 * 02367 * double death: 02368 * R no reply, S dies, R dies: free sms 02369 * R no reply, R dies, S dies: free sms 02370 * R replied, S dies, R dies: sms freed when S dies, as in single death 02371 * R replied, R dies, S dies: sms freed when S dies, as in single death 02372 * 02373 * History: 02374 * 01-13-91 DavidPe Ported. 02375 \***********************************************************************/ 02376 02377 VOID SendMsgCleanup( 02378 PTHREADINFO ptiCurrent) 02379 { 02380 PSMS *ppsms; 02381 PSMS psmsNext; 02382 02383 CheckCritIn(); 02384 02385 for (ppsms = &gpsmsList; *ppsms; ) { 02386 psmsNext = (*ppsms)->psmsNext; 02387 02388 if ((*ppsms)->ptiSender == ptiCurrent || 02389 (*ppsms)->ptiCallBackSender == ptiCurrent) { 02390 SenderDied(*ppsms, ppsms); 02391 } else if ((*ppsms)->ptiReceiver == ptiCurrent) { 02392 ReceiverDied(*ppsms, ppsms); 02393 } 02394 02395 /* 02396 * If the message was not unlinked, go to the next one. 02397 */ 02398 if (*ppsms != psmsNext) 02399 ppsms = &(*ppsms)->psmsNext; 02400 } 02401 } 02402 02403 02404 /***********************************************************************\ 02405 * ClearSendMessages 02406 * 02407 * This function marks messages destined for a given window as invalid. 02408 * 02409 * History: 02410 * 01-13-91 DavidPe Ported. 02411 \***********************************************************************/ 02412 02413 VOID ClearSendMessages( 02414 PWND pwnd) 02415 { 02416 PSMS psms, psmsNext; 02417 PSMS *ppsms; 02418 02419 CheckCritIn(); 02420 02421 psms = gpsmsList; 02422 while (psms != NULL) { 02423 /* 02424 * Grab the next one beforehand in case we free the current one. 02425 */ 02426 psmsNext = psms->psmsNext; 02427 02428 if (psms->spwnd == pwnd) { 02429 02430 /* 02431 * If the sender has died, then mark this receiver free so the 02432 * receiver will destroy it in its processing. 02433 */ 02434 if (psms->flags & SMF_SENDERDIED) { 02435 psms->flags |= SMF_REPLY | SMF_RECEIVERFREE; 02436 } else { 02437 /* 02438 * The sender is alive. If the receiver hasn't replied to 02439 * this yet, make a reply so the sender gets it. Make sure 02440 * the receiver is the one free it so we don't have a race 02441 * condition. 02442 */ 02443 if (!(psms->flags & SMF_REPLY)) { 02444 02445 /* 02446 * The sms is either still on the receive list 02447 * or is currently being received. Since the sender 02448 * is alive, we want the sender to get the reply 02449 * to this SMS. If it hasn't been received, take 02450 * it off the receive list and reply to it. If it 02451 * has been received, then just leave it alone: 02452 * it'll get replied to normally. 02453 */ 02454 if (psms->flags & SMF_CB_REQUEST) { 02455 /* 02456 * From SendMessageCallback REQUEST callback. Send the 02457 * message back with a the REPLY value. 02458 */ 02459 TL tlpwnd; 02460 INTRSENDMSGEX ism; 02461 02462 psms->flags |= SMF_REPLY; 02463 02464 ism.fuCall = ISM_CALLBACK | ISM_REPLY; 02465 if (psms->flags & SMF_CB_CLIENT) 02466 ism.fuCall |= ISM_CB_CLIENT; 02467 ism.lpResultCallBack = psms->lpResultCallBack; 02468 ism.dwData = psms->dwData; 02469 ism.lRet = 0L; /* null return */ 02470 02471 ThreadLock(psms->spwnd, &tlpwnd); 02472 02473 xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L, 02474 NULL, psms->ptiCallBackSender, &ism ); 02475 02476 ThreadUnlock(&tlpwnd); 02477 } else if (!(psms->flags & SMF_RECEIVERBUSY)) { 02478 /* 02479 * If there is no sender, this is a notification 02480 * message (nobody to reply to). In this case, 02481 * just set the SMF_REPLY bit (SMF_RECEIVERFREE 02482 * is already set) and this'll cause ReceiveMessage 02483 * to just free this SMS and return. 02484 */ 02485 if (psms->ptiSender == NULL) { 02486 psms->flags |= SMF_REPLY; 02487 } else { 02488 /* 02489 * There is a sender, and it wants a reply: take 02490 * this SMS off the receive list, and reply 02491 * to the sender. 02492 */ 02493 for (ppsms = &(psms->ptiReceiver->psmsReceiveList); 02494 *ppsms != NULL; 02495 ppsms = &((*ppsms)->psmsReceiveNext)) { 02496 02497 if (*ppsms == psms) { 02498 *ppsms = psms->psmsReceiveNext; 02499 break; 02500 } 02501 } 02502 02503 02504 /* 02505 * Reply to this message so the sender 02506 * wakes up. 02507 */ 02508 psms->flags |= SMF_REPLY; 02509 psms->lRet = 0; 02510 psms->psmsReceiveNext = NULL; 02511 SetWakeBit(psms->ptiSender, QS_SMSREPLY); 02512 02513 /* 02514 * 16 bit senders need to be notifed that sends completed 02515 * otherwise it may wait for a very long time for the reply. 02516 */ 02517 if (psms->ptiSender->TIF_flags & TIF_16BIT) { 02518 DirectedScheduleTask(psms->ptiReceiver, psms->ptiSender, FALSE, psms); 02519 } 02520 } 02521 } 02522 } 02523 } 02524 02525 /* 02526 * Unlock the pwnd from the SMS structure. 02527 */ 02528 Unlock(&psms->spwnd); 02529 } 02530 02531 psms = psmsNext; 02532 } 02533 } 02534 02535 /***********************************************************************\ 02536 * ReceiverDied 02537 * 02538 * This function cleans up the send message structures after a message 02539 * receiver window or queue has died. It fakes a reply if one has not 02540 * already been sent and the sender has not died. It frees the sms if 02541 * the sender has died. 02542 * 02543 * History: 02544 * 01-13-91 DavidPe Ported. 02545 \***********************************************************************/ 02546 02547 VOID ReceiverDied( 02548 PSMS psms, 02549 PSMS *ppsmsUnlink) 02550 { 02551 PSMS *ppsms; 02552 PTHREADINFO ptiReceiver; 02553 PTHREADINFO ptiSender; 02554 02555 /* 02556 * mark that the receiver died 02557 */ 02558 ptiReceiver = psms->ptiReceiver; 02559 psms->ptiReceiver = NULL; 02560 psms->flags |= SMF_RECEIVERDIED; 02561 02562 /* 02563 * Unlink sms from thread if it is not dying. We need to do 02564 * this for journal cleanup. 02565 */ 02566 if (!(ptiReceiver->TIF_flags & TIF_INCLEANUP)) { 02567 02568 /* 02569 * unlink sms from the receiver's receive list 02570 */ 02571 for (ppsms = &(ptiReceiver->psmsReceiveList); *ppsms != NULL; 02572 ppsms = &((*ppsms)->psmsReceiveNext)) { 02573 02574 if (*ppsms == psms) { 02575 *ppsms = psms->psmsReceiveNext; 02576 break; 02577 } 02578 } 02579 02580 /* 02581 * clear the QS_SENDMESSAGE bit if there are no more messages 02582 */ 02583 if (ptiReceiver->psmsReceiveList == NULL) { 02584 ptiReceiver->pcti->fsWakeBits &= ~QS_SENDMESSAGE; 02585 ptiReceiver->pcti->fsChangeBits &= ~QS_SENDMESSAGE; 02586 } 02587 } else { 02588 02589 /* 02590 * The receiver thread is dying. Clear the received flag 02591 * so that if there is a sender, it will free the sms. 02592 */ 02593 psms->flags &= ~SMF_RECEIVERBUSY; 02594 } 02595 02596 psms->psmsReceiveNext = NULL; 02597 02598 /* 02599 * Check if the sender died or if the receiver was marked to 02600 * free the sms. 02601 */ 02602 if (psms->ptiSender == NULL) { 02603 02604 if (!(psms->flags & SMF_SENDERDIED) && 02605 (psms->flags & (SMF_CB_REQUEST | SMF_REPLY)) == SMF_CB_REQUEST) { 02606 02607 /* 02608 * From SendMessageCallback REQUEST callback. Send the message 02609 * back with a the REPLY value. 02610 */ 02611 TL tlpwnd; 02612 INTRSENDMSGEX ism; 02613 02614 psms->flags |= SMF_REPLY; 02615 02616 ism.fuCall = ISM_CALLBACK | ISM_REPLY; 02617 if (psms->flags & SMF_CB_CLIENT) 02618 ism.fuCall |= ISM_CB_CLIENT; 02619 ism.lpResultCallBack = psms->lpResultCallBack; 02620 ism.dwData = psms->dwData; 02621 ism.lRet = 0L; /* null return */ 02622 02623 ThreadLock(psms->spwnd, &tlpwnd); 02624 02625 xxxInterSendMsgEx(psms->spwnd, psms->message, 0L, 0L, 02626 NULL, psms->ptiCallBackSender, &ism ); 02627 02628 ThreadUnlock(&tlpwnd); 02629 } 02630 02631 /* 02632 * If the receiver is not processing the message, free it. 02633 */ 02634 if (!(psms->flags & SMF_RECEIVERBUSY)) 02635 UnlinkSendListSms(psms, ppsmsUnlink); 02636 return; 02637 02638 } else if (!(psms->flags & SMF_REPLY)) { 02639 02640 /* 02641 * fake a reply 02642 */ 02643 psms->flags |= SMF_REPLY; 02644 psms->lRet = 0; 02645 psms->ptiReceiver = NULL; 02646 02647 /* 02648 * wake the sender if he was waiting for us 02649 */ 02650 SetWakeBit(psms->ptiSender, QS_SMSREPLY); 02651 } else { 02652 /* 02653 * There is a reply. We know the receiver is dying, so clear the 02654 * SMF_RECEIVERFREE bit or the sender won't free this SMS! 02655 * Although the sender's wake bit has already been set by the 02656 * call to ClearSendMessages() earlier in the cleanup code, 02657 * set it here again for safety. 02658 * 02659 * ??? Why would SMF_RECEIVERFREE be set? 02660 */ 02661 psms->flags &= ~SMF_RECEIVERFREE; 02662 SetWakeBit(psms->ptiSender, QS_SMSREPLY); 02663 } 02664 02665 /* 02666 * If the sender is a WOW task, that task is now blocked in the non- 02667 * preemptive scheduler waiting for a reply. DestroyTask will 02668 * clean this up (even if ptiReceiver is 32-bit). 02669 */ 02670 ptiSender = psms->ptiSender; 02671 if (ptiSender->TIF_flags & TIF_16BIT) { 02672 DirectedScheduleTask(ptiReceiver, ptiSender, FALSE, psms); 02673 } 02674 02675 /* 02676 * Unlock this window from the sms: it is no longer needed, and will get 02677 * rid of lock warnings. 02678 */ 02679 Unlock(&psms->spwnd); 02680 } 02681 02682 02683 /***********************************************************************\ 02684 * SenderDied 02685 * 02686 * This function cleans up the send message structures after a message 02687 * sender has died. 02688 * 02689 * History: 02690 * 01-13-91 DavidPe Ported. 02691 \***********************************************************************/ 02692 02693 VOID SenderDied( 02694 PSMS psms, 02695 PSMS *ppsmsUnlink) 02696 { 02697 PTHREADINFO ptiSender; 02698 BOOL fReply = FALSE; 02699 02700 /* 02701 * mark the death 02702 */ 02703 if (psms->ptiSender != NULL) 02704 ptiSender = psms->ptiSender; 02705 else 02706 ptiSender = psms->ptiCallBackSender; 02707 psms->ptiSender = NULL; 02708 psms->flags |= SMF_SENDERDIED; 02709 02710 /* 02711 * There are two cases where we leave the sms alone so the receiver 02712 * can handle the message and then free the sms itself. 02713 * 02714 * 1. When the receiver is processing the message. 02715 * 02716 * 2. When the message has not yet been received. 02717 */ 02718 02719 /* 02720 * If the receiver is processing the message, make it free the sms. 02721 * Fake a reply for journal cancel. 02722 */ 02723 if (psms->flags & SMF_RECEIVERBUSY) { 02724 psms->flags |= SMF_RECEIVERFREE; 02725 fReply = TRUE; 02726 } 02727 02728 /* 02729 * This sms may be in the process of being sent, but has not yet 02730 * been received. In so, fake a reply and wake the sender. 02731 * The last thread to touch the sms, either the sender or 02732 * receiver, will free the sms. 02733 */ 02734 if (ptiSender->psmsSent == psms) 02735 fReply = TRUE; 02736 02737 /* 02738 * If journalling is being cancelled and reply needs to be made, 02739 * fake a reply and return. 02740 */ 02741 if (!(ptiSender->TIF_flags & TIF_INCLEANUP) && fReply) { 02742 02743 /* 02744 * fake a reply 02745 */ 02746 psms->flags |= SMF_REPLY; 02747 psms->lRet = 0; 02748 02749 /* 02750 * wake the sender if he was waiting for us 02751 */ 02752 SetWakeBit(ptiSender, QS_SMSREPLY); 02753 return; 02754 } 02755 02756 /* 02757 * If the receiver isn't dead, check to see if it has honestly replied to 02758 * this SMS. If it has not replied, leave it alone so the receiver can 02759 * reply to it (it'll then clean it up). If it has replied, then it's 02760 * ok to free it. 02761 * 02762 * It is also ok to free it if the receiver is dead. 02763 */ 02764 if ((psms->flags & SMF_RECEIVERDIED) || 02765 (psms->flags & (SMF_REPLY | SMF_RECEIVERFREE)) == SMF_REPLY) { 02766 UnlinkSendListSms(psms, ppsmsUnlink); 02767 } else { 02768 psms->flags |= SMF_RECEIVERFREE; 02769 } 02770 } 02771 02772 02773 /***********************************************************************\ 02774 * UnlinkSendListSms 02775 * 02776 * This function unlinks an sms structure from both its SendMsg chain and 02777 * the global gpsmsList and frees it. 02778 * 02779 * History: 02780 * 01-13-91 DavidPe Ported. 02781 \***********************************************************************/ 02782 02783 VOID UnlinkSendListSms( 02784 PSMS psms, 02785 PSMS *ppsmsUnlink) 02786 { 02787 #if DBG 02788 PSMS psmsT; 02789 BOOL fUpdateSendList; 02790 PSMS *ppsms; 02791 #endif 02792 02793 CheckCritIn(); 02794 02795 #ifdef DEBUG_SMS 02796 ValidateSmsSendLists(psms); 02797 #endif 02798 02799 UserAssert(psms->psmsReceiveNext == NULL); 02800 02801 #if DBG 02802 /* 02803 * Remember ahead of time if the psms we're unlinking is also the 02804 * head of the sms send list (so we know if we need to update this field 02805 * member in every SMS in this list). 02806 */ 02807 fUpdateSendList = (psms == psms->psmsSendList); 02808 02809 /* 02810 * Unlink sms from the sendlist chain. This effectively unlinks the SMS 02811 * and updates psms->psmsSendList with the right head.... 02812 */ 02813 ppsms = &(psms->psmsSendList); 02814 while (*ppsms != NULL) { 02815 if (*ppsms == psms) { 02816 *ppsms = psms->psmsSendNext; 02817 break; 02818 } 02819 ppsms = &(*ppsms)->psmsSendNext; 02820 } 02821 02822 /* 02823 * Update psmsSendList if necessary. psms->psmsSendList has been updated 02824 * with the right sms send list head... distribute this head to all other 02825 * sms's in this chain if this sms we're removing the current head. 02826 */ 02827 if (fUpdateSendList) { 02828 for (psmsT = psms->psmsSendList; psmsT != NULL; 02829 psmsT = psmsT->psmsSendNext) { 02830 psmsT->psmsSendList = psms->psmsSendList; 02831 } 02832 } 02833 02834 psms->psmsSendList = NULL; 02835 #endif 02836 02837 /* 02838 * This unlinks an sms structure from the global gpsmsList and frees it. 02839 */ 02840 if (ppsmsUnlink == NULL) { 02841 ppsmsUnlink = &gpsmsList; 02842 02843 while (*ppsmsUnlink && (*ppsmsUnlink != psms)) { 02844 ppsmsUnlink = &((*ppsmsUnlink)->psmsNext); 02845 } 02846 } 02847 02848 UserAssert(*ppsmsUnlink); 02849 02850 *ppsmsUnlink = psms->psmsNext; 02851 02852 Unlock(&psms->spwnd); 02853 02854 #if DBG 02855 UserAssert(!(psms == psms->psmsSendList && psms->psmsSendNext != NULL)); 02856 #endif 02857 02858 if (psms->pvCapture) 02859 UserFreePool(psms->pvCapture); 02860 02861 FreeSMS(psms); 02862 } 02863 02864 02865 /***************************************************************************\ 02866 * xxxSendSizeMessages 02867 * 02868 * 02869 * 02870 * History: 02871 * 10-19-90 darrinm Ported from Win 3.0 sources. 02872 \***************************************************************************/ 02873 02874 void xxxSendSizeMessage( 02875 PWND pwnd, 02876 UINT cmdSize) 02877 { 02878 RECT rc; 02879 CheckLock(pwnd); 02880 02881 // Added by Chicago: HACK ALERT: 02882 // If the window is minimized then the real client width and height are 02883 // zero. But, in win3.1 they were non-zero. Under Chicago, PrintShop 02884 // Deluxe ver 1.2 hits a divide by zero. To fix this we fake the width 02885 // and height for old apps to be non-zero values. 02886 // GetClientRect does that job for us. 02887 _GetClientRect(pwnd, &rc); 02888 02889 xxxSendMessage(pwnd, WM_SIZE, cmdSize, 02890 MAKELONG(rc.right - rc.left, rc.bottom - rc.top)); 02891 } 02892 02893 02894 /***************************************************************************\ 02895 * xxxProcessAsyncSendMessage 02896 * 02897 * Processes an event message posted by xxxSystemBroadcastMessage by 02898 * sending a message to the window stored in the event. 02899 * 02900 * History: 02901 * 05-12-94 JimA Created. 02902 \***************************************************************************/ 02903 02904 VOID xxxProcessAsyncSendMessage( 02905 PASYNCSENDMSG pmsg) 02906 { 02907 PWND pwnd; 02908 TL tlpwndT; 02909 WCHAR awchString[MAX_PATH]; 02910 ATOM Atom = 0; 02911 LARGE_UNICODE_STRING str; 02912 02913 pwnd = RevalidateHwnd(pmsg->hwnd); 02914 if (pwnd != NULL) { 02915 ThreadLockAlways(pwnd, &tlpwndT); 02916 switch (pmsg->message) { 02917 case WM_WININICHANGE: 02918 case WM_DEVMODECHANGE: 02919 if (pmsg->lParam) { 02920 if (UserGetAtomName((ATOM)pmsg->lParam, awchString, sizeof(awchString))) { 02921 Atom = (ATOM)pmsg->lParam; 02922 RtlInitLargeUnicodeString(&str, awchString, (UINT)-1); 02923 pmsg->lParam = (LPARAM)&str; 02924 } else { 02925 UserAssert(FALSE); 02926 pmsg->lParam = 0; 02927 } 02928 } 02929 break; 02930 } 02931 xxxSendMessage(pwnd, pmsg->message, pmsg->wParam, pmsg->lParam); 02932 ThreadUnlock(&tlpwndT); 02933 } 02934 if (Atom) { 02935 UserDeleteAtom(Atom); 02936 } 02937 UserFreePool(pmsg); 02938 } 02939 02940 02941 /***************************************************************************\ 02942 * xxxBroadcastMessage 02943 * 02944 * 02945 * 02946 * History: 02947 * 02-21-91 DavidPe Created. 02948 \***************************************************************************/ 02949 02950 LONG xxxBroadcastMessage( 02951 PWND pwnd, 02952 UINT message, 02953 WPARAM wParam, 02954 LPARAM lParam, 02955 UINT wCmd, 02956 PBROADCASTMSG pbcm) 02957 { 02958 PBWL pbwl; 02959 HWND *phwnd; 02960 TL tlpwnd; 02961 PASYNCSENDMSG pmsg; 02962 PPROCESSINFO ppiCurrent; 02963 LONG lRet = TRUE; 02964 TL tlPool; 02965 PTHREADINFO ptiCurrent = PtiCurrent(); 02966 BOOL fPrivateMessage = (message >= WM_USER) && (message < MAXINTATOM); 02967 02968 if (fPrivateMessage) { 02969 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to broadcast a private message"); 02970 } 02971 02972 if (pwnd == NULL) { 02973 LARGE_UNICODE_STRING str; 02974 PLARGE_STRING pstr; 02975 02976 /* 02977 * Handle special system-wide broadcasts. 02978 */ 02979 switch (message) { 02980 case WM_SPOOLERSTATUS: 02981 xxxSystemBroadcastMessage(message, wParam, lParam, wCmd, pbcm); 02982 return 1; 02983 02984 case WM_WININICHANGE: 02985 case WM_DEVMODECHANGE: 02986 02987 /* 02988 * Probe and capture the string. 02989 */ 02990 if (lParam) { 02991 UINT cbAlloc; 02992 NTSTATUS Status; 02993 02994 /* 02995 * Allocate a temp buffer and convert 02996 * the string to Unicode 02997 */ 02998 pstr = ((PLARGE_STRING)lParam); 02999 if (pstr->bAnsi) 03000 cbAlloc = (pstr->Length + 1) * sizeof(WCHAR); 03001 else 03002 cbAlloc = pstr->Length + sizeof(WCHAR); 03003 str.Buffer = UserAllocPoolWithQuota(cbAlloc, TAG_SMS_STRING); 03004 if (str.Buffer == NULL) { 03005 return 0; 03006 } 03007 str.MaximumLength = cbAlloc; 03008 str.bAnsi = FALSE; 03009 try { 03010 if (pstr->bAnsi) { 03011 Status = RtlMultiByteToUnicodeN( 03012 (PWCH)str.Buffer, 03013 cbAlloc, 03014 &cbAlloc, 03015 (PCH)pstr->Buffer, 03016 pstr->Length 03017 ); 03018 str.Length = cbAlloc; 03019 } else { 03020 str.Length = pstr->Length; 03021 RtlCopyMemory(str.Buffer, pstr->Buffer, str.Length); 03022 Status = STATUS_SUCCESS; 03023 } 03024 str.Buffer[str.Length / sizeof(WCHAR)] = 0; 03025 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 03026 Status = GetExceptionCode(); 03027 } 03028 if (!NT_SUCCESS(Status)) { 03029 UserFreePool(str.Buffer); 03030 return 0; 03031 } 03032 pstr->Buffer = str.Buffer; 03033 } 03034 if (lParam) { 03035 ThreadLockPool(ptiCurrent, str.Buffer, &tlPool); 03036 } 03037 xxxSystemBroadcastMessage(message, wParam, 03038 lParam ? (LPARAM)&str : 0, wCmd, pbcm); 03039 if (lParam) 03040 ThreadUnlockAndFreePool(ptiCurrent, &tlPool); 03041 return 1; 03042 03043 case WM_TIMECHANGE: 03044 /* 03045 * We automatically broadcast a WM_TIMECHANGE message whenever the 03046 * kernel tells us the time has changed, so blow off any apps who 03047 * are trying to do the same thing. 03048 */ 03049 if (!(ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD)) { 03050 RIPMSG0(RIP_WARNING, "Only system should broadcast WM_TIMECHANGE"); 03051 return 0; 03052 } 03053 break; 03054 } 03055 03056 UserAssert(ptiCurrent->rpdesk); 03057 03058 pwnd = ptiCurrent->rpdesk->pDeskInfo->spwnd; 03059 03060 if (pwnd == NULL) { 03061 RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "sender must have an associated desktop"); 03062 return 0; 03063 } 03064 } 03065 03066 pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL); 03067 if (pbwl == NULL) 03068 return 0; 03069 03070 ppiCurrent = PpiCurrent(); 03071 03072 for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { 03073 03074 /* 03075 * Make sure this hwnd is still around. 03076 */ 03077 if ((pwnd = RevalidateHwnd(*phwnd)) == NULL) 03078 continue; 03079 03080 /* 03081 * Make sure this window can handle broadcast messages 03082 */ 03083 if (!fBroadcastProc(pwnd)) 03084 continue; 03085 03086 if (fPrivateMessage && TestWF(pwnd, WFWIN40COMPAT)) { // Don't broadcast 03087 continue; // private message 03088 } // to 4.0 apps. 03089 03090 /* 03091 * Don't bother sending palette messages to windows that are not 03092 * visible on threads that are not palette aware. 03093 */ 03094 if ((message == WM_PALETTEISCHANGING || message == WM_PALETTECHANGED) && 03095 !TestWF(pwnd, WFVISIBLE) && 03096 !(GETPTI(pwnd)->TIF_flags & TIF_PALETTEAWARE)) { 03097 continue; 03098 } 03099 03100 ThreadLockAlways(pwnd, &tlpwnd); 03101 03102 switch (wCmd) { 03103 case BMSG_SENDMSG: 03104 xxxSendMessage(pwnd, message, wParam, lParam); 03105 break; 03106 03107 case BMSG_SENDNOTIFYMSG: 03108 { 03109 ATOM Atom = 0; 03110 03111 switch (message) { 03112 case WM_WININICHANGE: 03113 case WM_DEVMODECHANGE: 03114 if (lParam) { 03115 PLARGE_STRING pstr = (PLARGE_STRING)lParam; 03116 03117 /* 03118 * Convert strings to atoms for the post. 03119 */ 03120 if (pstr) 03121 Atom = UserAddAtom(pstr->Buffer, FALSE); 03122 if (!Atom) { 03123 lRet = FALSE; 03124 break; 03125 } 03126 } 03127 03128 /* 03129 * These messages need to be able to cross 03130 * desktops so PostEvent 'em. 03131 */ 03132 pmsg = UserAllocPool(sizeof(ASYNCSENDMSG), 03133 TAG_SMS_ASYNC); 03134 if (pmsg == NULL) { 03135 goto CleanupAtom; 03136 } 03137 03138 pmsg->hwnd = *phwnd; 03139 pmsg->message = message; 03140 pmsg->wParam = wParam; 03141 pmsg->lParam = Atom; 03142 03143 if (!PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq, 03144 QEVENT_ASYNCSENDMSG,NULL, 0, 03145 (WPARAM)pmsg, 0)) { 03146 03147 UserFreePool(pmsg); 03148 CleanupAtom: 03149 if (Atom) { 03150 UserDeleteAtom(Atom); 03151 } 03152 lRet = FALSE; 03153 } 03154 break; 03155 03156 default: 03157 /* 03158 * A regular kind of guy. No desktop crossing. 03159 */ 03160 xxxSendNotifyMessage(pwnd, message, wParam, lParam); 03161 break; 03162 } 03163 } 03164 break; 03165 03166 case BMSG_SENDNOTIFYMSGPROCESS: 03167 UserAssert(message != WM_WININICHANGE && message != WM_DEVMODECHANGE); 03168 03169 /* 03170 * Intra-process messages are synchronous; 22238. 03171 * WM_PALETTECHANGED was being sent after the WM_DESTROY 03172 * but console thread must not be synchronous. 03173 */ 03174 if ((GETPTI(pwnd)->ppi == ppiCurrent) && !(GETPTI(pwnd)->TIF_flags & TIF_CSRSSTHREAD)) { 03175 xxxSendMessage(pwnd, message, wParam, lParam); 03176 } else { 03177 xxxSendNotifyMessage(pwnd, message, wParam, lParam); 03178 } 03179 break; 03180 03181 case BMSG_POSTMSG: 03182 /* 03183 * Don't broadcast-post to owned windows (Win3.1 compatiblilty) 03184 */ 03185 if (pwnd->spwndOwner == NULL) 03186 _PostMessage(pwnd, message, wParam, lParam); 03187 break; 03188 03189 case BMSG_SENDMSGCALLBACK: 03190 xxxSendMessageCallback(pwnd, message, wParam, lParam, 03191 pbcm->cb.lpResultCallBack, pbcm->cb.dwData, pbcm->cb.bClientRequest); 03192 break; 03193 03194 case BMSG_SENDMSGTIMEOUT: 03195 xxxSendMessageTimeout(pwnd, message, wParam, lParam, 03196 pbcm->to.fuFlags, pbcm->to.uTimeout, pbcm->to.lpdwResult); 03197 break; 03198 } 03199 03200 ThreadUnlock(&tlpwnd); 03201 } 03202 03203 FreeHwndList(pbwl); 03204 03205 /* 03206 * Excel-Solver 3.0 expects a non-zero return value from a 03207 * SendMessage(-1,WM_DDE_INITIATE,....); Because, we had 03208 * FFFE_FARFRAME in 3.0, the DX register at this point always had 03209 * a value of 0x102; But, because we removed it under Win3.1, we get 03210 * a zero value in ax and dx; This makes solver think that the DDE has 03211 * failed. So, to support the existing SOLVER, we make dx nonzero. 03212 * Fix for Bug #6005 -- SANKAR -- 05-16-91 -- 03213 */ 03214 return 1; 03215 }

Generated on Sat May 15 19:41:45 2004 for test by doxygen 1.3.7