Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1478 lines
40 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #define SECURITY_WIN32
  4. #ifdef NTSDDEBUG
  5. #define NTSDDBGPRINT(x) DbgPrint x
  6. #else
  7. #define NTSDDBGPRINT(x)
  8. #endif
  9. #include "winsvcp.h" // defines I_ScSendTSMessage
  10. #include "conntfy.h"
  11. //#ifdef MAKARANDS_HIGHER_WARNING_LEVEL
  12. #pragma warning(push, 4)
  13. #pragma warning(disable:4201) // nameless structure.
  14. //#endif
  15. #define INVALID_SESSIONID 0xffffffff
  16. #define INVALID_SESSIONSERIAL 0xffffffff
  17. // 0x1 fConnected
  18. // 0x2 fLoggedOn
  19. // 0x3 fRemote
  20. // 0x4 fWelcome
  21. typedef struct _WTSSESSION_STATE
  22. {
  23. unsigned int bConnected: 1;
  24. unsigned int bLoggedOn: 1;
  25. unsigned int bConsole: 1;
  26. unsigned int bRemote: 1;
  27. unsigned int bLocked: 1;
  28. } WTSSESSION_STATE, *PWTSSESSION_STATE;
  29. /*
  30. WTS_CONSOLE_CONNECT bConnected, bConsole, !bRemote,
  31. WTS_CONSOLE_DISCONNECT !bConnected, !bConsole, !bRemote
  32. WTS_REMOTE_CONNECT bConnected, !bConsole, bremote
  33. WTS_REMOTE_DISCONNECT !bConnected, !bConsole, !bRemote
  34. WTS_SESSION_LOGON bLoggedOn
  35. WTS_SESSION_LOGOFF !bLoggedOn
  36. WTS_SESSION_LOCK bLocked
  37. WTS_SESSION_UNLOCK !bLocked
  38. */
  39. //
  40. // this is head for hwnds list.
  41. // this links NOTIFY_ENTRY or NOTIFY_ENTRY_GLOBAL together.
  42. //
  43. typedef struct _NOTIFY_LIST
  44. {
  45. LIST_ENTRY Links; // links to other NOTIFY_LISTs. not used in case of global notification list.
  46. LIST_ENTRY ListHead; // head of notification entries. links NOTIFY_ENTRYs (or NOTIFY_ENTRY_GLOBAL) together
  47. RTL_CRITICAL_SECTION ListLock; // lock to travel the entries.
  48. ULONG SessionId; // session id ( not used in case of global list)
  49. ULONG SessonSerialNumber; // serial number ( not used in case of global list)
  50. WTSSESSION_STATE SessionState; // state of the session.
  51. } NOTIFY_LIST, *PNOTIFY_LIST;
  52. //
  53. // entry in notification list per winstation.
  54. //
  55. typedef struct _NOTIFY_ENTRY
  56. {
  57. LIST_ENTRY Links; // links to other entries
  58. ULONG hWnd; // hwnd to be notified
  59. ULONG RefCount; // how many times was this hwnd registered ?
  60. } NOTIFY_ENTRY, *PNOTIFY_ENTRY;
  61. //
  62. // Entry in Notification list for all sessions Notifications.
  63. //
  64. typedef struct _NOTIFY_ENTRY_GLOBAL
  65. {
  66. struct _NOTIFY_ENTRY; // above structure +
  67. ULONG SessionId; // since this is global entry, it needs to keep session id per hwnd.
  68. } NOTIFY_ENTRY_GLOBAL, *PNOTIFY_ENTRY_GLOBAL;
  69. //
  70. // The notification Queue.
  71. //
  72. typedef struct _NOTIFICATION_QUEUE
  73. {
  74. LIST_ENTRY ListHead; // head of queue reuests. links NOTIFICATION_REQUESTs together
  75. RTL_CRITICAL_SECTION ListLock; // lock to travel the queue
  76. HANDLE hNotificationEvent; // syncronization between woker and caller of queue.
  77. } NOTIFICATION_QUEUE, *PNOTIFICATION_QUEUE;
  78. //
  79. // Entry in Notification Queue.
  80. //
  81. typedef struct _NOTIFICATION_REQUEST
  82. {
  83. LIST_ENTRY Links; // links to other entries.
  84. ULONG SessionId; // session id for the session this notificaiton is to be sent.
  85. ULONG SessonSerialNumber; // serial number for the session this notificaiton is to be sent.
  86. WPARAM NotificationCode; // notificaiton code
  87. } NOTIFICATION_REQUEST, *PNOTIFICATION_REQUEST;
  88. //
  89. // our main data structure.
  90. //
  91. typedef struct _NOTIFY_LLIST
  92. {
  93. LIST_ENTRY ListHead; // head of notification lists. links NOTIFY_LISTs together.
  94. RTL_CRITICAL_SECTION ListLock; // lock to travel the head list.
  95. NOTIFY_LIST GlobalList; // global notification list.
  96. NOTIFICATION_QUEUE RequestQueue; // notification queue.
  97. NOTIFY_LIST InvlidHwndList; // invalid window list
  98. } NOTIFY_LLIST, PNOTIFY_LLIST;
  99. //
  100. // File Globals.
  101. //
  102. NOTIFY_LLIST gNotifyLList;
  103. //
  104. // private functions
  105. //
  106. BOOL DoesHWndExists (
  107. PNOTIFY_LIST pNotifyList,
  108. ULONG hWnd
  109. );
  110. PNOTIFY_ENTRY GetHWndEntryFromSessionList (
  111. PNOTIFY_LIST pNotifyList,
  112. ULONG hWnd
  113. );
  114. PNOTIFY_ENTRY_GLOBAL GetHWndEntryFromGlobalList (
  115. PNOTIFY_LIST pNotifyList,
  116. ULONG hWnd,
  117. ULONG SessionId
  118. );
  119. NTSTATUS GetNoficationListFromSessionId (
  120. ULONG SessionId,
  121. PNOTIFY_LIST *ppNofificationList,
  122. BOOL bKeepLListLocked
  123. );
  124. NTSTATUS GetGlobalNotificationList (
  125. PNOTIFY_LIST *ppConChgNtfy
  126. );
  127. NTSTATUS GetInvlidHwndList(PNOTIFY_LIST *ppConChgNtfy);
  128. NTSTATUS NotifyConsole (
  129. ULONG SessionId,
  130. ULONG SessionSerialNumber,
  131. WPARAM wParam
  132. );
  133. NTSTATUS SendConsoleNotification (
  134. ULONG SessionId,
  135. ULONG hWnd,
  136. ULONG Msg,
  137. WPARAM wParam,
  138. WTSSESSION_NOTIFICATION wtsConsoleNotification
  139. );
  140. BOOL IsGlobalList(PNOTIFY_LIST pNtfyList);
  141. int GetListCount (
  142. LIST_ENTRY *pListHead
  143. );
  144. NTSTATUS DestroyLock ( PNOTIFY_LIST pNtfyList);
  145. NTSTATUS CreateLock ( PNOTIFY_LIST pNtfyList);
  146. NTSTATUS
  147. InitializeNotificationQueue ();
  148. NTSTATUS
  149. QueueNotificationRequest (
  150. ULONG SessionSerialNumber,
  151. ULONG SessionId,
  152. WPARAM notification
  153. );
  154. PNOTIFICATION_REQUEST
  155. UnQueueNotificationRequest ();
  156. DWORD NotificationQueueWorker (
  157. LPVOID
  158. );
  159. NTSTATUS RemoveGlobalNotification (ULONG SessionId);
  160. NTSTATUS RemoveInvalidWindowsFromLists ();
  161. NTSTATUS UnRegisterConsoleNotificationInternal (ULONG hWnd, ULONG SessionId, BOOL bDcrRef);
  162. void ReleaseNotificationList (PNOTIFY_LIST pNotifyList);
  163. void UpdateSessionState(PNOTIFY_LIST pNotifyList, WPARAM wNotification)
  164. {
  165. /*
  166. WTS_CONSOLE_CONNECT bConnected, bConsole, !bRemote,
  167. WTS_CONSOLE_DISCONNECT !bConnected, !bConsole, !bRemote
  168. WTS_REMOTE_CONNECT bConnected, !bConsole, bremote
  169. WTS_REMOTE_DISCONNECT !bConnected, !bConsole, !bRemote
  170. WTS_SESSION_LOGON bLoggedOn
  171. WTS_SESSION_LOGOFF !bLoggedOn
  172. WTS_SESSION_LOCK bLocked
  173. WTS_SESSION_UNLOCK !bLocked
  174. */
  175. ASSERT(!IsGlobalList(pNotifyList));
  176. ASSERT(!pNotifyList->SessionState.bConsole || !pNotifyList->SessionState.bRemote);
  177. ASSERT(!pNotifyList->SessionState.bConnected || pNotifyList->SessionState.bConsole || pNotifyList->SessionState.bRemote);
  178. switch (wNotification)
  179. {
  180. case WTS_CONSOLE_CONNECT:
  181. ASSERT(!pNotifyList->SessionState.bConsole);
  182. ASSERT(!pNotifyList->SessionState.bRemote);
  183. pNotifyList->SessionState.bConnected = 1;
  184. pNotifyList->SessionState.bConsole = 1;
  185. break;
  186. case WTS_CONSOLE_DISCONNECT:
  187. ASSERT(pNotifyList->SessionState.bConsole);
  188. ASSERT(pNotifyList->SessionState.bConnected);
  189. ASSERT(!pNotifyList->SessionState.bRemote);
  190. pNotifyList->SessionState.bConnected = 0;
  191. pNotifyList->SessionState.bConsole = 0;
  192. break;
  193. case WTS_REMOTE_DISCONNECT:
  194. ASSERT(pNotifyList->SessionState.bRemote);
  195. ASSERT(pNotifyList->SessionState.bConnected);
  196. ASSERT(!pNotifyList->SessionState.bConsole);
  197. pNotifyList->SessionState.bConnected = 0;
  198. pNotifyList->SessionState.bRemote = 0;
  199. break;
  200. case WTS_REMOTE_CONNECT:
  201. ASSERT(!pNotifyList->SessionState.bRemote);
  202. ASSERT(!pNotifyList->SessionState.bConnected);
  203. ASSERT(!pNotifyList->SessionState.bConsole);
  204. pNotifyList->SessionState.bConnected = 1;
  205. pNotifyList->SessionState.bRemote = 1;
  206. break;
  207. case WTS_SESSION_LOGON:
  208. ASSERT(pNotifyList->SessionState.bLoggedOn == 0);
  209. pNotifyList->SessionState.bLoggedOn = 1;
  210. break;
  211. case WTS_SESSION_LOGOFF:
  212. ASSERT(pNotifyList->SessionState.bLoggedOn == 1);
  213. pNotifyList->SessionState.bLoggedOn = 0;
  214. break;
  215. case WTS_SESSION_LOCK:
  216. ASSERT(pNotifyList->SessionState.bLocked == 0);
  217. pNotifyList->SessionState.bLocked = 1;
  218. break;
  219. case WTS_SESSION_UNLOCK:
  220. ASSERT(pNotifyList->SessionState.bLocked == 1);
  221. pNotifyList->SessionState.bLocked = 0;
  222. break;
  223. default:
  224. ASSERT(FALSE);
  225. }
  226. ASSERT(!pNotifyList->SessionState.bConsole || !pNotifyList->SessionState.bRemote);
  227. ASSERT(!pNotifyList->SessionState.bConnected || pNotifyList->SessionState.bConsole || pNotifyList->SessionState.bRemote);
  228. }
  229. //
  230. // Global initialization.
  231. //
  232. NTSTATUS InitializeConsoleNotification ()
  233. {
  234. NTSTATUS Status;
  235. InitializeListHead( &gNotifyLList.ListHead );
  236. Status = RtlInitializeCriticalSection( &gNotifyLList.ListLock );
  237. if ( !NT_SUCCESS( Status ) )
  238. {
  239. return (Status);
  240. }
  241. //
  242. // following members are unused in for global list.
  243. //
  244. gNotifyLList.GlobalList.Links.Blink = NULL;
  245. gNotifyLList.GlobalList.Links.Flink = NULL;
  246. gNotifyLList.GlobalList.SessionId = INVALID_SESSIONID;
  247. gNotifyLList.GlobalList.SessonSerialNumber = INVALID_SESSIONSERIAL;
  248. InitializeListHead( &gNotifyLList.GlobalList.ListHead);
  249. Status = RtlInitializeCriticalSection( &gNotifyLList.GlobalList.ListLock );
  250. if ( !NT_SUCCESS( Status ) )
  251. {
  252. RtlDeleteCriticalSection( &gNotifyLList.ListLock );
  253. return (Status);
  254. }
  255. gNotifyLList.InvlidHwndList.Links.Blink = NULL;
  256. gNotifyLList.InvlidHwndList.Links.Flink = NULL;
  257. gNotifyLList.InvlidHwndList.SessionId = INVALID_SESSIONID;
  258. gNotifyLList.InvlidHwndList.SessonSerialNumber = INVALID_SESSIONSERIAL;
  259. InitializeListHead(&gNotifyLList.InvlidHwndList.ListHead) ;
  260. Status = RtlInitializeCriticalSection( &gNotifyLList.InvlidHwndList.ListLock );
  261. if ( !NT_SUCCESS( Status ) )
  262. {
  263. RtlDeleteCriticalSection( &gNotifyLList.ListLock );
  264. RtlDeleteCriticalSection( &gNotifyLList.GlobalList.ListLock );
  265. return (Status);
  266. }
  267. Status = InitializeNotificationQueue ();
  268. if ( !NT_SUCCESS( Status ) )
  269. {
  270. RtlDeleteCriticalSection( &gNotifyLList.ListLock );
  271. RtlDeleteCriticalSection( &gNotifyLList.GlobalList.ListLock );
  272. RtlDeleteCriticalSection( &gNotifyLList.InvlidHwndList.ListLock );
  273. }
  274. return (Status);
  275. }
  276. //
  277. // per winstation initialization.
  278. //
  279. NTSTATUS InitializeSessionNotification (PWINSTATION pWinStation)
  280. {
  281. NTSTATUS Status;
  282. PNOTIFY_LIST pNewNotifyList;
  283. ASSERT(pWinStation);
  284. if (pWinStation->Terminating)
  285. {
  286. // dont create notification list if this winstation is already terminating.
  287. // its possible that a winstation is being terminated before getting completely created,
  288. // in such case we might end up calling RemoveSessionNotification before InitializeSessionNotification.
  289. // so essentially leaving this session never to deleted. (Bug #414330)
  290. return STATUS_SUCCESS;
  291. }
  292. #ifdef DBG
  293. // BUGBUG - is it possible that a old session with the same session id is still there?
  294. Status = GetNoficationListFromSessionId(pWinStation->LogonId, &pNewNotifyList, FALSE);
  295. //
  296. // we are just being asked to initialize notification
  297. // we must not find list for this session in our LList.
  298. //
  299. ASSERT( STATUS_NO_SUCH_LOGON_SESSION == Status );
  300. #endif
  301. //
  302. // create a new hwnd list for this session
  303. //
  304. pNewNotifyList = MemAlloc(sizeof(NOTIFY_LIST));
  305. if (!pNewNotifyList)
  306. {
  307. return STATUS_NO_MEMORY;
  308. }
  309. pNewNotifyList->SessionId = pWinStation->LogonId;
  310. pNewNotifyList->SessonSerialNumber = pWinStation->SessionSerialNumber;
  311. //
  312. // initialize session state.
  313. //
  314. {
  315. pNewNotifyList->SessionState.bConnected = 0;
  316. pNewNotifyList->SessionState.bConsole = 0;
  317. pNewNotifyList->SessionState.bLoggedOn = 0;
  318. pNewNotifyList->SessionState.bRemote = 0;
  319. pNewNotifyList->SessionState.bLocked = 0; // bugbug we dont know the real welcome state ;(
  320. }
  321. InitializeListHead( &pNewNotifyList->ListHead);
  322. Status = RtlInitializeCriticalSection( &pNewNotifyList->ListLock );
  323. if ( !NT_SUCCESS( Status ) )
  324. {
  325. MemFree(pNewNotifyList);
  326. pNewNotifyList = NULL;
  327. return Status;
  328. }
  329. // now link this new list into our main list of lists.
  330. ENTERCRIT(&gNotifyLList.ListLock);
  331. InsertTailList( &gNotifyLList.ListHead, &pNewNotifyList->Links);
  332. LEAVECRIT(&gNotifyLList.ListLock);
  333. return STATUS_SUCCESS;
  334. }
  335. //
  336. // must be called when a session ends.
  337. //
  338. NTSTATUS RemoveSessionNotification(ULONG SessionId, ULONG SessionSerialNumber)
  339. {
  340. NTSTATUS Status;
  341. PNOTIFY_LIST pListTobeRemoved;
  342. UNREFERENCED_PARAMETER(SessionSerialNumber); // it's referenced only for Chk builds.
  343. // BUGBUG - is it possible that a new session with the same session id was created while we are here ?
  344. Status = GetNoficationListFromSessionId( SessionId, &pListTobeRemoved, TRUE);
  345. if (!NT_SUCCESS( Status ))
  346. {
  347. //
  348. // we are being asked to remove session notification
  349. // but its possible that we dont have session notification list created for this session.
  350. // This can happen if the session is being terminate during session creation process.
  351. //
  352. ASSERT( !pListTobeRemoved );
  353. return Status;
  354. }
  355. ASSERT( pListTobeRemoved );
  356. ASSERT( SessionSerialNumber == pListTobeRemoved->SessonSerialNumber );
  357. RemoveEntryList( &pListTobeRemoved->Links );
  358. LEAVECRIT(&gNotifyLList.ListLock);
  359. //
  360. // walk throught this list and free all the nodes.
  361. //
  362. while (!IsListEmpty(&pListTobeRemoved->ListHead))
  363. {
  364. PNOTIFY_ENTRY pEntry;
  365. PLIST_ENTRY Next;
  366. Next = pListTobeRemoved->ListHead.Flink;
  367. ASSERT(Next);
  368. pEntry = CONTAINING_RECORD( Next, NOTIFY_ENTRY, Links );
  369. ASSERT(pEntry);
  370. RemoveEntryList( &pEntry->Links );
  371. MemFree(pEntry);
  372. pEntry = NULL;
  373. }
  374. // we are no more going to use this list lock.
  375. RtlDeleteCriticalSection( &pListTobeRemoved->ListLock );
  376. MemFree(pListTobeRemoved);
  377. pListTobeRemoved = NULL;
  378. return RemoveGlobalNotification (SessionId);
  379. // return QueueNotificationRequest(pWinStation->SessionSerialNumber, pWinStation->LogonId, 0);
  380. }
  381. NTSTATUS RemoveGlobalNotification (ULONG SessionId)
  382. {
  383. PLIST_ENTRY Head, Next;
  384. PNOTIFY_LIST pListTobeRemoved = NULL;
  385. NTSTATUS Status = GetGlobalNotificationList(&pListTobeRemoved);
  386. if ( !NT_SUCCESS( Status ) )
  387. {
  388. return (Status);
  389. }
  390. ASSERT(pListTobeRemoved);
  391. Head = &pListTobeRemoved->ListHead;
  392. Next = Head->Flink;
  393. while (Head != Next)
  394. {
  395. PNOTIFY_ENTRY_GLOBAL pEntryGlobal = CONTAINING_RECORD( Next, NOTIFY_ENTRY_GLOBAL, Links );
  396. Next = Next->Flink;
  397. ASSERT(pEntryGlobal);
  398. if (pEntryGlobal->SessionId == SessionId)
  399. {
  400. RemoveEntryList( &pEntryGlobal->Links );
  401. MemFree(pEntryGlobal);
  402. pEntryGlobal = NULL;
  403. }
  404. }
  405. ReleaseNotificationList( pListTobeRemoved );
  406. pListTobeRemoved = NULL;
  407. // now lets remove the invalid Windows associated with this session.
  408. // from the list if there is any.
  409. pListTobeRemoved = NULL;
  410. Status = GetInvlidHwndList(&pListTobeRemoved);
  411. if ( !NT_SUCCESS( Status ) )
  412. {
  413. return (Status);
  414. }
  415. ASSERT(pListTobeRemoved);
  416. Head = &pListTobeRemoved->ListHead;
  417. Next = Head->Flink;
  418. while (Head != Next)
  419. {
  420. PNOTIFY_ENTRY_GLOBAL pEntryGlobal = CONTAINING_RECORD( Next, NOTIFY_ENTRY_GLOBAL, Links );
  421. Next = Next->Flink;
  422. ASSERT(pEntryGlobal);
  423. if (pEntryGlobal->SessionId == SessionId)
  424. {
  425. RemoveEntryList( &pEntryGlobal->Links );
  426. MemFree(pEntryGlobal);
  427. pEntryGlobal = NULL;
  428. }
  429. }
  430. ReleaseNotificationList(pListTobeRemoved);
  431. return STATUS_SUCCESS;
  432. }
  433. NTSTATUS RegisterConsoleNotification ( ULONG hWnd, ULONG SessionId, DWORD dwFlags )
  434. {
  435. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  436. PNOTIFY_LIST pNotifyList = NULL;
  437. PNOTIFY_LIST pNotifyListGlobal = NULL;
  438. PNOTIFY_ENTRY pEntry = NULL;
  439. PNOTIFY_ENTRY_GLOBAL pEntryGlobal = NULL;
  440. if (dwFlags != NOTIFY_FOR_THIS_SESSION && dwFlags != NOTIFY_FOR_ALL_SESSIONS)
  441. {
  442. //
  443. // invalid flag value
  444. //
  445. return STATUS_INVALID_PARAMETER_3;
  446. }
  447. //
  448. // get the global session notificaiton list
  449. //
  450. Status = GetGlobalNotificationList(&pNotifyListGlobal);
  451. if (!NT_SUCCESS(Status))
  452. {
  453. return Status;
  454. }
  455. //
  456. // get the session specific list for this window
  457. //
  458. Status = GetNoficationListFromSessionId( SessionId, &pNotifyList, FALSE);
  459. if (!NT_SUCCESS(Status))
  460. {
  461. ReleaseNotificationList (pNotifyListGlobal);
  462. return Status;
  463. }
  464. ASSERT( pNotifyList );
  465. ASSERT( pNotifyListGlobal );
  466. pEntry = GetHWndEntryFromSessionList(pNotifyList, hWnd);
  467. pEntryGlobal = GetHWndEntryFromGlobalList(pNotifyListGlobal, hWnd, SessionId);
  468. //
  469. // entry must not exist in both the lists.
  470. //
  471. ASSERT(!(pEntry && pEntryGlobal));
  472. if (pEntry)
  473. {
  474. //
  475. // Let other list go
  476. //
  477. ReleaseNotificationList( pNotifyListGlobal );
  478. ASSERT( pEntry );
  479. ASSERT( pEntry->RefCount > 0 );
  480. //
  481. // entry already exists, just increment its reference count.
  482. //
  483. pEntry->RefCount++;
  484. ReleaseNotificationList( pNotifyList );
  485. }
  486. else if (pEntryGlobal)
  487. {
  488. ReleaseNotificationList (pNotifyList);
  489. ASSERT( pEntryGlobal );
  490. ASSERT( pEntryGlobal->RefCount > 0 );
  491. //
  492. // entry already exists, just increment its reference count.
  493. //
  494. pEntryGlobal->RefCount++;
  495. ReleaseNotificationList( pNotifyListGlobal );
  496. }
  497. else
  498. {
  499. //
  500. // the entry does not exists in either of the lists.
  501. // so we need to create a new entry
  502. //
  503. if (dwFlags & NOTIFY_FOR_ALL_SESSIONS)
  504. {
  505. ReleaseNotificationList (pNotifyList);
  506. pEntryGlobal = MemAlloc( sizeof(NOTIFY_ENTRY_GLOBAL) );
  507. if (pEntryGlobal == NULL )
  508. {
  509. Status = STATUS_NO_MEMORY;
  510. }
  511. else
  512. {
  513. pEntryGlobal->hWnd = hWnd;
  514. pEntryGlobal->SessionId = SessionId;
  515. pEntryGlobal->RefCount = 1;
  516. InsertTailList( &(pNotifyListGlobal->ListHead), &(pEntryGlobal->Links) );
  517. }
  518. ReleaseNotificationList( pNotifyListGlobal );
  519. }
  520. else
  521. {
  522. ReleaseNotificationList( pNotifyListGlobal );
  523. pEntry = MemAlloc( sizeof(NOTIFY_ENTRY) );
  524. if (pEntry == NULL )
  525. {
  526. Status = STATUS_NO_MEMORY;
  527. }
  528. else
  529. {
  530. pEntry->hWnd = hWnd;
  531. pEntry->RefCount = 1;
  532. InsertTailList( &(pNotifyList->ListHead), &(pEntry->Links) );
  533. }
  534. ReleaseNotificationList (pNotifyList);
  535. }
  536. }
  537. return (Status);
  538. }
  539. NTSTATUS UnRegisterConsoleNotification (ULONG hWnd, ULONG SessionId)
  540. {
  541. return UnRegisterConsoleNotificationInternal (hWnd, SessionId, TRUE);
  542. }
  543. NTSTATUS UnRegisterConsoleNotificationInternal (ULONG hWnd, ULONG SessionId, BOOL bDcrRef)
  544. {
  545. NTSTATUS Status;
  546. PNOTIFY_LIST pNotifyList;
  547. PNOTIFY_ENTRY pEntry;
  548. //
  549. // get the notification list for the Session
  550. //
  551. Status = GetNoficationListFromSessionId( SessionId, &pNotifyList, FALSE);
  552. if (NT_SUCCESS(Status))
  553. {
  554. ASSERT(pNotifyList);
  555. pEntry = GetHWndEntryFromSessionList(pNotifyList,hWnd);
  556. if (pEntry)
  557. {
  558. ASSERT( pEntry->RefCount > 0 );
  559. // decrement ref count
  560. pEntry->RefCount--;
  561. if (pEntry->RefCount == 0 || !bDcrRef)
  562. {
  563. RemoveEntryList( &pEntry->Links );
  564. MemFree(pEntry);
  565. pEntry = NULL;
  566. }
  567. ReleaseNotificationList (pNotifyList);
  568. }
  569. else
  570. {
  571. PNOTIFY_LIST pNotifyListGlobal = NULL;
  572. PNOTIFY_ENTRY_GLOBAL pEntryGlobal = NULL;
  573. ReleaseNotificationList (pNotifyList);
  574. //
  575. // now check the global session notificaiton entry
  576. //
  577. Status = GetGlobalNotificationList(&pNotifyListGlobal);
  578. if (NT_SUCCESS(Status))
  579. {
  580. pEntryGlobal = GetHWndEntryFromGlobalList(pNotifyListGlobal, hWnd, SessionId);
  581. if (pEntryGlobal)
  582. {
  583. ASSERT(pEntryGlobal->RefCount > 0);
  584. pEntryGlobal->RefCount--;
  585. if (pEntryGlobal->RefCount == 0 || !bDcrRef)
  586. {
  587. RemoveEntryList( &pEntryGlobal->Links );
  588. MemFree(pEntryGlobal);
  589. pEntryGlobal = NULL;
  590. }
  591. }
  592. else
  593. {
  594. Status = STATUS_NOT_FOUND;
  595. }
  596. ReleaseNotificationList( pNotifyListGlobal );
  597. }
  598. }
  599. }
  600. return (Status);
  601. }
  602. NTSTATUS NotifySessionChange (PWINSTATION pWinStation, WPARAM wNotification)
  603. {
  604. return QueueNotificationRequest(pWinStation->SessionSerialNumber, pWinStation->LogonId, wNotification);
  605. }
  606. NTSTATUS NotifyLogon(PWINSTATION pWinStation)
  607. {
  608. return NotifySessionChange(pWinStation, WTS_SESSION_LOGON);
  609. }
  610. NTSTATUS NotifyLogoff(PWINSTATION pWinStation)
  611. {
  612. return NotifySessionChange(pWinStation, WTS_SESSION_LOGOFF);
  613. }
  614. NTSTATUS NotifyConnect (PWINSTATION pWinStation, BOOL bConsole)
  615. {
  616. return NotifySessionChange(pWinStation, bConsole ? WTS_CONSOLE_CONNECT : WTS_REMOTE_CONNECT);
  617. }
  618. NTSTATUS NotifyDisconnect (PWINSTATION pWinStation, BOOL bConsole)
  619. {
  620. return NotifySessionChange(pWinStation, bConsole ? WTS_CONSOLE_DISCONNECT : WTS_REMOTE_DISCONNECT);
  621. }
  622. NTSTATUS NofifyWelcomeOn (PWINSTATION pWinStation)
  623. {
  624. return NotifySessionChange(pWinStation, WTS_SESSION_LOCK);
  625. }
  626. NTSTATUS NotifyWelcomeOff (PWINSTATION pWinStation)
  627. {
  628. return NotifySessionChange(pWinStation, WTS_SESSION_UNLOCK);
  629. }
  630. NTSTATUS SendNotificationToHwnd(PWINSTATION pWinstation, ULONG hWnd, ULONG SessionId, WPARAM wParam)
  631. {
  632. WINSTATION_APIMSG WMsg;
  633. //
  634. // now pupulate the WMSG for delievery.
  635. //
  636. WMsg.u.sMsg.Msg = WM_WTSSESSION_CHANGE;
  637. WMsg.u.sMsg.wParam = wParam;
  638. WMsg.ApiNumber = SMWinStationSendWindowMessage ;
  639. WMsg.WaitForReply = FALSE;
  640. WMsg.u.sMsg.dataBuffer = NULL;
  641. WMsg.u.sMsg.bufferSize = 0;
  642. WMsg.u.sMsg.lParam = SessionId;
  643. WMsg.u.sMsg.hWnd = (HWND)ULongToHandle( hWnd );
  644. return SendWinStationCommand( pWinstation, &WMsg, 0);
  645. }
  646. NTSTATUS NotifyConsole (ULONG SessionId, ULONG SessionSerialNumber, WPARAM wParam)
  647. {
  648. NTSTATUS Status = STATUS_SUCCESS;
  649. DWORD dwError;
  650. PWINSTATION pWinStation=NULL;
  651. Status = RemoveInvalidWindowsFromLists();
  652. ASSERT(NT_SUCCESS(Status));
  653. pWinStation = FindWinStationById(SessionId, FALSE);
  654. //
  655. // if we find the session we were looking for
  656. // note: we must check for the serialnumber, as the session id is not unique.
  657. //
  658. if (pWinStation)
  659. {
  660. if (SessionSerialNumber == pWinStation->SessionSerialNumber)
  661. {
  662. PNOTIFY_LIST pConsoleList;
  663. Status = GetNoficationListFromSessionId(pWinStation->LogonId, &pConsoleList, FALSE);
  664. if (NT_SUCCESS(Status) && pConsoleList)
  665. {
  666. PLIST_ENTRY Head, Next;
  667. Head = &pConsoleList->ListHead;
  668. for ( Next = Head->Flink; Next != Head; Next = Next->Flink )
  669. {
  670. PNOTIFY_ENTRY pEntry;
  671. pEntry = CONTAINING_RECORD( Next, NOTIFY_ENTRY, Links );
  672. ASSERT(pEntry);
  673. Status = SendNotificationToHwnd(pWinStation, pEntry->hWnd, SessionId, wParam);
  674. if (!NT_SUCCESS(Status))
  675. {
  676. NTSDDBGPRINT(("conntfy.c - SendWinStationCommand failed, Status = %d.\n", Status));
  677. }
  678. }
  679. UpdateSessionState(pConsoleList, wParam);
  680. ReleaseNotificationList( pConsoleList );
  681. }
  682. }
  683. ReleaseWinStation( pWinStation );
  684. }
  685. //
  686. // now send notifications to windows registered for all session notificaitons.
  687. //
  688. {
  689. PNOTIFY_LIST pNotifyListGlobal = NULL;
  690. Status = GetGlobalNotificationList(&pNotifyListGlobal);
  691. if (NT_SUCCESS(Status))
  692. {
  693. PLIST_ENTRY Head, Next;
  694. Head = &pNotifyListGlobal->ListHead;
  695. for ( Next = Head->Flink; Next != Head; Next = Next->Flink )
  696. {
  697. PNOTIFY_ENTRY_GLOBAL pEntryGlobal = NULL;
  698. pEntryGlobal = CONTAINING_RECORD( Next, NOTIFY_ENTRY_GLOBAL, Links );
  699. ASSERT(pEntryGlobal);
  700. pWinStation = FindWinStationById(pEntryGlobal->SessionId, FALSE);
  701. if (pWinStation)
  702. {
  703. if (!pWinStation->Terminating)
  704. {
  705. Status = SendNotificationToHwnd(pWinStation, pEntryGlobal->hWnd, SessionId, wParam);
  706. if (!NT_SUCCESS(Status))
  707. {
  708. NTSDDBGPRINT(("conntfy.c - SendWinStationCommand failed, Status = %d.\n", Status));
  709. }
  710. }
  711. ReleaseWinStation( pWinStation );
  712. }
  713. }
  714. ReleaseNotificationList(pNotifyListGlobal);
  715. }
  716. else
  717. {
  718. NTSDDBGPRINT(("conntfy.c - Failed to get all session notification list - status = 0x%x.\n", Status));
  719. }
  720. }
  721. //
  722. // now lets notify SCM which will notify all the services registered for SERVICE_ACCEPT_SESSIONCHANGE
  723. //
  724. //
  725. // logon logoff notifications for session 0 are sent by winlogon. rest are handled here.
  726. //
  727. if (SessionId != 0 || ( wParam != WTS_SESSION_LOGON && wParam != WTS_SESSION_LOGOFF))
  728. {
  729. WTSSESSION_NOTIFICATION wtsConsoleNotification;
  730. wtsConsoleNotification.cbSize = sizeof(WTSSESSION_NOTIFICATION);
  731. wtsConsoleNotification.dwSessionId = SessionId;
  732. dwError = I_ScSendTSMessage(
  733. SERVICE_CONTROL_SESSIONCHANGE, // op code
  734. (DWORD)wParam, // event code,
  735. wtsConsoleNotification.cbSize, // data size
  736. (LPBYTE)&wtsConsoleNotification // data.
  737. );
  738. }
  739. return Status;
  740. }
  741. NTSTATUS DestroyLock( PNOTIFY_LIST pNtfyList)
  742. {
  743. return RtlDeleteCriticalSection( &pNtfyList->ListLock );
  744. }
  745. NTSTATUS CreateLock (PNOTIFY_LIST pNtfyList)
  746. {
  747. return RtlInitializeCriticalSection( &pNtfyList->ListLock );
  748. }
  749. BOOL IsInvalidHWndList (PNOTIFY_LIST pNtfyList)
  750. {
  751. return (pNtfyList == &gNotifyLList.InvlidHwndList);
  752. }
  753. BOOL IsGlobalList(PNOTIFY_LIST pNtfyList)
  754. {
  755. return (pNtfyList == &gNotifyLList.GlobalList);
  756. }
  757. int GetListCount (LIST_ENTRY *pListHead)
  758. {
  759. PLIST_ENTRY Head, Next;
  760. int iCount = 0;
  761. ASSERT(pListHead);
  762. Head = pListHead;
  763. for ( Next = Head->Flink; Next != Head; Next = Next->Flink )
  764. {
  765. iCount++;
  766. }
  767. return iCount;
  768. }
  769. PNOTIFY_ENTRY GetHWndEntryFromSessionList(PNOTIFY_LIST pNotifyList, ULONG hWnd)
  770. {
  771. PLIST_ENTRY Head = NULL;
  772. PLIST_ENTRY Next = NULL;
  773. PNOTIFY_ENTRY pEntry = NULL;
  774. Head = &pNotifyList->ListHead;
  775. for ( Next = Head->Flink; Next != Head; Next = Next->Flink )
  776. {
  777. pEntry = CONTAINING_RECORD( Next, NOTIFY_ENTRY, Links );
  778. ASSERT(pEntry);
  779. if (pEntry->hWnd == hWnd)
  780. {
  781. return pEntry;
  782. }
  783. }
  784. return NULL;
  785. }
  786. PNOTIFY_ENTRY_GLOBAL GetHWndEntryFromGlobalList(PNOTIFY_LIST pNotifyList, ULONG hWnd, ULONG SessionId)
  787. {
  788. PLIST_ENTRY Head = NULL;
  789. PLIST_ENTRY Next = NULL;
  790. PNOTIFY_ENTRY_GLOBAL pEntry = NULL;
  791. Head = &pNotifyList->ListHead;
  792. for ( Next = Head->Flink; Next != Head; Next = Next->Flink )
  793. {
  794. pEntry = CONTAINING_RECORD( Next, NOTIFY_ENTRY_GLOBAL, Links );
  795. ASSERT(pEntry);
  796. if (pEntry->hWnd == hWnd && SessionId == pEntry->SessionId)
  797. {
  798. return pEntry;
  799. }
  800. }
  801. return NULL;
  802. }
  803. //
  804. // returns PNOTIFY_LIST list for the given session.
  805. //
  806. NTSTATUS GetNoficationListFromSessionId (ULONG SessionId, PNOTIFY_LIST *ppNotifyList, BOOL bKeepLListLocked)
  807. {
  808. PLIST_ENTRY Next, Head;
  809. ASSERT(ppNotifyList);
  810. *ppNotifyList = NULL;
  811. // lock our list of lists.
  812. ENTERCRIT(&gNotifyLList.ListLock);
  813. Head = &gNotifyLList.ListHead;
  814. Next = Head->Flink;
  815. while (Head != Next)
  816. {
  817. PNOTIFY_LIST pNotifyList = CONTAINING_RECORD( Next, NOTIFY_LIST, Links );
  818. ASSERT( pNotifyList );
  819. //
  820. // we always take gNotifyLList.ListLock first and then the Listlock
  821. // therefore we must never have PNOTIFY_LIST.ListLock at this time.
  822. //
  823. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != pNotifyList->ListLock.OwningThread );
  824. if (pNotifyList->SessionId == SessionId)
  825. {
  826. //
  827. // did we find more that 1 matching notify list ???, should never happen!
  828. //
  829. ASSERT(*ppNotifyList == NULL);
  830. //
  831. // ok we found the session list we were looking for
  832. //
  833. *ppNotifyList = pNotifyList;
  834. #ifndef DBG
  835. break;
  836. #endif
  837. }
  838. Next = Next->Flink;
  839. }
  840. //
  841. // if we have found the list we were looking for
  842. //
  843. if (*ppNotifyList)
  844. {
  845. //
  846. // lock the list before returning.
  847. //
  848. ENTERCRIT(&(*ppNotifyList)->ListLock);
  849. }
  850. if (!(*ppNotifyList) || !bKeepLListLocked)
  851. {
  852. //
  853. // unlock llist lock.
  854. //
  855. LEAVECRIT(&gNotifyLList.ListLock);
  856. }
  857. if (*ppNotifyList)
  858. {
  859. return STATUS_SUCCESS;
  860. }
  861. else
  862. {
  863. return STATUS_NO_SUCH_LOGON_SESSION;
  864. }
  865. }
  866. void ReleaseNotificationList (PNOTIFY_LIST pNotifyList)
  867. {
  868. ASSERT(pNotifyList);
  869. if (IsInvalidHWndList(pNotifyList))
  870. {
  871. // we must take invalid hwnd list before taking global list.
  872. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != (gNotifyLList.GlobalList.ListLock).OwningThread );
  873. // we must take invalid hwnd list before taking LList.
  874. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != (gNotifyLList.ListLock).OwningThread );
  875. }
  876. else if (IsGlobalList(pNotifyList))
  877. {
  878. // we must take invalid hwnd list before taking LList.
  879. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != (gNotifyLList.ListLock).OwningThread );
  880. }
  881. LEAVECRIT(&pNotifyList->ListLock);
  882. }
  883. NTSTATUS GetInvlidHwndList(PNOTIFY_LIST *ppConChgNtfy)
  884. {
  885. ASSERT(ppConChgNtfy);
  886. // we must take invalid hwnd list before taking global list.
  887. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != (gNotifyLList.GlobalList.ListLock).OwningThread );
  888. // we must take invalid hwnd list before taking LList.
  889. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != (gNotifyLList.ListLock).OwningThread );
  890. *ppConChgNtfy = &gNotifyLList.InvlidHwndList;
  891. ENTERCRIT(&(*ppConChgNtfy)->ListLock);
  892. ASSERT(gNotifyLList.InvlidHwndList.Links.Blink == NULL);
  893. ASSERT(gNotifyLList.InvlidHwndList.Links.Flink == NULL);
  894. ASSERT(gNotifyLList.InvlidHwndList.SessionId == INVALID_SESSIONID);
  895. ASSERT(gNotifyLList.InvlidHwndList.SessonSerialNumber == INVALID_SESSIONSERIAL);
  896. return STATUS_SUCCESS;
  897. }
  898. NTSTATUS GetGlobalNotificationList(PNOTIFY_LIST *ppConChgNtfy)
  899. {
  900. ASSERT(ppConChgNtfy);
  901. // we must LLIst after global list.
  902. ASSERT( (HANDLE)LongToHandle( GetCurrentThreadId() ) != (gNotifyLList.ListLock).OwningThread );
  903. *ppConChgNtfy = &gNotifyLList.GlobalList;
  904. ENTERCRIT(&(*ppConChgNtfy)->ListLock);
  905. ASSERT(gNotifyLList.GlobalList.Links.Blink == NULL);
  906. ASSERT(gNotifyLList.GlobalList.Links.Flink == NULL);
  907. ASSERT(gNotifyLList.GlobalList.SessionId == INVALID_SESSIONID);
  908. ASSERT(gNotifyLList.GlobalList.SessonSerialNumber == INVALID_SESSIONSERIAL);
  909. return (STATUS_SUCCESS);
  910. }
  911. NTSTATUS InitializeNotificationQueue ()
  912. {
  913. DWORD ThreadId;
  914. NTSTATUS Status;
  915. HANDLE hSessionNotifyThread;
  916. InitializeListHead( &gNotifyLList.RequestQueue.ListHead);
  917. gNotifyLList.RequestQueue.hNotificationEvent = CreateEvent(
  918. NULL, // SD
  919. FALSE, // reset type
  920. FALSE, // initial state
  921. NULL // object name
  922. );
  923. if (gNotifyLList.RequestQueue.hNotificationEvent == NULL)
  924. {
  925. // we failed to create event.
  926. // return GetLastError()
  927. return STATUS_UNSUCCESSFUL;
  928. }
  929. Status = RtlInitializeCriticalSection( &gNotifyLList.RequestQueue.ListLock );
  930. if (!NT_SUCCESS(Status))
  931. {
  932. CloseHandle(gNotifyLList.RequestQueue.hNotificationEvent);
  933. gNotifyLList.RequestQueue.hNotificationEvent = NULL;
  934. return Status;
  935. }
  936. //
  937. // now create thread for notifications.
  938. //
  939. hSessionNotifyThread = CreateThread(
  940. NULL,
  941. 0,
  942. (LPTHREAD_START_ROUTINE)NotificationQueueWorker,
  943. NULL,
  944. 0,
  945. &ThreadId);
  946. //
  947. // Just close it, we can do without this handle.
  948. //
  949. if( hSessionNotifyThread )
  950. {
  951. NtClose( hSessionNotifyThread );
  952. }
  953. else
  954. {
  955. RtlDeleteCriticalSection( &gNotifyLList.RequestQueue.ListLock );
  956. CloseHandle(gNotifyLList.RequestQueue.hNotificationEvent);
  957. gNotifyLList.RequestQueue.hNotificationEvent = NULL;
  958. return STATUS_UNSUCCESSFUL;
  959. }
  960. return STATUS_SUCCESS;
  961. }
  962. void LockNotificationQueue()
  963. {
  964. ENTERCRIT(&gNotifyLList.RequestQueue.ListLock);
  965. }
  966. void UnLockNotificationQueue()
  967. {
  968. LEAVECRIT(&gNotifyLList.RequestQueue.ListLock);
  969. }
  970. //
  971. // Queues a notification entry
  972. //
  973. NTSTATUS QueueNotificationRequest(ULONG SessionSerialNumber, ULONG SessionId, WPARAM notification)
  974. {
  975. PNOTIFICATION_REQUEST pRequest = NULL;
  976. pRequest = MemAlloc( sizeof(NOTIFICATION_REQUEST) );
  977. if (!pRequest)
  978. {
  979. return STATUS_NO_MEMORY;
  980. }
  981. pRequest->SessonSerialNumber = SessionSerialNumber;
  982. pRequest->SessionId = SessionId;
  983. pRequest->NotificationCode = notification;
  984. // now lock the queue
  985. LockNotificationQueue();
  986. InsertHeadList(&gNotifyLList.RequestQueue.ListHead, &pRequest->Links);
  987. UnLockNotificationQueue();
  988. // let the waiting thread process this notification.
  989. PulseEvent(gNotifyLList.RequestQueue.hNotificationEvent);
  990. return STATUS_SUCCESS;
  991. }
  992. //
  993. // takes out a notification entry from queue.
  994. //
  995. PNOTIFICATION_REQUEST UnQueueNotificationRequest()
  996. {
  997. PLIST_ENTRY pEntry;
  998. PNOTIFICATION_REQUEST pRequest = NULL;
  999. //
  1000. // Remove a request from the list.
  1001. //
  1002. LockNotificationQueue();
  1003. if (!IsListEmpty(&gNotifyLList.RequestQueue.ListHead))
  1004. {
  1005. pEntry = RemoveTailList(&gNotifyLList.RequestQueue.ListHead);
  1006. pRequest = CONTAINING_RECORD(pEntry, NOTIFICATION_REQUEST, Links);
  1007. }
  1008. UnLockNotificationQueue();
  1009. return pRequest;
  1010. }
  1011. // This thread is a helper for the next function. We do this because the
  1012. // compiler defies reason by insisting not all control paths return a value.
  1013. VOID NotificationQueueWorkerEx()
  1014. {
  1015. PNOTIFICATION_REQUEST pRequest = NULL;
  1016. for(;;)
  1017. {
  1018. WaitForSingleObject(gNotifyLList.RequestQueue.hNotificationEvent, INFINITE); // wait for the event to be signaled.
  1019. while ((pRequest = UnQueueNotificationRequest()) != NULL)
  1020. {
  1021. if (!pRequest->NotificationCode)
  1022. {
  1023. ASSERT(FALSE);
  1024. // this is not a real notificaiton request.
  1025. // this request is for session removal.
  1026. // RemoveGlobalNotification(pRequest->SessionId, pRequest->SessonSerialNumber);
  1027. }
  1028. else
  1029. {
  1030. NotifyConsole (pRequest->SessionId, pRequest->SessonSerialNumber, pRequest->NotificationCode);
  1031. }
  1032. MemFree(pRequest);
  1033. pRequest = NULL;
  1034. }
  1035. }
  1036. }
  1037. //
  1038. // this thread takes a notification request from queue and executes it.
  1039. // this thread gets signaled when a new item is added to the queue.
  1040. //
  1041. DWORD NotificationQueueWorker(LPVOID ThreadParameter)
  1042. {
  1043. UNREFERENCED_PARAMETER(ThreadParameter);
  1044. NotificationQueueWorkerEx();
  1045. return 0;
  1046. }
  1047. NTSTATUS SetLockedState (PWINSTATION pWinStation, BOOL bLocked)
  1048. {
  1049. ASSERT(pWinStation);
  1050. if (bLocked)
  1051. {
  1052. return NofifyWelcomeOn (pWinStation);
  1053. }
  1054. else
  1055. {
  1056. return NotifyWelcomeOff (pWinStation);
  1057. }
  1058. }
  1059. NTSTATUS GetLockedState (PWINSTATION pWinStation, BOOL *pbLocked)
  1060. {
  1061. NTSTATUS Status;
  1062. PNOTIFY_LIST pNotifyList;
  1063. ASSERT(pbLocked);
  1064. ASSERT(pWinStation);
  1065. Status = GetNoficationListFromSessionId(pWinStation->LogonId, &pNotifyList, FALSE);
  1066. if ( !NT_SUCCESS( Status ) )
  1067. {
  1068. return (Status);
  1069. }
  1070. *pbLocked = pNotifyList->SessionState.bLocked;
  1071. ReleaseNotificationList(pNotifyList);
  1072. return STATUS_SUCCESS;
  1073. }
  1074. /*
  1075. NTSTATUS GetSessionState (PWINSTATION pWinStation, WTSSESSION_STATE *pSessionState)
  1076. {
  1077. NTSTATUS Status;
  1078. PNOTIFY_LIST pNotifyList;
  1079. ASSERT(pSessionState);
  1080. ASSERT(pWinStation);
  1081. Status = GetNoficationListFromSessionId(pWinStation->LogonId, &pNotifyList, FALSE);
  1082. if ( !NT_SUCCESS( Status ) )
  1083. {
  1084. return (Status);
  1085. }
  1086. *pSessionState = pNotifyList->SessionState;
  1087. ReleaseNotificationList(pNotifyList);
  1088. return STATUS_SUCCESS;
  1089. }
  1090. */
  1091. NTSTATUS RemoveBadHwnd(ULONG hWnd, ULONG SessionId)
  1092. {
  1093. PNOTIFY_ENTRY_GLOBAL pInvalidHwndEntry;
  1094. PNOTIFY_LIST pInvalidHwndList;
  1095. NTSTATUS Status;
  1096. Status = GetInvlidHwndList(&pInvalidHwndList);
  1097. if ( !NT_SUCCESS( Status ) )
  1098. {
  1099. return (Status);
  1100. }
  1101. pInvalidHwndEntry = GetHWndEntryFromGlobalList(pInvalidHwndList, hWnd, SessionId);
  1102. //
  1103. // this entry must not already exist in invalid list.
  1104. //
  1105. if(!pInvalidHwndEntry)
  1106. {
  1107. // it alreay exists in our list.
  1108. pInvalidHwndEntry = MemAlloc(sizeof(NOTIFY_ENTRY_GLOBAL));
  1109. if (pInvalidHwndEntry)
  1110. {
  1111. pInvalidHwndEntry->hWnd = hWnd;
  1112. pInvalidHwndEntry->SessionId = SessionId;
  1113. InsertHeadList(&pInvalidHwndList->ListHead, &pInvalidHwndEntry->Links);
  1114. }
  1115. }
  1116. ReleaseNotificationList( pInvalidHwndList );
  1117. if (pInvalidHwndEntry)
  1118. return STATUS_SUCCESS;
  1119. else
  1120. return STATUS_NO_MEMORY;
  1121. }
  1122. NTSTATUS RemoveInvalidWindowsFromLists()
  1123. {
  1124. PNOTIFY_LIST pInvalidHwndList;
  1125. PLIST_ENTRY Next, Head;
  1126. NTSTATUS Status;
  1127. Status = GetInvlidHwndList(&pInvalidHwndList);
  1128. if ( !NT_SUCCESS( Status ) )
  1129. {
  1130. return (Status);
  1131. }
  1132. Head = &pInvalidHwndList->ListHead;
  1133. Next = Head->Flink;
  1134. while (Head != Next)
  1135. {
  1136. PNOTIFY_ENTRY_GLOBAL pInvalidHwndEntry = CONTAINING_RECORD( Next, NOTIFY_ENTRY_GLOBAL, Links );
  1137. Next = Next->Flink;
  1138. ASSERT(pInvalidHwndEntry);
  1139. Status = UnRegisterConsoleNotificationInternal (pInvalidHwndEntry->hWnd, pInvalidHwndEntry->SessionId, FALSE);
  1140. // we are done removing this invalid hwnd entry from our lists.
  1141. RemoveEntryList( &pInvalidHwndEntry->Links );
  1142. MemFree(pInvalidHwndEntry);
  1143. pInvalidHwndEntry = NULL;
  1144. }
  1145. ReleaseNotificationList(pInvalidHwndList);
  1146. return STATUS_SUCCESS;
  1147. }
  1148. /*
  1149. our order of locks is
  1150. 0. Invalid Hwnd List.
  1151. 1. Global Notification List
  1152. 2. Winstation
  1153. 3. List of Lists lock.
  1154. 4. Session Notification List
  1155. */
  1156. //#ifdef MAKARANDS_HIGHER_WARNING_LEVEL
  1157. #pragma warning(pop)
  1158. //#endif