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

806 lines
24 KiB

  1. // **************************************************************************
  2. //
  3. // Status.C
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1999-2001
  7. // All rights reserved
  8. //
  9. // This application implements a common status dialog for factory functions.
  10. //
  11. // 04/01/2001 Stephen Lodwick
  12. // Project started
  13. //
  14. //
  15. // *************************************************************************/
  16. //
  17. // Includes
  18. //
  19. #include "factoryp.h"
  20. typedef struct _STATUSWINDOWS
  21. {
  22. HWND hStatusWindow;
  23. LPSTATUSNODE lpCurrent;
  24. struct _STATUSWINDOWS*lpNext;
  25. } STATUSWINDOWS, *LPSTATUSWINDOWS, **LPLPSTATUSWINDOWS;
  26. typedef struct _DIALOGPARAM
  27. {
  28. LPSTATUSWINDOW lpswParam;
  29. LPSTATUSNODE lpsnParam;
  30. HWND hStatusWindow;
  31. HANDLE hEvent;
  32. } DIALOGPARAM, *LPDIALOGPARAM, **LPLPDIALOGPARAM;
  33. //
  34. // Internal Function Prototype(s):
  35. //
  36. LRESULT CALLBACK StatusDlgProc(HWND, UINT, WPARAM, LPARAM);
  37. DWORD StatusDisplayList(HWND, LPSTATUSNODE);
  38. BOOL StatusAddWindow(HWND, LPLPSTATUSWINDOWS, LPSTATUSNODE, BOOL);
  39. VOID StatusCreateDialogThread(LPDIALOGPARAM);
  40. //
  41. // Internal Define(s):
  42. //
  43. #define FIRST_SPACING 7 // Spacing (pixel) between the title and the first app
  44. #define LINE_SPACING 7 // Spacing (pixel) between additional applcations
  45. #define WM_FINISHED (WM_USER + 0x0001) // User defined message to indicate the dialog should be destroyed
  46. #define WM_PROGRESS (WM_USER + 0x0002) // User defined message to indicate that we are progressing to the next app
  47. /*++
  48. Routine:
  49. StatusAddNode
  50. Routine Description:
  51. This routine takes a string and adds that string onto the end of our
  52. linked list.
  53. Arguments:
  54. lpszNodeText - Pointer to string of text that you would like to add to list
  55. lplpsnHead - Pointer to a LPSTATUSNODE list
  56. Return Value:
  57. TRUE - Node was added to list
  58. FALSE - If the Node was not added to list
  59. --*/
  60. BOOL StatusAddNode(
  61. LPTSTR lpszNodeText, // Text that you would like to add to the current list
  62. LPLPSTATUSNODE lplpsnHead // List that we will be adding status node to
  63. )
  64. {
  65. LPSTATUSNODE lpsnTemp = NULL;
  66. if ( lpszNodeText && *lpszNodeText == NULLCHR )
  67. return FALSE;
  68. // Go to the end of the list
  69. //
  70. while ( lplpsnHead && *lplpsnHead )
  71. lplpsnHead=&((*lplpsnHead)->lpNext);
  72. if ( (lpsnTemp = (LPSTATUSNODE)MALLOC(sizeof(STATUSNODE)) ) && lpszNodeText )
  73. {
  74. lstrcpyn(lpsnTemp->szStatusText, lpszNodeText, AS( lpsnTemp->szStatusText ) );
  75. lpsnTemp->lpNext = NULL;
  76. // Make sure the previous node points to the new node
  77. //
  78. if ( lplpsnHead )
  79. *lplpsnHead = lpsnTemp;
  80. return TRUE;
  81. }
  82. else
  83. return FALSE;
  84. }
  85. /*++
  86. Routine:
  87. StatusIncrement
  88. Routine Description:
  89. This routine increments the status to the next node in the list
  90. Arguments:
  91. hStatusDialog - Handle of the StatusDialog
  92. bLastResult - Result of the last node (whether it succeeded or failed)
  93. Return Value:
  94. TRUE - Message sent to status dialog
  95. FALSE - Message was not sent to status dialog
  96. --*/
  97. BOOL StatusIncrement(
  98. HWND hStatusDialog,
  99. BOOL bLastResult
  100. )
  101. {
  102. // We must have a valid handle to the status dialog
  103. //
  104. if ( IsWindow(hStatusDialog) )
  105. {
  106. // Send a message to the dialog proc to go to the next caption
  107. //
  108. SendMessage(hStatusDialog, WM_PROGRESS,(WPARAM) NULL,(LPARAM) bLastResult);
  109. return TRUE;
  110. }
  111. return FALSE;
  112. }
  113. /*++
  114. Routine:
  115. StatusEndDialog
  116. Routine Description:
  117. This routine sends a message to a status dialog to end.
  118. Arguments:
  119. hStatusDialog - Handle of the StatusDialog
  120. Return Value:
  121. TRUE - Message sent to status dialog
  122. FALSE - Message was not sent to status dialog
  123. --*/
  124. BOOL StatusEndDialog(
  125. HWND hStatusDialog // handle to status dialog
  126. )
  127. {
  128. // We must have a valid handle to the status dialog
  129. //
  130. if ( IsWindow(hStatusDialog) )
  131. {
  132. // Send a message to the dialog proc to end the dialog
  133. //
  134. SendMessage(hStatusDialog, WM_FINISHED,(WPARAM) NULL,(LPARAM) NULL);
  135. return TRUE;
  136. }
  137. return FALSE;
  138. }
  139. /*++
  140. Routine:
  141. StatusCreateDialogThread
  142. Routine Description:
  143. This routine creates the dialog for the status window and processes until the window is ended.
  144. Arguments:
  145. lpDialog - Pointer to structure that contains information to create thread/dialog
  146. Return Value:
  147. None.
  148. --*/
  149. VOID StatusCreateDialogThread(LPDIALOGPARAM lpDialog)
  150. {
  151. MSG msg;
  152. HWND hWnd;
  153. HANDLE hEvent = lpDialog->hEvent;
  154. hWnd = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_RUN), NULL, StatusDlgProc, (LPARAM) lpDialog);
  155. while (GetMessage(&msg, hWnd, 0, 0) != 0)
  156. {
  157. TranslateMessage(&msg);
  158. DispatchMessage(&msg);
  159. }
  160. // Event has not been been signaled, null out the hwnd and signal event
  161. //
  162. if ( WaitForSingleObject(hEvent, 0) == WAIT_TIMEOUT )
  163. {
  164. // Reset the status window handle to null, and set the event
  165. //
  166. lpDialog->hStatusWindow = NULL;
  167. SetEvent(lpDialog->hEvent);
  168. }
  169. else
  170. {
  171. // Close the event handle
  172. //
  173. CloseHandle(hEvent);
  174. }
  175. }
  176. /*++
  177. Routine:
  178. StatusCreateDialog
  179. Routine Description:
  180. Main function that creates the status dialog
  181. Arguments:
  182. lpswStatus - Pointer to structure that contains information about Status Window
  183. lpsnStatus - Pointer to struction that contains head node for status labels
  184. Return Value:
  185. HWND - Handle to window that was created, NULL if window was not created.
  186. --*/
  187. HWND StatusCreateDialog(
  188. LPSTATUSWINDOW lpswStatus, // structure that contains information about the window
  189. LPSTATUSNODE lpsnStatus // head node for status text
  190. )
  191. {
  192. DIALOGPARAM dpStatus;
  193. DWORD dwThread;
  194. HANDLE hThread;
  195. HANDLE hEvent;
  196. // Determine if we have the required structures to continue, an hInstance, and some status text
  197. //
  198. if ( !lpswStatus || !lpsnStatus || !lpsnStatus->szStatusText[0])
  199. return NULL;
  200. // Zero out memory
  201. //
  202. ZeroMemory(&dpStatus, sizeof(dpStatus));
  203. // Create an event, non-signaled to determine if dialog is initialized
  204. //
  205. if ( hEvent = CreateEvent(NULL, TRUE, FALSE, NULL) )
  206. {
  207. // Need a single variable for the dialog box parameter
  208. //
  209. dpStatus.lpswParam = lpswStatus;
  210. dpStatus.lpsnParam = lpsnStatus;
  211. dpStatus.hStatusWindow = NULL;
  212. dpStatus.hEvent = hEvent;
  213. // Create the thread to initialize the dialog
  214. //
  215. if (hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) StatusCreateDialogThread, (LPVOID) &dpStatus, 0, &dwThread) )
  216. {
  217. MSG msg;
  218. // Wait for the event from WM_INITDIALOG
  219. //
  220. WaitForSingleObject(hEvent, INFINITE);
  221. // Close the handle to the thread
  222. //
  223. CloseHandle(hThread);
  224. }
  225. // Reset and close the event only if we failed to create window, otherwise, StatusCreateDialogThread will close handle
  226. //
  227. if ( !dpStatus.hStatusWindow )
  228. CloseHandle(hEvent);
  229. }
  230. // Return the handle to the StatusDialog
  231. //
  232. return ( dpStatus.hStatusWindow );
  233. }
  234. /*++
  235. Routine:
  236. StatusDlgProc
  237. Routine Description:
  238. Main dialog procedure for StatusCreateDialog.
  239. Arguments:
  240. hWnd - Handle to window
  241. uMsg - Message being sent to window
  242. uParam - Upper parameter being sent
  243. lParam - Lower parameter being sent
  244. Return Value:
  245. LRESULT - Result of message that was processed
  246. --*/
  247. LRESULT CALLBACK StatusDlgProc(HWND hWnd, UINT uMsg, WPARAM uParam, LPARAM lParam)
  248. {
  249. static HFONT hNormFont = NULL;
  250. static HFONT hBoldFont = NULL;
  251. static HANDLE hIconSuccess = NULL;
  252. static HANDLE hIconError = NULL;
  253. static LPSTATUSWINDOWS lpStatusWindows;
  254. switch (uMsg)
  255. {
  256. case WM_INITDIALOG:
  257. {
  258. LPSTATUSWINDOW lpswWindow = NULL;
  259. LPSTATUSNODE lpHead = NULL,
  260. lpWindowHead = NULL;
  261. HANDLE hEvent = NULL;
  262. if ( lParam )
  263. {
  264. // Determine the window, and current node
  265. //
  266. lpswWindow = ((LPDIALOGPARAM)lParam)->lpswParam;
  267. lpHead = ((LPDIALOGPARAM)lParam)->lpsnParam;
  268. hEvent = ((LPDIALOGPARAM)lParam)->hEvent;
  269. // Check to make sure that we have pointers to the required structures
  270. //
  271. if ( !lpswWindow || !lpHead || !hEvent)
  272. {
  273. PostMessage(hWnd, WM_FINISHED,(WPARAM) NULL,(LPARAM) NULL);
  274. return FALSE;
  275. }
  276. // Copy the list that was passed in, to our own buffer
  277. //
  278. while ( lpHead )
  279. {
  280. StatusAddNode(lpHead->szStatusText, &lpWindowHead);
  281. lpHead = lpHead->lpNext;
  282. }
  283. // Add this window to our list of windows
  284. //
  285. StatusAddWindow(hWnd, &lpStatusWindows, lpWindowHead, FALSE);
  286. // Set the status window if there is one specified
  287. //
  288. if (lpswWindow->szWindowText[0] )
  289. SetWindowText(hWnd, lpswWindow->szWindowText);
  290. // Set the status window description if there is one specified.
  291. //
  292. if ( lpswWindow->lpszDescription )
  293. {
  294. SetDlgItemText(hWnd, IDC_TITLE, lpswWindow->lpszDescription);
  295. }
  296. // Set the status window description if there is one specified.
  297. //
  298. if ( lpswWindow->hMainIcon )
  299. {
  300. SendDlgItemMessage(hWnd, IDC_STATUS_ICON, STM_SETICON, (WPARAM) lpswWindow->hMainIcon, 0L);
  301. }
  302. // Display the list
  303. //
  304. StatusDisplayList(hWnd, lpWindowHead);
  305. // Move the window if a position was given
  306. //
  307. if ( lpswWindow->X || lpswWindow->Y )
  308. {
  309. // See if either coordinate is relative to the other
  310. // side of the screen.
  311. //
  312. if ( ( lpswWindow->X < 0 ) ||
  313. ( lpswWindow->Y < 0 ) )
  314. {
  315. RECT rc;
  316. // Need to get the size of our work area on the main monitor.
  317. //
  318. if ( SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0) )
  319. {
  320. RECT rcHwnd;
  321. POINT point;
  322. // This code will get the current window size/position,
  323. // set the point structure to the upper left coordinate
  324. // for the window if we wanted the lower right part of
  325. // window to touch the lower right part of the desktop.
  326. //
  327. GetWindowRect(hWnd, &rcHwnd);
  328. point.x = rc.right - (rcHwnd.right - rcHwnd.left);
  329. point.y = rc.bottom - (rcHwnd.bottom - rcHwnd.top);
  330. MapWindowPoints(NULL, hWnd, &point, 1);
  331. // Now if they passed in negative coordinates, add those
  332. // to our point structure so the window moves away from
  333. // the bottom or right part of the screen by the number
  334. // of units they specifed.
  335. //
  336. if ( lpswWindow->X < 0 )
  337. {
  338. lpswWindow->X += point.x;
  339. }
  340. if ( lpswWindow->Y < 0 )
  341. {
  342. lpswWindow->Y += point.y;
  343. }
  344. }
  345. }
  346. // Now move the window.
  347. //
  348. SetWindowPos(hWnd, 0, lpswWindow->X, lpswWindow->Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  349. }
  350. // Build the new fonts
  351. //
  352. if(!hNormFont)
  353. hNormFont = GetFont((HWND) GetDlgItem(hWnd, IDC_TITLE), NULL, 0, FW_NORMAL, FALSE);
  354. if(!hBoldFont)
  355. hBoldFont = GetFont((HWND) GetDlgItem(hWnd, IDC_TITLE), NULL, 0, FW_BOLD, FALSE);
  356. // Bold the first item in the list
  357. //
  358. if ( lpWindowHead && hBoldFont)
  359. SendMessage((HWND)lpWindowHead->hLabelWin, WM_SETFONT, (WPARAM) hBoldFont, MAKELPARAM(TRUE, 0));
  360. // Now make sure we show the window now.
  361. //
  362. ShowWindow(hWnd, SW_SHOW);
  363. ((LPDIALOGPARAM)lParam)->hStatusWindow = hWnd;
  364. // Set event stating that dialog is initialized
  365. //
  366. SetEvent(hEvent);
  367. }
  368. else
  369. PostMessage(hWnd, WM_FINISHED,(WPARAM) NULL,(LPARAM) NULL);
  370. }
  371. break;
  372. case WM_PROGRESS:
  373. {
  374. // Progress to the next item, if there are no items, end the dialog
  375. //
  376. LPSTATUSWINDOWS lpswNext = lpStatusWindows;
  377. BOOL bFound = FALSE;
  378. LPSTATUSNODE lpsnTemp = NULL;
  379. // Locate the current node given a window handle
  380. //
  381. while ( lpswNext && !bFound)
  382. {
  383. if ( lpswNext->hStatusWindow == hWnd )
  384. bFound = TRUE;
  385. else
  386. lpswNext = lpswNext->lpNext;
  387. }
  388. // If there is a current node, lets unbold it, increment and bold the next item
  389. //
  390. if ( bFound && lpswNext && lpswNext->lpCurrent )
  391. {
  392. if ( hNormFont )
  393. SendMessage((HWND)lpswNext->lpCurrent->hLabelWin, WM_SETFONT, (WPARAM) hNormFont, MAKELPARAM(TRUE, 0));
  394. if ( !hIconSuccess )
  395. hIconSuccess = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_STATUSSUCCESS), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  396. if ( !hIconError )
  397. hIconError = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_STATUSERROR), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  398. if ( hIconSuccess && hIconError )
  399. SendMessage(lpswNext->lpCurrent->hIconWin,STM_SETIMAGE, (WPARAM)IMAGE_ICON, (BOOL)lParam ? (LPARAM)hIconSuccess : (LPARAM)hIconError );
  400. // Increment to the next node in the list
  401. //
  402. lpsnTemp = lpswNext->lpCurrent;
  403. lpswNext->lpCurrent = lpswNext->lpCurrent->lpNext;
  404. // Free this memory since we allocated it
  405. //
  406. FREE(lpsnTemp);
  407. // If there is not a current node, end the dialog, otherwise, bold the item
  408. //
  409. if ( lpswNext->lpCurrent && hBoldFont)
  410. SendMessage(lpswNext->lpCurrent->hLabelWin, WM_SETFONT, (WPARAM) hBoldFont, MAKELPARAM(TRUE, 0));
  411. }
  412. }
  413. break;
  414. case WM_FINISHED:
  415. {
  416. // Destroy the dialog
  417. //
  418. if ( hWnd )
  419. {
  420. // If there are status windows, let's remove the one that we are ending
  421. //
  422. if ( lpStatusWindows )
  423. StatusAddWindow(hWnd, &lpStatusWindows, NULL, TRUE);
  424. // Check to see if there are any windows left, if not, do some clean up
  425. //
  426. if ( !lpStatusWindows )
  427. {
  428. // Delete fonts static to dlgproc
  429. //
  430. if (hNormFont)
  431. {
  432. DeleteObject(hNormFont);
  433. hNormFont = NULL;
  434. }
  435. if (hBoldFont)
  436. {
  437. DeleteObject(hBoldFont);
  438. hBoldFont = NULL;
  439. }
  440. }
  441. // Quit and end the dialog
  442. //
  443. EndDialog(hWnd, 1);
  444. }
  445. return FALSE;
  446. }
  447. break;
  448. default:
  449. return FALSE;
  450. }
  451. return FALSE;
  452. }
  453. /*++
  454. Routine:
  455. StatusDisplayList
  456. Routine Description:
  457. Function that displays list to user interface
  458. Arguments:
  459. hWnd - Handle to Status window
  460. lpsnList - List to head Status Node
  461. Return Value:
  462. DWORD - Number of entries that were added to the dialog
  463. --*/
  464. DWORD StatusDisplayList(HWND hWnd, LPSTATUSNODE lpsnList)
  465. {
  466. LPSTATUSNODE lpsnTempList = lpsnList;
  467. HWND hWndLabel,
  468. hWndIcon;
  469. RECT Rect,
  470. WindowRect;
  471. POINT Point;
  472. DWORD dwEntries = 0;
  473. HFONT hNormFont = NULL;
  474. LPTSTR lpTempRunName;
  475. HDC hdc;
  476. SIZE size = { 0, 0 };
  477. LONG nWidestControl;
  478. GetWindowRect(GetDlgItem(hWnd, IDC_TITLE), &Rect);
  479. Rect.right -= Rect.left; // The width of the control.
  480. Rect.bottom -= Rect.top; // The height of the control.
  481. Point.x = Rect.left;
  482. Point.y = Rect.top;
  483. nWidestControl = Rect.right;
  484. MapWindowPoints(NULL, hWnd, &Point, 1);
  485. Point.y += FIRST_SPACING;
  486. while(lpsnTempList)
  487. {
  488. // Calculate the point of the first label window
  489. //
  490. Point.y += Rect.bottom + LINE_SPACING;
  491. // Get the size of the text in pixels
  492. //
  493. if (hdc = GetWindowDC(hWnd))
  494. {
  495. GetTextExtentPoint32(hdc, lpsnTempList->szStatusText, lstrlen(lpsnTempList->szStatusText), &size);
  496. if (size.cx > nWidestControl)
  497. nWidestControl = size.cx;
  498. ReleaseDC(hWnd, hdc);
  499. }
  500. // Create the label window
  501. //
  502. hWndIcon = CreateWindow(_T("STATIC"), _T(""), WS_CHILD | WS_VISIBLE | SS_ICON | SS_CENTERIMAGE, Point.x - 16, Point.y - 2, 16, 16, hWnd, NULL, g_hInstance, NULL);
  503. hWndLabel = CreateWindow(_T("STATIC"), _T(""), WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, Point.x, Point.y, (Rect.right > size.cx ? Rect.right : size.cx) , Rect.bottom, hWnd, NULL, g_hInstance, NULL);
  504. // If the font is NULL, get a font
  505. //
  506. if ( hNormFont == NULL )
  507. hNormFont = (HFONT) SendDlgItemMessage(hWnd, IDC_TITLE, WM_GETFONT, 0, 0L);
  508. // Set the font to the same font as the title
  509. //
  510. SendMessage(hWndLabel, WM_SETFONT, (WPARAM) hNormFont, MAKELPARAM(FALSE, 0));
  511. // Set the Window text to the name of the program
  512. //
  513. SetWindowText(hWndLabel, lpsnTempList->szStatusText);
  514. // Set the hWndTemp (created from CreateWindow) in the list
  515. //
  516. lpsnTempList->hLabelWin = hWndLabel;
  517. lpsnTempList->hIconWin = hWndIcon;
  518. // Goto the next item in the list
  519. //
  520. lpsnTempList = lpsnTempList->lpNext;
  521. // Increment for each of the applications in the list
  522. //
  523. dwEntries++;
  524. }
  525. GetWindowRect(hWnd, &WindowRect);
  526. WindowRect.right = WindowRect.right - WindowRect.left + nWidestControl - Rect.right; // The width of the winodw.
  527. WindowRect.bottom -= WindowRect.top; // The height of the window.
  528. // Resize the dialog to fit the label text.
  529. //
  530. SetWindowPos(hWnd, 0, 0, 0, WindowRect.right, WindowRect.bottom + ((Rect.bottom + LINE_SPACING)*dwEntries), SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOZORDER );
  531. return dwEntries;
  532. }
  533. /*++
  534. ===============================================================================
  535. Routine Description:
  536. StatusAddWindow
  537. Adds a new window to the list. This function is used internally for the status
  538. dialog.
  539. Arguments:
  540. hStatusWindow - Handle to Status Window
  541. lplpswHead - Head of the Windows list
  542. lpsnHead - Current head node for Status Window
  543. bRemove - Indicates wheter we add or remove the window from the list
  544. Return Value:
  545. None
  546. ===============================================================================
  547. --*/
  548. BOOL StatusAddWindow(
  549. HWND hStatusWindow, // Text that you would like to add to the current list
  550. LPLPSTATUSWINDOWS lplpswHead, // List that we will be adding status window to
  551. LPSTATUSNODE lpsnHead, // Head of the STATUSNODE structure
  552. BOOL bRemove // Indicates if we are removing the window from our list
  553. )
  554. {
  555. LPLPSTATUSWINDOWS lplpswNext = lplpswHead;
  556. LPSTATUSWINDOWS lpswTemp = NULL;
  557. LPSTATUSNODE lpsnTemp = NULL;
  558. BOOL bFound = FALSE;
  559. // If there is no status window we have nothing to add
  560. //
  561. if ( !hStatusWindow )
  562. return FALSE;
  563. // Attempt to find the window passed in, if not, we are at the end of the list
  564. //
  565. while ( *lplpswNext && !bFound)
  566. {
  567. if ( (*lplpswNext)->hStatusWindow == hStatusWindow )
  568. bFound = TRUE;
  569. else
  570. lplpswNext=&((*lplpswNext)->lpNext);
  571. }
  572. // If we are adding it and we didn't find it in the list go ahead an add the new node
  573. //
  574. if ( !bRemove && !bFound)
  575. {
  576. if ( lpswTemp = (LPSTATUSWINDOWS)MALLOC(sizeof(STATUSWINDOWS)) )
  577. {
  578. lpswTemp->hStatusWindow = hStatusWindow;
  579. lpswTemp->lpNext = NULL;
  580. lpswTemp->lpCurrent = lpsnHead;
  581. // Make sure the previous node points to the new node
  582. //
  583. *lplpswNext = lpswTemp;
  584. }
  585. else
  586. return FALSE;
  587. }
  588. else if ( bRemove && bFound && *lplpswNext)
  589. {
  590. // If there are nodes left in for the window, lets clean them up
  591. //
  592. if ( (*lplpswNext)->lpCurrent )
  593. StatusDeleteNodes((*lplpswNext)->lpCurrent);
  594. // Free the window node
  595. //
  596. lpswTemp = (*lplpswNext);
  597. (*lplpswNext) = (*lplpswNext)->lpNext;
  598. FREE(lpswTemp);
  599. }
  600. else
  601. {
  602. return FALSE;
  603. }
  604. return TRUE;
  605. }
  606. /*++
  607. ===============================================================================
  608. Routine Description:
  609. VOID StatusDeleteNodes
  610. Deletes all the Nodes in a STATUSNODE list
  611. Arguments:
  612. lpsnHead - current head of the list
  613. Return Value:
  614. None
  615. ===============================================================================
  616. --*/
  617. VOID StatusDeleteNodes(
  618. LPSTATUSNODE lpsnHead
  619. )
  620. {
  621. LPSTATUSNODE lpsnTemp = NULL;
  622. while ( lpsnHead )
  623. {
  624. lpsnTemp = lpsnHead;
  625. lpsnHead = lpsnHead->lpNext;
  626. FREE(lpsnTemp);
  627. }
  628. }