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.

767 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: msgina.c
  7. //
  8. // Contents: Microsoft Logon GUI DLL
  9. //
  10. // History: 7-14-94 RichardW Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "testgina.h"
  14. #include <stdio.h>
  15. #include <wchar.h>
  16. HINSTANCE hDllInstance; // Dll instance,
  17. DWORD DllVersion; // Dll Version
  18. HINSTANCE hAppInstance; // App instance, for dialogs, etc.
  19. HWND hMainWindow; // Main window
  20. WNDCLASS WndClass; // Window class
  21. HICON hIcon;
  22. WNDCLASS StatusClass; // Status Window class
  23. HWND hStatusWindow; // Status Window
  24. HMENU hDebugMenu; // Debug Menu
  25. USER_SAS UserDefSas[MAX_USER_SASES];
  26. DWORD UserSases;
  27. DWORD CurrentDesktop;
  28. PWLX_DESKTOP Desktops[ MAX_DESKTOPS ];
  29. DWORD DesktopCount;
  30. DWORD OtherDesktop;
  31. LRESULT StatusProc(HWND, UINT, WPARAM, LPARAM);
  32. WLX_DISPATCH_VERSION_1_3 WlxDispatchTable = {
  33. WlxUseCtrlAltDel,
  34. WlxSetContextPointer,
  35. WlxSasNotify,
  36. WlxSetTimeout,
  37. WlxAssignShellProtection,
  38. WlxMessageBox,
  39. WlxDialogBox,
  40. WlxDialogBoxParam,
  41. WlxDialogBoxIndirect,
  42. WlxDialogBoxIndirectParam,
  43. WlxSwitchDesktopToUser,
  44. WlxSwitchDesktopToWinlogon,
  45. WlxChangePasswordNotify,
  46. WlxGetSourceDesktop,
  47. WlxSetReturnDesktop,
  48. WlxCreateUserDesktop,
  49. WlxChangePasswordNotifyEx,
  50. WlxCloseUserDesktop,
  51. WlxSetOption,
  52. WlxGetOption,
  53. WlxWin31Migrate,
  54. WlxQueryClientCredentials,
  55. WlxQueryICCredentials,
  56. WlxDisconnect };
  57. PWLX_NEGOTIATE pWlxNegotiate;
  58. PWLX_INITIALIZE pWlxInitialize;
  59. PWLX_DISPLAYSASNOTICE pWlxDisplaySASNotice;
  60. PWLX_LOGGEDOUTSAS pWlxLoggedOutSAS;
  61. PWLX_ACTIVATEUSERSHELL pWlxActivateUserShell;
  62. PWLX_LOGGEDONSAS pWlxLoggedOnSAS;
  63. PWLX_DISPLAYLOCKEDNOTICE pWlxDisplayLockedNotice;
  64. PWLX_WKSTALOCKEDSAS pWlxWkstaLockedSAS;
  65. PWLX_LOGOFF pWlxLogoff;
  66. PWLX_SHUTDOWN pWlxShutdown;
  67. WinstaState GinaState; // State of the GinaTest
  68. DWORD fTestGina; // Flags
  69. DWORD GinaBreakFlags; // Break points for Gina debugging
  70. WCHAR szGinaDll[MAX_PATH]; // Path and name of the DLL
  71. DWORD SizeX, SizeY;
  72. DWORD PosX, PosY;
  73. DWORD StatusHeight = 24;
  74. DWORD StatusDeltaX;
  75. DWORD StatusDeltaY;
  76. DWORD LastRetCode;
  77. BOOL LastBoolRet;
  78. PWSTR szErrorMessages[] = { TEXT("Internal TestGina Error!"),
  79. TEXT("Invalid hWlx Handle Passed"),
  80. TEXT("Improper SAS supplied"),
  81. TEXT("Invalid Protocol Level"),
  82. TEXT("Load of DLL Failed"),
  83. TEXT("Missing Function"),
  84. TEXT("Unknown HWND"),
  85. TEXT("No Window for SAS message"),
  86. TEXT("Invalid SAS code in message"),
  87. TEXT("Invalid return code from function")
  88. };
  89. PWSTR szStates[] = { TEXT("Pre Load"),
  90. TEXT("Initialize"),
  91. TEXT("No One Logged On"),
  92. TEXT("No One Logged On -- Display Notice"),
  93. TEXT("No One Logged On -- SAS Received"),
  94. TEXT("User Logged On -- Start Shell"),
  95. TEXT("User Logged On"),
  96. TEXT("User Logged On -- SAS Received"),
  97. TEXT("Wksta Locked"),
  98. TEXT("Wksta Locked -- SAS Received"),
  99. TEXT("Waiting to Shutdown"),
  100. TEXT("Shutdown")
  101. };
  102. PWSTR szRetcodes[] = { TEXT("N/A"),
  103. TEXT("WLX_SAS_ACTION_USER_LOGON"),
  104. TEXT("WLX_SAS_ACTION_NONE"),
  105. TEXT("WLX_SAS_ACTION_LOCK_WKSTA"),
  106. TEXT("WLX_SAS_ACTION_LOGOFF"),
  107. TEXT("WLX_SAS_ACTION_SHUTDOWN"),
  108. TEXT("WLX_SAS_ACTION_PWD_CHANGED"),
  109. TEXT("WLX_SAS_ACTION_TASKLIST"),
  110. TEXT("WLX_SAS_ACTION_UNLOCK_WKSTA"),
  111. TEXT("WLX_SAS_ACTION_FORCE_LOGOFF"),
  112. TEXT("WLX_SAS_ACTION_SHUTDOWN_POWER_OFF"),
  113. TEXT("WLX_SAS_ACTION_SHUTDOWN_REBOOT")
  114. };
  115. BOOLEAN
  116. AmIBeingDebugged(void)
  117. {
  118. HANDLE DebugPort;
  119. NTSTATUS Status;
  120. DebugPort = (HANDLE) NULL;
  121. Status = NtQueryInformationProcess(
  122. NtCurrentProcess(),
  123. ProcessDebugPort,
  124. (PVOID) &DebugPort,
  125. sizeof(DebugPort),
  126. NULL );
  127. if (NT_SUCCESS(Status) && DebugPort)
  128. {
  129. return(TRUE);
  130. }
  131. return(FALSE);
  132. }
  133. void
  134. TestGinaError( DWORD dwError,
  135. PWSTR pszFunction)
  136. {
  137. int mbret;
  138. BOOLEAN fDbg;
  139. WCHAR szBuffer[MAX_PATH];
  140. WCHAR szCaption[MAX_PATH];
  141. if (dwError > (sizeof(szErrorMessages) / sizeof(PWSTR)))
  142. {
  143. dwError = 0;
  144. }
  145. fDbg = AmIBeingDebugged();
  146. wsprintf(szCaption, TEXT("%ws: Error %d"), pszFunction, dwError);
  147. if (fDbg)
  148. {
  149. wsprintf(szBuffer, TEXT("The following error occurred:\n%ws\nPress OK to exit, Cancel to debug"),
  150. szErrorMessages[dwError]);
  151. }
  152. else
  153. wsprintf(szBuffer, TEXT("The following error occurred:\n%ws\nPress OK to exit."),
  154. szErrorMessages[dwError]);
  155. mbret = MessageBox( hMainWindow,
  156. szBuffer,
  157. szCaption,
  158. MB_ICONSTOP | (fDbg ? MB_OKCANCEL : MB_OK) );
  159. if (fDbg && (mbret == IDCANCEL))
  160. {
  161. DbgBreakPoint();
  162. mbret = MessageBox(hMainWindow, TEXT("Continue after error?"),
  163. TEXT("TestGina"), MB_OKCANCEL);
  164. if (mbret == IDOK)
  165. {
  166. return;
  167. }
  168. }
  169. ExitProcess(dwError);
  170. }
  171. void
  172. DoClass(void)
  173. {
  174. WndClass.style = 0;
  175. WndClass.lpfnWndProc = WndProc;
  176. WndClass.cbClsExtra = 0;
  177. WndClass.cbWndExtra = 0;
  178. WndClass.hInstance = hAppInstance;
  179. WndClass.hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(TESTGINAICON));
  180. hIcon = WndClass.hIcon;
  181. WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
  182. WndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  183. WndClass.lpszMenuName = MAKEINTRESOURCE(TESTGINAMENU);
  184. WndClass.lpszClassName = TEXT("TestGina");
  185. RegisterClass(&WndClass);
  186. }
  187. int
  188. WinMain(
  189. HINSTANCE hInstance,
  190. HINSTANCE hPrev,
  191. LPSTR pszCommandLine,
  192. int nCmdShow)
  193. {
  194. MSG msg;
  195. HMENU hMenu;
  196. hAppInstance = hInstance;
  197. InitCommonControls();
  198. DoClass();
  199. SizeX = (DWORD) CW_USEDEFAULT;
  200. SizeY = (DWORD) CW_USEDEFAULT;
  201. PosX = (DWORD) CW_USEDEFAULT;
  202. PosY = (DWORD) CW_USEDEFAULT;
  203. LoadParameters();
  204. InitializeDesktops();
  205. hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(TESTGINAMENU));
  206. if (szGinaDll[0] == TEXT('\0'))
  207. {
  208. DeleteMenu(hMenu, IDM_DLL_LOAD_LAST, MF_BYCOMMAND);
  209. }
  210. else
  211. {
  212. WCHAR tmp[32];
  213. PWSTR pszName;
  214. if (wcslen(szGinaDll) > 32)
  215. {
  216. pszName = wcsrchr(szGinaDll, TEXT('\\'));
  217. if (!pszName)
  218. {
  219. wcsncpy(tmp, szGinaDll, 31);
  220. }
  221. else
  222. {
  223. wcsncpy(tmp, szGinaDll, 3);
  224. wcscpy(tmp + 3, TEXT("..."));
  225. wcsncpy(tmp+6, pszName, 25);
  226. }
  227. ModifyMenu(hMenu, IDM_DLL_LOAD_LAST, MF_BYCOMMAND | MF_STRING,
  228. IDM_DLL_LOAD_LAST, (LPCTSTR) tmp);
  229. }
  230. else
  231. {
  232. ModifyMenu(hMenu, IDM_DLL_LOAD_LAST, MF_BYCOMMAND | MF_STRING,
  233. IDM_DLL_LOAD_LAST, szGinaDll);
  234. }
  235. }
  236. if (AmIBeingDebugged())
  237. {
  238. hDebugMenu = LoadMenu(hInstance, MAKEINTRESOURCE(DEBUGGINAMENU));
  239. InsertMenu(hMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT) hDebugMenu, TEXT("&Debug"));
  240. }
  241. hMainWindow = CreateWindow(
  242. TEXT("TestGina"),
  243. TEXT("TestGina"),
  244. WS_OVERLAPPEDWINDOW,
  245. PosX,
  246. PosY,
  247. SizeX,
  248. SizeY,
  249. NULL,
  250. hMenu,
  251. hInstance,
  252. NULL);
  253. if (!hMainWindow)
  254. {
  255. return(0);
  256. }
  257. RegisterHotKey(hMainWindow, 0, MOD_CONTROL, VK_DELETE);
  258. RegisterHotKey(hMainWindow, 1, MOD_CONTROL, VK_ADD);
  259. ShowWindow(hMainWindow, nCmdShow);
  260. StatusDeltaX = GetSystemMetrics(SM_CXFRAME);
  261. StatusDeltaY = GetSystemMetrics(SM_CYFRAME);
  262. ShowWindow(hMainWindow, nCmdShow);
  263. SetFocus(hMainWindow);
  264. UpdateMenuBar();
  265. EnableOptions(FALSE);
  266. while (GetMessage(&msg, NULL, 0, 0))
  267. {
  268. TranslateMessage(&msg);
  269. DispatchMessage(&msg);
  270. }
  271. return 0 ;
  272. }
  273. void
  274. UpdateGinaState(DWORD Update)
  275. {
  276. LogEvent( 0, "UpdateGinaState(%d): CurrentDesktop = %d, OtherDesktop = %d\n",
  277. Update, CurrentDesktop, OtherDesktop );
  278. switch (Update)
  279. {
  280. case UPDATE_INITIALIZE:
  281. GinaState = Winsta_NoOne;
  282. CurrentDesktop = WINLOGON_DESKTOP;
  283. OtherDesktop = WINLOGON_DESKTOP;
  284. break;
  285. case UPDATE_DISPLAY_NOTICE:
  286. if (GinaState != Winsta_NoOne)
  287. {
  288. TestGinaError(0, TEXT("UpdateGinaState_1"));
  289. }
  290. GinaState = Winsta_NoOne_Display;
  291. CurrentDesktop = WINLOGON_DESKTOP;
  292. OtherDesktop = WINLOGON_DESKTOP;
  293. break;
  294. case UPDATE_SAS_BYPASS:
  295. //
  296. // The kind of weird state of skipping DISPLAY and invoking the
  297. //
  298. if ((GinaState == Winsta_NoOne) || (GinaState == Winsta_NoOne_Display))
  299. {
  300. GinaState = Winsta_NoOne_SAS;
  301. }
  302. else if ((GinaState == Winsta_LoggedOnUser))
  303. {
  304. GinaState = Winsta_LoggedOn_SAS;
  305. }
  306. else if (GinaState == Winsta_Locked)
  307. {
  308. GinaState = Winsta_Locked_SAS;
  309. }
  310. LastRetCode = 0;
  311. CurrentDesktop = WINLOGON_DESKTOP;
  312. OtherDesktop = WINLOGON_DESKTOP;
  313. break;
  314. case UPDATE_SAS_RECEIVED:
  315. if ((GinaState == Winsta_NoOne) || (GinaState == Winsta_NoOne_Display))
  316. {
  317. GinaState = Winsta_NoOne_SAS;
  318. }
  319. else if (GinaState == Winsta_LoggedOnUser)
  320. {
  321. GinaState = Winsta_LoggedOn_SAS;
  322. }
  323. else if (GinaState == Winsta_Locked)
  324. {
  325. GinaState = Winsta_Locked_SAS;
  326. }
  327. OtherDesktop = CurrentDesktop;
  328. CurrentDesktop = WINLOGON_DESKTOP;
  329. LastRetCode = 0;
  330. break;
  331. case UPDATE_USER_LOGON:
  332. if (GinaState != Winsta_NoOne_SAS)
  333. {
  334. TestGinaError(0, TEXT("UpdateGinaState_2"));
  335. }
  336. GinaState = Winsta_LoggedOnUser;
  337. OtherDesktop = WINLOGON_DESKTOP;
  338. CurrentDesktop = DEFAULT_DESKTOP;
  339. break;
  340. case UPDATE_LOCK_WKSTA:
  341. if (GinaState != Winsta_LoggedOn_SAS)
  342. {
  343. TestGinaError(0, TEXT("UpdateGinaState_3"));
  344. }
  345. GinaState = Winsta_Locked;
  346. CurrentDesktop = WINLOGON_DESKTOP;
  347. break;
  348. case UPDATE_UNLOCK_WKSTA:
  349. if (GinaState != Winsta_Locked_SAS)
  350. {
  351. TestGinaError(0, TEXT("UpdateGinaState_4"));
  352. }
  353. GinaState = Winsta_LoggedOnUser;
  354. CurrentDesktop = OtherDesktop;
  355. OtherDesktop = WINLOGON_DESKTOP;
  356. break;
  357. case UPDATE_SAS_COMPLETE:
  358. if (GinaState == Winsta_LoggedOn_SAS)
  359. {
  360. GinaState = Winsta_LoggedOnUser;
  361. CurrentDesktop = OtherDesktop;
  362. OtherDesktop = WINLOGON_DESKTOP;
  363. }
  364. if (GinaState == Winsta_NoOne_SAS)
  365. {
  366. GinaState = Winsta_NoOne;
  367. }
  368. if (GinaState == Winsta_Locked_SAS)
  369. {
  370. GinaState = Winsta_Locked;
  371. }
  372. break;
  373. case UPDATE_LOGOFF:
  374. LastRetCode = 0;
  375. GinaState = Winsta_NoOne;
  376. break;
  377. }
  378. LogEvent( 0, "UpdateGinaState: CurrentDesktop = %d, OtherDesktop = %d\n",
  379. CurrentDesktop, OtherDesktop );
  380. UpdateStatusBar( );
  381. }
  382. void
  383. LoadGinaSpecificParameters(
  384. VOID )
  385. {
  386. PWSTR pszGina;
  387. HKEY hKey;
  388. HKEY hRealKey;
  389. int err;
  390. DWORD cbBuffer;
  391. DWORD dwType;
  392. WCHAR szTemp[512];
  393. DWORD i;
  394. PWSTR pszWalk;
  395. DWORD RealBuf;
  396. DWORD disp;
  397. pszGina = wcsrchr( szGinaDll, TEXT('\\') );
  398. if (!pszGina)
  399. {
  400. pszGina = szGinaDll;
  401. }
  402. else
  403. {
  404. pszGina++;
  405. }
  406. err = RegCreateKey( HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\TestGina"), &hKey );
  407. if (err)
  408. {
  409. return;
  410. }
  411. err = RegCreateKeyEx( hKey,
  412. pszGina,
  413. 0,
  414. TEXT(""),
  415. REG_OPTION_NON_VOLATILE,
  416. KEY_READ | KEY_WRITE,
  417. NULL,
  418. &hRealKey,
  419. &disp );
  420. RegCloseKey( hKey );
  421. if (err)
  422. {
  423. return;
  424. }
  425. cbBuffer = 512 * sizeof(WCHAR);
  426. err = RegQueryValueEx( hRealKey,
  427. TEXT("Order"),
  428. NULL,
  429. &dwType,
  430. (LPBYTE) szTemp,
  431. &cbBuffer );
  432. if (err || (dwType != REG_MULTI_SZ))
  433. {
  434. RegCloseKey( hRealKey );
  435. return;
  436. }
  437. pszWalk = szTemp;
  438. for (i = 0; i < 4 ; i++ )
  439. {
  440. RealBuf = sizeof(DWORD);
  441. err = RegQueryValueEx( hRealKey,
  442. pszWalk,
  443. NULL,
  444. &dwType,
  445. (LPBYTE) &UserDefSas[i].Value,
  446. &RealBuf );
  447. if (err || ( dwType != REG_DWORD))
  448. {
  449. RegCloseKey( hRealKey );
  450. return;
  451. }
  452. wcsncpy( UserDefSas[i].Name, pszWalk, 128 );
  453. pszWalk += wcslen(pszWalk) + 1;
  454. if (*pszWalk == TEXT('\0'))
  455. {
  456. break;
  457. }
  458. }
  459. RegCloseKey( hRealKey );
  460. UserSases = i + 1;
  461. }
  462. void
  463. SaveGinaSpecificParameters(void)
  464. {
  465. PWSTR pszGina;
  466. HKEY hKey;
  467. HKEY hRealKey;
  468. int err;
  469. DWORD cbBuffer;
  470. WCHAR szTemp[512];
  471. DWORD i;
  472. DWORD disp;
  473. pszGina = wcsrchr( szGinaDll, TEXT('\\') );
  474. if (!pszGina)
  475. {
  476. pszGina = szGinaDll;
  477. }
  478. else
  479. {
  480. pszGina++;
  481. }
  482. err = RegCreateKey( HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\TestGina"), &hKey );
  483. if (err)
  484. {
  485. return;
  486. }
  487. err = RegCreateKeyEx( hKey,
  488. pszGina,
  489. 0,
  490. TEXT(""),
  491. REG_OPTION_NON_VOLATILE,
  492. KEY_READ | KEY_WRITE,
  493. NULL,
  494. &hRealKey,
  495. &disp );
  496. RegCloseKey( hKey );
  497. if (err)
  498. {
  499. return;
  500. }
  501. cbBuffer = 0;
  502. for (i = 0; i < UserSases ; i++ )
  503. {
  504. wcscpy( &szTemp[cbBuffer],
  505. UserDefSas[i].Name );
  506. cbBuffer += wcslen(UserDefSas[i].Name) + 1;
  507. }
  508. szTemp[cbBuffer++] = TEXT('\0');
  509. RegSetValueEx( hRealKey,
  510. TEXT("Order"),
  511. 0,
  512. REG_MULTI_SZ,
  513. (LPBYTE) szTemp,
  514. cbBuffer * 2);
  515. for (i = 0; i < UserSases ; i++ )
  516. {
  517. RegSetValueEx( hRealKey,
  518. UserDefSas[i].Name,
  519. 0,
  520. REG_DWORD,
  521. (LPBYTE) &UserDefSas[i].Value,
  522. sizeof(DWORD) );
  523. }
  524. RegCloseKey( hRealKey );
  525. }
  526. void
  527. LoadParameters(void)
  528. {
  529. HKEY hKey;
  530. int err;
  531. DWORD dwX;
  532. DWORD cbBuffer;
  533. DWORD dwType;
  534. err = RegCreateKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\TestGina"), &hKey);
  535. if (err)
  536. {
  537. return;
  538. }
  539. cbBuffer = sizeof(dwX);
  540. err = RegQueryValueEx(hKey, TEXT("Size"), NULL, &dwType, (LPBYTE)&dwX, &cbBuffer);
  541. if (err)
  542. {
  543. RegCloseKey(hKey);
  544. return;
  545. }
  546. SizeX = LOWORD(dwX);
  547. SizeY = HIWORD(dwX);
  548. err = RegQueryValueEx(hKey, TEXT("Pos"), NULL, &dwType, (LPBYTE)&dwX, &cbBuffer);
  549. if (err)
  550. {
  551. RegCloseKey(hKey);
  552. return;
  553. }
  554. PosX = LOWORD(dwX);
  555. PosY = HIWORD(dwX);
  556. cbBuffer = sizeof(szGinaDll);
  557. err = RegQueryValueEx(hKey, TEXT("Dll"), NULL, &dwType, (LPBYTE)szGinaDll, &cbBuffer);
  558. RegCloseKey(hKey);
  559. }
  560. void
  561. SaveParameters(void)
  562. {
  563. HKEY hKey;
  564. int err;
  565. DWORD dwX;
  566. err = RegCreateKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\TestGina"), &hKey);
  567. if (err)
  568. {
  569. return;
  570. }
  571. dwX = (SizeY << 16) + (SizeX & 0x0000FFFF);
  572. err = RegSetValueEx(hKey, TEXT("Size"), 0, REG_DWORD, (LPBYTE)&dwX, sizeof(DWORD));
  573. if (err)
  574. {
  575. RegCloseKey(hKey);
  576. return;
  577. }
  578. dwX = (PosY << 16) + (PosX & 0x0000FFFF);
  579. err = RegSetValueEx(hKey, TEXT("Pos"), 0, REG_DWORD, (LPBYTE)&dwX, sizeof(DWORD));
  580. if (err)
  581. {
  582. RegCloseKey(hKey);
  583. return;
  584. }
  585. err = RegSetValueEx(hKey, TEXT("Dll"), 0, REG_SZ, (LPBYTE) szGinaDll, (wcslen(szGinaDll) + 1) * sizeof(WCHAR));
  586. RegCloseKey(hKey);
  587. }
  588. PrintStatus(HWND hWnd)
  589. {
  590. WCHAR szText[128];
  591. PWSTR pszRet;
  592. wsprintf( szText, TEXT("GINA State: %s"), szStates[ GinaState ] );
  593. SendMessage( hStatusWindow, SB_SETTEXT, 0, (LPARAM) szText );
  594. if ( LastRetCode == WLX_SAS_ACTION_BOOL_RET )
  595. {
  596. if ( LastBoolRet )
  597. {
  598. pszRet = TEXT("TRUE");
  599. }
  600. else
  601. {
  602. pszRet = TEXT("FALSE");
  603. }
  604. }
  605. else
  606. {
  607. pszRet = szRetcodes[ LastRetCode ];
  608. }
  609. wsprintf( szText, TEXT("Last Return: %s"), pszRet );
  610. SendMessage( hStatusWindow, SB_SETTEXT, 1, (LPARAM) szText );
  611. wsprintf( szText, TEXT("Desktop: %s"), Desktops[ CurrentDesktop ]->pszDesktopName );
  612. SendMessage( hStatusWindow, SB_SETTEXT, 2, (LPARAM) szText );
  613. return(0);
  614. }
  615. void
  616. UpdateStatusBar(VOID)
  617. {
  618. RECT rect;
  619. int Widths[4];
  620. GetClientRect( hStatusWindow, &rect );
  621. rect.right -= 15; // Reduce by size grip
  622. Widths[0] = rect.right / 3;
  623. Widths[1] = rect.right / 3 + Widths[0] ;
  624. Widths[2] = rect.right / 3 + Widths[1] ;
  625. SendMessage( hStatusWindow, SB_SETPARTS, (WPARAM) 3, (LPARAM) Widths );
  626. PrintStatus( hStatusWindow );
  627. }