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

queue.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: queue.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains the low-level code for working with the Q structure. 00007 * 00008 * History: 00009 * 12-02-90 DavidPe Created. 00010 * 02-06-91 IanJa HWND revalidation added 00011 \***************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 VOID DestroyProcessesObjects(PPROCESSINFO ppi); 00017 VOID DestroyThreadsMessages(PQ pq, PTHREADINFO pti); 00018 void CheckProcessForeground(PTHREADINFO pti); 00019 void ScreenSaverCheck(PTHREADINFO pti); 00020 DWORD xxxPollAndWaitForSingleObject(PKEVENT pEvent, PVOID pExecObject, 00021 DWORD dwMilliseconds); 00022 00023 NTSTATUS InitiateShutdown(PETHREAD Thread, PULONG lpdwFlags); 00024 NTSTATUS EndShutdown(PETHREAD Thread, NTSTATUS StatusShutdown); 00025 void SetVDMCursorBounds(LPRECT lprc); 00026 NTSTATUS InitQEntryLookaside(VOID); 00027 void SetAppStarting (PPROCESSINFO ppi); 00028 00029 #pragma alloc_text(INIT, InitQEntryLookaside) 00030 00031 PW32PROCESS gpwpCalcFirst; 00032 00033 #if DBG 00034 #define MSG_SENT 0 00035 #define MSG_POST 1 00036 #define MSG_RECV 2 00037 #define MSG_PEEK 3 00038 VOID TraceDdeMsg(UINT msg, HWND hwndFrom, HWND hwndTo, UINT code); 00039 #else 00040 #define TraceDdeMsg(m, h1, h2, c) 00041 #endif // DBG 00042 00043 PPAGED_LOOKASIDE_LIST QLookaside; 00044 PPAGED_LOOKASIDE_LIST QEntryLookaside; 00045 00046 #if DBG 00047 void DebugValidateMLIST(PMLIST pml) 00048 { 00049 int c; 00050 PQMSG pqmsg; 00051 00052 /* 00053 * Check that the message list is properly terminated. 00054 */ 00055 UserAssert(!pml->pqmsgRead || !pml->pqmsgRead->pqmsgPrev); 00056 UserAssert(!pml->pqmsgWriteLast || !pml->pqmsgWriteLast->pqmsgNext); 00057 00058 /* 00059 * Check that there aren't loops in the Next list. 00060 */ 00061 c = pml->cMsgs; 00062 UserAssert(c >= 0); 00063 pqmsg = pml->pqmsgRead; 00064 while (--c >= 0) { 00065 UserAssert(pqmsg); 00066 if (c == 0) { 00067 UserAssert(pqmsg == pml->pqmsgWriteLast); 00068 } 00069 00070 pqmsg = pqmsg->pqmsgNext; 00071 } 00072 00073 UserAssert(!pqmsg); 00074 00075 /* 00076 * Check that there aren't loops in the Prev list. 00077 */ 00078 c = pml->cMsgs; 00079 pqmsg = pml->pqmsgWriteLast; 00080 while (--c >= 0) { 00081 UserAssert(pqmsg); 00082 if (c == 0) { 00083 UserAssert(pqmsg == pml->pqmsgRead); 00084 } 00085 00086 pqmsg = pqmsg->pqmsgPrev; 00087 } 00088 00089 UserAssert(!pqmsg); 00090 } 00091 00092 void DebugValidateMLISTandQMSG(PMLIST pml, PQMSG pqmsg) 00093 { 00094 PQMSG pqmsgT; 00095 00096 DebugValidateMLIST(pml); 00097 for (pqmsgT = pml->pqmsgRead; pqmsgT; pqmsgT = pqmsgT->pqmsgNext) { 00098 if (pqmsgT == pqmsg) { 00099 return; 00100 } 00101 } 00102 00103 UserAssert(pqmsgT == pqmsg); 00104 } 00105 00106 #else 00107 #define DebugValidateMLIST(pml) 00108 #define DebugValidateMLISTandQMSG(pml, pqmsg) 00109 #endif 00110 00111 /***************************************************************************\ 00112 * xxxSetProcessInitState 00113 * 00114 * Set process initialization state. What state is set depends 00115 * on whether another process is waiting on this process. 00116 * 00117 * 04-02-95 JimA Created. 00118 \***************************************************************************/ 00119 00120 BOOL xxxSetProcessInitState( 00121 PEPROCESS Process, 00122 DWORD dwFlags) 00123 { 00124 PW32PROCESS W32Process; 00125 NTSTATUS Status; 00126 00127 CheckCritIn(); 00128 UserAssert(IsWinEventNotifyDeferredOK()); 00129 00130 /* 00131 * If the W32Process structure has not been allocated, do it now. 00132 */ 00133 W32Process = (PW32PROCESS)Process->Win32Process; 00134 if (W32Process == NULL) { 00135 Status = AllocateW32Process(Process); 00136 if (!NT_SUCCESS(Status)) { 00137 return FALSE; 00138 } 00139 W32Process = (PW32PROCESS)Process->Win32Process; 00140 #if DBG 00141 /* 00142 * The above AllocateW32Process(Process, FALSE) won't set the 00143 * W32PF_PROCESSCONNECTED flag (and if it wasn't previously set), 00144 * make sure we're not on the gppiStarting list, because if we are, 00145 * we will not be removed without the W32PF_PROCESSCONNECTED bit. 00146 */ 00147 if ((W32Process->W32PF_Flags & W32PF_PROCESSCONNECTED) == 0) { 00148 UserAssert((W32Process->W32PF_Flags & W32PF_APPSTARTING) == 0); 00149 } 00150 #endif 00151 } 00152 00153 /* 00154 * Defer WinEvent notifications, because the thread isn't initialized yet. 00155 */ 00156 DeferWinEventNotify(); 00157 if (dwFlags == 0) { 00158 if (!(W32Process->W32PF_Flags & W32PF_WOW)) { 00159 00160 /* 00161 * Check to see if the startglass is on, and if so turn it off and update. 00162 */ 00163 if (W32Process->W32PF_Flags & W32PF_STARTGLASS) { 00164 W32Process->W32PF_Flags &= ~W32PF_STARTGLASS; 00165 zzzCalcStartCursorHide(NULL, 0); 00166 } 00167 00168 /* 00169 * Found it. Set the console bit and reset the wait event so any sleepers 00170 * wake up. 00171 */ 00172 W32Process->W32PF_Flags |= W32PF_CONSOLEAPPLICATION; 00173 SET_PSEUDO_EVENT(&W32Process->InputIdleEvent); 00174 } 00175 } else if (!(W32Process->W32PF_Flags & W32PF_INITIALIZED)) { 00176 W32Process->W32PF_Flags |= W32PF_INITIALIZED; 00177 00178 /* 00179 * Set global state to allow the new process to become 00180 * foreground. xxxInitProcessInfo() will set 00181 * W32PF_ALLOWFOREGROUNDACTIVATE when the process initializes. 00182 */ 00183 SET_PUDF(PUDF_ALLOWFOREGROUNDACTIVATE); 00184 TAGMSG1(DBGTAG_FOREGROUND, "xxxSetProcessInitState set PUDF. %#p", W32Process); 00185 00186 00187 /* 00188 * If this is the win32 server process, force off start glass feedback 00189 */ 00190 if (Process == gpepCSRSS) { 00191 dwFlags |= STARTF_FORCEOFFFEEDBACK; 00192 } 00193 00194 /* 00195 * Show the app start cursor for 2 seconds if it was requested from 00196 * the application. 00197 */ 00198 if (dwFlags & STARTF_FORCEOFFFEEDBACK) { 00199 W32Process->W32PF_Flags |= W32PF_FORCEOFFFEEDBACK; 00200 zzzCalcStartCursorHide(NULL, 0); 00201 } else if (dwFlags & STARTF_FORCEONFEEDBACK) { 00202 zzzCalcStartCursorHide(W32Process, 2000); 00203 } 00204 } 00205 /* 00206 * Have to defer without processing, because we don't have a ptiCurrent yet 00207 */ 00208 EndDeferWinEventNotifyWithoutProcessing(); 00209 return TRUE; 00210 } 00211 00212 /***************************************************************************\ 00213 * CheckAllowForeground 00214 * 00215 * Bug 273518 - joejo 00216 * 00217 * Removed this loop from xxxInitProcessInfo to allow code shareing between 00218 * that function and xxxUserNotifyConsoleApplication. This will allow console 00219 * windows to set foreground correctly on new process' it launches, as opposed 00220 * it just forcing foreground. 00221 \***************************************************************************/ 00222 BOOL CheckAllowForeground( 00223 PEPROCESS pep) 00224 { 00225 BOOL fCreator = TRUE; 00226 HANDLE hpid = (HANDLE)pep->InheritedFromUniqueProcessId; 00227 LUID luid; 00228 PACCESS_TOKEN pat; 00229 PEPROCESS pepParent; 00230 PPROCESSINFO ppiParent; 00231 UINT uAncestors = 0; 00232 BOOL fAllowForeground = FALSE; 00233 NTSTATUS Status; 00234 00235 do { 00236 /* 00237 * Get the ppi for the parent process. 00238 */ 00239 LeaveCrit(); 00240 Status = LockProcessByClientId(hpid, &pepParent); 00241 EnterCrit(); 00242 if (!NT_SUCCESS(Status)) { 00243 /* 00244 * Bug 294193 - joejo 00245 * 00246 * If this is a process that was created after it'a creator was 00247 * destroyed, then lets attempt to give it foreground. This is a 00248 * typical scenario when a stub exe trys to create another process 00249 * in it's place. 00250 */ 00251 if (HasForegroundActivateRight(pep->InheritedFromUniqueProcessId)) { 00252 fAllowForeground = TRUE; 00253 } 00254 break; 00255 } 00256 00257 ppiParent = PpiFromProcess(pepParent); 00258 if (ppiParent == NULL) { 00259 UnlockProcess(pepParent); 00260 break; 00261 } 00262 /* 00263 * If we're walking the parent chain, 00264 * stop when we get to the shell or to a process that 00265 * is not running on the IO winsta 00266 */ 00267 if (!fCreator 00268 && (IsShellProcess(ppiParent) 00269 || ((ppiParent->rpwinsta != NULL) 00270 && (ppiParent->rpwinsta->dwWSF_Flags & WSF_NOIO)))) { 00271 00272 UnlockProcess(pepParent); 00273 break; 00274 } 00275 fAllowForeground = CanForceForeground(ppiParent); 00276 if (!fAllowForeground) { 00277 /* 00278 * Bug 285639 - joejo 00279 * 00280 * If the first thread of the parent process has allow set foreground 00281 * than we allow the setting of the foreground. 00282 */ 00283 if (ppiParent->ptiList != NULL 00284 && (ppiParent->ptiList->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE)) { 00285 fAllowForeground = TRUE; 00286 } 00287 00288 if (!fAllowForeground){ 00289 /* 00290 * Let's try an ancestor (this might be a worker process). 00291 */ 00292 hpid = (HANDLE)pepParent->InheritedFromUniqueProcessId; 00293 /* 00294 * If this is launched by a system process, let it come to 00295 * the foreground (i.e. CSRSS launching an OLE server). 00296 */ 00297 if (fCreator) { 00298 fCreator = FALSE; 00299 pat = PsReferencePrimaryToken(pepParent); 00300 if (pat != NULL) { 00301 Status = SeQueryAuthenticationIdToken(pat, &luid); 00302 if (NT_SUCCESS(Status)) { 00303 fAllowForeground = RtlEqualLuid(&luid, &luidSystem); 00304 /* 00305 * If it is a system process, give it the 00306 * permanent right so we won't have to check 00307 * its luid again 00308 */ 00309 if (fAllowForeground) { 00310 ppiParent->W32PF_Flags |= W32PF_ALLOWSETFOREGROUND; 00311 } 00312 } 00313 ObDereferenceObject(pat); 00314 } 00315 } 00316 } 00317 } 00318 UnlockProcess(pepParent); 00319 /* 00320 * InheritedFromUniqueProcessId cannot be quite trusted because 00321 * process ids get reused very often. So we just check few levels up 00322 */ 00323 } while (!fAllowForeground && (uAncestors++ < 5)); 00324 00325 return fAllowForeground || GiveUpForeground(); 00326 } 00327 00328 /***************************************************************************\ 00329 * xxxUserNotifyConsoleApplication 00330 * 00331 * This is called by the console init code - it tells us that the starting 00332 * application is a console application. We want to know this for various 00333 * reasons, one being that WinExec() doesn't wait on a starting console 00334 * application. 00335 * 00336 * 09-18-91 ScottLu Created. 00337 * 01-12-99 JoeJo Bug 273518 00338 * Adding bug fix and optimization for bug fix 00339 \***************************************************************************/ 00340 00341 void xxxUserNotifyConsoleApplication( 00342 PCONSOLE_PROCESS_INFO pcpi) 00343 { 00344 NTSTATUS Status; 00345 PEPROCESS Process; 00346 BOOL retval; 00347 00348 /* 00349 * First search for this process in our process information list. 00350 */ 00351 LeaveCrit(); 00352 Status = LockProcessByClientId((HANDLE)LongToHandle( pcpi->dwProcessID ), &Process); 00353 EnterCrit(); 00354 00355 if (!NT_SUCCESS(Status)) { 00356 RIPMSG2(RIP_WARNING, "xxxUserNotifyConsoleApplication: Failed with Process ID == %X, Status = %x\n", 00357 pcpi->dwProcessID, Status); 00358 return; 00359 } 00360 00361 retval = xxxSetProcessInitState(Process, 0); 00362 /* 00363 * Bug 273518 - joejo 00364 * 00365 * This will allow console windows to set foreground correctly on new 00366 * process' it launches, as opposed it just forcing foreground. 00367 */ 00368 if (retval) { 00369 if (pcpi->dwFlags & CPI_NEWPROCESSWINDOW) { 00370 PPROCESSINFO ppiCurrent = PpiCurrent(); 00371 if (CheckAllowForeground(Process)) { 00372 if (!(ppiCurrent->W32PF_Flags & W32PF_APPSTARTING)) { 00373 SetAppStarting(ppiCurrent); 00374 } 00375 SET_PUDF(PUDF_ALLOWFOREGROUNDACTIVATE); 00376 TAGMSG0(DBGTAG_FOREGROUND, "xxxUserNotifyConsoleApplication set PUDF"); 00377 ppiCurrent->W32PF_Flags |= W32PF_ALLOWFOREGROUNDACTIVATE; 00378 } 00379 00380 TAGMSG3(DBGTAG_FOREGROUND, "xxxUserNotifyConsoleApplication %s W32PF %#p-%#p", 00381 ((ppiCurrent->W32PF_Flags & W32PF_ALLOWFOREGROUNDACTIVATE) ? "set" : "NOT"), 00382 ppiCurrent, PpiFromProcess(Process)); 00383 } 00384 } else { 00385 RIPMSG1(RIP_WARNING, "xxxUserNotifyConsoleApplication - SetProcessInitState failed on %#p", Process); 00386 } 00387 00388 00389 00390 UnlockProcess(Process); 00391 } 00392 00393 00394 /***************************************************************************\ 00395 * UserSetConsoleProcessWindowStation 00396 * 00397 * This is called by the console init code - it tells us that the starting 00398 * application is a console application and which window station they are associated 00399 * with. The window station pointer is stored in the EPROCESS for the Global atom 00400 * calls to find the correct global atom table when called from a console application 00401 * 00402 \***************************************************************************/ 00403 00404 void UserSetConsoleProcessWindowStation( 00405 DWORD idProcess, 00406 HWINSTA hwinsta 00407 ) 00408 { 00409 NTSTATUS Status; 00410 PEPROCESS Process; 00411 00412 /* 00413 * First search for this process in our process information list. 00414 */ 00415 LeaveCrit(); 00416 Status = LockProcessByClientId((HANDLE)LongToHandle( idProcess ), &Process); 00417 EnterCrit(); 00418 00419 if (!NT_SUCCESS(Status)) { 00420 RIPMSG2(RIP_WARNING, "UserSetConsoleProcessWindowStation: Failed with Process ID == %X, Status = %x\n", 00421 idProcess, Status); 00422 return; 00423 } 00424 00425 Process->Win32WindowStation = hwinsta; 00426 00427 UnlockProcess(Process); 00428 } 00429 00430 00431 /***************************************************************************\ 00432 * xxxUserNotifyProcessCreate 00433 * 00434 * This is a special notification that we get from the base while process data 00435 * structures are being created, but before the process has started. We use 00436 * this notification for startup synchronization matters (winexec, startup 00437 * activation, type ahead, etc). 00438 * 00439 * This notification is called on the server thread for the client thread 00440 * starting the process. 00441 * 00442 * 09-09-91 ScottLu Created. 00443 \***************************************************************************/ 00444 00445 BOOL xxxUserNotifyProcessCreate( 00446 DWORD idProcess, 00447 DWORD idParentThread, 00448 ULONG_PTR dwData, 00449 DWORD dwFlags) 00450 { 00451 PEPROCESS Process; 00452 PETHREAD Thread; 00453 PTHREADINFO pti; 00454 NTSTATUS Status; 00455 BOOL retval; 00456 00457 CheckCritIn(); 00458 00459 00460 GiveForegroundActivateRight((HANDLE)idProcess); 00461 00462 /* 00463 * 0x1 bit means give feedback (app start cursor). 00464 * 0x2 bit means this is a gui app (meaning, call CreateProcessInfo() 00465 * so we get app start synchronization (WaitForInputIdle()). 00466 * 0x8 bit means this process is a WOW process, set W32PF_WOW. 0x1 00467 * and 0x2 bits will also be set. 00468 * 0x4 value means this is really a shared WOW task starting 00469 */ 00470 00471 /* 00472 * If we want feedback, we need to create a process info structure, 00473 * so do it: it will be properly cleaned up. 00474 */ 00475 if ((dwFlags & 0xb) != 0) { 00476 LeaveCrit(); 00477 Status = LockProcessByClientId((HANDLE)LongToHandle( idProcess ), &Process); 00478 EnterCrit(); 00479 00480 if (!NT_SUCCESS(Status)) { 00481 RIPMSG2(RIP_WARNING, "xxxUserNotifyProcessCreate: Failed with Process ID == %X, Status = %x\n", 00482 idProcess, Status); 00483 return FALSE; 00484 } 00485 00486 retval = xxxSetProcessInitState(Process, ((dwFlags & 1) ? STARTF_FORCEONFEEDBACK : STARTF_FORCEOFFFEEDBACK)); 00487 if (!retval) { 00488 RIPMSG1(RIP_WARNING, "xxxUserNotifyProcessCreate - SetProcessInitState failed on %#p", Process); 00489 } 00490 if (dwFlags & 0x8) { 00491 if (Process->Win32Process) 00492 ((PW32PROCESS)Process->Win32Process)->W32PF_Flags |= W32PF_WOW; 00493 } 00494 00495 UnlockProcess(Process); 00496 00497 /* 00498 * Find out who is starting this app. If it is a 16 bit app, allow 00499 * it to bring itself back to the foreground if it calls 00500 * SetActiveWindow() or SetFocus(). This is because this could be 00501 * related to OLE to DDE activation. Notes has a case where after it 00502 * lauches pbrush to edit an embedded bitmap, it brings up a message 00503 * box on top if the bitmap is read only. This message box won't appear 00504 * foreground unless we allow it to. This usually isn't a problem 00505 * because most apps don't bring up windows on top of editors 00506 * like this. 32 bit apps will call SetForegroundWindow(). 00507 */ 00508 00509 LeaveCrit(); 00510 Status = LockThreadByClientId((HANDLE)LongToHandle( idParentThread ), &Thread); 00511 EnterCrit(); 00512 00513 if (!NT_SUCCESS(Status)) { 00514 RIPMSG2(RIP_WARNING, "xxxUserNotifyProcessCreate: Failed with Thread ID == %X, Status = %x\n", 00515 idParentThread, Status); 00516 return FALSE; 00517 } 00518 00519 pti = PtiFromThread(Thread); 00520 if (pti && (pti->TIF_flags & TIF_16BIT)) { 00521 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 00522 TAGMSG1(DBGTAG_FOREGROUND, "xxxUserNotifyProcessCreate set TIF %#p", pti); 00523 } 00524 00525 UnlockThread(Thread); 00526 00527 } else if (dwFlags == 4) { 00528 /* 00529 * A WOW task is starting up. Create the WOW per thread info 00530 * structure here in case someone calls WaitForInputIdle 00531 * before the thread is created. 00532 */ 00533 PWOWTHREADINFO pwti; 00534 00535 /* 00536 * Look for a matching thread in the WOW thread info list. 00537 */ 00538 for (pwti = gpwtiFirst; pwti != NULL; pwti = pwti->pwtiNext) { 00539 if (pwti->idTask == idProcess) { 00540 break; 00541 } 00542 } 00543 00544 /* 00545 * If we didn't find one, allocate a new one and add it to 00546 * the head of the list. 00547 */ 00548 if (pwti == NULL) { 00549 pwti = (PWOWTHREADINFO)UserAllocPoolWithQuota( 00550 sizeof(WOWTHREADINFO), TAG_WOWTHREADINFO); 00551 if (pwti == NULL) { 00552 return FALSE; 00553 } 00554 INIT_PSEUDO_EVENT(&pwti->pIdleEvent); 00555 pwti->idTask = idProcess; 00556 pwti->pwtiNext = gpwtiFirst; 00557 gpwtiFirst = pwti; 00558 } else { 00559 RESET_PSEUDO_EVENT(&pwti->pIdleEvent); 00560 } 00561 00562 pwti->idWaitObject = dwData; 00563 LeaveCrit(); 00564 Status = LockThreadByClientId((HANDLE)LongToHandle( idParentThread ), &Thread); 00565 EnterCrit(); 00566 if (!NT_SUCCESS(Status)) 00567 return FALSE; 00568 00569 if (!NT_SUCCESS(Status)) { 00570 RIPMSG2(RIP_WARNING, "xxxUserNotifyProcessCreate: Failed with Thread ID == %X, Status = %x\n", 00571 idParentThread, Status); 00572 return FALSE; 00573 } 00574 00575 pwti->idParentProcess = HandleToUlong(Thread->Cid.UniqueProcess); 00576 UnlockThread(Thread); 00577 } 00578 00579 return TRUE; 00580 } 00581 00582 00583 /***************************************************************************\ 00584 * zzzCalcStartCursorHide 00585 * 00586 * Calculates when to hide the startup cursor. 00587 * 00588 * 05-14-92 ScottLu Created. 00589 \***************************************************************************/ 00590 00591 void zzzCalcStartCursorHide( 00592 PW32PROCESS pwp, 00593 DWORD timeAdd) 00594 { 00595 DWORD timeNow; 00596 PW32PROCESS pwpT; 00597 PW32PROCESS *ppwpT; 00598 00599 00600 timeNow = NtGetTickCount(); 00601 00602 if (pwp != NULL) { 00603 00604 /* 00605 * We were passed in a timeout. Recalculate when we timeout 00606 * and add the pwp to the starting list. 00607 */ 00608 if (!(pwp->W32PF_Flags & W32PF_STARTGLASS)) { 00609 00610 /* 00611 * Add it to the list only if it is not already in the list 00612 */ 00613 for (pwpT = gpwpCalcFirst; pwpT != NULL; pwpT = pwpT->NextStart) { 00614 if (pwpT == pwp) 00615 break; 00616 } 00617 00618 if (pwpT != pwp) { 00619 pwp->NextStart = gpwpCalcFirst; 00620 gpwpCalcFirst = pwp; 00621 } 00622 } 00623 pwp->StartCursorHideTime = timeAdd + timeNow; 00624 pwp->W32PF_Flags |= W32PF_STARTGLASS; 00625 } 00626 00627 gtimeStartCursorHide = 0; 00628 for (ppwpT = &gpwpCalcFirst; (pwpT = *ppwpT) != NULL; ) { 00629 00630 /* 00631 * If the app isn't starting or feedback is forced off, remove 00632 * it from the list so we don't look at it again. 00633 */ 00634 if (!(pwpT->W32PF_Flags & W32PF_STARTGLASS) || 00635 (pwpT->W32PF_Flags & W32PF_FORCEOFFFEEDBACK)) { 00636 *ppwpT = pwpT->NextStart; 00637 continue; 00638 } 00639 00640 /* 00641 * Find the greatest hide cursor timeout value. 00642 */ 00643 if (gtimeStartCursorHide < pwpT->StartCursorHideTime) 00644 gtimeStartCursorHide = pwpT->StartCursorHideTime; 00645 00646 /* 00647 * If this app has timed out, it isn't starting anymore! 00648 * Remove it from the list. 00649 */ 00650 if (ComputeTickDelta(timeNow, pwpT->StartCursorHideTime) > 0) { 00651 pwpT->W32PF_Flags &= ~W32PF_STARTGLASS; 00652 *ppwpT = pwpT->NextStart; 00653 continue; 00654 } 00655 00656 /* 00657 * Step to the next pwp in the list. 00658 */ 00659 ppwpT = &pwpT->NextStart; 00660 } 00661 00662 /* 00663 * If the hide time is still less than the current time, then turn off 00664 * the app starting cursor. 00665 */ 00666 if (gtimeStartCursorHide <= timeNow) 00667 gtimeStartCursorHide = 0; 00668 00669 /* 00670 * Update the cursor image with the new info (doesn't do anything unless 00671 * the cursor is really changing). 00672 */ 00673 zzzUpdateCursorImage(); 00674 } 00675 00676 00677 #define QUERY_VALUE_BUFFER 80 00678 00679 /* 00680 * Install hack. 00681 * 00682 * We have a hack inherited from Chicago that allows the shell to 00683 * clean up registry information after a setup program runs. A 00684 * setup program is defined as an app with one of a list of names. -- FritzS 00685 */ 00686 00687 PUNICODE_STRING gpastrSetupExe; // These are initialized in the routine 00688 int giSetupExe; // CreateSetupNameArray in setup.c 00689 00690 00691 /***************************************************************************\ 00692 * SetAppImeCompatFlags - NOTE pstrModName->Buffer must be zero terminated. 00693 * 00694 * 00695 * History: 00696 * 07-17-97 DaveHart Split from SetAppCompatFlags -- misleadingly it also 00697 * returns a BOOL indicating whether the filename is 00698 * recognized as a setup program. Used by SetAppCompatFlags 00699 * for 32-bit apps and zzzInitTask for 16-bit ones. 00700 \***************************************************************************/ 00701 00702 BOOL SetAppImeCompatFlags( 00703 PTHREADINFO pti, 00704 PUNICODE_STRING pstrModName, 00705 PUNICODE_STRING pstrBaseFileName) 00706 { 00707 DWORD dwImeFlags = 0; 00708 WCHAR szHex[QUERY_VALUE_BUFFER]; 00709 WORD wPrimaryLangID; 00710 LCID lcid; 00711 int iSetup; 00712 BOOL fSetup = FALSE; 00713 int iAppName; 00714 int cAppNames; 00715 PUNICODE_STRING rgpstrAppNames[2]; 00716 UNICODE_STRING strHex; 00717 00718 /* 00719 * Because can't access pClientInfo of another process 00720 */ 00721 UserAssert(pti->ppi == PpiCurrent()); 00722 00723 /* 00724 * Because it is used as a zero-terminated profile key name. 00725 */ 00726 UserAssert(0 == pstrModName->Buffer[ pstrModName->Length / sizeof(WCHAR) ]); 00727 00728 if (FastGetProfileStringW( 00729 NULL, 00730 PMAP_IMECOMPAT, 00731 pstrModName->Buffer, 00732 NULL, 00733 szHex, 00734 sizeof(szHex) 00735 )) { 00736 00737 /* 00738 * Found some flags. Attempt to convert the hex string 00739 * into numeric value. Specify base 0, so 00740 * RtlUnicodeStringToInteger will handle the 0x format 00741 */ 00742 RtlInitUnicodeString(&strHex, szHex); 00743 RtlUnicodeStringToInteger(&strHex, 0, (PULONG)&dwImeFlags); 00744 } 00745 00746 /* 00747 * if current layout is not IME layout, Actually, we don't need to 00748 * get compatible flags for IME. But now, we don't have any scheme 00749 * to get this flags when the keyboard layout is switched. then 00750 * we get it here, even this flags are not nessesary for non-IME 00751 * keyboard layouts. 00752 */ 00753 ZwQueryDefaultLocale(FALSE, &lcid); 00754 wPrimaryLangID = PRIMARYLANGID(lcid); 00755 00756 if ((wPrimaryLangID == LANG_KOREAN || wPrimaryLangID == LANG_JAPANESE) && 00757 (LOWORD(pti->dwExpWinVer) <= VER31)) { 00758 /* 00759 * IME compatibility flags are needed even it's a 32 bit app 00760 */ 00761 pti->ppi->dwImeCompatFlags = dwImeFlags; 00762 } else { 00763 pti->ppi->dwImeCompatFlags = dwImeFlags & (IMECOMPAT_NOFINALIZECOMPSTR | IMECOMPAT_HYDRACLIENT); 00764 if (dwImeFlags & IMECOMPAT_NOFINALIZECOMPSTR) { 00765 RIPMSG1(RIP_WARNING, "IMECOMPAT_NOFINALIZECOMPSTR is set to ppi=0x%p", pti->ppi); 00766 } 00767 if (dwImeFlags & IMECOMPAT_HYDRACLIENT) { 00768 RIPMSG1(RIP_WARNING, "IMECOMPAT_HYDRACLIENT is set to ppi=0x%p", pti->ppi); 00769 } 00770 } 00771 00772 00773 if (gpastrSetupExe == NULL) { 00774 return fSetup; 00775 } 00776 00777 rgpstrAppNames[0] = pstrModName; 00778 cAppNames = 1; 00779 if (pstrBaseFileName) { 00780 rgpstrAppNames[1] = pstrBaseFileName; 00781 cAppNames = 2; 00782 } 00783 00784 for (iAppName = 0; 00785 iAppName < cAppNames && !fSetup; 00786 iAppName++) { 00787 00788 iSetup = 0; 00789 while (iSetup < giSetupExe) { 00790 int i; 00791 if ((i = RtlCompareUnicodeString(rgpstrAppNames[iAppName], &(gpastrSetupExe[iSetup]), TRUE)) == 0) { 00792 fSetup = TRUE; 00793 break; 00794 } 00795 iSetup++; 00796 } 00797 } 00798 00799 return fSetup; 00800 } 00801 00802 /***************************************************************************\ 00803 * SetAppCompatFlags 00804 * 00805 * 00806 * History: 00807 * 03-23-92 JimA Created. 00808 * 07-17-97 FritzS add return for fSetup -- returns TRUE if app is a setup app. 00809 * 09-03-97 DaveHart Split out IME, WOW doesn't use this function anymore. 00810 * 07-14-98 MCostea Add Compatibility2 flags 00811 * 01-21-99 MCostea Add DesiredOSVersion 00812 \***************************************************************************/ 00813 00814 BOOL SetAppCompatFlags( 00815 PTHREADINFO pti) 00816 { 00817 DWORD dwFlags = 0; 00818 DWORD dwFlags2 = 0; 00819 WCHAR szHex[QUERY_VALUE_BUFFER]; 00820 WCHAR szKey[90]; 00821 WCHAR *pchStart, *pchEnd; 00822 DWORD cb; 00823 PUNICODE_STRING pstrAppName; 00824 UNICODE_STRING strKey; 00825 UNICODE_STRING strImageName; 00826 ULONG cbSize; 00827 typedef struct tagCompat2Key { 00828 DWORD dwCompatFlags2; 00829 DWORD dwMajorVersion; 00830 DWORD dwMinorVersion; 00831 DWORD dwBuildNumber; 00832 DWORD dwPlatformId; 00833 } COMPAT2KEY, *PCOMPAT2KEY; 00834 COMPAT2KEY Compat2Key; 00835 00836 /* 00837 * Because can't access pClientInfo of another process 00838 */ 00839 UserAssert(pti->ppi == PpiCurrent()); 00840 00841 UserAssert(pti->ppi->ptiList); 00842 00843 UserAssert(!(pti->TIF_flags & TIF_16BIT)); 00844 00845 /* 00846 * We assume here that pti was just inserted in at the head of ptiList 00847 */ 00848 UserAssert(pti == pti->ppi->ptiList); 00849 00850 if (pti->ptiSibling) { 00851 pti->pClientInfo->dwCompatFlags = pti->dwCompatFlags = pti->ptiSibling->dwCompatFlags; 00852 pti->pClientInfo->dwCompatFlags2 = pti->dwCompatFlags2 = pti->ptiSibling->dwCompatFlags2; 00853 return FALSE; 00854 } 00855 00856 try { 00857 /* 00858 * PEB can be trashed from the client side, so we need to probe pointers in it 00859 * MCostea 317180 00860 */ 00861 /* 00862 * Find end of app name 00863 */ 00864 if (pti->pstrAppName != NULL) 00865 pstrAppName = pti->pstrAppName; 00866 else { 00867 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters = pti->pEThread->ThreadsProcess->Peb->ProcessParameters; 00868 00869 ProbeForRead(ProcessParameters, sizeof(*ProcessParameters), sizeof(BYTE)); 00870 strImageName = ProbeAndReadUnicodeString(&ProcessParameters->ImagePathName); 00871 ProbeForReadUnicodeStringBuffer(strImageName); 00872 pstrAppName = &strImageName; 00873 } 00874 pchStart = pchEnd = pstrAppName->Buffer + 00875 (pstrAppName->Length / sizeof(WCHAR)); 00876 00877 /* 00878 * Locate start of extension 00879 */ 00880 while (TRUE) { 00881 if (pchEnd == pstrAppName->Buffer) { 00882 pchEnd = pchStart; 00883 break; 00884 } 00885 00886 if (*pchEnd == TEXT('.')) 00887 break; 00888 00889 pchEnd--; 00890 } 00891 00892 /* 00893 * Locate start of filename 00894 */ 00895 pchStart = pchEnd; 00896 00897 while (pchStart != pstrAppName->Buffer) { 00898 if (*pchStart == TEXT('\\') || *pchStart == TEXT(':')) { 00899 pchStart++; 00900 break; 00901 } 00902 00903 pchStart--; 00904 } 00905 00906 #define MODULESUFFIXSIZE (8*sizeof(WCHAR)) 00907 #define MAXMODULENAMELEN (sizeof(szKey) - MODULESUFFIXSIZE) 00908 /* 00909 * Get a copy of the filename 00910 * Allow extra spaces for the 'ImageSubsystemMajorVersionMinorVersion' 00911 * i.e. 3.5 that will get appended at the end of the module name 00912 */ 00913 cb = (DWORD)(pchEnd - pchStart) * sizeof(WCHAR); 00914 if (cb >= MAXMODULENAMELEN) 00915 cb = MAXMODULENAMELEN - sizeof(WCHAR); 00916 RtlCopyMemory(szKey, pchStart, cb); 00917 } except (W32ExceptionHandler(FALSE, RIP_ERROR)) { 00918 return FALSE; 00919 } 00920 00921 szKey[(cb / sizeof(WCHAR))] = 0; 00922 #undef MAXMODULENAMELEN 00923 00924 if (FastGetProfileStringW( 00925 NULL, 00926 PMAP_COMPAT32, 00927 szKey, 00928 NULL, 00929 szHex, 00930 sizeof(szHex) 00931 )) { 00932 00933 UNICODE_STRING strHex; 00934 00935 /* 00936 * Found some flags. Attempt to convert the hex string 00937 * into numeric value. Specify base 0, so 00938 * RtlUnicodeStringToInteger will handle the 0x format 00939 */ 00940 RtlInitUnicodeString(&strHex, szHex); 00941 RtlUnicodeStringToInteger(&strHex, 0, (PULONG)&dwFlags); 00942 } 00943 00944 pti->dwCompatFlags = dwFlags; 00945 pti->pClientInfo->dwCompatFlags = dwFlags; 00946 00947 /* 00948 * Retrieve the image version 00949 */ 00950 { 00951 PIMAGE_NT_HEADERS pnthdr; 00952 USHORT uMinorImage, uMajorImage; 00953 PWCHAR pWritePtr = szKey + cb/sizeof(WCHAR); 00954 00955 try { 00956 pnthdr = RtlImageNtHeader(pti->pEThread->ThreadsProcess->SectionBaseAddress); 00957 if (pnthdr != NULL) { 00958 uMinorImage = pnthdr->OptionalHeader.MinorImageVersion & 0xFF; 00959 uMajorImage = pnthdr->OptionalHeader.MajorImageVersion & 0xFF; 00960 } else { 00961 uMinorImage = uMajorImage = 0; 00962 } 00963 } except (W32ExceptionHandler(FALSE, RIP_ERROR)) { 00964 goto Compat2Failed; 00965 } 00966 swprintf(pWritePtr, L"%u.%u", uMajorImage, uMinorImage); 00967 } 00968 cbSize = FastGetProfileValue( 00969 NULL, 00970 PMAP_COMPAT2, 00971 szKey, 00972 NULL, 00973 (LPBYTE)&Compat2Key, 00974 sizeof(Compat2Key)); 00975 /* 00976 * The first DWORD in Compat2 is the CompatFlags. There might be or not 00977 * version information but dwCompatFlags2 is always there if the key exist. 00978 * We will be able to include extra data in these keys by setting the 00979 * MajorVersion to zero and thus the version information will not be changed 00980 */ 00981 if (cbSize >= sizeof(DWORD)) { 00982 pti->dwCompatFlags2 = pti->pClientInfo->dwCompatFlags2 = Compat2Key.dwCompatFlags2; 00983 00984 if (cbSize >= sizeof(COMPAT2KEY) && Compat2Key.dwMajorVersion != 0) { 00985 PPEB Peb = pti->pEThread->ThreadsProcess->Peb; 00986 00987 Peb->OSMajorVersion = Compat2Key.dwMajorVersion; 00988 Peb->OSMinorVersion = Compat2Key.dwMinorVersion; 00989 Peb->OSBuildNumber = (USHORT)(Compat2Key.dwBuildNumber); 00990 Peb->OSPlatformId = Compat2Key.dwPlatformId; 00991 } 00992 } 00993 00994 Compat2Failed: 00995 /* 00996 * Restore the string 00997 */ 00998 szKey[(cb / sizeof(WCHAR))] = 0; 00999 RtlInitUnicodeString(&strKey, szKey); 01000 01001 return SetAppImeCompatFlags(pti, &strKey, NULL); 01002 } 01003 01004 /***************************************************************************\ 01005 * GetAppCompatFlags 01006 * 01007 * Compatibility flags for < Win 3.1 apps running on 3.1 01008 * 01009 * History: 01010 * 04-??-92 ScottLu Created. 01011 * 05-04-92 DarrinM Moved to USERRTL.DLL. 01012 \***************************************************************************/ 01013 01014 DWORD GetAppCompatFlags( 01015 PTHREADINFO pti) 01016 { 01017 // From GRE with pti = NULL 01018 // We got to use PtiCurrentShared() 01019 if (pti == NULL) 01020 pti = PtiCurrentShared(); 01021 01022 return pti->dwCompatFlags; 01023 } 01024 /***************************************************************************\ 01025 * GetAppCompatFlags2 01026 * 01027 * Compatibility flags for < wVer apps 01028 * 01029 * History: 01030 * 07-01-98 MCostea Created. 01031 \***************************************************************************/ 01032 01033 DWORD GetAppCompatFlags2( 01034 WORD wVer) 01035 { 01036 return GetAppCompatFlags2ForPti(PtiCurrentShared(), wVer); 01037 } 01038 01039 DWORD GetAppImeCompatFlags( 01040 PTHREADINFO pti) 01041 { 01042 if (pti == NULL) { 01043 pti = PtiCurrentShared(); 01044 } 01045 01046 UserAssert(pti->ppi); 01047 return pti->ppi->dwImeCompatFlags; 01048 } 01049 01050 /***************************************************************************\ 01051 * CheckAppStarting 01052 * 01053 * This is a timer proc (see SetAppStarting) which removes ppi's from the 01054 * starting list once their initialization time has expired. 01055 * 01056 * History: 01057 * 08/26/97 GerardoB Created 01058 \***************************************************************************/ 01059 VOID CheckAppStarting(PWND pwnd, UINT message, UINT_PTR nID, LPARAM lParam) 01060 { 01061 LARGE_INTEGER liStartingTimeout; 01062 PPROCESSINFO *pppi = &gppiStarting; 01063 01064 KeQuerySystemTime(&liStartingTimeout); /* 1 unit == 100ns */ 01065 liStartingTimeout.QuadPart -= (LONGLONG)(CMSAPPSTARTINGTIMEOUT * 10000); 01066 while (*pppi != NULL) { 01067 if (liStartingTimeout.QuadPart > (*pppi)->Process->CreateTime.QuadPart) { 01068 (*pppi)->W32PF_Flags &= ~(W32PF_APPSTARTING | W32PF_ALLOWFOREGROUNDACTIVATE); 01069 TAGMSG1(DBGTAG_FOREGROUND, "CheckAppStarting clear W32PF %#p", *pppi); 01070 *pppi = (*pppi)->ppiNext; 01071 } else { 01072 pppi = &(*pppi)->ppiNext; 01073 } 01074 } 01075 01076 TAGMSG0(DBGTAG_FOREGROUND, "Removing all entries from ghCanActivateForegroundPIDs array"); 01077 RtlZeroMemory(ghCanActivateForegroundPIDs, sizeof(ghCanActivateForegroundPIDs)); 01078 return; 01079 UNREFERENCED_PARAMETER(pwnd); 01080 UNREFERENCED_PARAMETER(message); 01081 UNREFERENCED_PARAMETER(nID); 01082 UNREFERENCED_PARAMETER(lParam); 01083 } 01084 /***************************************************************************\ 01085 * SetAppStarting 01086 * 01087 * Add a process to the starting list and mark it as such. The process will 01088 * remain in the list until it activates a window, our timer goes off or the 01089 * process goes away, whichever happens first. 01090 * 01091 * History: 01092 * 08/26/97 GerardoB Created 01093 \***************************************************************************/ 01094 void SetAppStarting (PPROCESSINFO ppi) 01095 { 01096 static UINT_PTR guAppStartingId = 0; 01097 01098 // This ppi had better not be in the list already, or we will be creating 01099 // a loop (as seen in stress) 01100 UserAssert((ppi->W32PF_Flags & W32PF_APPSTARTING) == 0); 01101 01102 /* 01103 * if we add this to the gppiStartingList without this bit set, we will 01104 * skip removing it from the list in DestroyProcessInfo(), but continue 01105 * to free it in FreeW32Process called by W32pProcessCallout 01106 */ 01107 UserAssert((ppi->W32PF_Flags & W32PF_PROCESSCONNECTED)); 01108 01109 ppi->W32PF_Flags |= W32PF_APPSTARTING; 01110 ppi->ppiNext = gppiStarting; 01111 gppiStarting = ppi; 01112 /* 01113 * Some system processes are initialized before the RIT has setup the master 01114 * timer; so check for it 01115 */ 01116 if (gptmrMaster != NULL) { 01117 guAppStartingId = InternalSetTimer(NULL, guAppStartingId, 01118 CMSAPPSTARTINGTIMEOUT + CMSHUNGAPPTIMEOUT, 01119 CheckAppStarting, TMRF_RIT | TMRF_ONESHOT); 01120 } 01121 } 01122 /***************************************************************************\ 01123 * ClearAppStarting 01124 * 01125 * Remove a process from the app starting list and clear the W32PF_APPSTARTING 01126 * flag. No major action here, just a centralized place to take care of this. 01127 * 01128 * History: 01129 * 08/26/97 GerardoB Created 01130 \***************************************************************************/ 01131 void ClearAppStarting (PPROCESSINFO ppi) 01132 { 01133 REMOVE_FROM_LIST(PROCESSINFO, gppiStarting, ppi, ppiNext); 01134 ppi->W32PF_Flags &= ~W32PF_APPSTARTING; 01135 } 01136 01137 /***************************************************************************\ 01138 * zzzInitTask -- called by WOW startup for each app 01139 * 01140 * 01141 * History: 01142 * 02-21-91 MikeHar Created. 01143 * 02-23-92 MattFe Altered for WOW 01144 * 09-03-97 DaveHart WOW supplies compat flags, we tell it about setup apps. 01145 \***************************************************************************/ 01146 01147 NTSTATUS zzzInitTask( 01148 UINT dwExpWinVer, 01149 DWORD dwAppCompatFlags, 01150 PUNICODE_STRING pstrModName, 01151 PUNICODE_STRING pstrBaseFileName, 01152 DWORD hTaskWow, 01153 DWORD dwHotkey, 01154 DWORD idTask, 01155 DWORD dwX, 01156 DWORD dwY, 01157 DWORD dwXSize, 01158 DWORD dwYSize) 01159 { 01160 PTHREADINFO ptiCurrent; 01161 PTDB ptdb; 01162 PPROCESSINFO ppi; 01163 PWOWTHREADINFO pwti; 01164 01165 ptiCurrent = PtiCurrent(); 01166 ppi = ptiCurrent->ppi; 01167 01168 /* 01169 * Set the real name of the module. (Instead of 'NTVDM') 01170 * We've already probed pstrModName->Buffer for Length+sizeof(WCHAR) so 01171 * we can copy the UNICODE_NULL terminator as well. 01172 */ 01173 if (ptiCurrent->pstrAppName != NULL) 01174 UserFreePool(ptiCurrent->pstrAppName); 01175 ptiCurrent->pstrAppName = UserAllocPoolWithQuota(sizeof(UNICODE_STRING) + 01176 pstrModName->Length + sizeof(WCHAR), TAG_TEXT); 01177 if (ptiCurrent->pstrAppName != NULL) { 01178 ptiCurrent->pstrAppName->Buffer = (PWCHAR)(ptiCurrent->pstrAppName + 1); 01179 try { 01180 RtlCopyMemory(ptiCurrent->pstrAppName->Buffer, pstrModName->Buffer, 01181 pstrModName->Length); 01182 ptiCurrent->pstrAppName->Buffer[pstrModName->Length / sizeof(WCHAR)] = 0; 01183 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01184 UserFreePool(ptiCurrent->pstrAppName); 01185 ptiCurrent->pstrAppName = NULL; 01186 return STATUS_OBJECT_NAME_INVALID; 01187 } 01188 ptiCurrent->pstrAppName->MaximumLength = pstrModName->Length + sizeof(WCHAR); 01189 ptiCurrent->pstrAppName->Length = pstrModName->Length; 01190 } else 01191 return STATUS_OBJECT_NAME_INVALID; 01192 01193 /* 01194 * An app is starting! 01195 */ 01196 if (!(ppi->W32PF_Flags & W32PF_APPSTARTING)) { 01197 SetAppStarting(ppi); 01198 } 01199 01200 /* 01201 * We never want to use the ShowWindow defaulting mechanism for WOW 01202 * apps. If STARTF_USESHOWWINDOW was set in the client-side 01203 * STARTUPINFO structure, WOW has already picked it up and used 01204 * it for the first (command-line) app. 01205 */ 01206 ppi->usi.dwFlags &= ~STARTF_USESHOWWINDOW; 01207 01208 /* 01209 * If WOW passed us a hotkey for this app, save it for CreateWindow's use. 01210 */ 01211 if (dwHotkey != 0) { 01212 ppi->dwHotkey = dwHotkey; 01213 } 01214 01215 /* 01216 * If WOW passed us a non-default window position use it, otherwise clear it. 01217 */ 01218 ppi->usi.cb = sizeof(ppi->usi); 01219 01220 if (dwX == CW_USEDEFAULT || dwX == CW2_USEDEFAULT) { 01221 ppi->usi.dwFlags &= ~STARTF_USEPOSITION; 01222 } else { 01223 ppi->usi.dwFlags |= STARTF_USEPOSITION; 01224 ppi->usi.dwX = dwX; 01225 ppi->usi.dwY = dwY; 01226 } 01227 01228 /* 01229 * If WOW passed us a non-default window size use it, otherwise clear it. 01230 */ 01231 if (dwXSize == CW_USEDEFAULT || dwXSize == CW2_USEDEFAULT) { 01232 ppi->usi.dwFlags &= ~STARTF_USESIZE; 01233 } else { 01234 ppi->usi.dwFlags |= STARTF_USESIZE; 01235 ppi->usi.dwXSize = dwXSize; 01236 ppi->usi.dwYSize = dwYSize; 01237 } 01238 01239 /* 01240 * Alloc and Link in new task into the task list 01241 */ 01242 if ((ptdb = (PTDB)UserAllocPoolWithQuota(sizeof(TDB), TAG_WOWTDB)) == NULL) 01243 return STATUS_NO_MEMORY; 01244 ptiCurrent->ptdb = ptdb; 01245 01246 /* 01247 * Set the flags to say this is a 16-bit thread - before attaching 01248 * queues! 01249 */ 01250 ptiCurrent->TIF_flags |= TIF_16BIT | TIF_FIRSTIDLE; 01251 01252 /* 01253 * If this task is running in the shared WOW VDM, we handle 01254 * WaitForInputIdle a little differently than separate WOW 01255 * VDMs. This is because CreateProcess returns a real process 01256 * handle when you start a separate WOW VDM, so the "normal" 01257 * WaitForInputIdle works. For the shared WOW VDM, CreateProcess 01258 * returns an event handle. 01259 */ 01260 ptdb->pwti = NULL; 01261 if (idTask) { 01262 ptiCurrent->TIF_flags |= TIF_SHAREDWOW; 01263 01264 /* 01265 * Look for a matching thread in the WOW thread info list. 01266 */ 01267 if (idTask != (DWORD)-1) { 01268 for (pwti = gpwtiFirst; pwti != NULL; pwti = pwti->pwtiNext) { 01269 if (pwti->idTask == idTask) { 01270 ptdb->pwti = pwti; 01271 break; 01272 } 01273 } 01274 #if DBG 01275 if (pwti == NULL) { 01276 RIPMSG0(RIP_WARNING, "InitTask couldn't find WOW struct\n"); 01277 } 01278 #endif 01279 } 01280 } 01281 ptiCurrent->pClientInfo->dwTIFlags |= ptiCurrent->TIF_flags; 01282 01283 /* 01284 * We need this thread to share the queue of other win16 apps. 01285 * If we're journalling, all apps are sharing a queue, so we wouldn't 01286 * want to interrupt that - so only cause queue recalculation 01287 * if we aren't journalling. 01288 * ptdb may be freed by DestroyTask during a callback, so defer WinEvent 01289 * notifications until we don't need ptdb any more. 01290 */ 01291 DeferWinEventNotify(); 01292 if (!FJOURNALRECORD() && !FJOURNALPLAYBACK()) 01293 zzzReattachThreads(FALSE); 01294 01295 /* 01296 * Save away the 16 bit task handle: we use this later when calling 01297 * wow back to close a WOW task. 01298 */ 01299 ptdb->hTaskWow = LOWORD(hTaskWow); 01300 01301 /* 01302 * Setup the app start cursor for 5 second timeout. 01303 */ 01304 zzzCalcStartCursorHide((PW32PROCESS)ppi, 5000); 01305 01306 /* 01307 * HIWORD: != 0 if wants proportional font 01308 * LOWORD: Expected windows version (3.00 [300], 3.10 [30A], etc) 01309 */ 01310 ptiCurrent->dwExpWinVer = dwExpWinVer; 01311 ptiCurrent->pClientInfo->dwExpWinVer = dwExpWinVer; 01312 01313 /* 01314 * Mark this guy and add him to the global task list so he can run. 01315 */ 01316 #define NORMAL_PRIORITY_TASK 10 01317 01318 /* 01319 * To be Compatible it super important that the new task run immediately 01320 * Set its priority accordingly. No other task should ever be set to 01321 * CREATION priority 01322 */ 01323 ptdb->nPriority = NORMAL_PRIORITY_TASK; 01324 ptdb->nEvents = 0; 01325 ptdb->pti = ptiCurrent; 01326 ptdb->ptdbNext = NULL; 01327 ptdb->TDB_Flags = 0; 01328 01329 InsertTask(ppi, ptdb); 01330 zzzEndDeferWinEventNotify(); 01331 01332 ptiCurrent->dwCompatFlags = dwAppCompatFlags; 01333 ptiCurrent->pClientInfo->dwCompatFlags = dwAppCompatFlags; 01334 01335 UserAssert(ptiCurrent->ppi->ptiList); 01336 /* 01337 * We haven't captured pstrBaseFileName's buffer, we 01338 * may fault touching it in SetAppImeCompatFlags. If 01339 * so the IME flags have been set already and we 01340 * can safely assume it's not a setup app. 01341 */ 01342 01343 try { 01344 if (SetAppImeCompatFlags(ptiCurrent, ptiCurrent->pstrAppName, 01345 pstrBaseFileName)) { 01346 /* 01347 * Flag task as a setup app. 01348 */ 01349 ptdb->TDB_Flags = TDBF_SETUP; 01350 ppi->W32PF_Flags |= W32PF_SETUPAPP; 01351 } 01352 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01353 } 01354 01355 /* 01356 * Force this new task to be the active task (WOW will ensure the 01357 * currently running task does a Yield which will put it into the 01358 * non preemptive scheduler. 01359 */ 01360 ppi->pwpi->ptiScheduled = ptiCurrent; 01361 ppi->pwpi->CSLockCount = -1; 01362 01363 EnterWowCritSect(ptiCurrent, ppi->pwpi); 01364 01365 /* 01366 * ensure app gets focus 01367 */ 01368 zzzShowStartGlass(10000); 01369 01370 return STATUS_SUCCESS; 01371 } 01372 01373 /***************************************************************************\ 01374 * zzzShowStartGlass 01375 * 01376 * This routine is called by WOW when first starting or when starting an 01377 * additional WOW app. 01378 * 01379 * 12-07-92 ScottLu Created. 01380 \***************************************************************************/ 01381 01382 void zzzShowStartGlass( 01383 DWORD dwTimeout) 01384 { 01385 PPROCESSINFO ppi; 01386 01387 /* 01388 * If this is the first call to zzzShowStartGlass(), then the 01389 * W32PF_ALLOWFOREGROUNDACTIVATE bit has already been set in the process 01390 * info - we don't want to set it again because it may have been 01391 * purposefully cleared when the user hit a key or mouse clicked. 01392 */ 01393 ppi = PpiCurrent(); 01394 if (ppi->W32PF_Flags & W32PF_SHOWSTARTGLASSCALLED) { 01395 /* 01396 * Allow this wow app to come to the foreground. This'll be cancelled 01397 * if the user mouse clicks or hits any keys. 01398 */ 01399 SET_PUDF(PUDF_ALLOWFOREGROUNDACTIVATE); 01400 TAGMSG0(DBGTAG_FOREGROUND, "zzzShowStartGlass set PUDF"); 01401 ppi->W32PF_Flags |= W32PF_ALLOWFOREGROUNDACTIVATE; 01402 TAGMSG1(DBGTAG_FOREGROUND, "zzzShowStartGlass set W32PF %#p", ppi); 01403 } 01404 ppi->W32PF_Flags |= W32PF_SHOWSTARTGLASSCALLED; 01405 01406 /* 01407 * Show the start glass cursor for this much longer. 01408 */ 01409 zzzCalcStartCursorHide((PW32PROCESS)ppi, dwTimeout); 01410 } 01411 /***************************************************************************\ 01412 * GetJournallingQueue 01413 * 01414 * 03/21/97 GerardoB Created 01415 \***************************************************************************/ 01416 PQ GetJournallingQueue(PTHREADINFO pti) 01417 { 01418 PHOOK phook; 01419 /* 01420 * fail if we cannot journal this thread 01421 */ 01422 if ((pti->TIF_flags & TIF_DONTJOURNALATTACH) 01423 || (pti->rpdesk == NULL)) { 01424 01425 return NULL; 01426 } 01427 /* 01428 * Get the journalling hook if any. 01429 */ 01430 phook = PhkFirstGlobalValid(pti, WH_JOURNALPLAYBACK); 01431 if (phook == NULL) { 01432 phook = PhkFirstGlobalValid(pti, WH_JOURNALRECORD); 01433 } 01434 /* 01435 * Validate fsHooks bits. 01436 */ 01437 UserAssert((phook == NULL) 01438 ^ IsHooked(pti, (WHF_FROM_WH(WH_JOURNALPLAYBACK) | WHF_FROM_WH(WH_JOURNALRECORD)))); 01439 01440 /* 01441 * return the queue if we found a journalling hook 01442 */ 01443 return ((phook == NULL) ? NULL : GETPTI(phook)->pq); 01444 } 01445 01446 /***************************************************************************\ 01447 * ClearQueueServerEvent 01448 * 01449 * This function should be called when a thread needs to wait for some kind of 01450 * input. This clears pEventQueueServer which means we won't return from the 01451 * wait until new input of the required type arrives. Setting the wake mask 01452 * controls what input will wake us up. WOW apps skip this since their 01453 * scheduler controls when they wake up. 01454 * 01455 * History: 01456 * 09/12/97 GerardoB Created 01457 \***************************************************************************/ 01458 void ClearQueueServerEvent (WORD wWakeMask) 01459 { 01460 PTHREADINFO ptiCurrent = PtiCurrent(); 01461 UserAssert(wWakeMask != 0); 01462 ptiCurrent->pcti->fsWakeMask = wWakeMask; 01463 KeClearEvent(ptiCurrent->pEventQueueServer); 01464 } 01465 /***************************************************************************\ 01466 * xxxCreateThreadInfo 01467 * 01468 * Allocate the main thread information structure 01469 * 01470 * History: 01471 * 03-18-95 JimA Created. 01472 \***************************************************************************/ 01473 01474 ULONG ParseReserved( 01475 WCHAR *pchReserved, 01476 WCHAR *pchFind) 01477 { 01478 ULONG dw; 01479 WCHAR *pch, *pchT, ch; 01480 UNICODE_STRING uString; 01481 01482 dw = 0; 01483 if (pchReserved != NULL && (pch = wcsstr(pchReserved, pchFind)) != NULL) { 01484 pch += wcslen(pchFind); 01485 01486 pchT = pch; 01487 while (*pchT >= '0' && *pchT <= '9') 01488 pchT++; 01489 01490 ch = *pchT; 01491 *pchT = 0; 01492 RtlInitUnicodeString(&uString, pch); 01493 *pchT = ch; 01494 01495 RtlUnicodeStringToInteger(&uString, 0, &dw); 01496 } 01497 01498 return dw; 01499 } 01500 01501 NTSTATUS xxxCreateThreadInfo( 01502 PETHREAD pEThread, 01503 BOOL IsSystemThread) 01504 { 01505 DWORD dwTIFlags = 0; 01506 PPROCESSINFO ppi; 01507 PTHREADINFO ptiCurrent; 01508 PEPROCESS pEProcess = pEThread->ThreadsProcess; 01509 PUSERSTARTUPINFO pusi; 01510 PRTL_USER_PROCESS_PARAMETERS ProcessParams; 01511 PDESKTOP pdesk = NULL; 01512 HDESK hdesk = NULL; 01513 HWINSTA hwinsta; 01514 PQ pq; 01515 NTSTATUS Status; 01516 BOOL fFirstThread; 01517 PTEB pteb = NtCurrentTeb(); 01518 TL tlpdesk; 01519 01520 CheckCritIn(); 01521 UserAssert(IsWinEventNotifyDeferredOK()); 01522 01523 ValidateProcessSessionId(pEProcess); 01524 01525 /* 01526 * If CleanupResources was called for the last GUI thread then 01527 * we should not allow any more GUI threads 01528 */ 01529 if (gbCleanedUpResources) { 01530 RIPMSG0(RIP_ERROR, "No more GUI threads should be created"); 01531 return STATUS_PROCESS_IS_TERMINATING; 01532 } 01533 01534 /* 01535 * Increment the number of GUI threads in the session 01536 */ 01537 gdwGuiThreads++; 01538 01539 /* 01540 * Although all threads now have a ETHREAD structure, server-side 01541 * threads (RIT, Console, etc) don't have a client-server eventpair 01542 * handle. We use this to distinguish the two cases. 01543 */ 01544 01545 if (IsSystemThread) { 01546 dwTIFlags = TIF_SYSTEMTHREAD | TIF_DONTATTACHQUEUE | TIF_DISABLEIME; 01547 } 01548 01549 if (!(dwTIFlags & TIF_SYSTEMTHREAD) && pEProcess == gpepCSRSS) { 01550 dwTIFlags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE | TIF_DISABLEIME; 01551 } 01552 01553 ProcessParams = (pEProcess->Peb ? pEProcess->Peb->ProcessParameters : NULL); 01554 01555 /* 01556 * Locate the processinfo structure for the new thread. 01557 */ 01558 ppi = PpiCurrent(); 01559 01560 #if defined(_WIN64) 01561 /* 01562 * If the process is marked as an emulated 32bit app thus, 01563 * mark the thread as an emulated 32bit thread. 01564 * This is to be consistent with the way WOW16 marks threads. 01565 */ 01566 if (ppi->W32PF_Flags & W32PF_WOW64) { 01567 dwTIFlags |= TIF_WOW64; 01568 } 01569 #endif //defined(_WIN64) 01570 01571 /* 01572 * For Winlogon, only the first thread can have IME processing. 01573 */ 01574 if (gpidLogon == pEThread->Cid.UniqueProcess) { 01575 if (ppi->ptiList != NULL) { 01576 dwTIFlags |= TIF_DISABLEIME; 01577 RIPMSG1(RIP_VERBOSE, "WinLogon, second or other thread. pti=%x", pEThread->Tcb.Win32Thread); 01578 } 01579 } 01580 01581 /* 01582 * Allocate the thread-info structure. If it's a SYSTEMTHREAD, then 01583 * make sure we have enough space for the (pwinsta) pointer. This 01584 * is referenced in (paint.c: DoPaint) to assure desktop/input can 01585 * have a winsta to view. 01586 */ 01587 ptiCurrent = (PTHREADINFO)pEThread->Tcb.Win32Thread; 01588 01589 ptiCurrent->TIF_flags = dwTIFlags; 01590 Lock(&ptiCurrent->spklActive, gspklBaseLayout); 01591 ptiCurrent->pcti = &(ptiCurrent->cti); 01592 01593 /* 01594 * Check if no IME processing for all threads 01595 * in the same process. 01596 */ 01597 if (ppi->W32PF_Flags & W32PF_DISABLEIME) 01598 ptiCurrent->TIF_flags |= TIF_DISABLEIME; 01599 01600 /* 01601 * Hook up this queue to this process info structure, increment 01602 * the count of threads using this process info structure. Set up 01603 * the ppi before calling SetForegroundPriority(). 01604 */ 01605 UserAssert(ppi != NULL); 01606 01607 ptiCurrent->ppi = ppi; 01608 ptiCurrent->ptiSibling = ppi->ptiList; 01609 ppi->ptiList = ptiCurrent; 01610 ppi->cThreads++; 01611 01612 01613 if (pteb != NULL) 01614 pteb->Win32ThreadInfo = ptiCurrent; 01615 01616 /* 01617 * Point to the client info. 01618 */ 01619 if (dwTIFlags & TIF_SYSTEMTHREAD) { 01620 ptiCurrent->pClientInfo = UserAllocPoolWithQuota(sizeof(CLIENTINFO), 01621 TAG_CLIENTTHREADINFO); 01622 if (ptiCurrent->pClientInfo == NULL) { 01623 Status = STATUS_NO_MEMORY; 01624 goto CreateThreadInfoFailed; 01625 } 01626 } else { 01627 /* 01628 * If this is not a system thread then grab the user mode client info 01629 * elsewhere we use the GetClientInfo macro which looks here 01630 */ 01631 UserAssert(NtCurrentTeb() != NULL); 01632 ptiCurrent->pClientInfo = ((PCLIENTINFO)((NtCurrentTeb())->Win32ClientInfo)); 01633 01634 /* 01635 * set the SECURE flag in the thread flags if this is a secure process 01636 */ 01637 if (((PW32PROCESS)ppi)->W32PF_Flags & W32PF_RESTRICTED) { 01638 ptiCurrent->TIF_flags |= TIF_RESTRICTED; 01639 } 01640 } 01641 01642 01643 /* 01644 * Create the input event. 01645 */ 01646 Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, 01647 EVENT_ALL_ACCESS, 01648 NULL, 01649 SynchronizationEvent, 01650 FALSE); 01651 01652 if (NT_SUCCESS(Status)) { 01653 Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 01654 EVENT_ALL_ACCESS, 01655 *ExEventObjectType, 01656 UserMode, 01657 &ptiCurrent->pEventQueueServer, 01658 NULL); 01659 if (NT_SUCCESS(Status)) { 01660 Status = ProtectHandle(ptiCurrent->hEventQueueClient, TRUE); 01661 } else if (Status == STATUS_INVALID_HANDLE) { 01662 ptiCurrent->hEventQueueClient = NULL; 01663 } 01664 } 01665 if (!NT_SUCCESS(Status)) { 01666 goto CreateThreadInfoFailed; 01667 } 01668 01669 /* 01670 * Mark the process as having threads that need cleanup. See 01671 * DestroyProcessesObjects(). 01672 */ 01673 fFirstThread = !(ppi->W32PF_Flags & W32PF_THREADCONNECTED); 01674 ppi->W32PF_Flags |= W32PF_THREADCONNECTED; 01675 01676 /* 01677 * If we haven't copied over our startup info yet, do it now. 01678 * Don't bother copying the info if we aren't going to use it. 01679 */ 01680 if (ProcessParams) { 01681 01682 pusi = &ppi->usi; 01683 01684 if ((pusi->cb == 0) && (ProcessParams->WindowFlags != 0)) { 01685 pusi->cb = sizeof(USERSTARTUPINFO); 01686 pusi->dwX = ProcessParams->StartingX; 01687 pusi->dwY = ProcessParams->StartingY; 01688 pusi->dwXSize = ProcessParams->CountX; 01689 pusi->dwYSize = ProcessParams->CountY; 01690 pusi->dwFlags = ProcessParams->WindowFlags; 01691 pusi->wShowWindow = (WORD)ProcessParams->ShowWindowFlags; 01692 } 01693 01694 if (fFirstThread) { 01695 01696 /* 01697 * Set up the hot key, if there is one. 01698 * 01699 * If the STARTF_USEHOTKEY flag is given in the startup info, then 01700 * the hStdInput is the hotkey (new from Chicago). Otherwise, parse 01701 * it out in string format from the lpReserved string. 01702 */ 01703 if (ProcessParams->WindowFlags & STARTF_USEHOTKEY) { 01704 ppi->dwHotkey = HandleToUlong(ProcessParams->StandardInput); 01705 } else { 01706 ppi->dwHotkey = ParseReserved(ProcessParams->ShellInfo.Buffer, 01707 L"hotkey."); 01708 } 01709 01710 /* 01711 * Copy the monitor handle, if there is one. 01712 */ 01713 UserAssert(!ppi->hMonitor); 01714 if (ProcessParams->WindowFlags & STARTF_HASSHELLDATA) { 01715 HMONITOR hMonitor; 01716 01717 hMonitor = (HMONITOR)(ProcessParams->StandardOutput); 01718 if (ValidateHmonitor(hMonitor)) { 01719 ppi->hMonitor = hMonitor; 01720 } 01721 } 01722 } 01723 } 01724 01725 /* 01726 * Open the windowstation and desktop. If this is a system 01727 * thread only use the desktop that might be stored in the teb. 01728 */ 01729 UserAssert(ptiCurrent->rpdesk == NULL); 01730 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) && 01731 grpWinStaList) { 01732 01733 BOOL bShutDown = FALSE; 01734 01735 hdesk = xxxResolveDesktop( 01736 NtCurrentProcess(), 01737 &ProcessParams->DesktopInfo, 01738 &hwinsta, (ProcessParams->WindowFlags & STARTF_DESKTOPINHERIT), 01739 &bShutDown); 01740 01741 if (hdesk == NULL) { 01742 01743 if (bShutDown) { 01744 /* 01745 * Trying to create a new process during logoff 01746 */ 01747 ULONG_PTR adwParameters[5] = {0, 0, 0, 0, MB_DEFAULT_DESKTOP_ONLY}; 01748 ULONG ErrorResponse; 01749 01750 LeaveCrit(); 01751 01752 ExRaiseHardError((NTSTATUS)STATUS_DLL_INIT_FAILED_LOGOFF, 01753 ARRAY_SIZE(adwParameters), 01754 0, 01755 adwParameters, 01756 OptionOkNoWait, 01757 &ErrorResponse); 01758 01759 ZwTerminateProcess(NtCurrentProcess(), STATUS_DLL_INIT_FAILED); 01760 01761 EnterCrit(); 01762 } 01763 01764 Status = STATUS_DLL_INIT_FAILED; 01765 goto CreateThreadInfoFailed; 01766 01767 } else { 01768 01769 xxxSetProcessWindowStation(hwinsta, KernelMode); 01770 01771 /* 01772 * Reference the desktop handle 01773 */ 01774 Status = ObReferenceObjectByHandle( 01775 hdesk, 01776 0, 01777 *ExDesktopObjectType, 01778 KernelMode, 01779 &pdesk, 01780 NULL); 01781 01782 if (!NT_SUCCESS(Status)) { 01783 UserAssert(pdesk == NULL); 01784 goto CreateThreadInfoFailed; 01785 } 01786 01787 ThreadLockDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_CREATETHREADINFO); 01788 01789 ObDereferenceObject(pdesk); 01790 01791 /* 01792 * The first desktop is the default for all succeeding threads. 01793 */ 01794 if ((ppi->hdeskStartup == NULL) && 01795 (pEProcess->UniqueProcessId != gpidLogon)) { 01796 01797 LockDesktop(&ppi->rpdeskStartup, pdesk, LDL_PPI_DESKSTARTUP2, (ULONG_PTR)ppi); 01798 ppi->hdeskStartup = hdesk; 01799 } 01800 } 01801 } 01802 01803 /* 01804 * Remember dwExpWinVer. This is used to return GetAppVer() (and 01805 * GetExpWinVer(NULL). 01806 */ 01807 if (pEProcess->Peb != NULL) 01808 ptiCurrent->dwExpWinVer = RtlGetExpWinVer(pEProcess->SectionBaseAddress); 01809 else 01810 ptiCurrent->dwExpWinVer = VER40; 01811 01812 ptiCurrent->pClientInfo->dwExpWinVer = ptiCurrent->dwExpWinVer; 01813 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; 01814 01815 if (ptiCurrent->spklActive) { 01816 ptiCurrent->pClientInfo->CodePage = ptiCurrent->spklActive->CodePage; 01817 ptiCurrent->pClientInfo->hKL = ptiCurrent->spklActive->hkl; 01818 } else { 01819 ptiCurrent->pClientInfo->CodePage = CP_ACP; 01820 ptiCurrent->pClientInfo->hKL = 0; 01821 } 01822 01823 /* 01824 * Set the desktop even if it is NULL to ensure that ptiCurrent->pDeskInfo 01825 * is set. 01826 * NOTE: This adds the pti to the desktop's PtiList, but we don't yet have 01827 * a pti->pq. zzzRecalcThreadAttachment loops through this PtiList expects 01828 * a pq, so we must not leave the critsect until we have a queue. 01829 * zzzSetDesktop only zzz leaves the critsect if there is a pti->pq, so we 01830 * can BEGINATOMICCHECK to ensure this, and make sure we allocate the queue 01831 * before we leave the critical section. 01832 */ 01833 BEGINATOMICCHECK(); 01834 zzzSetDesktop(ptiCurrent, pdesk, hdesk); 01835 ENDATOMICCHECK(); 01836 01837 /* 01838 * If we have a desktop and are journalling on that desktop, use 01839 * the journal queue, otherwise create a new queue. 01840 */ 01841 if (pdesk == grpdeskRitInput) { 01842 PQ pq; 01843 UserAssert((pdesk == NULL) || (ptiCurrent->pDeskInfo == pdesk->pDeskInfo)); 01844 UserAssert(ptiCurrent->rpdesk == pdesk); 01845 pq = GetJournallingQueue(ptiCurrent); 01846 if (pq != NULL) { 01847 ptiCurrent->pq = pq; 01848 pq->cThreads++; 01849 } 01850 } 01851 01852 /* 01853 * If not journalling, give this thread its own queue 01854 */ 01855 if (ptiCurrent->pq == NULL) { 01856 if ((pq = AllocQueue(NULL, NULL)) == NULL) { 01857 Status = STATUS_NO_MEMORY; 01858 goto CreateThreadInfoFailed; 01859 } 01860 /* 01861 * Attach the Q to the THREADINFO. 01862 */ 01863 ptiCurrent->pq = pq; 01864 pq->ptiMouse = pq->ptiKeyboard = ptiCurrent; 01865 pq->cThreads++; 01866 } 01867 01868 /* 01869 * Remember that this is a screen saver. That way we can set its 01870 * priority appropriately when it is idle or when it needs to go 01871 * away. At first we set it to normal priority, then we set the 01872 * TIF_IDLESCREENSAVER bit so that when it activates it will get 01873 * lowered in priority. 01874 */ 01875 if (ProcessParams && ProcessParams->WindowFlags & STARTF_SCREENSAVER) { 01876 01877 if (fFirstThread) { 01878 UserAssert(gppiScreenSaver == NULL); 01879 01880 /* 01881 * Make sure the parent's process is WinLogon, since only WinLogon is allowed to 01882 * use the STARTF_SCREENSAVER flag. 01883 */ 01884 if (gpidLogon == 0 || pEProcess->InheritedFromUniqueProcessId != gpidLogon) { 01885 RIPMSG0(RIP_WARNING,"Only the Logon process can launch a screen saver."); 01886 ProcessParams->WindowFlags &= ~STARTF_SCREENSAVER; 01887 goto NotAScreenSaver; 01888 } 01889 01890 gppiScreenSaver = ppi; 01891 gptSSCursor = gpsi->ptCursor; 01892 ppi->W32PF_Flags |= W32PF_SCREENSAVER; 01893 } 01894 #if DBG 01895 else { 01896 UserAssert(ppi->W32PF_Flags & W32PF_SCREENSAVER); 01897 } 01898 #endif 01899 01900 SetForegroundPriority(ptiCurrent, TRUE); 01901 01902 if (fFirstThread) { 01903 ppi->W32PF_Flags |= W32PF_IDLESCREENSAVER; 01904 } 01905 01906 /* 01907 * Screen saver doesn't need any IME processing. 01908 */ 01909 ptiCurrent->TIF_flags |= TIF_DISABLEIME; 01910 } 01911 01912 NotAScreenSaver: 01913 01914 /* 01915 * Do special processing for the first thread of a process. 01916 */ 01917 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD))) { 01918 01919 /* 01920 * I changed the code a while ago to unregister classes when the last 01921 * GUI thread is destroyed. Simply, there was too much stuff getting 01922 * unlocked and destroyed to guarantee that it would work on a non-GUI 01923 * thread. So if a process destroys its last GUI thread and then makes 01924 * a thread GUI later, we need to re-register the classes. 01925 */ 01926 01927 if (!(ppi->W32PF_Flags & W32PF_CLASSESREGISTERED)) { 01928 if (!LW_RegisterWindows(FALSE)) { 01929 RIPMSG0(RIP_WARNING, "xxxCreateThreadInfo: LW_RegisterWindows failed"); 01930 Status = STATUS_UNSUCCESSFUL; 01931 goto CreateThreadInfoFailed; 01932 } 01933 ppi->W32PF_Flags |= W32PF_CLASSESREGISTERED; 01934 if (ptiCurrent->pClientInfo) { 01935 ptiCurrent->pClientInfo->CI_flags |= CI_REGISTERCLASSES; 01936 } 01937 } 01938 01939 if (fFirstThread) { 01940 01941 /* 01942 * If this is an application starting (ie. not some thread of 01943 * the server context), enable the app-starting cursor. 01944 */ 01945 DeferWinEventNotify(); 01946 zzzCalcStartCursorHide((PW32PROCESS)pEProcess->Win32Process, 5000); 01947 EndDeferWinEventNotifyWithoutProcessing(); 01948 01949 /* 01950 * Open the windowstation 01951 */ 01952 if (grpWinStaList && ppi->rpwinsta == NULL) { 01953 RIPERR0(ERROR_CAN_NOT_COMPLETE, RIP_WARNING, "System is not initialized\n"); 01954 Status = STATUS_UNSUCCESSFUL; 01955 goto CreateThreadInfoFailed; 01956 } 01957 } 01958 } else { 01959 01960 /* 01961 * Don't register system windows until cursors and icons 01962 * have been loaded. 01963 */ 01964 if ((SYSCUR(ARROW) != NULL) && 01965 !(ppi->W32PF_Flags & W32PF_CLASSESREGISTERED)) { 01966 01967 ppi->W32PF_Flags |= W32PF_CLASSESREGISTERED; 01968 if (!LW_RegisterWindows(ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD)) { 01969 RIPMSG0(RIP_WARNING, "xxxCreateThreadInfo: LW_RegisterWindows failed"); 01970 Status = STATUS_UNSUCCESSFUL; 01971 goto CreateThreadInfoFailed; 01972 } 01973 } 01974 } 01975 01976 01977 /* 01978 * Initialize hung timer value 01979 */ 01980 01981 SET_TIME_LAST_READ(ptiCurrent); 01982 01983 /* 01984 * If someone is waiting on this process propagate that info into 01985 * the thread info 01986 */ 01987 if (ppi->W32PF_Flags & W32PF_WAITFORINPUTIDLE) 01988 ptiCurrent->TIF_flags |= TIF_WAITFORINPUTIDLE; 01989 01990 /* 01991 * Mark the thread as initialized. 01992 */ 01993 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED; 01994 01995 /* 01996 * Allow the thread to come to foreground when it is created 01997 * if the current process is the foreground process or the last input owner 01998 * This Flag is a hack to fix Bug 28502. When we click on 01999 * "Map Network Drive" button on the toolbar, the explorer (Bobday) 02000 * creates another thread to create the dialog box. This will create 02001 * the dialog in the background. We are adding this fix at the request 02002 * of the Shell team so that this dialog comes up as foreground. 02003 * 02004 * If the process already has the foreground right, we don't give it 02005 * to this thread (it doesn't need it). We do this to narrow the number 02006 * of ways this process can force the foreground. 02007 * Also, if the process is starting, it already has the right unless 02008 * the user has canceled it -- in which case we don't want to give it back. 02009 * 02010 */ 02011 if (!(ppi->W32PF_Flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING))) { 02012 if (((gptiForeground != NULL) && (ppi == gptiForeground->ppi)) 02013 || ((glinp.ptiLastWoken != NULL) && (ppi == glinp.ptiLastWoken->ppi))) { 02014 02015 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 02016 TAGMSG1(DBGTAG_FOREGROUND, "xxxCreateThreadInfo set TIF %#p", ptiCurrent); 02017 } 02018 } 02019 02020 if (IS_IME_ENABLED()) { 02021 /* 02022 * Create per-thread default input context 02023 */ 02024 CreateInputContext(0); 02025 } 02026 02027 /* 02028 * Call back to the client to finish initialization. 02029 */ 02030 if (!(dwTIFlags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD))) { 02031 02032 if (SetAppCompatFlags(ptiCurrent)) { 02033 /* 02034 * Flag this process as a setup app. 02035 */ 02036 ppi->W32PF_Flags |= W32PF_SETUPAPP; 02037 } 02038 02039 Status = ClientThreadSetup(); 02040 if (!NT_SUCCESS(Status)) { 02041 RIPMSG1(RIP_WARNING, "ClientThreadSetup failed with NTSTATUS %lx", Status); 02042 goto CreateThreadInfoFailed; 02043 } 02044 } 02045 02046 if ((NT_SUCCESS(Status) && fFirstThread) && 02047 !(ppi->W32PF_Flags & W32PF_CONSOLEAPPLICATION)) { 02048 02049 /* 02050 * Don't play the sound for console processes 02051 * since we will play it when the console window 02052 * will be created 02053 */ 02054 PlayEventSound(USER_SOUND_OPEN); 02055 } 02056 02057 /* 02058 * Release desktop. 02059 * Some other thread might have been waiting to destroy this desktop 02060 * when xxxResolveDestktop got a handle to it. So let's double 02061 * check this now that we have called back several times after getting 02062 * the handle back. 02063 */ 02064 if (pdesk != NULL) { 02065 if (pdesk->dwDTFlags & DF_DESTROYED) { 02066 RIPMSG1(RIP_WARNING, "xxxCreateThreadInfo: pdesk destroyed:%#p", pdesk); 02067 Status = STATUS_UNSUCCESSFUL; 02068 goto CreateThreadInfoFailed; 02069 } 02070 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CREATETHREADINFO1); 02071 } 02072 02073 // We must return a success here. If the failure status is returned 02074 // W32Thread will be freed without us going thru xxxDestroyProcessInfo. 02075 UserAssert(NT_SUCCESS(Status)); 02076 02077 return Status; 02078 02079 CreateThreadInfoFailed: 02080 02081 RIPMSG2(RIP_WARNING, "xxxCreateThreadInfo: failed: pti %#p pdesk %#p", 02082 ptiCurrent, pdesk); 02083 02084 if (pdesk != NULL) { 02085 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CREATETHREADINFO2); 02086 } 02087 xxxDestroyThreadInfo(); 02088 return Status; 02089 } 02090 02091 /***************************************************************************\ 02092 * AllocQueue 02093 * 02094 * Allocates the memory for a TI structure and initializes its fields. 02095 * Each Win32 queue has it's own TI while all Win16 threads share the same 02096 * TI. 02097 * 02098 * History: 02099 * 02-21-91 MikeHar Created. 02100 \***************************************************************************/ 02101 02102 PQ AllocQueue( 02103 PTHREADINFO ptiKeyState, // if non-Null then use this key state 02104 // other wise use global AsyncKeyState 02105 PQ pq) // non-null == preallocated object 02106 { 02107 USHORT cLockCount; 02108 02109 if (pq == NULL) { 02110 pq = ExAllocateFromPagedLookasideList(QLookaside); 02111 if (pq == NULL) { 02112 return NULL; 02113 } 02114 cLockCount = 0; 02115 } else { 02116 DebugValidateMLIST(&pq->mlInput); 02117 /* 02118 * Preserve lock count. 02119 */ 02120 cLockCount = pq->cLockCount; 02121 } 02122 RtlZeroMemory(pq, sizeof(Q)); 02123 pq->cLockCount = cLockCount; 02124 02125 /* 02126 * This is a new queue; we need to update its key state table before 02127 * the first input event is put in the queue. 02128 * We do this by copying the current keystate table and NULLing the recent 02129 * down state table. If a key is really down it will be updated when 02130 * we get it repeats. 02131 * 02132 * He is the old way that did not work because if the first key was say an 02133 * alt key the Async table would be updated, then the UpdateKeyState 02134 * message and it would look like the alt key was PREVIOUSLY down. 02135 * 02136 * The queue will get updated when it first reads input: to allow the 02137 * app to query the key state before it calls GetMessage, set its initial 02138 * key state to the asynchronous key state. 02139 */ 02140 if (ptiKeyState) { 02141 RtlCopyMemory(pq->afKeyState, ptiKeyState->pq->afKeyState, CBKEYSTATE); 02142 } else { 02143 RtlCopyMemory(pq->afKeyState, gafAsyncKeyState, CBKEYSTATE); 02144 } 02145 02146 /* 02147 * If there isn't a mouse set iCursorLevel to -1 so the 02148 * mouse cursor won't be visible on the screen. 02149 */ 02150 if ( 02151 !TEST_GTERMF(GTERMF_MOUSE)) { 02152 pq->iCursorLevel--; 02153 } 02154 /* 02155 * While the thread is starting up... it has the wait cursor. 02156 */ 02157 LockQCursor(pq, SYSCUR(WAIT)); 02158 02159 DebugValidateMLIST(&pq->mlInput); 02160 return pq; 02161 } 02162 02163 /***************************************************************************\ 02164 * FreeQueue 02165 * 02166 * 04-04-96 GerardoB Created. 02167 \***************************************************************************/ 02168 VOID FreeQueue( 02169 PQ pq) 02170 { 02171 #if DBG 02172 /* 02173 * Turn off the flag indicating that this queue is in destruction. 02174 * We do this in either case that we are putting this into the free 02175 * list, or truly destroying the handle. We use this to try and 02176 * track cases where someone tries to lock elements into the queue 02177 * structure while it's going through destuction. 02178 */ 02179 pq->QF_flags &= ~QF_INDESTROY; 02180 #endif 02181 02182 UserAssertMsg0(pq != gpqForeground, "FreeQueue(gpqForeground) !"); 02183 UserAssertMsg0(pq != gpqForegroundPrev, "FreeQueue(gpqForegroundPrev) !"); 02184 UserAssertMsg0(pq != gpqCursor, "FreeQueue(gpqCursor) !"); 02185 ExFreeToPagedLookasideList(QLookaside, pq); 02186 } 02187 02188 /***************************************************************************\ 02189 * FreeCachedQueues 02190 * 02191 * 14-Jan-98 CLupu Created. 02192 \***************************************************************************/ 02193 VOID FreeCachedQueues( 02194 VOID) 02195 { 02196 if (QLookaside != NULL) { 02197 ExDeletePagedLookasideList(QLookaside); 02198 UserFreePool(QLookaside); 02199 QLookaside = NULL; 02200 } 02201 } 02202 02203 /***************************************************************************\ 02204 * zzzDestroyQueue 02205 * 02206 * 02207 * History: 02208 * 05-20-91 MikeHar Created. 02209 \***************************************************************************/ 02210 02211 void zzzDestroyQueue( 02212 PQ pq, 02213 PTHREADINFO pti) 02214 { 02215 PTHREADINFO ptiT; 02216 PTHREADINFO ptiAny, ptiBestMouse, ptiBestKey; 02217 PLIST_ENTRY pHead, pEntry; 02218 02219 #if DBG 02220 USHORT cDying = 0; 02221 #endif 02222 02223 BOOL fSetFMouseMoved = FALSE; 02224 02225 DebugValidateMLIST(&pq->mlInput); 02226 02227 UserAssert(pq->cThreads); 02228 pq->cThreads--; 02229 02230 if (pq->cThreads != 0) { 02231 02232 /* 02233 * Since we aren't going to destroy this queue, make sure 02234 * it isn't pointing to the THREADINFO that's going away. 02235 */ 02236 if (pq->ptiSysLock == pti) { 02237 CheckSysLock(6, pq, NULL); 02238 pq->ptiSysLock = NULL; 02239 } 02240 02241 if ((pq->ptiKeyboard == pti) || (pq->ptiMouse == pti)) { 02242 02243 /* 02244 * Run through THREADINFOs looking for one pointing to pq. 02245 */ 02246 ptiAny = NULL; 02247 ptiBestMouse = NULL; 02248 ptiBestKey = NULL; 02249 02250 pHead = &pti->rpdesk->PtiList; 02251 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 02252 ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 02253 02254 /* 02255 * Skip threads that are going away or belong to a 02256 * different queue. 02257 */ 02258 if ((ptiT->TIF_flags & TIF_INCLEANUP) || (ptiT->pq != pq)) { 02259 #if DBG 02260 if (ptiT->pq == pq && (ptiT->TIF_flags & TIF_INCLEANUP)) 02261 cDying++; 02262 #endif 02263 continue; 02264 } 02265 02266 ptiAny = ptiT; 02267 02268 if (pti->pcti->fsWakeBits & QS_MOUSE) { 02269 if (ptiT->pcti->fsWakeMask & QS_MOUSE) 02270 ptiBestMouse = ptiT; 02271 } 02272 02273 if (pti->pcti->fsWakeBits & QS_KEY) { 02274 if (ptiT->pcti->fsWakeMask & QS_KEY) 02275 ptiBestKey = ptiT; 02276 } 02277 } 02278 02279 if (ptiBestMouse == NULL) 02280 ptiBestMouse = ptiAny; 02281 if (ptiBestKey == NULL) 02282 ptiBestKey = ptiAny; 02283 02284 /* 02285 * Transfer any wake-bits to this new queue. This 02286 * is a common problem for QS_MOUSEMOVE which doesn't 02287 * get set on coalesced WM_MOUSEMOVE events, so we 02288 * need to make sure the new thread tries to process 02289 * any input waiting in the queue. 02290 */ 02291 if (ptiBestMouse != NULL) 02292 SetWakeBit(ptiBestMouse, pti->pcti->fsWakeBits & QS_MOUSE); 02293 if (ptiBestKey != NULL) 02294 SetWakeBit(ptiBestKey, pti->pcti->fsWakeBits & QS_KEY); 02295 02296 if (pq->ptiKeyboard == pti) 02297 pq->ptiKeyboard = ptiBestKey; 02298 02299 if (pq->ptiMouse == pti) 02300 pq->ptiMouse = ptiBestMouse; 02301 02302 #if DBG 02303 /* 02304 * Bad things happen if ptiKeyboard or ptiMouse are NULL 02305 */ 02306 if (pq->cThreads != cDying && (pq->ptiKeyboard == NULL || pq->ptiMouse == NULL)) { 02307 RIPMSG6(RIP_ERROR, 02308 "pq %#p pq->cThreads %x cDying %x pti %#p ptiK %#p ptiM %#p", 02309 pq, pq->cThreads, cDying, pti, pq->ptiKeyboard, pq->ptiMouse); 02310 } 02311 #endif 02312 } 02313 02314 return; 02315 } 02316 02317 /* 02318 * Unlock any potentially locked globals now that we know absolutely 02319 * that this queue is going away. 02320 */ 02321 UnlockCaptureWindow(pq); 02322 Unlock(&pq->spwndFocus); 02323 Unlock(&pq->spwndActive); 02324 Unlock(&pq->spwndActivePrev); 02325 Unlock(&pq->caret.spwnd); 02326 LockQCursor(pq, NULL); 02327 02328 #if DBG 02329 /* 02330 * Mark this queue as being in the destruction process. This is 02331 * cleared in FreeQueue() once we have determined it's safe to 02332 * place in the free-list, or destroy the handle. We use this 02333 * to track cases where someone will lock a cursor into the queue 02334 * while it's in the middle of being destroyed. 02335 */ 02336 pq->QF_flags |= QF_INDESTROY; 02337 #endif 02338 02339 /* 02340 * Free everything else that was allocated/created by AllocQueue. 02341 */ 02342 FreeMessageList(&pq->mlInput); 02343 02344 /* 02345 * If this queue is in the foreground, set gpqForeground 02346 * to NULL so no input is routed. At some point we'll want 02347 * to do slightly more clever assignment of gpqForeground here. 02348 */ 02349 if (gpqForeground == pq) { 02350 gpqForeground = NULL; 02351 } 02352 02353 if (gpqForegroundPrev == pq) { 02354 gpqForegroundPrev = NULL; 02355 } 02356 02357 if (gpqCursor == pq) { 02358 gpqCursor = NULL; 02359 fSetFMouseMoved = TRUE; 02360 } 02361 02362 if (pq->cLockCount == 0) { 02363 FreeQueue(pq); 02364 } 02365 02366 if (fSetFMouseMoved) { 02367 zzzSetFMouseMoved(); 02368 } 02369 02370 } 02371 02372 /**************************************************************************\ 02373 * UserDeleteW32Thread 02374 * 02375 * This function is called when the W32THREAD reference count goes 02376 * down to zero. So everything left around by xxxDestroyThreadInfo 02377 * must be cleaned up here. 02378 * 02379 * SO VERY IMPORTANT: 02380 * Note that this call is not in the context of the pti being cleaned up, 02381 * in other words, pti != PtiCurrent(). So only kernel calls are allowed here. 02382 * 02383 * 04-01-96 GerardoB Created 02384 \**************************************************************************/ 02385 VOID UserDeleteW32Thread (PW32THREAD pW32Thread) 02386 { 02387 PTHREADINFO pti = (PTHREADINFO)pW32Thread; 02388 02389 BEGIN_REENTERCRIT(); 02390 02391 /* 02392 * Make sure the ref count didn't get bumped up while we were waiting. 02393 */ 02394 if (pW32Thread->RefCount == 0) { 02395 02396 /* 02397 * Events 02398 */ 02399 if (pti->pEventQueueServer != NULL) { 02400 ObDereferenceObject(pti->pEventQueueServer); 02401 } 02402 if (pti->apEvent != NULL) { 02403 UserFreePool(pti->apEvent); 02404 } 02405 02406 /* 02407 * App name. 02408 */ 02409 if (pti->pstrAppName != NULL) { 02410 UserFreePool(pti->pstrAppName); 02411 } 02412 02413 /* 02414 * Unlock the queues and free them if no one is using them 02415 * (the queues were already destroyed in DestroyThreadInfo) 02416 */ 02417 if (pti->pq != NULL) { 02418 02419 UserAssert(pti->pq->cLockCount); 02420 --(pti->pq->cLockCount); 02421 02422 if ((pti->pq->cLockCount == 0) 02423 && (pti->pq->cThreads == 0)) { 02424 FreeQueue(pti->pq); 02425 } 02426 02427 } 02428 /* 02429 * zzzReattachThreads shouldn't call back while using pqAttach 02430 */ 02431 UserAssert(pti->pqAttach == NULL); 02432 #if 0 02433 if (pti->pqAttach != NULL) { 02434 02435 UserAssert(pti->pqAttach->cLockCount); 02436 --(pti->pqAttach->cLockCount); 02437 02438 if ((pti->pqAttach->cLockCount == 0) 02439 && (pti->pqAttach->cThreads == 0)) { 02440 FreeQueue(pti->pqAttach); 02441 } 02442 02443 } 02444 #endif 02445 /* 02446 * Unlock the desktop (pti already unlinked from ptiList) 02447 */ 02448 if (pti->rpdesk != NULL) { 02449 UnlockDesktop(&pti->rpdesk, LDU_PTI_DESK, (ULONG_PTR)pti); 02450 } 02451 02452 /* 02453 * Remove the pointer to this W32Thread and free the associated memory. 02454 */ 02455 InterlockedCompareExchangePointer(&pW32Thread->pEThread->Tcb.Win32Thread, NULL, pW32Thread); 02456 Win32FreePool(pW32Thread); 02457 } 02458 02459 END_REENTERCRIT(); 02460 } 02461 02462 /**************************************************************************\ 02463 * UserDeleteW32Process 02464 * 02465 * This function is called when the W32PROCESS reference count goes 02466 * down to zero. So everything left around by DestroyProcessInfo 02467 * must be cleaned up here. 02468 * 02469 * SO VERY IMPORTANT: 02470 * Note that this call may not be in the context of the ppi being cleaned up, 02471 * in other words, ppi != PpiCurrent(). So only kernel calls are allowed here. 02472 * 02473 * 04-01-96 GerardoB Created 02474 \**************************************************************************/ 02475 VOID UserDeleteW32Process(PW32PROCESS pW32Process) 02476 { 02477 PPROCESSINFO ppi = (PPROCESSINFO)pW32Process; 02478 02479 BEGIN_REENTERCRIT(); 02480 02481 /* 02482 * Make sure the ref count didn't get bumped up while we were waiting. 02483 */ 02484 if (pW32Process->RefCount == 0) { 02485 02486 /* 02487 * Grab the handle flags lock. We can't call into the object manager when 02488 * we have this or we might deadlock. 02489 */ 02490 EnterHandleFlagsCrit(); 02491 02492 /* 02493 * Delete handle flags attribute bitmap 02494 */ 02495 if (ppi->bmHandleFlags.Buffer) { 02496 UserFreePool(ppi->bmHandleFlags.Buffer); 02497 RtlInitializeBitMap(&ppi->bmHandleFlags, NULL, 0); 02498 } 02499 02500 /* 02501 * Remove the pointer to this W32Process and free the associated memory. 02502 */ 02503 InterlockedCompareExchangePointer(&pW32Process->Process->Win32Process, NULL, pW32Process); 02504 Win32FreePool(pW32Process); 02505 02506 /* 02507 * Release the handle flags lock. 02508 */ 02509 LeaveHandleFlagsCrit(); 02510 } 02511 02512 END_REENTERCRIT(); 02513 } 02514 02515 /***************************************************************************\ 02516 * FLastGuiThread 02517 * 02518 * Check if this is the last GUI thread in the process. 02519 \***************************************************************************/ 02520 02521 __inline BOOL FLastGuiThread(PTHREADINFO pti) 02522 { 02523 return (pti->ppi && 02524 pti->ppi->ptiList == pti && 02525 pti->ptiSibling == NULL); 02526 } 02527 02528 /***************************************************************************\ 02529 * xxxDestroyThreadInfo 02530 * 02531 * Destroys a THREADINFO created by xxxCreateThreadInfo(). 02532 * 02533 * Note that the current pti can be locked so it might be used after this 02534 * function returns, eventhough the thread execution has ended. 02535 * We want to stop any activity on this thread so we clean up any USER stuff 02536 * like messages, clipboard, queue, etc and specially anything that assumes 02537 * to be running on a Win32 thread and client side stuff. 02538 * The final cleanup will take place in UserDeleteW32Thread 02539 * 02540 * This function must not go into the user mode because the ntos data 02541 * structures may no longer support it and it may bluescreen the system. 02542 * 02543 * Make all callbacks before the thread objects are destroyed. If you callback 02544 * afterwards, new objects might be created and won't be cleaned up. 02545 * 02546 * History: 02547 * 02-15-91 DarrinM Created. 02548 * 02-27-91 mikeke Made it work 02549 * 02-27-91 Mikehar Removed queue from the global list 02550 \***************************************************************************/ 02551 02552 VOID xxxDestroyThreadInfo(VOID) 02553 { 02554 PTHREADINFO ptiCurrent; 02555 PTHREADINFO *ppti; 02556 02557 ptiCurrent = PtiCurrent(); 02558 UserAssert (ptiCurrent != NULL); 02559 UserAssert(IsWinEventNotifyDeferredOK()); 02560 02561 /* 02562 * If this thread is blocking input, stop it 02563 */ 02564 if (gptiBlockInput == ptiCurrent) { 02565 gptiBlockInput = NULL; 02566 } 02567 02568 /* 02569 * Don't mess with this ptiCurrent anymore. 02570 */ 02571 ptiCurrent->TIF_flags |= (TIF_DONTATTACHQUEUE | TIF_INCLEANUP); 02572 02573 /* 02574 * First do any preparation work: windows need to be "patched" so that 02575 * their window procs point to server only windowprocs, for example. 02576 */ 02577 PatchThreadWindows(ptiCurrent); 02578 02579 /* 02580 * If this thread terminated abnormally and was tracking tell 02581 * GDI to hide the trackrect. 02582 */ 02583 if (ptiCurrent->pmsd != NULL) { 02584 xxxCancelTrackingForThread(ptiCurrent); 02585 } 02586 02587 /* 02588 * Unlock the pmsd window. 02589 */ 02590 if (ptiCurrent->pmsd != NULL) { 02591 Unlock(&ptiCurrent->pmsd->spwnd); 02592 UserFreePool(ptiCurrent->pmsd); 02593 ptiCurrent->pmsd = NULL; 02594 } 02595 02596 /* 02597 * Free the clipboard if owned by this thread 02598 */ 02599 { 02600 PWINDOWSTATION pwinsta; 02601 pwinsta = _GetProcessWindowStation(NULL); 02602 if (pwinsta != NULL) { 02603 if (pwinsta->ptiClipLock == ptiCurrent) { 02604 xxxCloseClipboard(pwinsta); 02605 } 02606 if (pwinsta->ptiDrawingClipboard == ptiCurrent) { 02607 pwinsta->ptiDrawingClipboard = NULL; 02608 } 02609 } 02610 } 02611 02612 /* 02613 * Unlock all the objects stored in the menustate structure 02614 */ 02615 while (ptiCurrent->pMenuState != NULL) { 02616 PMENUSTATE pMenuState; 02617 PPOPUPMENU ppopupmenuRoot; 02618 02619 pMenuState = ptiCurrent->pMenuState; 02620 ppopupmenuRoot = pMenuState->pGlobalPopupMenu; 02621 02622 /* 02623 * If menu mode was running on this thread 02624 */ 02625 if (ptiCurrent == pMenuState->ptiMenuStateOwner) { 02626 /* 02627 * The menu's going away, so anyone who's locked it 02628 * is SOL anyway. Bug #375467. 02629 */ 02630 pMenuState->dwLockCount = 0; 02631 02632 /* 02633 * Close this menu. 02634 */ 02635 if (pMenuState->fModelessMenu) { 02636 xxxEndMenuLoop(pMenuState, ppopupmenuRoot); 02637 xxxMNEndMenuState(TRUE); 02638 } else { 02639 pMenuState->fInsideMenuLoop = FALSE; 02640 ptiCurrent->pq->QF_flags &= ~QF_CAPTURELOCKED; 02641 xxxMNCloseHierarchy(ppopupmenuRoot, pMenuState); 02642 xxxMNEndMenuState(ppopupmenuRoot->fIsMenuBar || ppopupmenuRoot->fDestroyed); 02643 } 02644 } else { 02645 /* 02646 * Menu mode is running on another thread. This thread 02647 * must own spwndNotify which is going away soon. 02648 * When spwndNotify is destroyed, we will clean up pMenuState 02649 * from this pti. So do nothing now as we'll need this 02650 * pMenuState at that time. 02651 */ 02652 UserAssert((ppopupmenuRoot->spwndNotify != NULL) 02653 && (GETPTI(ppopupmenuRoot->spwndNotify) == ptiCurrent)); 02654 02655 /* 02656 * Nested menus are not supposed to involve multiple threads 02657 */ 02658 UserAssert(pMenuState->pmnsPrev == NULL); 02659 break; 02660 } 02661 02662 } /* while (ptiCurrent->pMenuState != NULL) */ 02663 02664 #if DBG 02665 /* 02666 * This thread must not be using the desktop menu 02667 */ 02668 if ((ptiCurrent->rpdesk != NULL) && (ptiCurrent->rpdesk->spwndMenu != NULL)) { 02669 UserAssert(ptiCurrent != GETPTI(ptiCurrent->rpdesk->spwndMenu)); 02670 } 02671 #endif 02672 02673 /* 02674 * Unlock all the objects stored in the sbstate structure. 02675 */ 02676 if (ptiCurrent->pSBTrack) { 02677 Unlock(&ptiCurrent->pSBTrack->spwndSB); 02678 Unlock(&ptiCurrent->pSBTrack->spwndSBNotify); 02679 Unlock(&ptiCurrent->pSBTrack->spwndTrack); 02680 UserFreePool(ptiCurrent->pSBTrack); 02681 ptiCurrent->pSBTrack = NULL; 02682 } 02683 02684 /* 02685 * If this is the main input thread of this application, zero out 02686 * that field. 02687 */ 02688 if (ptiCurrent->ppi != NULL && ptiCurrent->ppi->ptiMainThread == ptiCurrent) 02689 ptiCurrent->ppi->ptiMainThread = NULL; 02690 02691 while (ptiCurrent->psiiList != NULL) { 02692 xxxDestroyThreadDDEObject(ptiCurrent, ptiCurrent->psiiList); 02693 } 02694 02695 if (ptiCurrent->TIF_flags & TIF_PALETTEAWARE) { 02696 PWND pwnd; 02697 TL tlpwnd; 02698 02699 UserAssert(ptiCurrent->rpdesk != NULL); 02700 02701 pwnd = ptiCurrent->rpdesk->pDeskInfo->spwnd; 02702 02703 ThreadLock(pwnd, &tlpwnd); 02704 xxxFlushPalette(pwnd); 02705 ThreadUnlock(&tlpwnd); 02706 } 02707 02708 /* 02709 * If this is the last GUI thread for the process that made a temporary 02710 * (fullscreen) mode change, restore the mode to what's in the registry. 02711 */ 02712 if (FLastGuiThread(ptiCurrent) && (gppiFullscreen == ptiCurrent->ppi)) { 02713 xxxUserChangeDisplaySettings(NULL, NULL, NULL, NULL, 0, 0, KernelMode); 02714 02715 UserAssert(gppiFullscreen != ptiCurrent->ppi); 02716 } 02717 02718 /*******************************************************************************************\ 02719 * * 02720 * CLEANING THREAD OBJECTS. AVOID CALLING BACK AFTER THIS POINT * 02721 * New objects might be created while calling back and won't be cleaned up * 02722 * * 02723 \*******************************************************************************************/ 02724 02725 /* 02726 * This thread might have some outstanding timers. Destroy them 02727 */ 02728 DestroyThreadsTimers(ptiCurrent); 02729 02730 /* 02731 * Free any windows hooks this thread has created. 02732 */ 02733 FreeThreadsWindowHooks(); 02734 02735 /* 02736 * Free any hwnd lists the thread was using 02737 */ 02738 { 02739 PBWL pbwl, pbwlNext; 02740 for (pbwl = gpbwlList; pbwl != NULL; ) { 02741 pbwlNext = pbwl->pbwlNext; 02742 if (pbwl->ptiOwner == ptiCurrent) { 02743 FreeHwndList(pbwl); 02744 } 02745 pbwl = pbwlNext; 02746 } 02747 } 02748 02749 /* 02750 * Destroy all the public objects created by this thread. 02751 */ 02752 DestroyThreadsHotKeys(); 02753 02754 DestroyThreadsObjects(); 02755 02756 /* 02757 * Free any synchronous Notifies pending for this thread and 02758 * free any Win Event Hooks this thread created. 02759 */ 02760 FreeThreadsWinEvents(ptiCurrent); 02761 02762 /* 02763 * Unlock the keyboard layouts here 02764 */ 02765 Unlock(&ptiCurrent->spklActive); 02766 02767 /* 02768 * Cleanup the global resources if this is the last GUI 02769 * thread for this session 02770 */ 02771 if (gdwGuiThreads == 1) { 02772 CleanupResources(); 02773 } 02774 02775 02776 if (FLastGuiThread(ptiCurrent)) { 02777 02778 /* 02779 * Check if this was a setup app. 02780 */ 02781 if (ptiCurrent->ppi->W32PF_Flags & W32PF_SETUPAPP) { 02782 PDESKTOPINFO pdeskinfo = GETDESKINFO(ptiCurrent); 02783 if (pdeskinfo->spwndShell) { 02784 _PostMessage(pdeskinfo->spwndShell, DTM_SETUPAPPRAN, 0, 0); 02785 } 02786 } 02787 02788 DestroyProcessesClasses(ptiCurrent->ppi); 02789 ptiCurrent->ppi->W32PF_Flags &= ~(W32PF_CLASSESREGISTERED); 02790 02791 02792 DestroyProcessesObjects(ptiCurrent->ppi); 02793 } 02794 02795 #ifdef FE_IME 02796 /* 02797 * Unlock default input context. 02798 */ 02799 Unlock(&ptiCurrent->spDefaultImc); 02800 #endif 02801 02802 if (ptiCurrent->pq != NULL) { 02803 /* 02804 * Remove this thread's cursor count from the queue. 02805 */ 02806 ptiCurrent->pq->iCursorLevel -= ptiCurrent->iCursorLevel; 02807 02808 /* 02809 * Have to recalc queue ownership after this thread 02810 * leaves if it is a member of a shared input queue. 02811 */ 02812 if (ptiCurrent->pq->cThreads != 1) 02813 { 02814 gpdeskRecalcQueueAttach = ptiCurrent->rpdesk; 02815 /* 02816 * Because we are in thread cleanup, we won't callback due 02817 * to WinEvents (zzzSetFMouseMoved calls zzzUpdateCursorImage) 02818 */ 02819 UserAssert(ptiCurrent->TIF_flags & TIF_INCLEANUP); 02820 UserAssert(gbExitInProgress == FALSE); 02821 zzzSetFMouseMoved(); 02822 } 02823 } 02824 02825 /* 02826 * Remove from the process' list, also. 02827 */ 02828 ppti = &PpiCurrent()->ptiList; 02829 if (*ppti != NULL) { 02830 while (*ppti != ptiCurrent && (*ppti)->ptiSibling != NULL) { 02831 ppti = &((*ppti)->ptiSibling); 02832 } 02833 if (*ppti == ptiCurrent) { 02834 *ppti = ptiCurrent->ptiSibling; 02835 ptiCurrent->ptiSibling = NULL; 02836 } 02837 } 02838 02839 { 02840 PDESKTOP rpdesk; 02841 PATTACHINFO *ppai; 02842 02843 /* 02844 * Temporarily lock the desktop until the THREADINFO structure is 02845 * freed. Note that locking a NULL ptiCurrent->rpdesk is OK. Use a 02846 * normal lock instead of a thread lock because the lock must 02847 * exist past the freeing of the ptiCurrent. 02848 */ 02849 rpdesk = NULL; 02850 LockDesktop(&rpdesk, ptiCurrent->rpdesk, LDL_FN_DESTROYTHREADINFO, (ULONG_PTR)PtiCurrent()); 02851 02852 /* 02853 * Cleanup SMS structures attached to this thread. Handles both 02854 * pending send and receive messages. MUST make sure we do SendMsgCleanup 02855 * AFTER window cleanup. 02856 */ 02857 SendMsgCleanup(ptiCurrent); 02858 02859 02860 /* 02861 * Allow this thread to be swapped 02862 */ 02863 if (ptiCurrent->cEnterCount) { 02864 BOOLEAN bool; 02865 02866 RIPMSG1(RIP_WARNING, "Thread exiting with stack locked. pti:%#p\n", ptiCurrent); 02867 bool = KeSetKernelStackSwapEnable(TRUE); 02868 ptiCurrent->cEnterCount = 0; 02869 UserAssert(!bool); 02870 } 02871 02872 if (ptiCurrent->ppi != NULL) { 02873 ptiCurrent->ppi->cThreads--; 02874 UserAssert(ptiCurrent->ppi->cThreads >= 0); 02875 } 02876 02877 /* 02878 * If this thread is a win16 task, remove it from the scheduler. 02879 */ 02880 if (ptiCurrent->TIF_flags & TIF_16BIT) { 02881 if ((ptiCurrent->ptdb) && (ptiCurrent->ptdb->hTaskWow != 0)) { 02882 _WOWCleanup(NULL, ptiCurrent->ptdb->hTaskWow); 02883 } 02884 DestroyTask(ptiCurrent->ppi, ptiCurrent); 02885 } 02886 02887 if (ptiCurrent->hEventQueueClient != NULL) { 02888 ProtectHandle(ptiCurrent->hEventQueueClient, FALSE); 02889 ZwClose(ptiCurrent->hEventQueueClient); 02890 ptiCurrent->hEventQueueClient = NULL; 02891 } 02892 02893 02894 if (gspwndInternalCapture != NULL) { 02895 if (GETPTI(gspwndInternalCapture) == ptiCurrent) { 02896 Unlock(&gspwndInternalCapture); 02897 } 02898 } 02899 02900 /* 02901 * Set gptiForeground to NULL if equal to this pti before exiting 02902 * this routine. 02903 */ 02904 if (gptiForeground == ptiCurrent) { 02905 if (FWINABLE()) { 02906 /* 02907 * Post these (WEF_ASYNC), since we can't make callbacks from here. 02908 */ 02909 xxxWindowEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, INDEXID_CONTAINER, WEF_ASYNC); 02910 xxxWindowEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, INDEXID_CONTAINER, WEF_ASYNC); 02911 } 02912 02913 /* 02914 * Call the Shell to ask it to activate its main window. 02915 * This will be accomplished with a PostMessage() to itself, 02916 * so the actual activation will take place later. 02917 */ 02918 UserAssert(rpdesk != NULL); 02919 02920 if (rpdesk->pDeskInfo->spwndProgman) 02921 _PostMessage(rpdesk->pDeskInfo->spwndProgman, guiActivateShellWindow, 0, 0); 02922 02923 /* 02924 * Set gptiForeground to NULL because we're destroying it. 02925 */ 02926 SetForegroundThread(NULL); 02927 02928 /* 02929 * If this thread is attached to gpqForeground AND it's the 02930 * last thread in the queue, then zzzDestroyQueue will NULL out 02931 * qpqForeground. Due to journalling attaching, gptiForegrouund 02932 * is not always attached to gpqForeground. This is one reason 02933 * why we no longer NULL out gpqForeground as stated in the old 02934 * comment. The other reason is that there might be other threads 02935 * in the foreground queue so there is no need to zap it. This was 02936 * messing up MsTest (now called VisualTest) 02937 * This is the old comment: 02938 * "Since gpqForeground is derived from the foreground thread 02939 * structure, set it to NULL as well, since there now is no 02940 * foreground thread structure" 02941 * 02942 * qpqForeground = NULL; 02943 */ 02944 } 02945 02946 02947 /* 02948 * If this thread got the last input event, pass ownership to another 02949 * thread in this process or to the foreground thread. 02950 */ 02951 if (ptiCurrent == glinp.ptiLastWoken) { 02952 UserAssert(PpiCurrent() == ptiCurrent->ppi); 02953 if (ptiCurrent->ppi->ptiList != NULL) { 02954 UserAssert (ptiCurrent != ptiCurrent->ppi->ptiList); 02955 glinp.ptiLastWoken = ptiCurrent->ppi->ptiList; 02956 } else { 02957 glinp.ptiLastWoken = gptiForeground; 02958 } 02959 } 02960 02961 /* 02962 * Make sure none of the other global thread pointers are pointing to us. 02963 */ 02964 if (gptiShutdownNotify == ptiCurrent) { 02965 gptiShutdownNotify = NULL; 02966 } 02967 if (gptiTasklist == ptiCurrent) { 02968 gptiTasklist = NULL; 02969 } 02970 if (gHardErrorHandler.pti == ptiCurrent) { 02971 gHardErrorHandler.pti = NULL; 02972 } 02973 02974 /* 02975 * May be called from xxxCreateThreadInfo before the queue is created 02976 * so check for NULL queue. 02977 * Lock the queues since this pti might be locked. They will be unlocked 02978 * in UserDeleteW32Thread 02979 */ 02980 if (ptiCurrent->pq != NULL) { 02981 UserAssert(ptiCurrent->pq != ptiCurrent->pqAttach); 02982 DestroyThreadsMessages(ptiCurrent->pq, ptiCurrent); 02983 (ptiCurrent->pq->cLockCount)++; 02984 zzzDestroyQueue(ptiCurrent->pq, ptiCurrent); 02985 } 02986 02987 /* 02988 * zzzReattachThreads shouldn't call back while using pqAttach 02989 */ 02990 UserAssert(ptiCurrent->pqAttach == NULL); 02991 #if 0 02992 if (ptiCurrent->pqAttach != NULL) { 02993 DestroyThreadsMessages(ptiCurrent->pqAttach, ptiCurrent); 02994 (ptiCurrent->pqAttach->cLockCount)++; 02995 zzzDestroyQueue(ptiCurrent->pqAttach, ptiCurrent); 02996 } 02997 #endif 02998 02999 /* 03000 * Remove the pti from its pti list and reset the pointers. 03001 */ 03002 if (ptiCurrent->rpdesk != NULL) { 03003 RemoveEntryList(&ptiCurrent->PtiLink); 03004 InitializeListHead(&ptiCurrent->PtiLink); 03005 } 03006 03007 FreeMessageList(&ptiCurrent->mlPost); 03008 03009 /* 03010 * Free any attachinfo structures pointing to this thread 03011 */ 03012 ppai = &gpai; 03013 while ((*ppai) != NULL) { 03014 if ((*ppai)->pti1 == ptiCurrent || (*ppai)->pti2 == ptiCurrent) { 03015 PATTACHINFO paiKill = *ppai; 03016 *ppai = (*ppai)->paiNext; 03017 UserFreePool((HLOCAL)paiKill); 03018 } else { 03019 ppai = &(*ppai)->paiNext; 03020 } 03021 } 03022 03023 /* 03024 * Change ownership of any objects that didn't get freed (because they 03025 * are locked or we have a bug and the object didn't get destroyed). 03026 */ 03027 MarkThreadsObjects(ptiCurrent); 03028 03029 /* 03030 * Free thread information visible from client 03031 */ 03032 if (rpdesk && ptiCurrent->pcti != NULL && ptiCurrent->pcti != &(ptiCurrent->cti)) { 03033 DesktopFree(rpdesk, ptiCurrent->pcti); 03034 ptiCurrent->pcti = &(ptiCurrent->cti); 03035 } 03036 03037 /* 03038 * Free the client info for system threads 03039 */ 03040 if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD && ptiCurrent->pClientInfo != NULL) { 03041 UserFreePool(ptiCurrent->pClientInfo); 03042 ptiCurrent->pClientInfo = NULL; 03043 } 03044 03045 /* 03046 * Unlock the temporary desktop lock. ptiCurrent->rpdesk is still locked 03047 * and will be unlocked in UserDeleteW32Thread. 03048 */ 03049 UnlockDesktop(&rpdesk, LDU_FN_DESTROYTHREADINFO, (ULONG_PTR)PtiCurrent()); 03050 } 03051 03052 /* 03053 * One more thread died. 03054 */ 03055 gdwGuiThreads--; 03056 } 03057 03058 03059 /***************************************************************************\ 03060 * CleanEventMessage 03061 * 03062 * This routine takes a message and destroys and event message related pieces, 03063 * which may be allocated. 03064 * 03065 * 12-10-92 ScottLu Created. 03066 \***************************************************************************/ 03067 03068 void CleanEventMessage( 03069 PQMSG pqmsg) 03070 { 03071 PASYNCSENDMSG pmsg; 03072 03073 /* 03074 * Certain special messages on the INPUT queue have associated 03075 * bits of memory that need to be freed. 03076 */ 03077 switch (pqmsg->dwQEvent) { 03078 case QEVENT_SETWINDOWPOS: 03079 UserFreePool((PSMWP)pqmsg->msg.wParam); 03080 break; 03081 03082 case QEVENT_UPDATEKEYSTATE: 03083 UserFreePool((PBYTE)pqmsg->msg.wParam); 03084 break; 03085 03086 case QEVENT_NOTIFYWINEVENT: 03087 DestroyNotify((PNOTIFY)pqmsg->msg.lParam); 03088 break; 03089 03090 case QEVENT_ASYNCSENDMSG: 03091 pmsg = (PASYNCSENDMSG)pqmsg->msg.wParam; 03092 UserDeleteAtom((ATOM)pmsg->lParam); 03093 UserFreePool(pmsg); 03094 break; 03095 } 03096 } 03097 03098 /***************************************************************************\ 03099 * FreeMessageList 03100 * 03101 * History: 03102 * 02-27-91 mikeke Created. 03103 * 11-03-92 scottlu Changed to work with MLIST structure. 03104 \***************************************************************************/ 03105 03106 VOID FreeMessageList( 03107 PMLIST pml) 03108 { 03109 PQMSG pqmsg; 03110 03111 DebugValidateMLIST(pml); 03112 03113 while ((pqmsg = pml->pqmsgRead) != NULL) { 03114 CleanEventMessage(pqmsg); 03115 DelQEntry(pml, pqmsg); 03116 } 03117 03118 DebugValidateMLIST(pml); 03119 } 03120 03121 /***************************************************************************\ 03122 * DestroyThreadsMessages 03123 * 03124 * History: 03125 * 02-21-96 jerrysh Created. 03126 \***************************************************************************/ 03127 03128 VOID DestroyThreadsMessages( 03129 PQ pq, 03130 PTHREADINFO pti) 03131 { 03132 PQMSG pqmsg; 03133 PQMSG pqmsgNext; 03134 03135 DebugValidateMLIST(&pq->mlInput); 03136 03137 pqmsg = pq->mlInput.pqmsgRead; 03138 while (pqmsg != NULL) { 03139 pqmsgNext = pqmsg->pqmsgNext; 03140 if (pqmsg->pti == pti) { 03141 /* 03142 * Make sure we don't leave any bogus references to this message 03143 * lying around. 03144 */ 03145 if (pq->idSysPeek == (ULONG_PTR)pqmsg) { 03146 CheckPtiSysPeek(8, pq, 0); 03147 pq->idSysPeek = 0; 03148 } 03149 CleanEventMessage(pqmsg); 03150 DelQEntry(&pq->mlInput, pqmsg); 03151 } 03152 pqmsg = pqmsgNext; 03153 } 03154 03155 DebugValidateMLIST(&pq->mlInput); 03156 } 03157 03158 /***************************************************************************\ 03159 * InitQEntryLookaside 03160 * 03161 * Initializes the Q entry lookaside list. This improves Q entry locality 03162 * by keeping Q entries in a single page 03163 * 03164 * 09-09-93 Markl Created. 03165 \***************************************************************************/ 03166 03167 03168 NTSTATUS 03169 InitQEntryLookaside() 03170 { 03171 QEntryLookaside = UserAllocPoolNonPaged(sizeof(PAGED_LOOKASIDE_LIST), TAG_LOOKASIDE); 03172 if (QEntryLookaside == NULL) { 03173 return STATUS_NO_MEMORY; 03174 } 03175 03176 ExInitializePagedLookasideList(QEntryLookaside, 03177 NULL, 03178 NULL, 03179 SESSION_POOL_MASK, 03180 sizeof(QMSG), 03181 TAG_QMSG, 03182 16); 03183 03184 QLookaside = UserAllocPoolNonPaged(sizeof(PAGED_LOOKASIDE_LIST), TAG_LOOKASIDE); 03185 if (QLookaside == NULL) { 03186 return STATUS_NO_MEMORY; 03187 } 03188 03189 ExInitializePagedLookasideList(QLookaside, 03190 NULL, 03191 NULL, 03192 SESSION_POOL_MASK, 03193 sizeof(Q), 03194 TAG_Q, 03195 16); 03196 return STATUS_SUCCESS; 03197 } 03198 03199 /***************************************************************************\ 03200 * AllocQEntry 03201 * 03202 * Allocates a message on a message list. DelQEntry deletes a message 03203 * on a message list. 03204 * 03205 * 10-22-92 ScottLu Created. 03206 \***************************************************************************/ 03207 03208 PQMSG AllocQEntry( 03209 PMLIST pml) 03210 { 03211 PQMSG pqmsg; 03212 03213 DebugValidateMLIST(pml); 03214 03215 if (pml->cMsgs >= gUserPostMessageLimit) { 03216 RIPMSG3(RIP_WARNING, "AllocQEntry: # of post messages exceeds the limit(%d) in pti=0x%p, pml=0x%p", 03217 gUserPostMessageLimit, W32GetCurrentThread(), pml); 03218 return NULL; 03219 } 03220 03221 /* 03222 * Allocate a Q message structure. 03223 */ 03224 if ((pqmsg = ExAllocateFromPagedLookasideList(QEntryLookaside)) == NULL) { 03225 return NULL; 03226 } 03227 03228 RtlZeroMemory(pqmsg, sizeof(*pqmsg)); 03229 03230 if (pml->pqmsgWriteLast != NULL) { 03231 pml->pqmsgWriteLast->pqmsgNext = pqmsg; 03232 pqmsg->pqmsgPrev = pml->pqmsgWriteLast; 03233 pml->pqmsgWriteLast = pqmsg; 03234 } else { 03235 pml->pqmsgWriteLast = pml->pqmsgRead = pqmsg; 03236 } 03237 03238 pml->cMsgs++; 03239 03240 DebugValidateMLISTandQMSG(pml, pqmsg); 03241 03242 return pqmsg; 03243 } 03244 03245 /***************************************************************************\ 03246 * DelQEntry 03247 * 03248 * Simply removes a message from a message queue list. 03249 * 03250 * 10-20-92 ScottLu Created. 03251 \***************************************************************************/ 03252 03253 void DelQEntry( 03254 PMLIST pml, 03255 PQMSG pqmsg) 03256 { 03257 DebugValidateMLISTandQMSG(pml, pqmsg); 03258 UserAssert((int)pml->cMsgs > 0); 03259 UserAssert(pml->pqmsgRead); 03260 UserAssert(pml->pqmsgWriteLast); 03261 03262 /* 03263 * Unlink this pqmsg from the message list. 03264 */ 03265 if (pqmsg->pqmsgPrev != NULL) 03266 pqmsg->pqmsgPrev->pqmsgNext = pqmsg->pqmsgNext; 03267 03268 if (pqmsg->pqmsgNext != NULL) 03269 pqmsg->pqmsgNext->pqmsgPrev = pqmsg->pqmsgPrev; 03270 03271 /* 03272 * Update the read/write pointers if necessary. 03273 */ 03274 if (pml->pqmsgRead == pqmsg) 03275 pml->pqmsgRead = pqmsg->pqmsgNext; 03276 03277 if (pml->pqmsgWriteLast == pqmsg) 03278 pml->pqmsgWriteLast = pqmsg->pqmsgPrev; 03279 03280 /* 03281 * Adjust the message count and free the message structure. 03282 */ 03283 pml->cMsgs--; 03284 03285 ExFreeToPagedLookasideList(QEntryLookaside, pqmsg); 03286 03287 DebugValidateMLIST(pml); 03288 } 03289 03290 /***************************************************************************\ 03291 * CheckRemoveHotkeyBit 03292 * 03293 * We have a special bit for the WM_HOTKEY message - QS_HOTKEY. When there 03294 * is a WM_HOTKEY message in the queue, that bit is on. When there isn't, 03295 * that bit is off. This checks for more than one hot key, because the one 03296 * is about to be deleted. If there is only one, the hot key bits are cleared. 03297 * 03298 * 11-12-92 ScottLu Created. 03299 \***************************************************************************/ 03300 03301 void CheckRemoveHotkeyBit( 03302 PTHREADINFO pti, 03303 PMLIST pml) 03304 { 03305 PQMSG pqmsg; 03306 DWORD cHotkeys; 03307 03308 /* 03309 * Remove the QS_HOTKEY bit if there is only one WM_HOTKEY message 03310 * in this message list. 03311 */ 03312 cHotkeys = 0; 03313 for (pqmsg = pml->pqmsgRead; pqmsg != NULL; pqmsg = pqmsg->pqmsgNext) { 03314 if (pqmsg->msg.message == WM_HOTKEY) 03315 cHotkeys++; 03316 } 03317 03318 /* 03319 * If there is 1 or fewer hot keys, remove the hotkey bits. 03320 */ 03321 if (cHotkeys <= 1) { 03322 pti->pcti->fsWakeBits &= ~QS_HOTKEY; 03323 pti->pcti->fsChangeBits &= ~QS_HOTKEY; 03324 } 03325 } 03326 03327 /***************************************************************************\ 03328 * FindQMsg 03329 * 03330 * Finds a qmsg that fits the filters by looping through the message list. 03331 * 03332 * 10-20-92 ScottLu Created. 03333 * 06-06-97 CLupu added processing for WM_DDE_ACK messages 03334 \***************************************************************************/ 03335 03336 PQMSG FindQMsg( 03337 PTHREADINFO pti, 03338 PMLIST pml, 03339 PWND pwndFilter, 03340 UINT msgMin, 03341 UINT msgMax, 03342 BOOL bProcessAck) 03343 { 03344 PWND pwnd; 03345 PQMSG pqmsgRead; 03346 PQMSG pqmsgRet = NULL; 03347 UINT message; 03348 03349 DebugValidateMLIST(pml); 03350 03351 pqmsgRead = pml->pqmsgRead; 03352 03353 while (pqmsgRead != NULL) { 03354 03355 /* 03356 * Make sure this window is valid and doesn't have the destroy 03357 * bit set (don't want to send it to any client side window procs 03358 * if destroy window has been called on it). 03359 */ 03360 pwnd = RevalidateHwnd(pqmsgRead->msg.hwnd); 03361 03362 if (pwnd == NULL && pqmsgRead->msg.hwnd != NULL) { 03363 /* 03364 * If we're removing a WM_HOTKEY message, we may need to 03365 * clear the QS_HOTKEY bit, since we have a special bit 03366 * for that message. 03367 */ 03368 if (pqmsgRead->msg.message == WM_HOTKEY) { 03369 CheckRemoveHotkeyBit(pti, pml); 03370 } 03371 /* 03372 * If the current thread's queue is locked waiting for this message, 03373 * we have to unlock it because we're eating the message. If there's 03374 * no more input/messages for this thread, the thread is going to 03375 * sleep; hence there might not be a next Get/PeekMessage call to 03376 * unlock the queue (ie, updating pti->idLast is not enough); 03377 * so we must unlock it now. 03378 * Win95 doesn't have this problem because their FindQMsg doesn't 03379 * eat messages; they call ReadPostMessage from FreeWindow 03380 * to take care of this scenario (== message for a destroyed window). 03381 * We could also do this if we have some problems with this fix. 03382 */ 03383 if ((pti->pq->idSysLock == (ULONG_PTR)pqmsgRead) 03384 && (pti->pq->ptiSysLock == pti)) { 03385 /* CheckSysLock(What number?, pti->pq, NULL); */ 03386 RIPMSG2(RIP_VERBOSE, "FindQMsg: Unlocking queue:%#p. Msg:%#lx", 03387 pti->pq, pqmsgRead->msg.message); 03388 pti->pq->ptiSysLock = NULL; 03389 } 03390 03391 DelQEntry(pml, pqmsgRead); 03392 goto nextMsgFromPml; 03393 } 03394 03395 /* 03396 * Process the WM_DDE_ACK messages if bProcessAck is set. 03397 */ 03398 if (bProcessAck && (PtoH(pwndFilter) == pqmsgRead->msg.hwnd) && 03399 (pqmsgRead->msg.message == (WM_DDE_ACK | MSGFLAG_DDE_MID_THUNK))) { 03400 03401 PXSTATE pxs; 03402 03403 pxs = (PXSTATE)HMValidateHandleNoRip((HANDLE)pqmsgRead->msg.lParam, TYPE_DDEXACT); 03404 03405 if (pxs != NULL && (pxs->flags & XS_FREEPXS)) { 03406 FreeDdeXact(pxs); 03407 DelQEntry(pml, pqmsgRead); 03408 goto nextMsgFromPml; 03409 } 03410 } 03411 03412 /* 03413 * Make sure this message fits both window handle and message 03414 * filters. 03415 */ 03416 if (!CheckPwndFilter(pwnd, pwndFilter)) 03417 goto nextMsg; 03418 03419 /* 03420 * If this is a fixed up dde message, then turn it into a normal 03421 * dde message for the sake of message filtering. 03422 */ 03423 message = pqmsgRead->msg.message; 03424 if (CheckMsgFilter(message, 03425 (WM_DDE_FIRST + 1) | MSGFLAG_DDE_MID_THUNK, 03426 WM_DDE_LAST | MSGFLAG_DDE_MID_THUNK)) { 03427 message = message & ~MSGFLAG_DDE_MID_THUNK; 03428 } 03429 03430 if (!CheckMsgFilter(message, msgMin, msgMax)) 03431 goto nextMsg; 03432 03433 /* 03434 * Found it. If bProcessAck is set, remember this pointer and go on 03435 * till we finish walking the list to process all WM_DDE_ACK messages. 03436 */ 03437 if (!bProcessAck) { 03438 DebugValidateMLIST(pml); 03439 return pqmsgRead; 03440 } 03441 03442 if (pqmsgRet == NULL) { 03443 pqmsgRet = pqmsgRead; 03444 } 03445 nextMsg: 03446 pqmsgRead = pqmsgRead->pqmsgNext; 03447 continue; 03448 03449 nextMsgFromPml: 03450 pqmsgRead = pml->pqmsgRead; 03451 continue; 03452 } 03453 03454 DebugValidateMLIST(pml); 03455 return pqmsgRet; 03456 } 03457 03458 /***************************************************************************\ 03459 * CheckQuitMessage 03460 * 03461 * Checks to see if a WM_QUIT message should be generated. 03462 * 03463 * 11-06-92 ScottLu Created. 03464 \***************************************************************************/ 03465 03466 BOOL CheckQuitMessage( 03467 PTHREADINFO pti, 03468 LPMSG lpMsg, 03469 BOOL fRemoveMsg) 03470 { 03471 /* 03472 * If there are no more posted messages in the queue and cQuit is != 03473 * 0, then generate a quit! 03474 */ 03475 if (pti->cQuit != 0 && pti->mlPost.cMsgs == 0) { 03476 /* 03477 * If we're "removing" the quit, set cQuit to 0 so another one isn't 03478 * generated. 03479 */ 03480 if (fRemoveMsg) 03481 pti->cQuit = 0; 03482 StoreMessage(lpMsg, NULL, WM_QUIT, (DWORD)pti->exitCode, 0, 0); 03483 return TRUE; 03484 } 03485 03486 return FALSE; 03487 } 03488 03489 03490 /***************************************************************************\ 03491 * ReadPostMessage 03492 * 03493 * If queue is not empty, read message satisfying filter conditions from 03494 * this queue to *lpMsg. This routine is used for the POST MESSAGE list only!! 03495 * 03496 * 10-19-92 ScottLu Created. 03497 \***************************************************************************/ 03498 03499 BOOL xxxReadPostMessage( 03500 PTHREADINFO pti, 03501 LPMSG lpMsg, 03502 PWND pwndFilter, 03503 UINT msgMin, 03504 UINT msgMax, 03505 BOOL fRemoveMsg) 03506 { 03507 PQMSG pqmsg; 03508 PMLIST pmlPost; 03509 03510 /* 03511 * Check to see if it is time to generate a quit message. 03512 */ 03513 if (CheckQuitMessage(pti, lpMsg, fRemoveMsg)) 03514 return TRUE; 03515 03516 /* 03517 * Loop through the messages in this list looking for the one that 03518 * fits the passed in filters. 03519 */ 03520 pmlPost = &pti->mlPost; 03521 pqmsg = FindQMsg(pti, pmlPost, pwndFilter, msgMin, msgMax, FALSE); 03522 if (pqmsg == NULL) { 03523 /* 03524 * Check again for quit... FindQMsg deletes some messages 03525 * in some instances, so we may match the conditions 03526 * for quit generation here. 03527 */ 03528 if (CheckQuitMessage(pti, lpMsg, fRemoveMsg)) 03529 return TRUE; 03530 } else { 03531 /* 03532 * Update the thread info fields with the info from this qmsg. 03533 */ 03534 pti->timeLast = pqmsg->msg.time; 03535 if (!RtlEqualMemory(&pti->ptLast, &pqmsg->msg.pt, sizeof(POINT))) { 03536 pti->TIF_flags |= TIF_MSGPOSCHANGED; 03537 } 03538 pti->ptLast = pqmsg->msg.pt; 03539 03540 pti->idLast = (ULONG_PTR)pqmsg; 03541 pti->pq->ExtraInfo = pqmsg->ExtraInfo; 03542 03543 /* 03544 * Are we supposed to yank out the message? If not, stick some 03545 * random id into idLast so we don't unlock the input queue until we 03546 * pull this message from the queue. 03547 */ 03548 *lpMsg = pqmsg->msg; 03549 if (!fRemoveMsg) { 03550 pti->idLast = 1; 03551 } else { 03552 /* 03553 * If we're removing a WM_HOTKEY message, we may need to 03554 * clear the QS_HOTKEY bit, since we have a special bit 03555 * for that message. 03556 */ 03557 if (pmlPost->pqmsgRead->msg.message == WM_HOTKEY) { 03558 CheckRemoveHotkeyBit(pti, pmlPost); 03559 } 03560 03561 03562 /* 03563 * Since we're removing an event from the queue, we 03564 * need to check priority. This resets the TIF_SPINNING 03565 * since we're no longer spinning. 03566 */ 03567 // We disable all MS badapp code and do it our way 03568 if (pti->TIF_flags & TIF_SPINNING) 03569 CheckProcessForeground(pti); 03570 03571 DelQEntry(pmlPost, pqmsg); 03572 } 03573 03574 /* 03575 * See if this is a dde message that needs to be fixed up. 03576 */ 03577 if (CheckMsgFilter(lpMsg->message, 03578 (WM_DDE_FIRST + 1) | MSGFLAG_DDE_MID_THUNK, 03579 WM_DDE_LAST | MSGFLAG_DDE_MID_THUNK)) { 03580 /* 03581 * Fixup the message value. 03582 */ 03583 lpMsg->message &= (UINT)~MSGFLAG_DDE_MID_THUNK; 03584 03585 /* 03586 * Call back the client to allocate the dde data for this message. 03587 */ 03588 xxxDDETrackGetMessageHook(lpMsg); 03589 03590 /* 03591 * Copy these values back into the queue if this message hasn't 03592 * been removed from the queue. Need to search through the 03593 * queue again because the pqmsg may have been removed when 03594 * we left the critical section above. 03595 */ 03596 if (!fRemoveMsg) { 03597 if (pqmsg == FindQMsg(pti, pmlPost, pwndFilter, msgMin, msgMax, FALSE)) { 03598 pqmsg->msg = *lpMsg; 03599 } 03600 } 03601 } 03602 #if DBG 03603 else if (CheckMsgFilter(lpMsg->message, WM_DDE_FIRST, WM_DDE_LAST)) { 03604 if (fRemoveMsg) { 03605 TraceDdeMsg(lpMsg->message, (HWND)lpMsg->wParam, lpMsg->hwnd, MSG_RECV); 03606 } else { 03607 TraceDdeMsg(lpMsg->message, (HWND)lpMsg->wParam, lpMsg->hwnd, MSG_PEEK); 03608 } 03609 } 03610 #endif 03611 } 03612 03613 /* 03614 * If there are no posted messages available, clear the post message 03615 * bit so we don't go looking for them again. 03616 */ 03617 if (pmlPost->cMsgs == 0 && pti->cQuit == 0) { 03618 pti->pcti->fsWakeBits &= ~(QS_POSTMESSAGE | QS_ALLPOSTMESSAGE); 03619 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE; 03620 } 03621 03622 return pqmsg != NULL; 03623 } 03624 03625 #ifdef HUNGAPP_GHOSTING 03626 03627 /***************************************************************************\ 03628 * xxxProcessHungThreadEvent 03629 * 03630 * We check when a thread gets unhung when it reads the posted queue message. 03631 * 03632 * 6-10-99 vadimg created 03633 \***************************************************************************/ 03634 03635 void xxxProcessHungThreadEvent(PWND pwnd) 03636 { 03637 PTHREADINFO ptiCurrent = PtiCurrent(); 03638 PWND pwndGhost; 03639 HWND hwnd; 03640 TL tlpwndT1, tlpwndT2; 03641 03642 CheckLock(pwnd); 03643 03644 /* 03645 * The app processed this queue message, so update time last read 03646 * used for hung app calculations. 03647 */ 03648 SET_TIME_LAST_READ(ptiCurrent); 03649 03650 pwndGhost = FindGhost(pwnd); 03651 03652 ThreadLockAlwaysWithPti(ptiCurrent, pwndGhost, &tlpwndT1); 03653 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT2); 03654 03655 if (pwndGhost != NULL) { 03656 PCHECKPOINT pcp, pcpGhost; 03657 03658 /* 03659 * Try to set the state of the hung window to the current state of 03660 * the ghost window. 03661 */ 03662 if (TestWF(pwndGhost, WFMAXIMIZED)) { 03663 xxxMinMaximize(pwnd, SW_MAXIMIZE, MINMAX_KEEPHIDDEN); 03664 } else if (TestWF(pwndGhost, WFMINIMIZED)) { 03665 xxxMinMaximize(pwnd, SW_SHOWMINNOACTIVE, MINMAX_KEEPHIDDEN); 03666 } else { 03667 DWORD dwFlags; 03668 PTHREADINFO pti = GETPTI(pwndGhost); 03669 03670 /* 03671 * If the ghost is the active foreground window, allow this 03672 * activation to bring the hung window to the foreground. 03673 */ 03674 if (pti->pq == gpqForeground && pti->pq->spwndActive == pwndGhost) { 03675 dwFlags = 0; 03676 GETPTI(pwnd)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 03677 } else { 03678 dwFlags = SWP_NOACTIVATE; 03679 } 03680 03681 /* 03682 * This will appropriately zorder, activate, and position the 03683 * hung window. 03684 */ 03685 xxxSetWindowPos(pwnd, pwndGhost, 03686 pwndGhost->rcWindow.left, pwndGhost->rcWindow.top, 03687 pwndGhost->rcWindow.right - pwndGhost->rcWindow.left, 03688 pwndGhost->rcWindow.bottom - pwndGhost->rcWindow.top, 03689 dwFlags); 03690 } 03691 03692 /* 03693 * Since the ghost window could've been minimized or maximized during 03694 * its lifetime, copy over the positioning checkpoint. 03695 */ 03696 if ((pcpGhost = (PCHECKPOINT)_GetProp(pwndGhost, 03697 PROP_CHECKPOINT, PROPF_INTERNAL)) != NULL) { 03698 03699 if ((pcp = (PCHECKPOINT)_GetProp(pwnd, 03700 PROP_CHECKPOINT, PROPF_INTERNAL)) == NULL) { 03701 pcp = CkptRestore(pwnd, &pwnd->rcWindow); 03702 } 03703 03704 if (pcp != NULL) { 03705 RtlCopyMemory(pcp, pcpGhost, sizeof(CHECKPOINT)); 03706 } 03707 } 03708 } 03709 03710 /* 03711 * Toggle the visible bit of the hung window and remove the ghost window 03712 * corresponding to this previously hung window. 03713 */ 03714 SetVisible(pwnd, SV_SET); 03715 RemoveGhost(pwnd); 03716 03717 /* 03718 * Make the shell aware again of the hung window. 03719 */ 03720 hwnd = PtoHq(pwnd); 03721 PostShellHookMessages(HSHELL_WINDOWCREATED, (LPARAM)hwnd); 03722 xxxCallHook(HSHELL_WINDOWCREATED, (WPARAM)hwnd, (LPARAM)0, WH_SHELL); 03723 03724 /* 03725 * Completely invalidate the hung window, since it became visible again. 03726 */ 03727 xxxRedrawWindow(pwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | 03728 RDW_ALLCHILDREN | RDW_FRAME); 03729 03730 ThreadUnlock(&tlpwndT2); 03731 ThreadUnlock(&tlpwndT1); 03732 } 03733 03734 #else // HUNGAPP_GHOSTING 03735 03736 void xxxProcessHungThreadEvent(PWND pwnd) 03737 { 03738 CheckLock(pwnd); 03739 03740 if (TestWF(pwnd, WFVISIBLE)) { 03741 RIPMSG0(RIP_WARNING, "xxxProcessHungThreadEvent: window is already visible"); 03742 } else { 03743 SetVisible(pwnd, SV_SET); 03744 03745 if (TestWF(pwnd, WFMINIMIZED)) { 03746 RIPMSG0(RIP_WARNING, "xxxProcessHungThreadEvent: window is already minmized"); 03747 } else { 03748 xxxMinMaximize(pwnd, SW_SHOWMINNOACTIVE, MINMAX_KEEPHIDDEN); 03749 } 03750 } 03751 } 03752 03753 #endif // HUNGAPP_GHOSTING 03754 03755 BEEPPROC pfnBP[] = { 03756 UpSiren, 03757 DownSiren, 03758 LowBeep, 03759 HighBeep, 03760 KeyClick}; 03761 03762 /***************************************************************************\ 03763 * xxxProcessEventMessage 03764 * 03765 * This handles our processing for 'event' messages. We return a BOOL 03766 * here telling the system whether or not to continue processing messages. 03767 * 03768 * History: 03769 * 06-17-91 DavidPe Created. 03770 \***************************************************************************/ 03771 03772 VOID xxxProcessEventMessage( 03773 PTHREADINFO ptiCurrent, 03774 PQMSG pqmsg) 03775 { 03776 PWND pwnd; 03777 TL tlpwndT; 03778 TL tlMsg; 03779 PQ pq; 03780 03781 UserAssert(IsWinEventNotifyDeferredOK()); 03782 UserAssert(ptiCurrent == PtiCurrent()); 03783 03784 ThreadLockPoolCleanup(ptiCurrent, pqmsg, &tlMsg, CleanEventMessage); 03785 03786 pq = ptiCurrent->pq; 03787 switch (pqmsg->dwQEvent) { 03788 case QEVENT_DESTROYWINDOW: 03789 /* 03790 * These events are posted from xxxDW_DestroyOwnedWindows 03791 * for owned windows that are not owned by the owner 03792 * window thread. 03793 */ 03794 pwnd = RevalidateHwnd((HWND)pqmsg->msg.wParam); 03795 if (pwnd != NULL) { 03796 if (!TestWF(pwnd, WFCHILD)) 03797 xxxDestroyWindow(pwnd); 03798 else { 03799 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 03800 xxxFreeWindow(pwnd, &tlpwndT); 03801 } 03802 } 03803 break; 03804 03805 case QEVENT_SHOWWINDOW: 03806 /* 03807 * These events are mainly used from within CascadeChildWindows() 03808 * and TileChildWindows() so that taskmgr doesn't hang while calling 03809 * these apis if it is trying to tile or cascade a hung application. 03810 */ 03811 /* The HIWORD of lParam now has the preserved state of gfAnimate at the 03812 * time of the call. 03813 */ 03814 pwnd = RevalidateHwnd((HWND)pqmsg->msg.wParam); 03815 if (pwnd != NULL && !TestWF(pwnd, WFINDESTROY)) { 03816 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 03817 xxxShowWindow(pwnd, (DWORD)pqmsg->msg.lParam); 03818 /* 03819 * If this is coming from an async SetWindowPlacement, update the 03820 * check point settings if the window is minimized. 03821 */ 03822 if ((pqmsg->msg.message & WPF_ASYNCWINDOWPLACEMENT) 03823 && TestWF(pwnd, WFMINIMIZED)) { 03824 03825 WPUpdateCheckPointSettings(pwnd, (UINT)pqmsg->msg.message); 03826 } 03827 ThreadUnlock(&tlpwndT); 03828 } 03829 break; 03830 03831 case QEVENT_NOTIFYWINEVENT: 03832 UserAssert(((PNOTIFY)pqmsg->msg.lParam)->dwWEFlags & WEF_POSTED); 03833 UserAssert(((PNOTIFY)pqmsg->msg.lParam)->dwWEFlags & WEF_ASYNC); 03834 xxxProcessNotifyWinEvent((PNOTIFY)pqmsg->msg.lParam); 03835 break; 03836 03837 case QEVENT_SETWINDOWPOS: 03838 /* 03839 * QEVENT_SETWINDOWPOS events are generated when a thread calls 03840 * SetWindowPos with a list of windows owned by threads other than 03841 * itself. This way all WINDOWPOSing on a window is done the thread 03842 * that owns (created) the window and we don't have any of those 03843 * nasty inter-thread synchronization problems. 03844 */ 03845 xxxProcessSetWindowPosEvent((PSMWP)pqmsg->msg.wParam); 03846 break; 03847 03848 case QEVENT_UPDATEKEYSTATE: 03849 /* 03850 * Update the local key state with the state from those 03851 * keys that have changed since the last time key state 03852 * was synchronized. 03853 */ 03854 ProcessUpdateKeyStateEvent(pq, (PBYTE)pqmsg->msg.wParam, (PBYTE)pqmsg->msg.wParam + CBKEYSTATE); 03855 break; 03856 03857 case QEVENT_ACTIVATE: 03858 { 03859 if (pqmsg->msg.lParam == 0) { 03860 03861 /* 03862 * Clear any visible tracking going on in system. We 03863 * only bother to do this if lParam == 0 since 03864 * xxxSetForegroundWindow2() deals with this in the 03865 * other case. 03866 */ 03867 xxxCancelTracking(); 03868 03869 /* 03870 * Remove the clip cursor rectangle - it is a global mode that 03871 * gets removed when switching. Also remove any LockWindowUpdate() 03872 * that's still around. 03873 */ 03874 zzzClipCursor(NULL); 03875 LockWindowUpdate2(NULL, TRUE); 03876 03877 /* 03878 * Reload pq because it may have changed. 03879 */ 03880 pq = ptiCurrent->pq; 03881 03882 /* 03883 * If this event didn't originate from an initializing app 03884 * coming to the foreground [wParam == 0] then go ahead 03885 * and check if there's already an active window and if so make 03886 * it visually active. Also make sure we're still the foreground 03887 * queue. 03888 */ 03889 if ((pqmsg->msg.wParam != 0) && (pq->spwndActive != NULL) && 03890 (pq == gpqForeground)) { 03891 PWND pwndActive; 03892 03893 ThreadLockAlwaysWithPti(ptiCurrent, pwndActive = pq->spwndActive, &tlpwndT); 03894 xxxSendMessage(pwndActive, WM_NCACTIVATE, TRUE, 0); 03895 xxxUpdateTray(pwndActive); 03896 xxxSetWindowPos(pwndActive, PWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 03897 ThreadUnlock(&tlpwndT); 03898 } else if (pq != gpqForeground) { 03899 03900 /* 03901 * If we're not being activated, make sure we don't become foreground. 03902 */ 03903 ptiCurrent->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE; 03904 TAGMSG1(DBGTAG_FOREGROUND, "xxxProcessEventMessage clear TIF %#p", ptiCurrent); 03905 ptiCurrent->ppi->W32PF_Flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE; 03906 TAGMSG1(DBGTAG_FOREGROUND, "xxxProcessEventMessage clear W32PF %#p", ptiCurrent->ppi); 03907 } 03908 03909 } else { 03910 03911 pwnd = RevalidateHwnd((HWND)pqmsg->msg.lParam); 03912 if (pwnd == NULL) 03913 break; 03914 03915 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 03916 03917 /* 03918 * If nobody is foreground, allow this app to become foreground. 03919 */ 03920 if (gpqForeground == NULL) { 03921 xxxSetForegroundWindow2(pwnd, ptiCurrent, 0); 03922 } else { 03923 if (pwnd != pq->spwndActive) { 03924 if (xxxActivateThisWindow(pwnd, (UINT)pqmsg->msg.wParam, 03925 (ATW_SETFOCUS | ATW_ASYNC) | 03926 ((pqmsg->msg.message & PEM_ACTIVATE_NOZORDER) ? ATW_NOZORDER : 0))) { 03927 03928 /* 03929 * This event was posted by SetForegroundWindow2 03930 * (i.e. pqmsg->msg.lParam != 0) so make sure 03931 * mouse is on this window. 03932 */ 03933 if (TestUP(ACTIVEWINDOWTRACKING)) { 03934 zzzActiveCursorTracking(pwnd); 03935 } 03936 } 03937 } else { 03938 BOOL fActive = (GETPTI(pwnd)->pq == gpqForeground); 03939 03940 xxxSendMessage(pwnd, WM_NCACTIVATE, 03941 (DWORD)(fActive), 0); 03942 if (fActive) { 03943 xxxUpdateTray(pwnd); 03944 } 03945 03946 /* 03947 * Only bring the window to the top if it is becoming active. 03948 */ 03949 if (fActive && !(pqmsg->msg.message & PEM_ACTIVATE_NOZORDER)) 03950 xxxSetWindowPos(pwnd, PWND_TOP, 0, 0, 0, 0, 03951 SWP_NOSIZE | SWP_NOMOVE); 03952 } 03953 } 03954 03955 /* 03956 * Check here to see if the window needs to be restored. This is a 03957 * hack so that we're compatible with what msmail expects out of 03958 * win3.1 alt-tab. msmail expects to always be active when it gets 03959 * asked to be restored. This will ensure that during alt-tab 03960 * activate. 03961 */ 03962 if (pqmsg->msg.message & PEM_ACTIVATE_RESTORE) { 03963 if (TestWF(pwnd, WFMINIMIZED)) { 03964 _PostMessage(pwnd, WM_SYSCOMMAND, SC_RESTORE, 0); 03965 } 03966 } 03967 03968 ThreadUnlock(&tlpwndT); 03969 } 03970 03971 } 03972 break; 03973 03974 case QEVENT_DEACTIVATE: 03975 xxxDeactivate(ptiCurrent, (DWORD)pqmsg->msg.wParam); 03976 break; 03977 03978 case QEVENT_CANCELMODE: 03979 if (pq->spwndCapture != NULL) { 03980 ThreadLockAlwaysWithPti(ptiCurrent, pq->spwndCapture, &tlpwndT); 03981 xxxSendMessage(pq->spwndCapture, WM_CANCELMODE, 0, 0); 03982 ThreadUnlock(&tlpwndT); 03983 03984 /* 03985 * Set QS_MOUSEMOVE so any sleeping modal loops, 03986 * like the move/size code, will wake up and figure 03987 * out that it should abort. 03988 */ 03989 SetWakeBit(ptiCurrent, QS_MOUSEMOVE); 03990 } 03991 break; 03992 03993 03994 case QEVENT_POSTMESSAGE: 03995 /* 03996 * This event is used in situations where we need to ensure that posted 03997 * messages are processed after previous QEVENT's. Normally, posting a 03998 * queue event and then calling postmessage will result in the posted 03999 * message being seen first by the app (because posted messages are 04000 * processed before input.) Instead we will post a QEVENT_POSTMESSAGE 04001 * instead of doing a postmessage directly, which will result in the 04002 * correct ordering of messages. 04003 * 04004 */ 04005 04006 if (pwnd = RevalidateHwnd((HWND)pqmsg->msg.hwnd)) { 04007 04008 _PostMessage(pwnd,pqmsg->msg.message,pqmsg->msg.wParam,pqmsg->msg.lParam); 04009 } 04010 break; 04011 04012 04013 case QEVENT_ASYNCSENDMSG: 04014 xxxProcessAsyncSendMessage((PASYNCSENDMSG)pqmsg->msg.wParam); 04015 break; 04016 04017 case QEVENT_HUNGTHREAD: 04018 pwnd = RevalidateHwnd((HWND)pqmsg->msg.hwnd); 04019 if (pwnd != NULL) { 04020 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 04021 xxxProcessHungThreadEvent(pwnd); 04022 ThreadUnlock(&tlpwndT); 04023 } 04024 break; 04025 04026 case QEVENT_CANCELMOUSEMOVETRK: { 04027 /* 04028 * hwnd: hwndTrack. message: dwDTFlags. 04029 * wParam: htEx. lParam: dwDTCancel 04030 */ 04031 PDESKTOP pdesk = ptiCurrent->rpdesk; 04032 pwnd = RevalidateHwnd((HWND)pqmsg->msg.hwnd); 04033 /* 04034 * Let's check that the app didn't manage to restart mouse leave 04035 * tracking before we had a chance to cancel it. 04036 */ 04037 UserAssert(!(pqmsg->msg.message & DF_TRACKMOUSELEAVE) 04038 || !(pdesk->dwDTFlags & DF_TRACKMOUSELEAVE) 04039 || (PtoHq(pdesk->spwndTrack) != pqmsg->msg.hwnd) 04040 || !((pdesk->htEx == HTCLIENT) ^ ((int)pqmsg->msg.wParam == HTCLIENT))); 04041 /* 04042 * If we're back tracking at the same spot, bail 04043 */ 04044 if ((pdesk->dwDTFlags & DF_MOUSEMOVETRK) 04045 && (PtoHq(pdesk->spwndTrack) == pqmsg->msg.hwnd) 04046 && (pdesk->htEx == (int)pqmsg->msg.wParam)) { 04047 /* 04048 * If we're tracking mouse leave, 04049 */ 04050 break; 04051 } 04052 /* 04053 * Don't nuke the tooltip if it has been reactivated. 04054 */ 04055 if (pdesk->dwDTFlags & DF_TOOLTIPACTIVE) { 04056 pqmsg->msg.lParam &= ~DF_TOOLTIP; 04057 } 04058 /* 04059 * Cancel tracking if the window is still around 04060 */ 04061 if (pwnd != NULL) { 04062 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 04063 xxxCancelMouseMoveTracking(pqmsg->msg.message, pwnd, 04064 (int)pqmsg->msg.wParam, 04065 (DWORD)pqmsg->msg.lParam); 04066 ThreadUnlock(&tlpwndT); 04067 } else if ((pqmsg->msg.lParam & DF_TOOLTIP) 04068 && (pqmsg->msg.message & DF_TOOLTIPSHOWING)) { 04069 /* 04070 * The window is gone and so must be tracking. 04071 * Just take care of the tooltip which is still showing. 04072 */ 04073 pwnd = pdesk->spwndTooltip; 04074 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 04075 xxxResetTooltip((PTOOLTIPWND)pwnd); 04076 ThreadUnlock(&tlpwndT); 04077 } 04078 } 04079 break; 04080 04081 case QEVENT_RITACCESSIBILITY: 04082 if (IsHooked(ptiCurrent, WHF_SHELL)) { 04083 xxxCallHook((UINT)pqmsg->msg.wParam, 04084 (WPARAM)pqmsg->msg.lParam, 04085 (LPARAM)0, 04086 WH_SHELL); 04087 } 04088 04089 PostShellHookMessages((UINT)pqmsg->msg.wParam, pqmsg->msg.lParam); 04090 break; 04091 04092 case QEVENT_RITSOUND: 04093 /* 04094 * This should only happen on the desktop thread. 04095 */ 04096 switch(pqmsg->msg.message) { 04097 case RITSOUND_UPSIREN: 04098 case RITSOUND_DOWNSIREN: 04099 case RITSOUND_LOWBEEP: 04100 case RITSOUND_HIGHBEEP: 04101 case RITSOUND_KEYCLICK: 04102 (pfnBP[pqmsg->msg.message])(); 04103 break; 04104 04105 case RITSOUND_DOBEEP: 04106 switch(pqmsg->msg.wParam) { 04107 case RITSOUND_UPSIREN: 04108 case RITSOUND_DOWNSIREN: 04109 case RITSOUND_LOWBEEP: 04110 case RITSOUND_HIGHBEEP: 04111 case RITSOUND_KEYCLICK: 04112 DoBeep(pfnBP[pqmsg->msg.wParam], (DWORD)pqmsg->msg.lParam); 04113 } 04114 break; 04115 } 04116 break; 04117 04118 case QEVENT_APPCOMMAND: { 04119 /* 04120 * qevent app commands so we can post a wm_appcommand to the queue 04121 */ 04122 THREADINFO *ptiWindowOwner; 04123 int cmd; 04124 UINT keystate; 04125 04126 /* 04127 * check the appcommand's are within reasonable ranges 04128 * if they aren't then we have an internal consistency error since xxxKeyEvent should 04129 * have generated correct ones for us 04130 */ 04131 UserAssert( pqmsg->msg.lParam >= VK_APPCOMMAND_FIRST && 04132 pqmsg->msg.lParam <= VK_APPCOMMAND_LAST ); 04133 04134 /* 04135 * We need to work out which window to send to here. Using the same 04136 * rules as from xxxScanSysQueue: 04137 * Assign the input to the focus window. If there is no focus 04138 * window, assign it to the active window as a SYS message. 04139 */ 04140 pwnd = ptiCurrent->pq->spwndFocus; 04141 if (!pwnd) { 04142 pwnd = ptiCurrent->pq->spwndActive; 04143 if (!pwnd ) { 04144 /* 04145 * At the moment we will just eat the message since we can't find a foreground q 04146 * This follows the method that any other app (eg hidserv) would mimic to 04147 * find the window to send to. 04148 */ 04149 break; 04150 } 04151 } 04152 04153 /* 04154 * We don't want to block on another thread since the xxxSendMessage is a synchronous call 04155 * so we post the message to the queue of the window owner thread 04156 */ 04157 ptiWindowOwner = GETPTI(pwnd); 04158 if (ptiCurrent != ptiWindowOwner) { 04159 /* 04160 * Post the event message to the window who should get it 04161 */ 04162 PostEventMessage(ptiWindowOwner, ptiWindowOwner->pq, QEVENT_APPCOMMAND, 04163 NULL, 0, (WPARAM)0, pqmsg->msg.lParam); 04164 04165 /* 04166 * break out of this since we've now posted the message to a different q - we 04167 * don't want to deal with it here 04168 */ 04169 break; 04170 } 04171 04172 cmd = APPCOMMAND_FIRST + ((UINT)pqmsg->msg.lParam - VK_APPCOMMAND_FIRST); 04173 keystate = GetMouseKeyFlags(ptiWindowOwner->pq); 04174 pqmsg->msg.lParam = MAKELPARAM(keystate, cmd); 04175 04176 04177 /* 04178 * Generate a WM_APPCOMMAND message from the keyboard keys 04179 */ 04180 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwndT); 04181 xxxSendMessage(pwnd, WM_APPCOMMAND, (WPARAM)pwnd, pqmsg->msg.lParam); 04182 ThreadUnlock(&tlpwndT); 04183 04184 break; 04185 } 04186 default: 04187 RIPMSG1(RIP_ERROR, "xxxProcessEventMessage Bad pqmsg->dwQEvent:%#lx", pqmsg->dwQEvent); 04188 break; 04189 } 04190 04191 ThreadUnlockPoolCleanup(ptiCurrent, &tlMsg); 04192 } 04193 04194 /***************************************************************************\ 04195 * _GetInputState (API) 04196 * 04197 * Returns the current input state for mouse buttons or keys. 04198 * 04199 * History: 04200 * 11-06-90 DavidPe Created. 04201 \***************************************************************************/ 04202 04203 #define QS_TEST_AND_CLEAR (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_SENDMESSAGE) 04204 #define QS_TEST (QS_MOUSEBUTTON | QS_KEY) 04205 04206 BOOL _GetInputState(VOID) 04207 { 04208 if (LOWORD(_GetQueueStatus(QS_TEST_AND_CLEAR)) & QS_TEST) { 04209 return TRUE; 04210 } else { 04211 return FALSE; 04212 } 04213 } 04214 04215 #undef QS_TEST_AND_CLEAR 04216 #undef QS_TEST 04217 04218 /***************************************************************************\ 04219 * _GetQueueStatus (API) 04220 * 04221 * Returns the changebits in the lo-word and wakebits in 04222 * the hi-word for the current queue. 04223 * 04224 * History: 04225 * 12-17-90 DavidPe Created. 04226 \***************************************************************************/ 04227 04228 DWORD _GetQueueStatus( 04229 UINT flags) 04230 { 04231 PTHREADINFO ptiCurrent; 04232 UINT fsChangeBits; 04233 04234 ptiCurrent = PtiCurrentShared(); 04235 04236 flags &= (QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_TRANSFER); 04237 04238 fsChangeBits = ptiCurrent->pcti->fsChangeBits; 04239 04240 /* 04241 * Clear out the change bits the app is looking at 04242 * so it'll know what changed since it's last call 04243 * to GetQueueStatus(). 04244 */ 04245 ptiCurrent->pcti->fsChangeBits &= ~flags; 04246 04247 /* 04248 * Return the current change/wake-bits. 04249 */ 04250 return MAKELONG(fsChangeBits & flags, 04251 (ptiCurrent->pcti->fsWakeBits | ptiCurrent->pcti->fsWakeBitsJournal) & flags); 04252 } 04253 04254 /***************************************************************************\ 04255 * xxxMsgWaitForMultipleObjects (API) 04256 * 04257 * Blocks until an 'event' satisifying dwWakeMask occurs for the 04258 * current thread as well as all other objects specified by the other 04259 * parameters which are the same as the base call WaitForMultipleObjects(). 04260 * 04261 * pfnNonMsg indicates that pHandles is big enough for nCount+1 handles 04262 * (empty slot at end, and to call pfnNonMsg for non message events. 04263 * 04264 * History: 04265 * 12-17-90 DavidPe Created. 04266 \***************************************************************************/ 04267 #ifdef LOCK_MOUSE_CODE 04268 #pragma alloc_text(MOUSE, xxxMsgWaitForMultipleObjects) 04269 #endif 04270 04271 DWORD xxxMsgWaitForMultipleObjects( 04272 DWORD nCount, 04273 PVOID *apObjects, 04274 MSGWAITCALLBACK pfnNonMsg, 04275 PKWAIT_BLOCK WaitBlockArray) 04276 { 04277 PTHREADINFO ptiCurrent = PtiCurrent(); 04278 NTSTATUS Status; 04279 04280 ptiCurrent = PtiCurrent(); 04281 UserAssert(IsWinEventNotifyDeferredOK()); 04282 04283 /* 04284 * Setup the wake mask for this thread. Wait for QS_EVENT or the app won't 04285 * get event messages like deactivate. 04286 */ 04287 ClearQueueServerEvent(QS_ALLINPUT | QS_EVENT); 04288 04289 /* 04290 * Stuff the event handle for the current queue at the end. 04291 */ 04292 apObjects[nCount] = ptiCurrent->pEventQueueServer; 04293 04294 /* 04295 * Check to see if any input came inbetween when we 04296 * last checked and the NtClearEvent() call. 04297 */ 04298 if (!(ptiCurrent->pcti->fsChangeBits & QS_ALLINPUT)) { 04299 04300 /* 04301 * This app is going idle. Clear the spin count check to see 04302 * if we need to make this process foreground again. 04303 */ 04304 if (ptiCurrent->TIF_flags & TIF_SPINNING) { 04305 CheckProcessForeground(ptiCurrent); 04306 } 04307 ptiCurrent->pClientInfo->cSpins = 0; 04308 04309 if (ptiCurrent == gptiForeground && 04310 IsHooked(ptiCurrent, WHF_FOREGROUNDIDLE)) { 04311 xxxCallHook(HC_ACTION, 0, 0, WH_FOREGROUNDIDLE); 04312 } 04313 04314 CheckForClientDeath(); 04315 04316 /* 04317 * Set the input idle event to wake up any threads waiting 04318 * for this thread to go into idle state. 04319 */ 04320 zzzWakeInputIdle(ptiCurrent); 04321 04322 Again: 04323 LeaveCrit(); 04324 04325 Status = KeWaitForMultipleObjects(nCount + 1, apObjects, 04326 WaitAny, WrUserRequest, 04327 UserMode, FALSE, 04328 NULL, WaitBlockArray); 04329 04330 EnterCrit(); 04331 04332 CheckForClientDeath(); 04333 04334 UserAssert(NT_SUCCESS(Status)); 04335 04336 04337 if ((Status == STATUS_WAIT_0) && (pfnNonMsg != NULL)) { 04338 /* 04339 * Call pfnNonMsg for the first event 04340 */ 04341 pfnNonMsg(DEVICE_TYPE_MOUSE); 04342 04343 /* 04344 * Setup again the wake mask for this thread. 04345 * Wait for QS_EVENT or the app won't 04346 * get event messages like deactivate. 04347 */ 04348 ptiCurrent->pcti->fsWakeMask = QS_ALLINPUT | QS_EVENT; 04349 goto Again; 04350 } 04351 04352 if (Status == (NTSTATUS)(STATUS_WAIT_0 + nCount)) { 04353 04354 /* 04355 * Reset the input idle event to block and threads waiting 04356 * for this thread to go into idle state. 04357 */ 04358 SleepInputIdle(ptiCurrent); 04359 } 04360 } else { 04361 Status = nCount; 04362 } 04363 04364 /* 04365 * Clear fsWakeMask since we're no longer waiting on the queue. 04366 */ 04367 ptiCurrent->pcti->fsWakeMask = 0; 04368 04369 return (DWORD)Status; 04370 } 04371 04372 /***************************************************************************\ 04373 * xxxSleepThread 04374 * 04375 * Blocks until an 'event' satisifying fsWakeMask occurs for the 04376 * current thread. 04377 * 04378 * History: 04379 * 10-28-90 DavidPe Created. 04380 \***************************************************************************/ 04381 04382 BOOL xxxSleepThread( 04383 UINT fsWakeMask, 04384 DWORD Timeout, 04385 BOOL fInputIdle) 04386 { 04387 PTHREADINFO ptiCurrent; 04388 LARGE_INTEGER li, *pli; 04389 NTSTATUS status = STATUS_SUCCESS; 04390 BOOL fExclusive = fsWakeMask & QS_EXCLUSIVE; 04391 WORD fsWakeMaskSaved; 04392 04393 UserAssert(IsWinEventNotifyDeferredOK()); 04394 04395 if (fExclusive) { 04396 /* 04397 * the exclusive bit is a 'dummy' arg, turn it off to 04398 * avoid any possible conflictions 04399 */ 04400 fsWakeMask = fsWakeMask & ~QS_EXCLUSIVE; 04401 } 04402 04403 if (Timeout) { 04404 /* 04405 * Convert dwMilliseconds to a relative-time(i.e. negative) 04406 * LARGE_INTEGER. NT Base calls take time values in 100 nanosecond 04407 * units. 04408 */ 04409 li.QuadPart = Int32x32To64(-10000, Timeout); 04410 pli = &li; 04411 } else 04412 pli = NULL; 04413 04414 CheckCritIn(); 04415 04416 ptiCurrent = PtiCurrent(); 04417 04418 fsWakeMaskSaved = ptiCurrent->pcti->fsWakeMask; 04419 04420 while (TRUE) { 04421 04422 /* 04423 * First check if the input has arrived. 04424 */ 04425 if (ptiCurrent->pcti->fsChangeBits & fsWakeMask) { 04426 /* 04427 * Restore the wake mask to what it was before we went to sleep 04428 * to allow possible callbacks before KeWait... but after the mask 04429 * has been set and also APCs from KeWait... to still be able to 04430 * wake up. Simply clearing the mask here if we're in such a 04431 * callback or in an APC means that the thread will never wake up. 04432 */ 04433 ptiCurrent->pcti->fsWakeMask = fsWakeMaskSaved; 04434 04435 /* 04436 * Update timeLastRead - it is used for hung app calculations. 04437 * If the thread is waking up to process input, it isn't hung! 04438 */ 04439 SET_TIME_LAST_READ(ptiCurrent); 04440 return TRUE; 04441 } 04442 04443 /* 04444 * Next check for SendMessages 04445 */ 04446 if (!fExclusive && ptiCurrent->pcti->fsWakeBits & QS_SENDMESSAGE) { 04447 xxxReceiveMessages(ptiCurrent); 04448 04449 /* 04450 * Restore the change bits we took out in PeekMessage() 04451 */ 04452 ptiCurrent->pcti->fsChangeBits |= (ptiCurrent->pcti->fsWakeBits & ptiCurrent->fsChangeBitsRemoved); 04453 ptiCurrent->fsChangeBitsRemoved = 0; 04454 } 04455 04456 /* 04457 * Check to see if some resources need expunging. 04458 * This will unload Hook DLLs, including WinEvent ones 04459 */ 04460 if (ptiCurrent->ppi->cSysExpunge != gcSysExpunge) { 04461 ptiCurrent->ppi->cSysExpunge = gcSysExpunge; 04462 if (ptiCurrent->ppi->dwhmodLibLoadedMask & gdwSysExpungeMask) 04463 xxxDoSysExpunge(ptiCurrent); 04464 } 04465 04466 /* 04467 * OR QS_SENDMESSAGE in since ReceiveMessage() will end up 04468 * trashing pq->fsWakeMask. Do the same for QS_SYSEXPUNGE. 04469 */ 04470 ClearQueueServerEvent((WORD)(fsWakeMask | (fExclusive ? 0 : QS_SENDMESSAGE))); 04471 04472 /* 04473 * If we have timed out then return our error to the caller. 04474 */ 04475 if (status == STATUS_TIMEOUT) { 04476 RIPERR1(ERROR_TIMEOUT, RIP_VERBOSE, "SleepThread: The timeout has expired %lX", Timeout); 04477 return FALSE; 04478 } 04479 04480 /* 04481 * Because we do a non-alertable wait, we know that a status 04482 * of STATUS_USER_APC means that the thread was terminated. 04483 * If we have terminated, get back to user mode. 04484 */ 04485 if (status == STATUS_USER_APC) { 04486 ClientDeliverUserApc(); 04487 return FALSE; 04488 } 04489 04490 /* 04491 * If this is the power state callout thread, we might need to bail 04492 * out early. 04493 */ 04494 if (gPowerState.pEvent == ptiCurrent->pEventQueueServer) { 04495 if (gPowerState.fCritical) { 04496 return FALSE; 04497 } 04498 } 04499 04500 UserAssert(status == STATUS_SUCCESS); 04501 /* 04502 * Check to see if any input came inbetween when we 04503 * last checked and the NtClearEvent() call. 04504 * 04505 * We call NtWaitForSingleObject() rather than 04506 * WaitForSingleObject() so we can set fAlertable 04507 * to TRUE and thus allow timer APCs to be processed. 04508 */ 04509 if (!(ptiCurrent->pcti->fsChangeBits & ptiCurrent->pcti->fsWakeMask)) { 04510 /* 04511 * This app is going idle. Clear the spin count check to see 04512 * if we need to make this process foreground again. 04513 */ 04514 if (fInputIdle) { 04515 if (ptiCurrent->TIF_flags & TIF_SPINNING) { 04516 CheckProcessForeground(ptiCurrent); 04517 } 04518 ptiCurrent->pClientInfo->cSpins = 0; 04519 } 04520 04521 04522 if (!(ptiCurrent->TIF_flags & TIF_16BIT)) { 04523 if (fInputIdle && ptiCurrent == gptiForeground && 04524 IsHooked(ptiCurrent, WHF_FOREGROUNDIDLE)) { 04525 xxxCallHook(HC_ACTION, 0, 0, WH_FOREGROUNDIDLE); 04526 } 04527 04528 CheckForClientDeath(); 04529 04530 /* 04531 * Set the input idle event to wake up any threads waiting 04532 * for this thread to go into idle state. 04533 */ 04534 if (fInputIdle) 04535 zzzWakeInputIdle(ptiCurrent); 04536 04537 xxxSleepTask(fInputIdle, NULL); 04538 04539 LeaveCrit(); 04540 status = KeWaitForSingleObject(ptiCurrent->pEventQueueServer, 04541 WrUserRequest, UserMode, FALSE, pli); 04542 CheckForClientDeath(); 04543 EnterCrit(); 04544 04545 /* 04546 * Reset the input idle event to block and threads waiting 04547 * for this thread to go into idle state. 04548 */ 04549 SleepInputIdle(ptiCurrent); 04550 04551 /* 04552 * ptiCurrent is 16bit! 04553 */ 04554 } else { 04555 if (fInputIdle) 04556 zzzWakeInputIdle(ptiCurrent); 04557 04558 xxxSleepTask(fInputIdle, NULL); 04559 } 04560 } 04561 } 04562 } 04563 04564 04565 /***************************************************************************\ 04566 * SetWakeBit 04567 * 04568 * Adds the specified wake bit to specified THREADINFO and wakes its 04569 * thread up if the bit is in its fsWakeMask. 04570 * 04571 * Nothing will happen in the system unless we come to this function. 04572 * so be fast and small. 04573 * 04574 * History: 04575 * 10-28-90 DavidPe Created. 04576 \***************************************************************************/ 04577 04578 VOID SetWakeBit( 04579 PTHREADINFO pti, 04580 UINT wWakeBit) 04581 { 04582 CheckCritIn(); 04583 04584 UserAssert(pti); 04585 04586 /* 04587 * Win3.1 changes ptiKeyboard and ptiMouse accordingly if we're setting 04588 * those bits. 04589 */ 04590 if (wWakeBit & QS_MOUSE) 04591 pti->pq->ptiMouse = pti; 04592 04593 if (wWakeBit & QS_KEY) 04594 pti->pq->ptiKeyboard = pti; 04595 04596 /* 04597 * OR in these bits - these bits represent what input this app has 04598 * (fsWakeBits), or what input has arrived since that last look 04599 * (fsChangeBits). 04600 */ 04601 pti->pcti->fsWakeBits |= wWakeBit; 04602 pti->pcti->fsChangeBits |= wWakeBit; 04603 04604 /* 04605 * Before waking, do screen saver check to see if it should 04606 * go away. 04607 */ 04608 if ((wWakeBit & QS_INPUT) 04609 && (pti->ppi->W32PF_Flags & W32PF_IDLESCREENSAVER)) { 04610 if ((wWakeBit & QS_MOUSEMOVE) 04611 && (gpsi->ptCursor.x == gptSSCursor.x) 04612 && (gpsi->ptCursor.y == gptSSCursor.y)) { 04613 goto SkipScreenSaverStuff; 04614 } 04615 04616 /* 04617 * Our idle screen saver needs to be given a priority boost so that it 04618 * can process input. 04619 */ 04620 pti->ppi->W32PF_Flags &= ~W32PF_IDLESCREENSAVER; 04621 SetForegroundPriority(pti, TRUE); 04622 } 04623 04624 SkipScreenSaverStuff: 04625 if (wWakeBit & pti->pcti->fsWakeMask) { 04626 /* 04627 * Wake the Thread 04628 */ 04629 if (pti->TIF_flags & TIF_16BIT) { 04630 pti->ptdb->nEvents++; 04631 gpsi->nEvents++; 04632 WakeWowTask(pti); 04633 } else { 04634 KeSetEvent(pti->pEventQueueServer, 2, FALSE); 04635 } 04636 } 04637 } 04638 04639 /***************************************************************************\ 04640 * TransferWakeBit 04641 * 04642 * We have a mesasge from the system queue. If out input bit for this 04643 * message isn't set, set ours and clear the guy whose bit was set 04644 * because of this message. 04645 * 04646 * 10-22-92 ScottLu Created. 04647 \***************************************************************************/ 04648 04649 void TransferWakeBit( 04650 PTHREADINFO pti, 04651 UINT message) 04652 { 04653 PTHREADINFO ptiT; 04654 UINT fsMask; 04655 04656 /* 04657 * Calculate the mask from the message range. Only interested 04658 * in hardware input here: mouse and keys. 04659 */ 04660 fsMask = CalcWakeMask(message, message, 0) & (QS_MOUSE | QS_KEY); 04661 04662 /* 04663 * If it is set in this thread's wakebits, nothing to do. 04664 * Otherwise transfer them from the owner to this thread. 04665 */ 04666 if (!(pti->pcti->fsWakeBits & fsMask)) { 04667 /* 04668 * Either mouse or key is set (not both). Remove this bit 04669 * from the thread that currently owns it, and change mouse / 04670 * key ownership to this thread. 04671 */ 04672 if (fsMask & QS_KEY) { 04673 ptiT = pti->pq->ptiKeyboard; 04674 pti->pq->ptiKeyboard = pti; 04675 } else { 04676 ptiT = pti->pq->ptiMouse; 04677 pti->pq->ptiMouse = pti; 04678 } 04679 ptiT->pcti->fsWakeBits &= ~fsMask; 04680 04681 /* 04682 * Transfer them to this thread (certainly this may be the 04683 * same thread for win32 threads not sharing queues). 04684 */ 04685 pti->pcti->fsWakeBits |= fsMask; 04686 pti->pcti->fsChangeBits |= fsMask; 04687 } 04688 } 04689 04690 /***************************************************************************\ 04691 * ClearWakeBit 04692 * 04693 * Clears wake bits. If fSysCheck is TRUE, this clears the input bits only 04694 * if no messages are in the input queue. Otherwise, it clears input bits 04695 * unconditionally. 04696 * 04697 * 11-05-92 ScottLu Created. 04698 \***************************************************************************/ 04699 04700 VOID ClearWakeBit( 04701 PTHREADINFO pti, 04702 UINT wWakeBit, 04703 BOOL fSysCheck) 04704 { 04705 04706 /* 04707 * If fSysCheck is TRUE, clear bits only if we are not doing journal 04708 * playback and there are no more messages in the queue. fSysCheck 04709 * is TRUE if clearing because of no more input. FALSE if just 04710 * transfering input ownership from one thread to another. 04711 */ 04712 if (fSysCheck) { 04713 if (pti->pq->mlInput.cMsgs != 0 || FJOURNALPLAYBACK()) 04714 return; 04715 if (pti->pq->QF_flags & QF_MOUSEMOVED) 04716 wWakeBit &= ~QS_MOUSEMOVE; 04717 } 04718 04719 /* 04720 * Only clear the wake bits, not the change bits as well! 04721 */ 04722 pti->pcti->fsWakeBits &= ~wWakeBit; 04723 } 04724 04725 04726 04727 /***************************************************************************\ 04728 * PtiFromThreadId 04729 * 04730 * Returns the THREADINFO for the specified thread or NULL if thread 04731 * doesn't exist or doesn't have a THREADINFO. 04732 * 04733 * History: 04734 * 01-30-91 DavidPe Created. 04735 \***************************************************************************/ 04736 04737 PTHREADINFO PtiFromThreadId( 04738 DWORD dwThreadId) 04739 { 04740 PETHREAD pEThread; 04741 PTHREADINFO pti; 04742 04743 /* 04744 * BUG BUG: Pretty much every place else we do call LockThreadByClientId 04745 * while outside the user critical section so we don't cause any 04746 * potential deadlock in the kernel. 04747 * It's too late to change it now. 2/17/99 04748 */ 04749 04750 if (!NT_SUCCESS(LockThreadByClientId((HANDLE)LongToHandle( dwThreadId ), &pEThread))) 04751 return NULL; 04752 04753 /* 04754 * If the thread is not terminating, look up the pti. This is 04755 * needed because the value returned by PtiFromThread() is 04756 * undefined if the thread is terminating. See PspExitThread in 04757 * ntos\ps\psdelete.c. 04758 */ 04759 if (!PsIsThreadTerminating(pEThread)) { 04760 pti = PtiFromThread(pEThread); 04761 } else { 04762 pti = NULL; 04763 } 04764 04765 /* 04766 * Do a sanity check on the pti to make sure it's really valid. 04767 */ 04768 if (pti != NULL) { 04769 try { 04770 if (pti->pEThread->Cid.UniqueThread != (HANDLE)LongToHandle( dwThreadId )) { 04771 pti = NULL; 04772 } else if (!(pti->TIF_flags & TIF_GUITHREADINITIALIZED)) { 04773 RIPMSG1(RIP_WARNING, "PtiFromThreadId: pti %#p not initialized", pti); 04774 pti = NULL; 04775 } else if (pti->TIF_flags & TIF_INCLEANUP) { 04776 RIPMSG1(RIP_WARNING, "PtiFromThreadId: pti %#p in cleanup", pti); 04777 pti = NULL; 04778 } 04779 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 04780 pti = NULL; 04781 } 04782 } 04783 04784 UnlockThread(pEThread); 04785 04786 return pti; 04787 } 04788 04789 04790 /***************************************************************************\ 04791 * StoreMessage 04792 * 04793 * 04794 * 04795 * History: 04796 * 10-31-90 DarrinM Ported from Win 3.0 sources. 04797 \***************************************************************************/ 04798 04799 void StoreMessage( 04800 LPMSG pmsg, 04801 PWND pwnd, 04802 UINT message, 04803 WPARAM wParam, 04804 LPARAM lParam, 04805 DWORD time) 04806 { 04807 CheckCritIn(); 04808 04809 pmsg->hwnd = HW(pwnd); 04810 pmsg->message = message; 04811 pmsg->wParam = wParam; 04812 pmsg->lParam = lParam; 04813 pmsg->time = (time != 0 ? time : NtGetTickCount()); 04814 04815 pmsg->pt = gpsi->ptCursor; 04816 } 04817 04818 04819 /***************************************************************************\ 04820 * StoreQMessage 04821 * 04822 * If 'time' is 0 grab the current time, if not, it means that this message 04823 * is for an input event and eventually the mouse/keyboard hooks want to see 04824 * the right time stamps. 04825 * 04826 * History: 04827 * 02-27-91 DavidPe Created. 04828 * 06-15-96 CLupu Add 'time' parameter 04829 \***************************************************************************/ 04830 04831 void StoreQMessage( 04832 PQMSG pqmsg, 04833 PWND pwnd, 04834 UINT message, 04835 WPARAM wParam, 04836 LPARAM lParam, 04837 DWORD time, 04838 DWORD dwQEvent, 04839 ULONG_PTR dwExtraInfo) 04840 { 04841 CheckCritIn(); 04842 04843 pqmsg->msg.hwnd = HW(pwnd); 04844 pqmsg->msg.message = message; 04845 pqmsg->msg.wParam = wParam; 04846 pqmsg->msg.lParam = lParam; 04847 pqmsg->msg.time = (time == 0) ? NtGetTickCount() : time; 04848 04849 #ifdef REDIRECTION 04850 if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) { 04851 pqmsg->msg.pt.x = LOWORD(lParam); 04852 pqmsg->msg.pt.y = HIWORD(lParam); 04853 } else { 04854 pqmsg->msg.pt = gpsi->ptCursor; 04855 } 04856 #else 04857 pqmsg->msg.pt = gpsi->ptCursor; 04858 #endif 04859 pqmsg->dwQEvent = dwQEvent; 04860 pqmsg->ExtraInfo = dwExtraInfo; 04861 } 04862 04863 04864 /***************************************************************************\ 04865 * xxxInitProcessInfo 04866 * 04867 * This initializes the process info. Usually gets created before the 04868 * CreateProcess() call returns (so we can synchronize with the starting 04869 * process in several different ways). 04870 * 04871 * 09-18-91 ScottLu Created. 04872 \***************************************************************************/ 04873 04874 NTSTATUS xxxInitProcessInfo( 04875 PW32PROCESS pwp) 04876 { 04877 PPROCESSINFO ppi = (PPROCESSINFO)pwp; 04878 NTSTATUS Status; 04879 04880 CheckCritIn(); 04881 04882 /* 04883 * Check if we need to initialize the process. 04884 */ 04885 if (pwp->W32PF_Flags & W32PF_PROCESSCONNECTED) { 04886 return STATUS_ALREADY_WIN32; 04887 } 04888 pwp->W32PF_Flags |= W32PF_PROCESSCONNECTED; 04889 04890 #if defined(_WIN64) 04891 /* Tag as emulated 32bit. Flag is copied to be consistent with 04892 * the way WOW16 apps are tagged for win32k. 04893 */ 04894 if (pwp->Process->Wow64Process) { 04895 pwp->W32PF_Flags |= W32PF_WOW64; 04896 } 04897 #endif 04898 04899 /* 04900 * Mark this app as "starting" - it will be starting until its first 04901 * window activates. 04902 */ 04903 UserVerify(xxxSetProcessInitState(pwp->Process, STARTF_FORCEOFFFEEDBACK)); 04904 04905 /* 04906 * link it into the starting processes list 04907 */ 04908 SetAppStarting(ppi); 04909 /* 04910 * link it into the global processes list 04911 */ 04912 ppi->ppiNextRunning = gppiList; 04913 gppiList = ppi; 04914 /* 04915 * If foreground activation has not been canceled and the parent process 04916 * (or an ancestor) can force a foreground change, then allow this process 04917 * to come to the foreground when it does its first activation. 04918 * 04919 * Bug 273518 - joejo 04920 * 04921 * This will allow console windows to set foreground correctly on new 04922 * process' it launches, as opposed it just forcing foreground. 04923 */ 04924 if (TEST_PUDF(PUDF_ALLOWFOREGROUNDACTIVATE) && CheckAllowForeground(pwp->Process)) { 04925 ppi->W32PF_Flags |= W32PF_ALLOWFOREGROUNDACTIVATE; 04926 } 04927 TAGMSG2(DBGTAG_FOREGROUND, "xxxInitProcessInfo %s W32PF %#p", 04928 ((ppi->W32PF_Flags & W32PF_ALLOWFOREGROUNDACTIVATE) ? "set" : "NOT"), 04929 ppi); 04930 04931 /* 04932 * Get the logon session id. This is used to determine which 04933 * windowstation to connect to and to identify attempts to 04934 * call hooks across security contexts. 04935 */ 04936 Status = GetProcessLuid(NULL, &ppi->luidSession); 04937 UserAssert(NT_SUCCESS(Status)); 04938 04939 /* 04940 * Ensure that we're in sync with the expunge count 04941 */ 04942 ppi->cSysExpunge = gcSysExpunge; 04943 04944 /* 04945 * Don't perform any LPK callbacks until GDI notifies 04946 * us that the LPK(s) are loaded and initialized. 04947 */ 04948 ppi->dwLpkEntryPoints = 0; 04949 04950 return STATUS_SUCCESS; 04951 } 04952 04953 /***************************************************************************\ 04954 * DestroyProcessInfo 04955 * 04956 * This function is executed when the last thread of a process goes 04957 * away. 04958 * 04959 * SO VERY IMPORTANT: 04960 * Note that the last thread of the process might not be a w32 thread. 04961 * So do not make any calls here that assume a w32 pti. Do avoid 04962 * any function calling PtiCurrent() as it probably assumes it is 04963 * on a nice w32 thread. 04964 * Also note that if the process is locked, the ppi is not going away; this 04965 * simply means that execution on this process has ended. So make sure to clean 04966 * up in a way that the ppi data is still valid (for example, if you free a pointer, 04967 * set it to NULL). 04968 * 04969 * zzz Note: Not a zzz routine although it calls zzzCalcStartCursorHide() - 04970 * Since we can't make callbacks on a non-GUI thread, we use 04971 * DeferWinEventNotify() & EndDeferWinEventNotifyWithoutProcessing() 04972 * to prevent callbacks. 04973 * 04974 * 04/08/96 GerardoB Added header 04975 \***************************************************************************/ 04976 BOOL DestroyProcessInfo( 04977 PW32PROCESS pwp) 04978 { 04979 PPROCESSINFO ppi = (PPROCESSINFO)pwp; 04980 PDESKTOPVIEW pdv, pdvNext; 04981 BOOL fHadThreads; 04982 PPUBOBJ ppo; 04983 04984 CheckCritIn(); 04985 04986 /* 04987 * Free up input idle event if it exists - wake everyone waiting on it 04988 * first. This object will get created sometimes even for non-windows 04989 * processes (usually for WinExec(), which calls WaitForInputIdle()). 04990 */ 04991 CLOSE_PSEUDO_EVENT(&pwp->InputIdleEvent); 04992 04993 /* 04994 * Check to see if the startglass is on, and if so turn it off and update. 04995 * DeferWinEventNotify to because we cannot process notifications for this 04996 * thread now (we may have no PtiCurrent, see comment above) 04997 */ 04998 BEGINATOMICCHECK(); 04999 DeferWinEventNotify(); 05000 if (pwp->W32PF_Flags & W32PF_STARTGLASS) { 05001 pwp->W32PF_Flags &= ~W32PF_STARTGLASS; 05002 zzzCalcStartCursorHide(NULL, 0); 05003 } 05004 /* 05005 * This is bookkeeping - restore original notification deferral but without 05006 * attempting to process any deferred notifications because we have no pti. 05007 */ 05008 EndDeferWinEventNotifyWithoutProcessing(); 05009 ENDATOMICCHECK(); 05010 05011 /* 05012 * If the process never called Win32k, we're done. 05013 */ 05014 if (!(pwp->W32PF_Flags & W32PF_PROCESSCONNECTED)) { 05015 return FALSE; 05016 } 05017 05018 /* 05019 * Play the Process Close sound for non-console processes 05020 * running on the I/O windowstation. 05021 */ 05022 05023 if ((ppi->W32PF_Flags & W32PF_IOWINSTA) && 05024 !(ppi->W32PF_Flags & W32PF_CONSOLEAPPLICATION) && 05025 (gspwndLogonNotify != NULL) && 05026 !(ppi->rpwinsta->dwWSF_Flags & WSF_OPENLOCK)) { 05027 05028 PTHREADINFO pti = GETPTI(gspwndLogonNotify); 05029 PQMSG pqmsg; 05030 05031 if ((pqmsg = AllocQEntry(&pti->mlPost)) != NULL) { 05032 StoreQMessage(pqmsg, gspwndLogonNotify, WM_LOGONNOTIFY, 05033 LOGON_PLAYEVENTSOUND, USER_SOUND_CLOSE, 0, 0, 0); 05034 05035 SetWakeBit(pti, QS_POSTMESSAGE | QS_ALLPOSTMESSAGE); 05036 } 05037 05038 } 05039 05040 /* 05041 * Be like WIN95. 05042 * If this is the shell process, then send a LOGON_RESTARTSHELL 05043 * notification to the winlogon process (only if not logging off) 05044 */ 05045 if (IsShellProcess(ppi)) { 05046 05047 /* 05048 * The shell process will get killed and it's better to set this 05049 * in the desktop info. 05050 */ 05051 ppi->rpdeskStartup->pDeskInfo->ppiShellProcess = NULL; 05052 05053 /* 05054 * If we're not logging off, notify winlogon 05055 */ 05056 if ((gspwndLogonNotify != NULL) && 05057 !(ppi->rpwinsta->dwWSF_Flags & WSF_OPENLOCK)) { 05058 05059 PTHREADINFO pti = GETPTI(gspwndLogonNotify); 05060 PQMSG pqmsg; 05061 05062 if ((pqmsg = AllocQEntry(&pti->mlPost)) != NULL) { 05063 StoreQMessage(pqmsg, gspwndLogonNotify, WM_LOGONNOTIFY, 05064 LOGON_RESTARTSHELL, ppi->Process->ExitStatus, 0, 0, 0); 05065 SetWakeBit(pti, QS_POSTMESSAGE | QS_ALLPOSTMESSAGE); 05066 } 05067 } 05068 } 05069 05070 if (ppi->cThreads) 05071 RIPMSG1(RIP_ERROR, "Disconnect with %d threads remaining\n", ppi->cThreads); 05072 05073 /* 05074 * If the app is still starting, remove it from the startup list 05075 */ 05076 if (ppi->W32PF_Flags & W32PF_APPSTARTING) { 05077 /* 05078 * Bug 294193 - joejo 05079 * 05080 * Handle case when creator process exits before the child 05081 * process makes it to CheckAllowForeground code. This is typical with 05082 * stub EXEs that do nothing but create other processes. 05083 */ 05084 GiveForegroundActivateRight(ppi->Process->UniqueProcessId); 05085 ClearAppStarting(ppi); 05086 } 05087 05088 /* 05089 * remove it from the global list 05090 */ 05091 REMOVE_FROM_LIST(PROCESSINFO, gppiList, ppi, ppiNextRunning); 05092 05093 /* 05094 * If any threads ever connected, there may be DCs, classes, 05095 * cursors, etc. still lying around. If no threads connected 05096 * (which is the case for console apps), skip all of this cleanup. 05097 */ 05098 fHadThreads = ppi->W32PF_Flags & W32PF_THREADCONNECTED; 05099 if (fHadThreads) { 05100 05101 /* 05102 * When a process dies we need to make sure any DCE's it owns 05103 * and have not been deleted are cleanup up. The clean up 05104 * earlier may have failed if the DC was busy in GDI. 05105 */ 05106 if (ppi->W32PF_Flags & W32PF_OWNDCCLEANUP) { 05107 DelayedDestroyCacheDC(); 05108 } 05109 05110 #if DBG 05111 { 05112 PHE pheT, pheMax; 05113 05114 /* 05115 * Loop through the table destroying all objects created by the current 05116 * process. All objects will get destroyed in their proper order simply 05117 * because of the object locking. 05118 */ 05119 pheMax = &gSharedInfo.aheList[giheLast]; 05120 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 05121 05122 /* 05123 * We should have no process objects left for this process. 05124 */ 05125 UserAssertMsg0( 05126 pheT->bFlags & HANDLEF_DESTROY || 05127 !(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) || 05128 (PPROCESSINFO)pheT->pOwner != ppi, 05129 "We should have no process objects left for this process!"); 05130 } 05131 } 05132 #endif 05133 } 05134 05135 if (pwp->UserHandleCount) 05136 RIPMSG1(RIP_ERROR, "Disconnect with %d User handle objects remaining\n", pwp->UserHandleCount); 05137 05138 /* 05139 * check if we need to zap PID's for DDE objects 05140 */ 05141 for (ppo = gpPublicObjectList; 05142 ppo != NULL; 05143 ppo = ppo->next) { 05144 if (ppo->pid == pwp->W32Pid) { 05145 ppo->pid = OBJECT_OWNER_PUBLIC; 05146 } 05147 } 05148 05149 05150 if (gppiScreenSaver == ppi) { 05151 UserAssert(ppi->W32PF_Flags & W32PF_SCREENSAVER); 05152 05153 gppiScreenSaver = NULL; 05154 } 05155 05156 if (gppiForegroundOld == ppi) { 05157 gppiForegroundOld = NULL; 05158 } 05159 05160 UnlockWinSta(&ppi->rpwinsta); 05161 UnlockDesktop(&ppi->rpdeskStartup, LDU_PPI_DESKSTARTUP3, (ULONG_PTR)ppi); 05162 05163 /* 05164 * Close the startup desktop handle now if it's still around. If we wait 05165 * until handle table cleanup time we could potentially deadlock. 05166 */ 05167 if (ppi->hdeskStartup) { 05168 UserVerify(NT_SUCCESS(CloseProtectedHandle(ppi->hdeskStartup))); 05169 ppi->hdeskStartup = NULL; 05170 } 05171 05172 /* 05173 * Mark the process as terminated so access checks will work. 05174 */ 05175 ppi->W32PF_Flags |= W32PF_TERMINATED; 05176 05177 /* 05178 * Cleanup wow process info struct, if any 05179 */ 05180 if (ppi->pwpi) { 05181 PWOWPROCESSINFO pwpi = ppi->pwpi; 05182 05183 ObDereferenceObject(pwpi->pEventWowExec); 05184 05185 REMOVE_FROM_LIST(WOWPROCESSINFO, gpwpiFirstWow, pwpi, pwpiNext); 05186 05187 UserFreePool(pwpi); 05188 ppi->pwpi = NULL; 05189 } 05190 05191 /* 05192 * Delete desktop views. System will do unmapping. 05193 */ 05194 pdv = ppi->pdvList; 05195 while (pdv) { 05196 pdvNext = pdv->pdvNext; 05197 UserFreePool(pdv); 05198 pdv = pdvNext; 05199 } 05200 ppi->pdvList = NULL; 05201 05202 /* 05203 * Clear the SendInput/Journalling hook caller ppi 05204 */ 05205 if (ppi == gppiInputProvider) { 05206 gppiInputProvider = NULL; 05207 } 05208 /* 05209 * If this ppi locked SetForegroundWindow, clean up 05210 */ 05211 if (ppi == gppiLockSFW) { 05212 gppiLockSFW = NULL; 05213 } 05214 05215 return fHadThreads; 05216 } 05217 05218 /***************************************************************************\ 05219 * ClearWakeMask 05220 * 05221 \***************************************************************************/ 05222 05223 VOID ClearWakeMask(VOID) 05224 { 05225 PtiCurrent()->pcti->fsWakeMask = 0; 05226 } 05227 05228 /***************************************************************************\ 05229 * xxxGetInputEvent 05230 * 05231 * Returns a duplicated event-handle that the client process can use to 05232 * wait on input events. 05233 * 05234 * History: 05235 * 05-02-91 DavidPe Created. 05236 \***************************************************************************/ 05237 05238 HANDLE xxxGetInputEvent( 05239 DWORD dwWakeMask) 05240 { 05241 PTHREADINFO ptiCurrent; 05242 WORD wFlags = HIWORD(dwWakeMask); 05243 UserAssert(IsWinEventNotifyDeferredOK()); 05244 05245 ptiCurrent = PtiCurrent(); 05246 05247 /* 05248 * If our wait condition is satisfied, signal the event and return. 05249 * (Since the wake mask could have been anything at the time the input 05250 * arrived, the event might not be signaled) 05251 */ 05252 if (GetInputBits(ptiCurrent->pcti, LOWORD(dwWakeMask), (wFlags & MWMO_INPUTAVAILABLE))) { 05253 KeSetEvent(ptiCurrent->pEventQueueServer, 2, FALSE); 05254 return ptiCurrent->hEventQueueClient; 05255 } 05256 05257 /* 05258 * If an idle hook is set, call it. 05259 */ 05260 if (ptiCurrent == gptiForeground && 05261 IsHooked(ptiCurrent, WHF_FOREGROUNDIDLE)) { 05262 xxxCallHook(HC_ACTION, 0, 0, WH_FOREGROUNDIDLE); 05263 } 05264 05265 CheckForClientDeath(); 05266 05267 /* 05268 * What is the criteria for an "idle process"? 05269 * Answer: The first thread that calls zzzWakeInputIdle, or SleepInputIdle or... 05270 * Any thread that calls xxxGetInputEvent with any of the following 05271 * bits set in its wakemask: (sanfords) 05272 */ 05273 if (dwWakeMask & (QS_POSTMESSAGE | QS_INPUT)) { 05274 ptiCurrent->ppi->ptiMainThread = ptiCurrent; 05275 } 05276 05277 /* 05278 * When we return, this app is going to sleep. Since it is in its 05279 * idle mode when it goes to sleep, wake any apps waiting for this 05280 * app to go idle. 05281 */ 05282 zzzWakeInputIdle(ptiCurrent); 05283 /* 05284 * Setup the wake mask for this thread. Wait for QS_EVENT or the app won't 05285 * get event messages like deactivate. 05286 */ 05287 ClearQueueServerEvent((WORD)(dwWakeMask | QS_EVENT)); 05288 /* 05289 * This app is going idle. Clear the spin count check to see 05290 * if we need to make this process foreground again. 05291 */ 05292 ptiCurrent->pClientInfo->cSpins = 0; 05293 if (ptiCurrent->TIF_flags & TIF_SPINNING) { 05294 CheckProcessForeground(ptiCurrent); 05295 } 05296 05297 UserAssert(ptiCurrent->pcti->fsWakeMask != 0); 05298 return ptiCurrent->hEventQueueClient; 05299 } 05300 05301 /***************************************************************************\ 05302 * xxxWaitForInputIdle 05303 * 05304 * This routine waits on a particular input queue for "input idle", meaning 05305 * it waits till that queue has no input to process. 05306 * 05307 * 09-13-91 ScottLu Created. 05308 \***************************************************************************/ 05309 05310 DWORD xxxWaitForInputIdle( 05311 ULONG_PTR idProcess, 05312 DWORD dwMilliseconds, 05313 BOOL fSharedWow) 05314 { 05315 PTHREADINFO ptiCurrent; 05316 PTHREADINFO pti; 05317 PEPROCESS Process; 05318 PW32PROCESS W32Process; 05319 PPROCESSINFO ppi; 05320 DWORD dwResult; 05321 NTSTATUS Status; 05322 TL tlProcess; 05323 05324 ptiCurrent = PtiCurrent(); 05325 05326 /* 05327 * If fSharedWow is set, the client passed in a fake process 05328 * handle which CreateProcess returns for Win16 apps started 05329 * in the shared WOW VDM. 05330 * 05331 * CreateProcess returns a real process handle when you start 05332 * a Win16 app in a separate WOW VDM. 05333 */ 05334 05335 if (fSharedWow) { // Waiting for a WOW task to go idle. 05336 PWOWTHREADINFO pwti; 05337 05338 05339 /* 05340 * Look for a matching thread in the WOW thread info list. 05341 */ 05342 for (pwti = gpwtiFirst; pwti != NULL; pwti = pwti->pwtiNext) { 05343 if (pwti->idParentProcess == HandleToUlong(ptiCurrent->pEThread->Cid.UniqueProcess) && 05344 pwti->idWaitObject == idProcess) { 05345 break; 05346 } 05347 } 05348 05349 /* 05350 * If we couldn't find the right thread, bail out. 05351 */ 05352 if (pwti == NULL) { 05353 RIPMSG0(RIP_WARNING, "WaitForInputIdle couldn't find 16-bit task\n"); 05354 return (DWORD)-1; 05355 } 05356 05357 /* 05358 * Now wait for it to go idle and return. 05359 */ 05360 dwResult = WaitOnPseudoEvent(&pwti->pIdleEvent, dwMilliseconds); 05361 if (dwResult == STATUS_ABANDONED) { 05362 dwResult = xxxPollAndWaitForSingleObject(pwti->pIdleEvent, 05363 NULL, 05364 dwMilliseconds); 05365 } 05366 return dwResult; 05367 05368 } 05369 05370 /* 05371 * We shouldn't get here for system threads. 05372 */ 05373 UserAssert(!(ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD)); 05374 05375 /* 05376 * If the app is waiting for itself to go idle, error. 05377 */ 05378 if (ptiCurrent->pEThread->Cid.UniqueProcess == (HANDLE)idProcess && 05379 ptiCurrent == ptiCurrent->ppi->ptiMainThread) { 05380 RIPMSG0(RIP_WARNING, "WaitForInputIdle waiting on self\n"); 05381 return (DWORD)-1; 05382 } 05383 05384 /* 05385 * Now find the ppi structure for this process. 05386 */ 05387 LeaveCrit(); 05388 Status = LockProcessByClientId((HANDLE)idProcess, &Process); 05389 EnterCrit(); 05390 05391 if (!NT_SUCCESS(Status)) 05392 return (DWORD)-1; 05393 05394 if (Process->ExitProcessCalled) { 05395 UnlockProcess(Process); 05396 return (DWORD)-1; 05397 } 05398 05399 W32Process = (PW32PROCESS)Process->Win32Process; 05400 05401 /* 05402 * Couldn't find that process info structure.... return error. 05403 */ 05404 if (W32Process == NULL) { 05405 RIPMSG0(RIP_WARNING, "WaitForInputIdle process not GUI process\n"); 05406 UnlockProcess(Process); 05407 return (DWORD)-1; 05408 } 05409 05410 05411 ppi = (PPROCESSINFO)W32Process; 05412 05413 /* 05414 * If this is a console application, don't wait on it. 05415 */ 05416 if (W32Process->W32PF_Flags & W32PF_CONSOLEAPPLICATION) { 05417 RIPMSG0(RIP_WARNING, "WaitForInputIdle process is console process\n"); 05418 UnlockProcess(Process); 05419 return (DWORD)-1; 05420 } 05421 05422 /* 05423 * Wait on this event for the passed in time limit. 05424 */ 05425 CheckForClientDeath(); 05426 05427 /* 05428 * We have to wait mark the Process as one which others are waiting on 05429 */ 05430 ppi->W32PF_Flags |= W32PF_WAITFORINPUTIDLE; 05431 for (pti = ppi->ptiList; pti != NULL; pti = pti->ptiSibling) { 05432 pti->TIF_flags |= TIF_WAITFORINPUTIDLE; 05433 } 05434 05435 /* 05436 * Thread lock the process to ensure that it will be dereferenced 05437 * if the thread exits. 05438 */ 05439 LockW32Process(W32Process, &tlProcess); 05440 UnlockProcess(Process); 05441 05442 dwResult = WaitOnPseudoEvent(&W32Process->InputIdleEvent, dwMilliseconds); 05443 if (dwResult == STATUS_ABANDONED) { 05444 dwResult = xxxPollAndWaitForSingleObject(W32Process->InputIdleEvent, 05445 Process, 05446 dwMilliseconds); 05447 } 05448 05449 /* 05450 * Clear all thread TIF_WAIT bits from the process. 05451 */ 05452 ppi->W32PF_Flags &= ~W32PF_WAITFORINPUTIDLE; 05453 for (pti = ppi->ptiList; pti != NULL; pti = pti->ptiSibling) { 05454 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE; 05455 } 05456 05457 UnlockW32Process(&tlProcess); 05458 05459 return dwResult; 05460 } 05461 05462 05463 #define INTERMEDIATE_TIMEOUT (500) // 1/2 second 05464 05465 /***************************************************************************\ 05466 * xxxPollAndWaitForSingleObject 05467 * 05468 * Sometimes we have to wait on an event but still want to periodically 05469 * wake up and see if the client process has been terminated. 05470 * 05471 * dwMilliseconds is initially the total amount of time to wait and after 05472 * each intermediate wait reflects the amount of time left to wait. 05473 * -1 means wait indefinitely. 05474 * 05475 * 02-Jul-1993 johnc Created. 05476 \***************************************************************************/ 05477 05478 // LATER!!! can we get rid of the Polling idea and wait additionally on 05479 // LATER!!! the hEventServer and set that when a thread dies 05480 05481 DWORD xxxPollAndWaitForSingleObject( 05482 PKEVENT pEvent, 05483 PVOID pExecObject, 05484 DWORD dwMilliseconds) 05485 { 05486 DWORD dwIntermediateMilliseconds, dwStartTickCount; 05487 PTHREADINFO ptiCurrent; 05488 UINT cEvent = 2; 05489 NTSTATUS Status = -1; 05490 LARGE_INTEGER li; 05491 TL tlEvent; 05492 05493 ptiCurrent = PtiCurrent(); 05494 05495 if (ptiCurrent->apEvent == NULL) { 05496 ptiCurrent->apEvent = UserAllocPoolNonPaged(POLL_EVENT_CNT * sizeof(PKEVENT), TAG_EVENT); 05497 if (ptiCurrent->apEvent == NULL) 05498 return (DWORD)-1; 05499 } 05500 05501 /* 05502 * Refcount the event to ensure that it won't go 05503 * away during the wait. By using a thread lock, the 05504 * event will be dereferenced if the thread exits 05505 * during a callback. The process pointer has already been 05506 * locked. 05507 */ 05508 ThreadLockObject(pEvent, &tlEvent); 05509 05510 /* 05511 * If a process was passed in, wait on it too. No need 05512 * to reference this because the caller has it referenced. 05513 */ 05514 if (pExecObject) { 05515 cEvent++; 05516 } 05517 05518 /* 05519 * We want to wake if there're sent messages pending 05520 */ 05521 ClearQueueServerEvent(QS_SENDMESSAGE); 05522 05523 /* 05524 * Wow Tasks MUST be descheduled while in the wait to allow 05525 * other tasks in the same wow scheduler to run. 05526 * 05527 * For example, 16 bit app A calls WaitForInputIdle on 32 bit app B. 05528 * App B starts up and tries to send a message to 16 bit app C. App C 05529 * will never be able to process the message unless app A yields 05530 * control to it, so app B will never go idle. 05531 */ 05532 05533 if (ptiCurrent->TIF_flags & TIF_16BIT) { 05534 xxxSleepTask(FALSE, HEVENT_REMOVEME); 05535 // caution: the wow task is no longer scheduled. 05536 } 05537 05538 dwStartTickCount = NtGetTickCount(); 05539 while (TRUE) { 05540 if (dwMilliseconds > INTERMEDIATE_TIMEOUT) { 05541 dwIntermediateMilliseconds = INTERMEDIATE_TIMEOUT; 05542 05543 /* 05544 * If we are not waiting an infinite amount of time then subtract 05545 * the last loop duration from time left to wait. 05546 */ 05547 if (dwMilliseconds != INFINITE) { 05548 DWORD dwNewTickCount = NtGetTickCount(); 05549 DWORD dwDelta = ComputePastTickDelta(dwNewTickCount, dwStartTickCount); 05550 dwStartTickCount = dwNewTickCount; 05551 if (dwDelta < dwMilliseconds) { 05552 dwMilliseconds -= dwDelta; 05553 } else { 05554 dwMilliseconds = 0; 05555 } 05556 } 05557 } else { 05558 dwIntermediateMilliseconds = dwMilliseconds; 05559 dwMilliseconds = 0; 05560 } 05561 05562 /* 05563 * Convert dwMilliseconds to a relative-time(i.e. negative) LARGE_INTEGER. 05564 * NT Base calls take time values in 100 nanosecond units. 05565 */ 05566 if (dwIntermediateMilliseconds != INFINITE) 05567 li.QuadPart = Int32x32To64(-10000, dwIntermediateMilliseconds); 05568 05569 /* 05570 * Load events into the wait array. Do this every time 05571 * through the loop in case of recursion. 05572 */ 05573 ptiCurrent->apEvent[IEV_IDLE] = pEvent; 05574 ptiCurrent->apEvent[IEV_INPUT] = ptiCurrent->pEventQueueServer; 05575 ptiCurrent->apEvent[IEV_EXEC] = pExecObject; 05576 05577 LeaveCrit(); 05578 05579 Status = KeWaitForMultipleObjects(cEvent, 05580 &ptiCurrent->apEvent[IEV_IDLE], 05581 WaitAny, 05582 WrUserRequest, 05583 UserMode, 05584 FALSE, 05585 (dwIntermediateMilliseconds == INFINITE ? 05586 NULL : &li), 05587 NULL); 05588 05589 EnterCrit(); 05590 05591 if (!NT_SUCCESS(Status)) { 05592 Status = -1; 05593 } else { 05594 05595 /* 05596 * Because we do a non-alertable wait, we know that a status 05597 * of STATUS_USER_APC means that the thread was terminated. 05598 * If we have terminated, get back to user mode 05599 */ 05600 if (Status == STATUS_USER_APC) { 05601 ClientDeliverUserApc(); 05602 Status = -1; 05603 } 05604 } 05605 05606 if (ptiCurrent->pcti->fsChangeBits & QS_SENDMESSAGE) { 05607 /* 05608 * Wow Tasks MUST wait to be rescheduled in the wow non-premptive 05609 * scheduler before doing anything which might invoke client code. 05610 */ 05611 if (ptiCurrent->TIF_flags & TIF_16BIT) { 05612 xxxDirectedYield(DY_OLDYIELD); 05613 } 05614 05615 xxxReceiveMessages(ptiCurrent); 05616 05617 if (ptiCurrent->TIF_flags & TIF_16BIT) { 05618 xxxSleepTask(FALSE, HEVENT_REMOVEME); 05619 // caution: the wow task is no longer scheduled. 05620 } 05621 } 05622 05623 /* 05624 * If we returned from the wait for some other reason than a timeout 05625 * or to receive messages we are done. If it is a timeout we are 05626 * only done waiting if the overall time is zero. 05627 */ 05628 if (Status != STATUS_TIMEOUT && Status != 1) 05629 break; 05630 05631 if (dwMilliseconds == 0) { 05632 /* 05633 * Fix up the return if the last poll was interupted by a message 05634 */ 05635 if (Status == 1) 05636 Status = WAIT_TIMEOUT; 05637 break; 05638 } 05639 05640 } 05641 05642 /* 05643 * reschedule the 16 bit app 05644 */ 05645 if (ptiCurrent->TIF_flags & TIF_16BIT) { 05646 xxxDirectedYield(DY_OLDYIELD); 05647 } 05648 05649 /* 05650 * Unlock the events. 05651 */ 05652 ThreadUnlockObject(&tlEvent); 05653 05654 return Status; 05655 } 05656 05657 05658 05659 /***************************************************************************\ 05660 * WaitOnPseudoEvent 05661 * 05662 * Similar semantics to WaitForSingleObject() but works with pseudo events. 05663 * Could fail if creation on the fly fails. 05664 * Returns STATUS_ABANDONED_WAIT if caller needs to wait on the event and event is 05665 * created and ready to be waited on. 05666 * 05667 * This assumes the event was created with fManualReset=TRUE, fInitState=FALSE 05668 * 05669 * 10/28/93 SanfordS Created 05670 \***************************************************************************/ 05671 DWORD WaitOnPseudoEvent( 05672 HANDLE *phE, 05673 DWORD dwMilliseconds) 05674 { 05675 HANDLE hEvent; 05676 NTSTATUS Status; 05677 05678 CheckCritIn(); 05679 if (*phE == PSEUDO_EVENT_OFF) { 05680 if (!NT_SUCCESS(ZwCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, 05681 NotificationEvent, FALSE))) { 05682 UserAssert(!"Could not create event on the fly."); 05683 if (dwMilliseconds != INFINITE) { 05684 return STATUS_TIMEOUT; 05685 } else { 05686 return (DWORD)-1; 05687 } 05688 } 05689 Status = ObReferenceObjectByHandle(hEvent, EVENT_ALL_ACCESS, *ExEventObjectType, 05690 KernelMode, phE, NULL); 05691 ZwClose(hEvent); 05692 if (!NT_SUCCESS(Status)) 05693 return (DWORD)-1; 05694 } else if (*phE == PSEUDO_EVENT_ON) { 05695 return STATUS_WAIT_0; 05696 } 05697 return(STATUS_ABANDONED); 05698 } 05699 05700 /***************************************************************************\ 05701 * xxxSetCsrssThreadDesktop 05702 * 05703 * Set/clear and lock/unlock a desktop for a csrss thread 05704 * When setting a desktop, ppdeskRestore must be valid and will receive 05705 * the old (previous) desktop, if any; the caller is expected to restore 05706 * this pdesk when done. 05707 * When restoring a desktop, ppdeskRestore must be NULL. pdesk must have been 05708 * previously returned by this same function (in *ppdeskRestore). 05709 * 05710 * History: 05711 * 02-18-97 GerardoB Extracted from SetInformationThread 05712 \***************************************************************************/ 05713 NTSTATUS xxxSetCsrssThreadDesktop(PDESKTOP pdesk, PDESKRESTOREDATA pdrdRestore) 05714 { 05715 PTHREADINFO ptiCurrent = PtiCurrent(); 05716 NTSTATUS Status = STATUS_SUCCESS; 05717 MSG msg; 05718 05719 /* 05720 * Only csr should come here 05721 */ 05722 UserAssert(ISCSRSS()); 05723 UserAssert(pdrdRestore); 05724 UserAssert(pdrdRestore->pdeskRestore == NULL); 05725 05726 if (pdesk->dwDTFlags & DF_DESTROYED) { 05727 RIPMSG1(RIP_WARNING, "xxxSetCsrssThreadDesktop: pdesk 0x%x destroyed", 05728 pdesk); 05729 return STATUS_UNSUCCESSFUL; 05730 } 05731 05732 /* 05733 * Lock the current desktop (set operation). Also, create and save a 05734 * handle to the new desktop. 05735 */ 05736 pdrdRestore->pdeskRestore = ptiCurrent->rpdesk; 05737 05738 if (pdrdRestore->pdeskRestore != NULL) { 05739 Status = ObReferenceObjectByPointer(pdrdRestore->pdeskRestore, 05740 MAXIMUM_ALLOWED, 05741 *ExDesktopObjectType, 05742 KernelMode); 05743 05744 if (!NT_SUCCESS(Status)) { 05745 pdrdRestore->pdeskRestore = NULL; 05746 pdrdRestore->hdeskNew = NULL; 05747 return Status; 05748 } 05749 LogDesktop(pdrdRestore->pdeskRestore, LD_REF_FN_SETCSRSSTHREADDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 05750 } 05751 05752 Status = ObOpenObjectByPointer( 05753 pdesk, 05754 0, 05755 NULL, 05756 EVENT_ALL_ACCESS, 05757 NULL, 05758 KernelMode, 05759 &(pdrdRestore->hdeskNew)); 05760 05761 05762 if (!NT_SUCCESS(Status)) { 05763 RIPNTERR2(Status, RIP_WARNING, "SetCsrssThreadDesktop, can't open handle, pdesk %#p. Status: %#x", pdesk, Status); 05764 if (pdrdRestore->pdeskRestore) { 05765 LogDesktop(pdrdRestore->pdeskRestore, LD_DEREF_FN_SETCSRSSTHREADDESKTOP1, FALSE, (ULONG_PTR)PtiCurrent()); 05766 ObDereferenceObject(pdrdRestore->pdeskRestore); 05767 pdrdRestore->pdeskRestore = NULL; 05768 } 05769 pdrdRestore->hdeskNew = NULL; 05770 return Status; 05771 } 05772 /* 05773 * Set the new desktop, if switching 05774 */ 05775 if (pdesk != ptiCurrent->rpdesk) { 05776 /* 05777 * Process any remaining messages before we leave the desktop 05778 */ 05779 if (ptiCurrent->rpdesk) { 05780 while (xxxPeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) 05781 xxxDispatchMessage(&msg); 05782 } 05783 05784 if (!xxxSetThreadDesktop(NULL, pdesk)) { 05785 RIPMSG1(RIP_WARNING, "xxxSetCsrssThreadDesktop: xxxSetThreadDesktop(%#p) failed", pdesk); 05786 Status = STATUS_INVALID_HANDLE; 05787 /* 05788 * We're failing so deref if needed. 05789 */ 05790 if (pdrdRestore->pdeskRestore != NULL) { 05791 LogDesktop(pdrdRestore->pdeskRestore, LD_DEREF_FN_SETCSRSSTHREADDESKTOP1, FALSE, (ULONG_PTR)PtiCurrent()); 05792 ObDereferenceObject(pdrdRestore->pdeskRestore); 05793 pdrdRestore->pdeskRestore = NULL; 05794 } 05795 CloseProtectedHandle(pdrdRestore->hdeskNew); 05796 pdrdRestore->hdeskNew = NULL; 05797 } 05798 } 05799 05800 UserAssert(NT_SUCCESS(Status)); 05801 return Status; 05802 } 05803 05804 NTSTATUS xxxRestoreCsrssThreadDesktop(PDESKRESTOREDATA pdrdRestore) 05805 { 05806 PTHREADINFO ptiCurrent = PtiCurrent(); 05807 NTSTATUS Status = STATUS_SUCCESS; 05808 MSG msg; 05809 05810 /* 05811 * Only csr should come here 05812 */ 05813 UserAssert(ISCSRSS()); 05814 UserAssert(pdrdRestore); 05815 05816 /* 05817 * Set the new desktop, if switching 05818 */ 05819 if (pdrdRestore->pdeskRestore != ptiCurrent->rpdesk) { 05820 /* 05821 * Process any remaining messages before we leave the desktop 05822 */ 05823 if (ptiCurrent->rpdesk) { 05824 while (xxxPeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) 05825 xxxDispatchMessage(&msg); 05826 } 05827 05828 if (!xxxSetThreadDesktop(NULL, pdrdRestore->pdeskRestore)) { 05829 RIPMSG1(RIP_WARNING, "xxxRestoreCsrssThreadDesktop: xxxRestoreThreadDesktop(%#p) failed", pdrdRestore->pdeskRestore); 05830 Status = STATUS_INVALID_HANDLE; 05831 } 05832 } 05833 05834 /* 05835 * Dereference the desktop, 05836 * even if failing the call. 05837 */ 05838 if (pdrdRestore->pdeskRestore != NULL) { 05839 LogDesktop(pdrdRestore->pdeskRestore, LD_DEREF_FN_SETCSRSSTHREADDESKTOP2, FALSE, 0); 05840 ObDereferenceObject(pdrdRestore->pdeskRestore); 05841 pdrdRestore->pdeskRestore = NULL; 05842 } 05843 05844 if(pdrdRestore->hdeskNew) { 05845 CloseProtectedHandle(pdrdRestore->hdeskNew); 05846 UserAssert(NT_SUCCESS(Status)); 05847 pdrdRestore->hdeskNew = NULL; 05848 } 05849 return Status; 05850 } 05851 05852 /***************************************************************************\ 05853 * GetTaskName 05854 * 05855 * Gets the application name from a thread. 05856 \***************************************************************************/ 05857 ULONG GetTaskName( 05858 PTHREADINFO pti, 05859 PWSTR Buffer, 05860 ULONG BufferLength) 05861 { 05862 ANSI_STRING strAppName; 05863 UNICODE_STRING strAppNameU; 05864 NTSTATUS Status; 05865 ULONG NameLength = 0; 05866 05867 if (pti == NULL) { 05868 *Buffer = 0; 05869 return 0; 05870 } 05871 if (pti->pstrAppName != NULL) { 05872 NameLength = min(pti->pstrAppName->Length + sizeof(WCHAR), BufferLength); 05873 RtlCopyMemory(Buffer, pti->pstrAppName->Buffer, NameLength); 05874 } else { 05875 RtlInitAnsiString(&strAppName, pti->pEThread->ThreadsProcess->ImageFileName); 05876 if (BufferLength < sizeof(WCHAR)) 05877 NameLength = (strAppName.Length + 1) * sizeof(WCHAR); 05878 else { 05879 strAppNameU.Buffer = Buffer; 05880 strAppNameU.MaximumLength = (SHORT)BufferLength - sizeof(WCHAR); 05881 Status = RtlAnsiStringToUnicodeString(&strAppNameU, &strAppName, 05882 FALSE); 05883 if (NT_SUCCESS(Status)) 05884 NameLength = strAppNameU.Length + sizeof(WCHAR); 05885 } 05886 } 05887 Buffer[(NameLength / sizeof(WCHAR)) - 1] = 0; 05888 05889 return NameLength; 05890 } 05891 05892 /***************************************************************************\ 05893 * QueryInformationThread 05894 * 05895 * Returns information about a thread. 05896 * 05897 * History: 05898 * 03-01-95 JimA Created. 05899 \***************************************************************************/ 05900 05901 NTSTATUS xxxQueryInformationThread( 05902 IN HANDLE hThread, 05903 IN USERTHREADINFOCLASS ThreadInfoClass, 05904 OUT PVOID ThreadInformation, 05905 IN ULONG ThreadInformationLength, 05906 OUT PULONG ReturnLength OPTIONAL) 05907 { 05908 PUSERTHREAD_SHUTDOWN_INFORMATION pShutdown; 05909 PUSERTHREAD_WOW_INFORMATION pWow; 05910 PETHREAD Thread; 05911 PTHREADINFO pti; 05912 NTSTATUS Status = STATUS_SUCCESS; 05913 ULONG LocalReturnLength = 0; 05914 DWORD dwClientFlags; 05915 05916 UNREFERENCED_PARAMETER(ThreadInformationLength); 05917 /* 05918 * Only allow CSRSS to make this call 05919 */ 05920 UserAssert(ISCSRSS()); 05921 05922 Status = ObReferenceObjectByHandle(hThread, 05923 THREAD_QUERY_INFORMATION, 05924 *PsThreadType, 05925 UserMode, 05926 &Thread, 05927 NULL); 05928 if (!NT_SUCCESS(Status)) 05929 return Status; 05930 05931 pti = PtiFromThread(Thread); 05932 05933 switch (ThreadInfoClass) { 05934 case UserThreadShutdownInformation: 05935 LocalReturnLength = sizeof(USERTHREAD_SHUTDOWN_INFORMATION); 05936 UserAssert(ThreadInformationLength == sizeof(USERTHREAD_SHUTDOWN_INFORMATION)); 05937 pShutdown = ThreadInformation; 05938 /* 05939 * Read the client flags and zero out the structure, 05940 * except for pdeskRestore (which is supposed 05941 * to be the last field) 05942 */ 05943 dwClientFlags = pShutdown->dwFlags; 05944 UserAssert(FIELD_OFFSET(USERTHREAD_SHUTDOWN_INFORMATION, drdRestore) 05945 == (sizeof(USERTHREAD_SHUTDOWN_INFORMATION) - sizeof(DESKRESTOREDATA))); 05946 RtlZeroMemory(pShutdown, 05947 sizeof(USERTHREAD_SHUTDOWN_INFORMATION) - sizeof(DESKRESTOREDATA)); 05948 05949 /* 05950 * Return the desktop window handle if the thread 05951 * has a desktop and the desktop is on a visible 05952 * windowstation. 05953 */ 05954 if (pti != NULL && pti->rpdesk != NULL && 05955 !(pti->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)) 05956 pShutdown->hwndDesktop = HW(pti->rpdesk->pDeskInfo->spwnd); 05957 05958 /* 05959 * Return shutdown status. Zero indicates that the thread 05960 * has windows and can be shut down in the normal manner. 05961 */ 05962 if (Thread->Cid.UniqueProcess == gpidLogon) { 05963 /* 05964 * Do not shutdown the logon process. 05965 */ 05966 pShutdown->StatusShutdown = SHUTDOWN_KNOWN_PROCESS; 05967 } else if (pti == NULL || pti->rpdesk == NULL) { 05968 05969 /* 05970 * The thread either is not a gui thread or it doesn't 05971 * have a desktop. Make console do the shutdown. 05972 */ 05973 pShutdown->StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS; 05974 } 05975 05976 /* 05977 * Return flags 05978 */ 05979 if (pti != NULL && pti->cWindows != 0) 05980 pShutdown->dwFlags |= USER_THREAD_GUI; 05981 05982 /* 05983 * If we return the desktop window handle and the 05984 * app should be shut down, switch to the desktop 05985 * and assign it to the shutdown worker thread. 05986 */ 05987 if ((pShutdown->dwFlags & USER_THREAD_GUI) && 05988 pShutdown->StatusShutdown == 0) { 05989 /* 05990 * The current csrss thread is going to 05991 * make activation calls, send messages, 05992 * switch video modes, etc so we need to 05993 * assign it to a dekstop 05994 */ 05995 PTHREADINFO ptiCurrent = PtiCurrent(); 05996 UserAssert(pti->rpdesk != NULL); 05997 05998 if (ptiCurrent->rpdesk != pti->rpdesk) { 05999 /* 06000 * If this thread already has a desktop, 06001 * restore the old one first. 06002 * This might happen when threads of the same 06003 * process are attached to different desktops. 06004 */ 06005 if (ptiCurrent->rpdesk != NULL) { 06006 Status = xxxRestoreCsrssThreadDesktop(&pShutdown->drdRestore); 06007 UserAssert(pti == PtiFromThread(Thread)); 06008 } 06009 if (NT_SUCCESS(Status)) { 06010 Status = xxxSetCsrssThreadDesktop(pti->rpdesk, &pShutdown->drdRestore); 06011 UserAssert(pti == PtiFromThread(Thread)); 06012 } 06013 } 06014 /* 06015 * If we're forcing a shutdown, then there is no need to switch 06016 * since we won't send any messages or bring up the EndTask dialog 06017 * (We still want to have a proper rpdesk since BoostHardError might 06018 * call PostThreadMessage) 06019 */ 06020 if (!(dwClientFlags & WMCS_NORETRY)) { 06021 if (NT_SUCCESS(Status)) { 06022 #if DBG 06023 BOOL fSwitch = 06024 #endif 06025 xxxSwitchDesktop(pti->rpdesk->rpwinstaParent, pti->rpdesk, FALSE); 06026 #if DBG 06027 UserAssert(pti == PtiFromThread(Thread)); 06028 if (!fSwitch) { 06029 if ((pti->rpdesk->rpwinstaParent == NULL) 06030 || !(pti->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)) { 06031 06032 if (!(pti->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_REALSHUTDOWN)) 06033 RIPMSG1(RIP_ERROR, "UserThreadShutdownInformation: xxxSwitchDesktop failed. pti:%#p", pti); 06034 06035 } 06036 } 06037 #endif 06038 } 06039 } 06040 } 06041 break; 06042 06043 case UserThreadFlags: 06044 LocalReturnLength = sizeof(DWORD); 06045 if (pti == NULL) 06046 Status = STATUS_INVALID_HANDLE; 06047 else { 06048 UserAssert(ThreadInformationLength == sizeof(DWORD)); 06049 *(LPDWORD)ThreadInformation = pti->TIF_flags; 06050 } 06051 break; 06052 06053 case UserThreadTaskName: 06054 LocalReturnLength = GetTaskName(pti, ThreadInformation, ThreadInformationLength); 06055 break; 06056 06057 case UserThreadWOWInformation: 06058 LocalReturnLength = sizeof(USERTHREAD_WOW_INFORMATION); 06059 UserAssert(ThreadInformationLength == sizeof(USERTHREAD_WOW_INFORMATION)); 06060 pWow = ThreadInformation; 06061 RtlZeroMemory(pWow, sizeof(USERTHREAD_WOW_INFORMATION)); 06062 06063 /* 06064 * If the thread is 16-bit, Status = the exit task function 06065 * and task id. 06066 */ 06067 if (pti && pti->TIF_flags & TIF_16BIT) { 06068 pWow->lpfnWowExitTask = pti->ppi->pwpi->lpfnWowExitTask; 06069 if (pti->ptdb) 06070 pWow->hTaskWow = pti->ptdb->hTaskWow; 06071 else 06072 pWow->hTaskWow = 0; 06073 } 06074 break; 06075 06076 case UserThreadHungStatus: 06077 LocalReturnLength = sizeof(DWORD); 06078 UserAssert(ThreadInformationLength >= sizeof(DWORD)); 06079 06080 /* 06081 * Return hung status. 06082 */ 06083 if (pti) 06084 *(PDWORD)ThreadInformation = 06085 (DWORD) FHungApp(pti, (DWORD)*(PDWORD)ThreadInformation); 06086 else 06087 *(PDWORD)ThreadInformation = FALSE; 06088 break; 06089 06090 default: 06091 Status = STATUS_INVALID_INFO_CLASS; 06092 UserAssert(FALSE); 06093 break; 06094 } 06095 06096 if (ARGUMENT_PRESENT(ReturnLength) ) { 06097 *ReturnLength = LocalReturnLength; 06098 } 06099 06100 UnlockThread(Thread); 06101 06102 return Status; 06103 } 06104 06105 /***************************************************************************\ 06106 * xxxSetInformationThread 06107 * 06108 * Sets information about a thread. 06109 * 06110 * History: 06111 * 03-01-95 JimA Created. 06112 \***************************************************************************/ 06113 06114 NTSTATUS xxxSetInformationThread( 06115 IN HANDLE hThread, 06116 IN USERTHREADINFOCLASS ThreadInfoClass, 06117 IN PVOID ThreadInformation, 06118 IN ULONG ThreadInformationLength) 06119 { 06120 PUSERTHREAD_FLAGS pFlags; 06121 HANDLE hClientThread; 06122 DWORD dwOldFlags; 06123 PTHREADINFO ptiT; 06124 NTSTATUS Status = STATUS_SUCCESS; 06125 PETHREAD Thread; 06126 PETHREAD ThreadClient; 06127 PTHREADINFO pti; 06128 HANDLE CsrPortHandle; 06129 06130 UNREFERENCED_PARAMETER(ThreadInformationLength); 06131 06132 /* 06133 * Only allow CSRSS to make this call 06134 */ 06135 UserAssert(ISCSRSS()); 06136 06137 Status = ObReferenceObjectByHandle(hThread, 06138 THREAD_SET_INFORMATION, 06139 *PsThreadType, 06140 UserMode, 06141 &Thread, 06142 NULL); 06143 if (!NT_SUCCESS(Status)) 06144 return Status; 06145 06146 pti = PtiFromThread(Thread); 06147 06148 switch (ThreadInfoClass) { 06149 case UserThreadFlags: 06150 if (pti == NULL) 06151 Status = STATUS_INVALID_HANDLE; 06152 else { 06153 UserAssert(ThreadInformationLength == sizeof(USERTHREAD_FLAGS)); 06154 pFlags = ThreadInformation; 06155 dwOldFlags = pti->TIF_flags; 06156 pti->TIF_flags ^= ((dwOldFlags ^ pFlags->dwFlags) & pFlags->dwMask); 06157 } 06158 break; 06159 06160 case UserThreadHungStatus: 06161 if (pti == NULL) 06162 Status = STATUS_INVALID_HANDLE; 06163 else { 06164 06165 /* 06166 * No arguments, simple set the last time read. 06167 */ 06168 SET_TIME_LAST_READ(pti); 06169 } 06170 break; 06171 06172 case UserThreadInitiateShutdown: 06173 UserAssert(ThreadInformationLength == sizeof(ULONG)); 06174 Status = InitiateShutdown(Thread, (PULONG)ThreadInformation); 06175 break; 06176 06177 case UserThreadEndShutdown: 06178 UserAssert(ThreadInformationLength == sizeof(NTSTATUS)); 06179 Status = EndShutdown(Thread, *(NTSTATUS *)ThreadInformation); 06180 break; 06181 06182 case UserThreadUseDesktop: 06183 UserAssert(ThreadInformationLength == sizeof(USERTHREAD_USEDESKTOPINFO)); 06184 if (pti == NULL) { 06185 Status = STATUS_INVALID_HANDLE; 06186 break; 06187 } 06188 06189 /* 06190 * If the caller provides a thread handle, then we use that 06191 * thread's pdesk and return the pdesk currently used 06192 * by the caller (set operation). Otherwise, 06193 * we use the pdesk provided by the caller (restore operation). 06194 */ 06195 hClientThread = ((PUSERTHREAD_USEDESKTOPINFO)ThreadInformation)->hThread; 06196 if (hClientThread != NULL) { 06197 Status = ObReferenceObjectByHandle(hClientThread, 06198 THREAD_QUERY_INFORMATION, 06199 *PsThreadType, 06200 UserMode, 06201 &ThreadClient, 06202 NULL); 06203 if (!NT_SUCCESS(Status)) 06204 break; 06205 06206 ptiT = PtiFromThread(ThreadClient); 06207 if ((ptiT == NULL) || (ptiT->rpdesk == NULL)) { 06208 Status = STATUS_INVALID_HANDLE; 06209 goto DerefClientThread; 06210 } 06211 Status = xxxSetCsrssThreadDesktop(ptiT->rpdesk, &((PUSERTHREAD_USEDESKTOPINFO)ThreadInformation)->drdRestore); 06212 } else { 06213 Status = xxxRestoreCsrssThreadDesktop(&((PUSERTHREAD_USEDESKTOPINFO)ThreadInformation)->drdRestore); 06214 } 06215 06216 06217 if (hClientThread != NULL) { 06218 DerefClientThread: 06219 ObDereferenceObject(ThreadClient); 06220 } 06221 break; 06222 06223 case UserThreadUseActiveDesktop: 06224 { 06225 UserAssert(ThreadInformationLength == sizeof(USERTHREAD_USEDESKTOPINFO)); 06226 if (pti == NULL || grpdeskRitInput == NULL) { 06227 Status = STATUS_INVALID_HANDLE; 06228 break; 06229 } 06230 Status = xxxSetCsrssThreadDesktop(grpdeskRitInput, 06231 &((PUSERTHREAD_USEDESKTOPINFO)ThreadInformation)->drdRestore); 06232 break; 06233 } 06234 case UserThreadCsrApiPort: 06235 06236 /* 06237 * Only CSR can call this 06238 */ 06239 if (Thread->ThreadsProcess != gpepCSRSS) { 06240 Status = STATUS_ACCESS_DENIED; 06241 break; 06242 } 06243 06244 UserAssert(ThreadInformationLength == sizeof(HANDLE)); 06245 06246 /* 06247 * Only set it once. 06248 */ 06249 if (CsrApiPort != NULL) 06250 break; 06251 06252 CsrPortHandle = *(PHANDLE)ThreadInformation; 06253 Status = ObReferenceObjectByHandle( 06254 CsrPortHandle, 06255 0, 06256 NULL, //*LpcPortObjectType, 06257 UserMode, 06258 &CsrApiPort, 06259 NULL); 06260 if (!NT_SUCCESS(Status)) { 06261 CsrApiPort = NULL; 06262 RIPMSG1(RIP_WARNING, 06263 "CSR port reference failed, Status=%#lx", 06264 Status); 06265 } 06266 06267 break; 06268 06269 default: 06270 Status = STATUS_INVALID_INFO_CLASS; 06271 UserAssert(FALSE); 06272 break; 06273 } 06274 06275 UnlockThread(Thread); 06276 06277 return Status; 06278 } 06279 06280 #ifdef USE_MIRRORING 06281 /***************************************************************************\ 06282 * _GetProcessDefaultLayout (API) 06283 * 06284 * Retreives the default layout information about a process. 06285 * 06286 * History: 06287 * 23-01-98 SamerA Created. 06288 \***************************************************************************/ 06289 BOOL _GetProcessDefaultLayout( 06290 OUT DWORD *pdwDefaultLayout) 06291 { 06292 NTSTATUS Status = STATUS_SUCCESS; 06293 06294 /* 06295 * Do not allow CSRSS to make this call. This call might 06296 * happen due to the inheritence code. See xxxCreateWindowEx(...) 06297 */ 06298 if (PsGetCurrentProcess() == gpepCSRSS) { 06299 return FALSE; 06300 } 06301 06302 try { 06303 *pdwDefaultLayout = PpiCurrent()->dwLayout; 06304 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 06305 Status = GetExceptionCode(); 06306 } 06307 06308 return NT_SUCCESS(Status); 06309 } 06310 06311 /***************************************************************************\ 06312 * _SetProcessDefaultLayout (API) 06313 * 06314 * Sets the default layout information about a process. 06315 * 06316 * History: 06317 * 23-01-98 SamerA Created. 06318 \***************************************************************************/ 06319 BOOL _SetProcessDefaultLayout( 06320 IN DWORD dwDefaultLayout) 06321 { 06322 /* 06323 * Do not allow CSRSS to make this call 06324 */ 06325 UserAssert(PsGetCurrentProcess() != gpepCSRSS); 06326 06327 /* 06328 * Validate dwDefaultLayout 06329 */ 06330 if (dwDefaultLayout & ~LAYOUT_ORIENTATIONMASK) 06331 { 06332 RIPERR1(ERROR_INVALID_PARAMETER, 06333 RIP_WARNING, 06334 "Calling SetProcessDefaultLayout with invalid layout = %lX", 06335 dwDefaultLayout); 06336 return FALSE; 06337 } 06338 06339 /* 06340 * Update the process default layout param 06341 */ 06342 PpiCurrent()->dwLayout = dwDefaultLayout; 06343 06344 return TRUE; 06345 } 06346 #endif 06347 06348 /***************************************************************************\ 06349 * SetInformationProcess 06350 * 06351 * Sets information about a process. 06352 * 06353 * History: 06354 * 09-27-96 GerardoB Created. 06355 \***************************************************************************/ 06356 06357 NTSTATUS SetInformationProcess( 06358 IN HANDLE hProcess, 06359 IN USERPROCESSINFOCLASS ProcessInfoClass, 06360 IN PVOID ProcessInformation, 06361 IN ULONG ProcessInformationLength) 06362 { 06363 PUSERPROCESS_FLAGS pFlags; 06364 DWORD dwOldFlags; 06365 NTSTATUS Status = STATUS_SUCCESS; 06366 PEPROCESS Process; 06367 PPROCESSINFO ppi; 06368 06369 UNREFERENCED_PARAMETER(ProcessInformationLength); 06370 06371 UserAssert(ISCSRSS()); 06372 06373 Status = ObReferenceObjectByHandle(hProcess, 06374 PROCESS_SET_INFORMATION, 06375 *PsProcessType, 06376 UserMode, 06377 &Process, 06378 NULL); 06379 if (!NT_SUCCESS(Status)) { 06380 return Status; 06381 } 06382 06383 ppi = PpiFromProcess(Process); 06384 06385 switch (ProcessInfoClass) { 06386 case UserProcessFlags: 06387 if (ppi == NULL) { 06388 Status = STATUS_INVALID_HANDLE; 06389 } else { 06390 UserAssert(ProcessInformationLength == sizeof(USERPROCESS_FLAGS)); 06391 pFlags = ProcessInformation; 06392 dwOldFlags = ppi->W32PF_Flags; 06393 ppi->W32PF_Flags ^= ((dwOldFlags ^ pFlags->dwFlags) & pFlags->dwMask); 06394 } 06395 break; 06396 06397 default: 06398 Status = STATUS_INVALID_INFO_CLASS; 06399 UserAssert(FALSE); 06400 break; 06401 } 06402 06403 UnlockProcess(Process); 06404 06405 return Status; 06406 } 06407 06408 06409 /***************************************************************************\ 06410 * xxxSetConsoleCaretInfo 06411 * 06412 * Store information about the console's homegrown caret and notify any 06413 * interested apps that it changed. We need this for accessibility. 06414 * 06415 * History: 06416 * 26-May-1999 JerrySh Created. 06417 \***************************************************************************/ 06418 06419 VOID xxxSetConsoleCaretInfo( 06420 PCONSOLE_CARET_INFO pcci) 06421 { 06422 PWND pwnd; 06423 TL tlpwnd; 06424 06425 if (FWINABLE()) { 06426 pwnd = ValidateHwnd(pcci->hwnd); 06427 if (pwnd && pwnd->head.rpdesk) { 06428 pwnd->head.rpdesk->cciConsole = *pcci; 06429 ThreadLock(pwnd, &tlpwnd); 06430 xxxWindowEvent(EVENT_OBJECT_LOCATIONCHANGE, pwnd, OBJID_CARET, INDEXID_CONTAINER, WEF_ASYNC); 06431 ThreadUnlock(&tlpwnd); 06432 } 06433 } 06434 } 06435 06436 /***************************************************************************\ 06437 * xxxConsoleControl 06438 * 06439 * Performs special control operations for console. 06440 * 06441 * History: 06442 * 03-01-95 JimA Created. 06443 \***************************************************************************/ 06444 06445 NTSTATUS xxxConsoleControl( 06446 IN CONSOLECONTROL ConsoleControl, 06447 IN PVOID ConsoleInformation, 06448 IN ULONG ConsoleInformationLength) 06449 { 06450 PCONSOLEDESKTOPCONSOLETHREAD pDesktopConsole; 06451 PCONSOLEWINDOWSTATIONPROCESS pConsoleWindowStationInfo; 06452 PDESKTOP pdesk; 06453 DWORD dwThreadIdOld; 06454 NTSTATUS Status = STATUS_SUCCESS; 06455 06456 UNREFERENCED_PARAMETER(ConsoleInformationLength); 06457 UserAssert(ISCSRSS()); 06458 06459 switch (ConsoleControl) { 06460 case ConsoleDesktopConsoleThread: 06461 UserAssert(ConsoleInformationLength == sizeof(CONSOLEDESKTOPCONSOLETHREAD)); 06462 pDesktopConsole = (PCONSOLEDESKTOPCONSOLETHREAD)ConsoleInformation; 06463 06464 Status = ObReferenceObjectByHandle( 06465 pDesktopConsole->hdesk, 06466 0, 06467 *ExDesktopObjectType, 06468 UserMode, 06469 &pdesk, 06470 NULL); 06471 if (!NT_SUCCESS(Status)) 06472 return Status; 06473 06474 LogDesktop(pdesk, LD_REF_FN_CONSOLECONTROL1, TRUE, (ULONG_PTR)PtiCurrent()); 06475 06476 dwThreadIdOld = pdesk->dwConsoleThreadId; 06477 06478 if (pDesktopConsole->dwThreadId != (DWORD)-1) { 06479 pdesk->dwConsoleThreadId = 06480 pDesktopConsole->dwThreadId; 06481 } 06482 06483 pDesktopConsole->dwThreadId = dwThreadIdOld; 06484 LogDesktop(pdesk, LD_DEREF_FN_CONSOLECONTROL1, FALSE, (ULONG_PTR)PtiCurrent()); 06485 ObDereferenceObject(pdesk); 06486 break; 06487 06488 case ConsoleClassAtom: 06489 UserAssert(ConsoleInformationLength == sizeof(ATOM)); 06490 gatomConsoleClass = *(ATOM *)ConsoleInformation; 06491 break; 06492 06493 case ConsoleNotifyConsoleApplication: 06494 /* 06495 * Bug 273518 - joejo 06496 * 06497 * Adding optimization to bug fix 06498 */ 06499 UserAssert(ConsoleInformationLength == sizeof(CONSOLE_PROCESS_INFO)); 06500 xxxUserNotifyConsoleApplication((PCONSOLE_PROCESS_INFO)ConsoleInformation); 06501 break; 06502 06503 case ConsoleSetVDMCursorBounds: 06504 UserAssert((ConsoleInformation == NULL) || 06505 (ConsoleInformationLength == sizeof(RECT))); 06506 SetVDMCursorBounds(ConsoleInformation); 06507 break; 06508 06509 case ConsolePublicPalette: 06510 UserAssert(ConsoleInformationLength == sizeof(HPALETTE)); 06511 GreSetPaletteOwner(*(HPALETTE *)ConsoleInformation, OBJECT_OWNER_PUBLIC); 06512 break; 06513 06514 case ConsoleWindowStationProcess: 06515 UserAssert(ConsoleInformationLength == sizeof(CONSOLEWINDOWSTATIONPROCESS)); 06516 06517 pConsoleWindowStationInfo = (PCONSOLEWINDOWSTATIONPROCESS)ConsoleInformation; 06518 UserSetConsoleProcessWindowStation(pConsoleWindowStationInfo->dwProcessId, 06519 pConsoleWindowStationInfo->hwinsta); 06520 break; 06521 06522 #if defined(FE_IME) 06523 /* 06524 * For console IME issue 06525 * 06526 * Console IME do register thread ID in DESKTOP info. 06527 * So should be per desktop. 06528 */ 06529 case ConsoleRegisterConsoleIME: 06530 { 06531 PCONSOLE_REGISTER_CONSOLEIME RegConIMEInfo; 06532 DWORD dwConsoleIMEThreadIdOld; 06533 06534 UserAssert(ConsoleInformationLength == sizeof(CONSOLE_REGISTER_CONSOLEIME)); 06535 06536 RegConIMEInfo = (PCONSOLE_REGISTER_CONSOLEIME)ConsoleInformation; 06537 RegConIMEInfo->dwConsoleInputThreadId = 0; 06538 06539 Status = ObReferenceObjectByHandle( 06540 RegConIMEInfo->hdesk, 06541 0, 06542 *ExDesktopObjectType, 06543 UserMode, 06544 &pdesk, 06545 NULL); 06546 if (!NT_SUCCESS(Status)) 06547 return Status; 06548 06549 LogDesktop(pdesk, LD_REF_FN_CONSOLECONTROL2, TRUE, (ULONG_PTR)PtiCurrent()); 06550 06551 Status = STATUS_SUCCESS; 06552 if (pdesk->dwConsoleThreadId) 06553 { 06554 /* 06555 * Exists console input thread 06556 */ 06557 RegConIMEInfo->dwConsoleInputThreadId = pdesk->dwConsoleThreadId; 06558 06559 dwConsoleIMEThreadIdOld = pdesk->dwConsoleIMEThreadId; 06560 06561 if (RegConIMEInfo->dwAction != REGCONIME_QUERY) { 06562 PTHREADINFO ptiConsoleIME; 06563 06564 if ((ptiConsoleIME = PtiFromThreadId(RegConIMEInfo->dwThreadId)) != NULL) 06565 { 06566 if ( (RegConIMEInfo->dwAction == REGCONIME_REGISTER) && 06567 !(ptiConsoleIME->TIF_flags & TIF_DONTATTACHQUEUE) ) 06568 { 06569 /* 06570 * Register 06571 */ 06572 ptiConsoleIME->TIF_flags |= TIF_DONTATTACHQUEUE; 06573 pdesk->dwConsoleIMEThreadId = RegConIMEInfo->dwThreadId; 06574 } 06575 else if ( (RegConIMEInfo->dwAction == REGCONIME_UNREGISTER) && 06576 (ptiConsoleIME->TIF_flags & TIF_DONTATTACHQUEUE) ) 06577 { 06578 /* 06579 * Unregister 06580 */ 06581 ptiConsoleIME->TIF_flags &= ~TIF_DONTATTACHQUEUE; 06582 pdesk->dwConsoleIMEThreadId = 0; 06583 } 06584 else if (RegConIMEInfo->dwAction == REGCONIME_TERMINATE) 06585 { 06586 /* 06587 * Terminate console IME (Logoff/Shutdown) 06588 */ 06589 pdesk->dwConsoleIMEThreadId = 0; 06590 } 06591 } 06592 else if (RegConIMEInfo->dwAction == REGCONIME_TERMINATE) 06593 { 06594 /* 06595 * Abnormal end console IME 06596 */ 06597 pdesk->dwConsoleIMEThreadId = 0; 06598 } 06599 else 06600 Status = STATUS_ACCESS_DENIED; 06601 } 06602 RegConIMEInfo->dwThreadId = dwConsoleIMEThreadIdOld; 06603 } 06604 LogDesktop(pdesk, LD_DEREF_FN_CONSOLECONTROL2, FALSE, (ULONG_PTR)PtiCurrent()); 06605 ObDereferenceObject(pdesk); 06606 return Status; 06607 } 06608 break; 06609 #endif 06610 06611 case ConsoleFullscreenSwitch: 06612 UserAssert(ConsoleInformationLength == sizeof(CONSOLE_FULLSCREEN_SWITCH)); 06613 xxxbFullscreenSwitch(((PCONSOLE_FULLSCREEN_SWITCH)ConsoleInformation)->bFullscreenSwitch, 06614 ((PCONSOLE_FULLSCREEN_SWITCH)ConsoleInformation)->hwnd); 06615 break; 06616 06617 case ConsoleSetCaretInfo: 06618 UserAssert(ConsoleInformationLength == sizeof(CONSOLE_CARET_INFO)); 06619 xxxSetConsoleCaretInfo((PCONSOLE_CARET_INFO)ConsoleInformation); 06620 break; 06621 06622 default: 06623 RIPMSG0(RIP_ERROR, "xxxConsoleControl - invalid control class\n"); 06624 UserAssert(FALSE); 06625 return STATUS_INVALID_INFO_CLASS; 06626 } 06627 return STATUS_SUCCESS; 06628 }

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