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.

1572 lines
47 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: Desktop.cpp
  4. // Created: Jan 1996
  5. // By: Ryan Marshall (a-ryanm) and Martin Holladay (a-martih)
  6. //
  7. // Project: Resource Kit Desktop Switcher (MultiDesk)
  8. //
  9. //
  10. // Revision History:
  11. //
  12. // March 1997 - Add external icon capability
  13. //
  14. ////////////////////////////////////////////////////////////////////////////////
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <assert.h>
  18. #include <shellapi.h>
  19. #include <lmaccess.h>
  20. #include <lmapibuf.h>
  21. #include <stdlib.h>
  22. #include <sddl.h>
  23. #include "Deskspc.h"
  24. #include "Desktop.h"
  25. #include "Registry.h"
  26. #include "resource.h"
  27. #include <saifer.h>
  28. extern APPVARS AppMember;
  29. BOOL __SetDesktopScheme(PDESKTOP_SCHEME pDS);
  30. BOOL __GetDesktopScheme(PDESKTOP_SCHEME pDS);
  31. BOOL __UpdateDesktopRegistry(PDESKTOP_SCHEME pDS);
  32. BOOL __CopyDesktopScheme(PDESKTOP_SCHEME pDS1, PDESKTOP_SCHEME pDS2);
  33. HICON __LoadBuiltinIcon(UINT nIconNumber, HINSTANCE hDeskInstance);
  34. BOOL __CreateDefaultName(UINT DeskNum, LPTSTR DesktopName);
  35. /*------------------------------------------------------------------------------*/
  36. /* */
  37. /* Purpose: Constructor for CDestop class. */
  38. /* */
  39. /*------------------------------------------------------------------------------*/
  40. CDesktop::CDesktop()
  41. {
  42. BeginRundown = FALSE;
  43. //
  44. // Set the default desktop
  45. //
  46. DefaultDesktop = GetThreadDesktop(GetCurrentThreadId());
  47. //
  48. // Intialize our default icons
  49. //
  50. ZeroMemory((PVOID) DefaultIconArray, (sizeof(HICON) * NUM_BUILTIN_ICONS));
  51. }
  52. /*------------------------------------------------------------------------------*/
  53. /* */
  54. /* Purpose: Destructor for CDestop class. */
  55. /* */
  56. /*------------------------------------------------------------------------------*/
  57. CDesktop::~CDesktop()
  58. {
  59. UINT i;
  60. // Need to cleanup DesktopList; closing the hDesktop in each node
  61. // and then delete node memory using GlobalFree(). In addition deletion
  62. // must start at the end of the list sawing off last node one at a time.
  63. //
  64. GlobalFree(m_DesktopList);
  65. //
  66. // Close up our default icons
  67. //
  68. for (i = 0; i < NUM_BUILTIN_ICONS; i++)
  69. {
  70. if (DefaultIconArray[i])
  71. DestroyIcon(DefaultIconArray[i]);
  72. }
  73. }
  74. /*------------------------------------------------------------------------------*/
  75. /*------------------------------- PUBLIC FUNCTIONS -----------------------------*/
  76. /*------------------------------------------------------------------------------*/
  77. UINT
  78. CDesktop::InitializeDesktops
  79. (
  80. DispatchFnType CreateDisplayFn,
  81. HINSTANCE hInstance
  82. )
  83. {
  84. UINT ii;
  85. UINT RegNumOfDesktops;
  86. BOOL m_bFirstTime = TRUE;
  87. //
  88. // Set the hInstance and get the default icons
  89. //
  90. hDeskInstance = hInstance;
  91. for (ii = 0; ii < NUM_BUILTIN_ICONS; ii++)
  92. DefaultIconArray[ii] = __LoadBuiltinIcon(ii+1, hDeskInstance);
  93. //
  94. // Get Information from the registry.
  95. //
  96. if (Profile_GetNewContext(&RegNumOfDesktops))
  97. {
  98. m_bFirstTime = FALSE;
  99. }
  100. if ((RegNumOfDesktops > 32) || (RegNumOfDesktops < 1))
  101. {
  102. m_bFirstTime = TRUE;
  103. }
  104. //// Allocate the first node ////
  105. m_DesktopList = (PDESKTOP_NODE) GlobalAlloc(GMEM_FIXED, sizeof(DESKTOP_NODE));
  106. assert(m_DesktopList != NULL);
  107. //// Fill in default values for first node ////
  108. m_DesktopList->nextDN = NULL;
  109. m_DesktopList->DS.Initialized = FALSE;
  110. m_DesktopList->ThreadId = GetCurrentThreadId();
  111. m_DesktopList->bThread = TRUE;
  112. m_DesktopList->hWnd = NULL;
  113. m_DesktopList->hDesktop = GetThreadDesktop(GetCurrentThreadId());
  114. m_DesktopList->nIconID = 0;
  115. m_DesktopList->RealDesktopName[0] = TEXT('\0');
  116. __GetDesktopScheme(&(m_DesktopList->DS));
  117. //
  118. // Set some environ vars to init states
  119. //
  120. NumOfDesktops = 1;
  121. CurrentDesktop = 0;
  122. if (m_bFirstTime)
  123. { // No old registry info, create default desktops
  124. //
  125. // Set desktop 0's name
  126. //
  127. __CreateDefaultName(1, m_DesktopList->DesktopName);
  128. if (DEFAULT_NUM_DESKTOPS > 1)
  129. {
  130. for (ii = 1; ii < DEFAULT_NUM_DESKTOPS; ii++)
  131. {
  132. AddDesktop(CreateDisplayFn, NULL);
  133. }
  134. }
  135. }
  136. else
  137. { // Registry info present
  138. //
  139. // Set desktop 0's name
  140. //
  141. if ( !Profile_LoadDesktopContext(0,
  142. m_DesktopList->DesktopName,
  143. m_DesktopList->SaiferName,
  144. &m_DesktopList->nIconID) )
  145. {
  146. __CreateDefaultName(1, m_DesktopList->DesktopName);
  147. m_DesktopList->nIconID = 0;
  148. }
  149. for (ii = 1; ii < RegNumOfDesktops; ii++)
  150. {
  151. TCHAR DesktopName[MAX_NAME_LENGTH];
  152. TCHAR SaiferName[MAX_NAME_LENGTH];
  153. UINT nIconID;
  154. AddDesktop(CreateDisplayFn, NULL);
  155. //// Place registry info into the node for this desktop ////
  156. if (Profile_LoadDesktopContext(ii,
  157. DesktopName,
  158. SaiferName,
  159. &nIconID) )
  160. {
  161. // Successfully got all info from registry
  162. SetDesktopName(ii, DesktopName);
  163. SetDesktopIconID(ii, nIconID);
  164. SetSaiferName(ii, SaiferName);
  165. }
  166. else
  167. {
  168. // Could not get all info from registry
  169. __CreateDefaultName(ii+1, DesktopName);
  170. SetDesktopName(ii, DesktopName);
  171. SetDesktopIconID(ii, ii);
  172. SetSaiferName(ii, TEXT(""));
  173. }
  174. if (!GetRegColorStruct(ii))
  175. DuplicateDefaultScheme(ii);
  176. } // End for loop
  177. }
  178. return NumOfDesktops;
  179. }
  180. /*------------------------------------------------------------------------------*/
  181. /* */
  182. /* Purpose: Access the default desktop handle. */
  183. /* */
  184. /* Returns: The default desktop handle. */
  185. /* */
  186. /*------------------------------------------------------------------------------*/
  187. HDESK CDesktop::GetDefaultDesktop(VOID) const
  188. {
  189. return DefaultDesktop;
  190. }
  191. /*------------------------------------------------------------------------------*/
  192. /* */
  193. /* Purpose: Access the number of desktops. */
  194. /* */
  195. /* Returns: The number of desktops. */
  196. /* */
  197. /*------------------------------------------------------------------------------*/
  198. UINT CDesktop::GetNumDesktops(VOID) const
  199. {
  200. return NumOfDesktops;
  201. }
  202. /*------------------------------------------------------------------------------*/
  203. /* */
  204. /* Purpose: Determine the currently active desktop. */
  205. /* */
  206. /* Returns: The active desktop. */
  207. /* */
  208. /*------------------------------------------------------------------------------*/
  209. UINT CDesktop::GetActiveDesktop(VOID) const
  210. {
  211. return CurrentDesktop;
  212. }
  213. /*------------------------------------------------------------------------------*/
  214. /* */
  215. /* Purpose: Creates a new desktop. */
  216. /* */
  217. /* Returns: The index number of the newly created desktop. Zero if error. */
  218. /* */
  219. /*------------------------------------------------------------------------------*/
  220. UINT CDesktop::AddDesktop
  221. (
  222. DispatchFnType CreateDisplayFn,
  223. LPSECURITY_ATTRIBUTES lpSA,
  224. UINT uTemplate
  225. )
  226. {
  227. PDESKTOP_NODE pCurrentNode;
  228. TCHAR szMessage[MAX_PATH];
  229. PTHREAD_DATA pData;
  230. HDESK hDesktop;
  231. LUID UniqueId;
  232. UINT i;
  233. TCHAR UniqueDesktopName[MAX_NAME_LENGTH];
  234. //// Create Desktop ////
  235. if (AllocateLocallyUniqueId(&UniqueId))
  236. {
  237. wsprintf(UniqueDesktopName, TEXT("%d"), UniqueId.LowPart);
  238. hDesktop = CreateDesktop(
  239. UniqueDesktopName,
  240. NULL,
  241. NULL,
  242. 0,
  243. MAXIMUM_ALLOWED,
  244. lpSA);
  245. if (hDesktop == NULL)
  246. {
  247. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY)
  248. {
  249. wsprintf(szMessage, TEXT("Not enough memory to create destkop.\n\nError: %d\n"), GetLastError());
  250. MessageBox(NULL, szMessage, TEXT("MultiDesk Desktop Not Created"), MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OK);
  251. }
  252. return 0;
  253. }
  254. }
  255. else
  256. {
  257. return 0;
  258. }
  259. //// Walk the desktop node list to find end
  260. //// Then add new node to end of list
  261. i = 1;
  262. pCurrentNode = m_DesktopList;
  263. while (pCurrentNode)
  264. {
  265. if ( !pCurrentNode->nextDN ) // Found end of list; let's add new node
  266. {
  267. NumOfDesktops++;
  268. pCurrentNode->nextDN = (PDESKTOP_NODE) GlobalAlloc(GMEM_FIXED, sizeof(DESKTOP_NODE));
  269. pCurrentNode = pCurrentNode->nextDN;
  270. pCurrentNode->hDesktop = hDesktop;
  271. pCurrentNode->hWnd = NULL;
  272. pCurrentNode->nextDN = NULL;
  273. pCurrentNode->ThreadId = 0;
  274. pCurrentNode->DS.Initialized = FALSE;
  275. if ( 0 == uTemplate )
  276. {
  277. __CopyDesktopScheme(&(m_DesktopList->DS), &(pCurrentNode->DS));
  278. }
  279. else
  280. {
  281. DESKTOP_NODE * pNode;
  282. pNode = GetDesktopNode(uTemplate);
  283. if ( pNode->DS.Initialized )
  284. {
  285. __CopyDesktopScheme(&(pNode->DS), &(pCurrentNode->DS));
  286. }
  287. else
  288. {
  289. __CopyDesktopScheme(&(m_DesktopList->DS), &(pCurrentNode->DS));
  290. }
  291. }
  292. lstrcpy(pCurrentNode->RealDesktopName, UniqueDesktopName);
  293. __CreateDefaultName(NumOfDesktops, pCurrentNode->DesktopName);
  294. pCurrentNode->SaiferName[0] = TEXT('\0');
  295. pCurrentNode->lpSA = lpSA;
  296. pCurrentNode->nIconID = i;
  297. pCurrentNode->bThread = TRUE;
  298. pCurrentNode->bShellStarted = FALSE;
  299. //// Alllocate THREAD_DATA struct and fill in.
  300. pData = (PTHREAD_DATA)GlobalAlloc(GMEM_FIXED, sizeof(THREAD_DATA));
  301. pData->hDesktop = hDesktop;
  302. pData->hDefaultDesktop = DefaultDesktop;
  303. pData->CreateDisplayFn = CreateDisplayFn;
  304. lstrcpy(pData->RealDesktopName, UniqueDesktopName);
  305. //// Start the thread to run this desktop ////
  306. HANDLE hThread;
  307. hThread = CreateThread(NULL,
  308. 0,
  309. (LPTHREAD_START_ROUTINE)ThreadInit,
  310. (LPVOID)pData,
  311. 0,
  312. &(pCurrentNode->ThreadId));
  313. CloseHandle(hThread);
  314. }
  315. i++;
  316. pCurrentNode = pCurrentNode->nextDN;
  317. }
  318. return NumOfDesktops;
  319. }
  320. /*------------------------------------------------------------------------------*/
  321. /* */
  322. /* Purpose: Returns pointer to desktop node given number of desktop. */
  323. /* */
  324. /*------------------------------------------------------------------------------*/
  325. DESKTOP_NODE *CDesktop::GetDesktopNode( UINT uNode )
  326. {
  327. DESKTOP_NODE * pNode = NULL;
  328. DESKTOP_NODE * pWalker = m_DesktopList;
  329. UINT uNumDesktops = GetNumDesktops();
  330. UINT ii;
  331. if ( uNode < uNumDesktops )
  332. {
  333. for ( ii = 0; ii < uNode; ii++ )
  334. {
  335. pWalker = pWalker->nextDN;
  336. }
  337. pNode = pWalker;
  338. }
  339. return pNode;
  340. }
  341. /*------------------------------------------------------------------------------*/
  342. /* */
  343. /* Purpose: Save scheme settings of current desktop to desktop node */
  344. /* */
  345. /*------------------------------------------------------------------------------*/
  346. BOOL
  347. CDesktop::SaveCurrentDesktopScheme()
  348. {
  349. DESKTOP_NODE * pNodeWalker;
  350. UINT ii;
  351. BOOL rVal = FALSE;
  352. ii = 0;
  353. pNodeWalker = m_DesktopList;
  354. while (pNodeWalker)
  355. {
  356. if (ii == CurrentDesktop)
  357. {
  358. __GetDesktopScheme(&(pNodeWalker->DS));
  359. rVal = TRUE;
  360. }
  361. ii++;
  362. pNodeWalker = pNodeWalker->nextDN;
  363. }
  364. return rVal;
  365. }
  366. /*------------------------------------------------------------------------------*/
  367. /* */
  368. /* Purpose: Removes an old desktop. */
  369. /* */
  370. /* Returns: The number of remaining desktops. Zero if error. */
  371. /* User GetLastError() to retrieve error information. */
  372. /* */
  373. /*------------------------------------------------------------------------------*/
  374. UINT CDesktop::RemoveDesktop(UINT DesktopNumber)
  375. {
  376. PDESKTOP_NODE pCurrentNode;
  377. PDESKTOP_NODE pPreviousNode;
  378. BOOL Found;
  379. UINT ii;
  380. UINT rValue = 0;
  381. //
  382. // Return an error if trying to delete desktop zero.
  383. //
  384. if ((DesktopNumber == 0) || (NumOfDesktops == 1))
  385. {
  386. SetLastError(ERROR_CANNOT_DELETE_DESKTOP_ZERO);
  387. return 0;
  388. }
  389. //
  390. // Return an error if an invalid desktop number
  391. //
  392. if (DesktopNumber > (NumOfDesktops - 1))
  393. {
  394. SetLastError(ERROR_INVALID_DESKTOP_NUMBER);
  395. return 0;
  396. }
  397. //
  398. // If we are deleting the active desktop. Switch to desktop zero.
  399. //
  400. if (DesktopNumber == CurrentDesktop)
  401. {
  402. if (!ActivateDesktop(0))
  403. {
  404. SetLastError(ERROR_CANNOT_DELETE_ACTIVE_DESKTOP);
  405. return FALSE;
  406. }
  407. }
  408. //
  409. // Find the data structure; walk the linked list of desktops
  410. //
  411. Found = FALSE;
  412. ii = 1;
  413. pPreviousNode = m_DesktopList;
  414. pCurrentNode = m_DesktopList->nextDN;
  415. while (pCurrentNode && (!Found))
  416. {
  417. if (DesktopNumber == ii)
  418. {
  419. //
  420. // Full Context desktop
  421. //
  422. if (pCurrentNode->bThread)
  423. {
  424. PostThreadMessage(pCurrentNode->ThreadId, WM_KILL_APPS, (WPARAM) pCurrentNode->hDesktop, (LPARAM) pCurrentNode->hWnd);
  425. Sleep(100);
  426. rValue = SUCCESS_THREAD_TERMINATION;
  427. }
  428. else
  429. {
  430. //
  431. // BUGBUG: Kill all virtual apps
  432. //
  433. rValue = SUCCESS_VIRTUAL_MOVE;
  434. }
  435. NumOfDesktops--;
  436. pPreviousNode->nextDN = pCurrentNode->nextDN;
  437. GlobalFree(pCurrentNode); // Destroy Node of removed desktop!!!
  438. Found = TRUE;
  439. }
  440. else
  441. { // Advance along list of nodes
  442. ii++;
  443. pPreviousNode = pCurrentNode;
  444. pCurrentNode = pCurrentNode->nextDN;
  445. }
  446. } // End while LOOP
  447. return rValue;
  448. }
  449. /*------------------------------------------------------------------------------*/
  450. /* */
  451. /* Purpose: Kill all programs on a desktop. */
  452. /* */
  453. /*------------------------------------------------------------------------------*/
  454. static BOOL CALLBACK __EnumWindowsForClose(HWND hWnd, LPARAM lParam)
  455. {
  456. TCHAR szClass[MAX_NAME_LENGTH];
  457. HWND hDesktopWnd;
  458. //
  459. // Make sure that it isn't the desktop window
  460. //
  461. hDesktopWnd = (HWND) lParam;
  462. if (hDesktopWnd == hWnd)
  463. {
  464. return TRUE;
  465. }
  466. GetClassName(hWnd, szClass, MAX_NAME_LENGTH);
  467. if (szClass[0] == TEXT('#'))
  468. {
  469. return TRUE;
  470. }
  471. //
  472. // Send a close message to the app
  473. //
  474. PostMessage(hWnd, WM_CLOSE, (WPARAM) WM_NO_CLOSE, 0);
  475. return TRUE;
  476. }
  477. static BOOL CALLBACK __EnumWindowsForQuit(HWND hWnd, LPARAM lParam)
  478. {
  479. TCHAR szClass[MAX_NAME_LENGTH];
  480. HWND hDesktopWnd;
  481. //
  482. // Make sure that it isn't the desktop window
  483. //
  484. hDesktopWnd = (HWND) lParam;
  485. if (hDesktopWnd == hWnd) return TRUE;
  486. //
  487. // Extract the Class Name
  488. //
  489. GetClassName(hWnd, szClass, MAX_NAME_LENGTH);
  490. if (szClass[0] == TEXT('#')) return TRUE;
  491. //
  492. // Send a quit message to the app
  493. //
  494. PostMessage(hWnd, WM_QUIT, (WPARAM) WM_NO_CLOSE, 0);
  495. return TRUE;
  496. }
  497. BOOL CDesktop::KillAppsOnDesktop(HDESK hDesk, HWND hWnd)
  498. {
  499. HWND hDesktopWnd;
  500. hDesktopWnd = GetDesktopWindow();
  501. EnumDesktopWindows(hDesk, (WNDENUMPROC) __EnumWindowsForClose, (LPARAM) hDesktopWnd);
  502. Sleep(0);
  503. EnumDesktopWindows(hDesk, (WNDENUMPROC) __EnumWindowsForQuit, (LPARAM) hDesktopWnd);
  504. return TRUE;
  505. }
  506. /*------------------------------------------------------------------------------*/
  507. /* */
  508. /* Purpose: Switches to an existing desktop. */
  509. /* */
  510. /* Returns: The index number of the newly created desktop. Zero if error. */
  511. /* */
  512. /*------------------------------------------------------------------------------*/
  513. BOOL
  514. CDesktop::ActivateDesktop(UINT DesktopNumber)
  515. {
  516. PDESKTOP_NODE pCurrentNode;
  517. BOOL Success;
  518. UINT i;
  519. PROCESS_INFORMATION pi;
  520. STARTUPINFO sui;
  521. TCHAR szShellPath[MAX_PATH + 1];
  522. //
  523. // Return immediately if trying to switch to ourself.
  524. //
  525. if (CurrentDesktop == DesktopNumber)
  526. {
  527. return FALSE;
  528. }
  529. //// Save desktop scheme for current desktop ////
  530. SaveCurrentDesktopScheme();
  531. //
  532. // Active the new desktop
  533. //
  534. i = 0;
  535. pCurrentNode = m_DesktopList;
  536. while (pCurrentNode)
  537. {
  538. if (i == DesktopNumber)
  539. {
  540. Success = SwitchDesktop(pCurrentNode->hDesktop);
  541. if (Success)
  542. {
  543. CurrentDesktop = i;
  544. // Start Explorer if necessary - skipping 0 == default desktop
  545. if (!pCurrentNode->bShellStarted && CurrentDesktop != 0)
  546. {
  547. HANDLE hToken = NULL;
  548. lstrcpy(szShellPath, TEXT("EXPLORER.EXE"));
  549. ZeroMemory((PVOID)&sui, sizeof(sui));
  550. sui.lpDesktop = pCurrentNode->RealDesktopName;
  551. sui.cb = sizeof(sui);
  552. sui.lpReserved = NULL;
  553. sui.lpTitle = NULL;
  554. sui.dwFlags = STARTF_USESHOWWINDOW;
  555. sui.wShowWindow = SW_SHOW;
  556. sui.cbReserved2 = 0;
  557. sui.cbReserved2 = NULL;
  558. #if 1
  559. if (pCurrentNode->SaiferName[0] != TEXT('\0'))
  560. {
  561. HAUTHZOBJECT hAuthzObj;
  562. if (CreateCodeAuthzObject(
  563. AUTHZSCOPE_HKCU, pCurrentNode->SaiferName,
  564. AUTHZ_OPENEXISTING, &hAuthzObj) ||
  565. CreateCodeAuthzObject(
  566. AUTHZSCOPE_HKLM, pCurrentNode->SaiferName,
  567. AUTHZ_OPENEXISTING, &hAuthzObj))
  568. {
  569. if (ComputeAccessTokenFromCodeAuthzObject(
  570. hAuthzObj,
  571. NULL, // source token
  572. &hToken, // target token
  573. 0)) // no flags
  574. {
  575. // We successfully got the Restricted Token
  576. // to use, so it had better be non-null.
  577. assert(hToken != NULL);
  578. }
  579. CloseCodeAuthzObject(hAuthzObj);
  580. }
  581. if (hToken == NULL)
  582. {
  583. CurrentDesktop = 0;
  584. SwitchDesktop(m_DesktopList->hDesktop);
  585. PostThreadMessage(m_DesktopList->ThreadId, WM_THREAD_SCHEME_UPDATE, 0, 0);
  586. Message(TEXT("The SAIFER Object Name specified for this "
  587. "desktop could not be successfully found or instantianted."));
  588. return FALSE;
  589. }
  590. }
  591. if (hToken != NULL) {
  592. Success = CreateProcessAsUser(
  593. hToken,
  594. NULL,
  595. szShellPath,
  596. NULL,
  597. NULL,
  598. FALSE,
  599. CREATE_DEFAULT_ERROR_MODE | CREATE_SEPARATE_WOW_VDM,
  600. NULL,
  601. NULL,
  602. &sui,
  603. &pi);
  604. CloseHandle(hToken);
  605. }
  606. else
  607. #endif
  608. Success = CreateProcess(
  609. NULL,
  610. szShellPath,
  611. NULL,
  612. NULL,
  613. FALSE,
  614. CREATE_DEFAULT_ERROR_MODE | CREATE_SEPARATE_WOW_VDM,
  615. NULL,
  616. NULL,
  617. &sui,
  618. &pi);
  619. pCurrentNode->bShellStarted = Success;
  620. if (Success) {
  621. CloseHandle(pi.hThread);
  622. CloseHandle(pi.hProcess);
  623. } else {
  624. CurrentDesktop = 0;
  625. SwitchDesktop(m_DesktopList->hDesktop);
  626. PostThreadMessage(m_DesktopList->ThreadId, WM_THREAD_SCHEME_UPDATE, 0, 0);
  627. Message(TEXT("The Windows shell could not be successfully launched."));
  628. return FALSE;
  629. }
  630. }
  631. PostThreadMessage(pCurrentNode->ThreadId, WM_THREAD_SCHEME_UPDATE, 0, 0);
  632. }
  633. return Success;
  634. }
  635. i++;
  636. pCurrentNode = pCurrentNode->nextDN;
  637. } // End while LOOP
  638. return FALSE;
  639. }
  640. /*------------------------------------------------------------------------------*/
  641. /* */
  642. /* Purpose: Sets a desktop name. (Rename) */
  643. /* */
  644. /*------------------------------------------------------------------------------*/
  645. BOOL CDesktop::SetDesktopName(UINT DesktopNumber, LPCTSTR DesktopName)
  646. {
  647. UINT i;
  648. BOOL Found;
  649. PDESKTOP_NODE pCurrentNode;
  650. //
  651. // Verify valid string.
  652. //
  653. if ((!DesktopName) || (lstrlen(DesktopName) > MAX_NAME_LENGTH))
  654. return FALSE;
  655. //
  656. // Change the name in our data structure.
  657. //
  658. i = 0;
  659. Found = FALSE;
  660. pCurrentNode = m_DesktopList;
  661. while (pCurrentNode && !Found)
  662. {
  663. if (i == DesktopNumber)
  664. {
  665. lstrcpy(pCurrentNode->DesktopName, DesktopName);
  666. Found = TRUE;
  667. }
  668. i++;
  669. pCurrentNode = pCurrentNode->nextDN;
  670. }
  671. return Found;
  672. }
  673. /*------------------------------------------------------------------------------*/
  674. /* */
  675. /* Purpose: Gets a desktop name. (Rename) */
  676. /* */
  677. /*------------------------------------------------------------------------------*/
  678. BOOL CDesktop::GetDesktopName(UINT DesktopNumber, LPTSTR DesktopName, UINT size) const
  679. {
  680. UINT i;
  681. BOOL Found;
  682. PDESKTOP_NODE pCurrentNode;
  683. //
  684. // Get the name from our data structure.
  685. //
  686. i = 0;
  687. Found = FALSE;
  688. pCurrentNode = m_DesktopList;
  689. while (pCurrentNode && !Found)
  690. {
  691. if (i == DesktopNumber)
  692. {
  693. if ((UINT) lstrlen(pCurrentNode->DesktopName) > size) return FALSE;
  694. lstrcpy(DesktopName, pCurrentNode->DesktopName);
  695. Found = TRUE;
  696. }
  697. i++;
  698. pCurrentNode = pCurrentNode->nextDN;
  699. }
  700. return Found;
  701. }
  702. /*------------------------------------------------------------------------------*/
  703. /* */
  704. /* Purpose: Sets a desktop SAIFER authorization object name. */
  705. /* */
  706. /*------------------------------------------------------------------------------*/
  707. BOOL CDesktop::SetSaiferName(UINT DesktopNumber, LPCTSTR SaiferName)
  708. {
  709. UINT i;
  710. BOOL Found;
  711. PDESKTOP_NODE pCurrentNode;
  712. //
  713. // Verify valid string.
  714. //
  715. if ((!SaiferName) || (lstrlen(SaiferName) > MAX_NAME_LENGTH))
  716. return FALSE;
  717. //
  718. // Change the name in our data structure.
  719. //
  720. i = 0;
  721. Found = FALSE;
  722. pCurrentNode = m_DesktopList;
  723. while (pCurrentNode && !Found)
  724. {
  725. if (i == DesktopNumber)
  726. {
  727. lstrcpy(pCurrentNode->SaiferName, SaiferName);
  728. Found = TRUE;
  729. }
  730. i++;
  731. pCurrentNode = pCurrentNode->nextDN;
  732. }
  733. return Found;
  734. }
  735. /*------------------------------------------------------------------------------*/
  736. /* */
  737. /* Purpose: Gets a desktop SAIFER authorization object name. */
  738. /* */
  739. /*------------------------------------------------------------------------------*/
  740. BOOL CDesktop::GetSaiferName(UINT DesktopNumber, LPTSTR SaiferName, UINT size) const
  741. {
  742. UINT i;
  743. BOOL Found;
  744. PDESKTOP_NODE pCurrentNode;
  745. //
  746. // Get the name from our data structure.
  747. //
  748. i = 0;
  749. Found = FALSE;
  750. pCurrentNode = m_DesktopList;
  751. while (pCurrentNode && !Found)
  752. {
  753. if (i == DesktopNumber)
  754. {
  755. if ((UINT) lstrlen(pCurrentNode->SaiferName) > size) return FALSE;
  756. lstrcpy(SaiferName, pCurrentNode->SaiferName);
  757. Found = TRUE;
  758. }
  759. i++;
  760. pCurrentNode = pCurrentNode->nextDN;
  761. }
  762. return Found;
  763. }
  764. /*------------------------------------------------------------------------------*/
  765. /* */
  766. /* Purpose: Gets the icon for a particular desktop */
  767. /* */
  768. /*------------------------------------------------------------------------------*/
  769. HICON CDesktop::GetDesktopIcon(UINT nDesktopNumber) const
  770. {
  771. UINT i;
  772. PDESKTOP_NODE pCurrentNode;
  773. //
  774. // Get the name from our data structure.
  775. //
  776. i = 0;
  777. pCurrentNode = m_DesktopList;
  778. while (pCurrentNode)
  779. {
  780. if (i == nDesktopNumber)
  781. {
  782. assert(pCurrentNode->nIconID >= 0 && pCurrentNode->nIconID < NUM_BUILTIN_ICONS);
  783. return DefaultIconArray[pCurrentNode->nIconID];
  784. }
  785. i++;
  786. pCurrentNode = pCurrentNode->nextDN;
  787. }
  788. return FALSE;
  789. }
  790. /*------------------------------------------------------------------------------*/
  791. /* */
  792. /* Purpose: Gets the icon ID for a particular desktop */
  793. /* */
  794. /*------------------------------------------------------------------------------*/
  795. UINT CDesktop::GetDesktopIconID(UINT nDesktopNumber) const
  796. {
  797. UINT i;
  798. PDESKTOP_NODE pCurrentNode;
  799. //
  800. // Get the name from our data structure.
  801. //
  802. i = 0;
  803. pCurrentNode = m_DesktopList;
  804. while (pCurrentNode)
  805. {
  806. if (i == nDesktopNumber)
  807. {
  808. return pCurrentNode->nIconID;
  809. }
  810. i++;
  811. pCurrentNode = pCurrentNode->nextDN;
  812. }
  813. return 0;
  814. }
  815. /*------------------------------------------------------------------------------*/
  816. /* */
  817. /* Purpose: Sets the Desktop Icon */
  818. /* */
  819. /*------------------------------------------------------------------------------*/
  820. BOOL CDesktop::SetDesktopIconID(UINT DesktopNumber, UINT nIconID)
  821. {
  822. UINT i;
  823. BOOL Found;
  824. PDESKTOP_NODE pCurrentNode;
  825. //
  826. // Change the name in our data structure.
  827. //
  828. i = 0;
  829. Found = FALSE;
  830. pCurrentNode = m_DesktopList;
  831. while (pCurrentNode && !Found)
  832. {
  833. if (i == DesktopNumber)
  834. {
  835. pCurrentNode->nIconID = nIconID;
  836. Found = TRUE;
  837. }
  838. i++;
  839. pCurrentNode = pCurrentNode->nextDN;
  840. }
  841. return Found;
  842. }
  843. /*------------------------------------------------------------------------------*/
  844. /* */
  845. /* Purpose: Sets the threads main window. */
  846. /* */
  847. /*------------------------------------------------------------------------------*/
  848. BOOL CDesktop::SetThreadWindow(DWORD ThreadId, HWND hWnd)
  849. {
  850. PDESKTOP_NODE pCurrentNode;
  851. pCurrentNode = m_DesktopList;
  852. while (pCurrentNode)
  853. {
  854. if (pCurrentNode->ThreadId == ThreadId)
  855. {
  856. pCurrentNode->hWnd = hWnd;
  857. }
  858. pCurrentNode = pCurrentNode->nextDN;
  859. }
  860. return FALSE;
  861. }
  862. /*------------------------------------------------------------------------------*/
  863. /* */
  864. /* Purpose: Gets the threads main window. */
  865. /* */
  866. /*------------------------------------------------------------------------------*/
  867. HWND CDesktop::GetThreadWindow(DWORD ThreadId) const
  868. {
  869. PDESKTOP_NODE pCurrentNode;
  870. pCurrentNode = m_DesktopList;
  871. while (pCurrentNode)
  872. {
  873. if (pCurrentNode->ThreadId == ThreadId)
  874. {
  875. return pCurrentNode->hWnd;
  876. }
  877. pCurrentNode = pCurrentNode->nextDN;
  878. }
  879. return 0;
  880. }
  881. /*------------------------------------------------------------------------------*/
  882. /* */
  883. /* Purpose: Gets the desktop id of a given thread. */
  884. /* */
  885. /*------------------------------------------------------------------------------*/
  886. UINT CDesktop::GetThreadDesktopID(DWORD ThreadId) const
  887. {
  888. PDESKTOP_NODE pCurrentNode;
  889. UINT i;
  890. i = 0;
  891. pCurrentNode = m_DesktopList;
  892. while (pCurrentNode)
  893. {
  894. if (pCurrentNode->ThreadId == ThreadId)
  895. {
  896. return i;
  897. }
  898. i++;
  899. pCurrentNode = pCurrentNode->nextDN;
  900. }
  901. return 0;
  902. }
  903. /*------------------------------------------------------------------------------*/
  904. /* */
  905. /* Purpose: Gets the threads main window. */
  906. /* */
  907. /*------------------------------------------------------------------------------*/
  908. HWND CDesktop::GetWindowDesktop(UINT DesktopNumber) const
  909. {
  910. PDESKTOP_NODE pCurrentNode;
  911. UINT i;
  912. i = 0;
  913. pCurrentNode = m_DesktopList;
  914. while (pCurrentNode)
  915. {
  916. if (DesktopNumber == i)
  917. {
  918. return pCurrentNode->hWnd;
  919. }
  920. i++;
  921. pCurrentNode = pCurrentNode->nextDN;
  922. }
  923. return 0;
  924. }
  925. /*------------------------------------------------------------------------------*/
  926. /* */
  927. /* Purpose: Gets the real desktop name. */
  928. /* */
  929. /*------------------------------------------------------------------------------*/
  930. BOOL CDesktop::GetRealDesktopName(HWND hWnd, LPTSTR szRealDesktopName) const
  931. {
  932. PDESKTOP_NODE pCurrentNode;
  933. pCurrentNode = m_DesktopList;
  934. while (pCurrentNode)
  935. {
  936. if (pCurrentNode->hWnd == hWnd)
  937. {
  938. if (pCurrentNode->RealDesktopName[0])
  939. lstrcpy(szRealDesktopName, pCurrentNode->RealDesktopName);
  940. else
  941. szRealDesktopName[0] = TEXT('\0');
  942. }
  943. pCurrentNode = pCurrentNode->nextDN;
  944. }
  945. return 0;
  946. }
  947. /*------------------------------------------------------------------------------*/
  948. /* */
  949. /* Purpose: Evaluate the setting of a desktop scheme. */
  950. /* */
  951. /*------------------------------------------------------------------------------*/
  952. BOOL CDesktop::FindSchemeAndSet(VOID)
  953. {
  954. PDESKTOP_NODE pCurrentNode;
  955. UINT i;
  956. if (!BeginRundown)
  957. {
  958. i = 0;
  959. pCurrentNode = m_DesktopList;
  960. while (pCurrentNode)
  961. {
  962. if (i == CurrentDesktop)
  963. {
  964. if (pCurrentNode->ThreadId == GetCurrentThreadId())
  965. {
  966. //
  967. // Set the desktop scheme
  968. //
  969. return __SetDesktopScheme(&(pCurrentNode->DS));
  970. }
  971. }
  972. i++;
  973. pCurrentNode = pCurrentNode->nextDN;
  974. }
  975. }
  976. else
  977. {
  978. //
  979. // Set the desktop scheme to that of desktop 1
  980. //
  981. __SetDesktopScheme(&(m_DesktopList->DS));
  982. }
  983. return FALSE;
  984. }
  985. /*------------------------------------------------------------------------------*/
  986. /* */
  987. /* Purpose: Copies the scheme from desktop 0 to desktop n. */
  988. /* */
  989. /*------------------------------------------------------------------------------*/
  990. BOOL CDesktop::DuplicateDefaultScheme(UINT DesktopNumber)
  991. {
  992. PDESKTOP_NODE pCurrentNode;
  993. BOOL Success = FALSE;
  994. UINT i;
  995. i = 0;
  996. pCurrentNode = m_DesktopList;
  997. while (pCurrentNode)
  998. {
  999. if (i == DesktopNumber)
  1000. Success = __CopyDesktopScheme(&(m_DesktopList->DS), &(pCurrentNode->DS));
  1001. i++;
  1002. pCurrentNode = pCurrentNode->nextDN;
  1003. }
  1004. return Success;
  1005. }
  1006. /*------------------------------------------------------------------------------*/
  1007. /* */
  1008. /* Purpose: Gets the color struct from registry for desktop n. */
  1009. /* */
  1010. /*------------------------------------------------------------------------------*/
  1011. BOOL CDesktop::GetRegColorStruct(UINT DesktopNumber)
  1012. {
  1013. PDESKTOP_NODE pCurrentNode;
  1014. BOOL Success = FALSE;
  1015. UINT i;
  1016. i = 0;
  1017. pCurrentNode = m_DesktopList;
  1018. while (pCurrentNode)
  1019. {
  1020. if (i == DesktopNumber)
  1021. Success = GetDesktopSchemeRegistry(DesktopNumber, &(pCurrentNode->DS));
  1022. i++;
  1023. pCurrentNode = pCurrentNode->nextDN;
  1024. }
  1025. return Success;
  1026. }
  1027. /*------------------------------------------------------------------------------*/
  1028. /* */
  1029. /* Purpose: Save off the schemes to the registry. */
  1030. /* */
  1031. /*------------------------------------------------------------------------------*/
  1032. BOOL CDesktop::RegSaveSettings(VOID)
  1033. {
  1034. PDESKTOP_NODE pCurrentNode;
  1035. UINT ii;
  1036. //
  1037. // Set Global settings
  1038. //
  1039. Profile_SetNewContext(NumOfDesktops);
  1040. //
  1041. // Dump settings desktop by desktop
  1042. //
  1043. ii = 0;
  1044. pCurrentNode = m_DesktopList;
  1045. while (pCurrentNode)
  1046. {
  1047. Profile_SaveDesktopContext(ii,
  1048. pCurrentNode->DesktopName,
  1049. pCurrentNode->SaiferName,
  1050. pCurrentNode->nIconID);
  1051. SetDesktopSchemeRegistry(ii, &(pCurrentNode->DS));
  1052. ii++;
  1053. pCurrentNode = pCurrentNode->nextDN;
  1054. }
  1055. return TRUE;
  1056. }
  1057. /*------------------------------------------------------------------------------*/
  1058. /* */
  1059. /* Purpose: Destroy the windows one by one. */
  1060. /* */
  1061. /*------------------------------------------------------------------------------*/
  1062. BOOL CDesktop::RunDown(VOID)
  1063. {
  1064. PDESKTOP_NODE pCurrentNode;
  1065. BOOL Success;
  1066. BeginRundown = TRUE;
  1067. //
  1068. // Set desktop schemes to that of desktop 1
  1069. //
  1070. pCurrentNode = m_DesktopList->nextDN;
  1071. while (pCurrentNode)
  1072. {
  1073. //
  1074. // Set the desktop scheme
  1075. //
  1076. PostThreadMessage(pCurrentNode->ThreadId, WM_THREAD_SCHEME_UPDATE, 0, 0);
  1077. pCurrentNode = pCurrentNode->nextDN;
  1078. }
  1079. //
  1080. // Remove the desktops
  1081. //
  1082. while (NumOfDesktops > 1)
  1083. {
  1084. Success = RemoveDesktop(NumOfDesktops - 1);
  1085. }
  1086. //
  1087. // Flush to registry
  1088. //
  1089. __UpdateDesktopRegistry(&(m_DesktopList->DS));
  1090. return TRUE;
  1091. }
  1092. /*------------------------------------------------------------------------------*/
  1093. /* */
  1094. /* Purpose: Create a default desktop name. */
  1095. /* */
  1096. /*------------------------------------------------------------------------------*/
  1097. static BOOL __CreateDefaultName(UINT DeskNum, LPTSTR DesktopName)
  1098. {
  1099. wsprintf(DesktopName, TEXT("Desktop %d"), DeskNum);
  1100. return TRUE;
  1101. }
  1102. /*------------------------------------------------------------------------------*/
  1103. /* */
  1104. /* Purpose: Gets the default icons. */
  1105. /* */
  1106. /*------------------------------------------------------------------------------*/
  1107. static HICON __LoadBuiltinIcon(UINT nIconNumber, HINSTANCE hDeskInstance)
  1108. {
  1109. UINT resid;
  1110. assert(NUM_BUILTIN_ICONS == 27);
  1111. switch(nIconNumber)
  1112. {
  1113. case 1: resid = IDI_WIN_ICON01; break;
  1114. case 2: resid = IDI_WIN_ICON02; break;
  1115. case 3: resid = IDI_WIN_ICON03; break;
  1116. case 4: resid = IDI_WIN_ICON04; break;
  1117. case 5: resid = IDI_WIN_ICON05; break;
  1118. case 6: resid = IDI_WIN_ICON06; break;
  1119. case 7: resid = IDI_WIN_ICON07; break;
  1120. case 8: resid = IDI_WIN_ICON08; break;
  1121. case 9: resid = IDI_WIN_ICON09; break;
  1122. case 10: resid = IDI_WIN_ICON10; break;
  1123. case 11: resid = IDI_WIN_ICON11; break;
  1124. case 12: resid = IDI_WIN_ICON12; break;
  1125. case 13: resid = IDI_WIN_ICON13; break;
  1126. case 14: resid = IDI_WIN_ICON14; break;
  1127. case 15: resid = IDI_WIN_ICON15; break;
  1128. case 16: resid = IDI_WIN_ICON16; break;
  1129. case 17: resid = IDI_WIN_ICON17; break;
  1130. case 18: resid = IDI_WIN_ICON18; break;
  1131. case 19: resid = IDI_WIN_ICON19; break;
  1132. case 20: resid = IDI_WIN_ICON20; break;
  1133. case 21: resid = IDI_WIN_ICON21; break;
  1134. case 22: resid = IDI_WIN_ICON22; break;
  1135. case 23: resid = IDI_WIN_ICON23; break;
  1136. case 24: resid = IDI_WIN_ICON24; break;
  1137. case 25: resid = IDI_WIN_ICON25; break;
  1138. case 26: resid = IDI_WIN_ICON26; break;
  1139. case 27: resid = IDI_WIN_ICON27; break;
  1140. default: return NULL;
  1141. }
  1142. return LoadIcon(hDeskInstance, MAKEINTRESOURCE(resid));
  1143. }
  1144. HICON CDesktop::GetBuiltinIcon(UINT nIconNumber) const
  1145. {
  1146. if (nIconNumber < NUM_BUILTIN_ICONS)
  1147. return DefaultIconArray[nIconNumber];
  1148. else
  1149. return NULL;
  1150. }
  1151. /*------------------------------------------------------------------------------*/
  1152. /* */
  1153. /* Purpose: Create a new desktop. */
  1154. /* */
  1155. /*------------------------------------------------------------------------------*/
  1156. VOID ThreadInit(LPVOID hData)
  1157. {
  1158. USEROBJECTFLAGS uof;
  1159. PTHREAD_DATA ptd;
  1160. BOOL Success;
  1161. DWORD Err;
  1162. //
  1163. // Passed-in data
  1164. //
  1165. ptd = (THREAD_DATA*)hData;
  1166. //
  1167. // Inheiritance and flags
  1168. //
  1169. uof.fInherit = TRUE;
  1170. uof.fReserved = FALSE;
  1171. uof.dwFlags = DF_ALLOWOTHERACCOUNTHOOK;
  1172. Success = SetUserObjectInformation (ptd->hDesktop,
  1173. UOI_FLAGS,
  1174. (LPVOID)&uof,
  1175. sizeof(uof));
  1176. //
  1177. // Assign the thread to its desktop
  1178. //
  1179. Success = SetThreadDesktop(ptd->hDesktop);
  1180. Err = GetLastError();
  1181. //
  1182. // Begin the Display dialog and start the shell.
  1183. //
  1184. ptd->CreateDisplayFn();
  1185. //
  1186. // End the thread
  1187. //
  1188. SetThreadDesktop(ptd->hDefaultDesktop);
  1189. Success = CloseDesktop(ptd->hDesktop);
  1190. GlobalFree(ptd);
  1191. return;
  1192. }
  1193. /*------------------------------------------------------------------------------*/
  1194. /*----------------------------- PROTECTED FUNCTIONS ----------------------------*/
  1195. /*------------------------------------------------------------------------------*/
  1196. BOOL CDesktop::GetDesktopSchemeRegistry(UINT DesktopNumber, PDESKTOP_SCHEME pDS)
  1197. {
  1198. BOOL bSuccess = FALSE;
  1199. assert(pDS);
  1200. bSuccess = Profile_LoadScheme(DesktopNumber, pDS);
  1201. pDS->Initialized = bSuccess;
  1202. return bSuccess;
  1203. }
  1204. BOOL CDesktop::SetDesktopSchemeRegistry(UINT DesktopNumber, PDESKTOP_SCHEME pDS)
  1205. {
  1206. BOOL bSuccess = FALSE;
  1207. assert(pDS);
  1208. if (!pDS->Initialized) return FALSE;
  1209. bSuccess = Profile_SaveScheme(DesktopNumber, pDS);
  1210. return bSuccess;
  1211. }
  1212. static BOOL __SetDesktopScheme(PDESKTOP_SCHEME pDS)
  1213. {
  1214. //
  1215. // Check if structure has been filled in
  1216. //
  1217. assert(pDS);
  1218. if (!pDS->Initialized) return FALSE;
  1219. //
  1220. // Structure has info - Lets update the desktop scheme
  1221. //
  1222. Reg_SetSysColors(pDS->dwColor);
  1223. Reg_SetWallpaper(pDS->szWallpaper, pDS->szTile);
  1224. Reg_SetPattern(pDS->szPattern);
  1225. Reg_SetScreenSaver(pDS->szScreenSaver, pDS->szSecure, pDS->szTimeOut, pDS->szActive);
  1226. //
  1227. // Now invalidate the Wallpaper and Pattern
  1228. //
  1229. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pDS->szWallpaper, SPIF_SENDCHANGE);
  1230. SystemParametersInfo(SPI_SETDESKPATTERN, 0, pDS->szPattern, SPIF_SENDCHANGE);
  1231. return TRUE;
  1232. }
  1233. static BOOL __GetDesktopScheme(PDESKTOP_SCHEME pDS)
  1234. {
  1235. //
  1236. // Read the color settings from the desktop and fill in the structure
  1237. //
  1238. assert(pDS);
  1239. if (Reg_GetSysColors(pDS->dwColor) &&
  1240. Reg_GetWallpaper(pDS->szWallpaper, pDS->szTile) &&
  1241. Reg_GetPattern(pDS->szPattern) &&
  1242. Reg_GetScreenSaver(pDS->szScreenSaver, pDS->szSecure, pDS->szTimeOut, pDS->szActive))
  1243. {
  1244. //
  1245. // Structure filled!
  1246. //
  1247. pDS->Initialized = TRUE;
  1248. return TRUE;
  1249. }
  1250. return FALSE;
  1251. }
  1252. static BOOL __UpdateDesktopRegistry(PDESKTOP_SCHEME pDS)
  1253. {
  1254. //
  1255. // Update the registry
  1256. //
  1257. assert(pDS);
  1258. Reg_UpdateColorRegistry(pDS->dwColor);
  1259. return TRUE;
  1260. }
  1261. static BOOL __CopyDesktopScheme(PDESKTOP_SCHEME pDS1, PDESKTOP_SCHEME pDS2)
  1262. {
  1263. UINT i;
  1264. //
  1265. // Copy the contents of pDS1 into pDS2
  1266. //
  1267. assert(pDS2 != NULL);
  1268. assert(pDS1 != NULL);
  1269. if (!pDS1->Initialized)
  1270. {
  1271. pDS2->Initialized = FALSE;
  1272. return FALSE;
  1273. }
  1274. //
  1275. // Copy the strings over
  1276. //
  1277. lstrcpy(pDS2->szWallpaper, pDS1->szWallpaper);
  1278. lstrcpy(pDS2->szTile, pDS1->szTile);
  1279. lstrcpy(pDS2->szPattern, pDS1->szPattern);
  1280. lstrcpy(pDS2->szScreenSaver, pDS1->szScreenSaver);
  1281. lstrcpy(pDS2->szSecure, pDS1->szSecure);
  1282. lstrcpy(pDS2->szTimeOut, pDS1->szTimeOut);
  1283. lstrcpy(pDS2->szActive, pDS1->szActive);
  1284. //
  1285. // Copy the colors over
  1286. //
  1287. for (i = 0; i < NUM_COLOR_ELEMENTS; i++)
  1288. {
  1289. pDS2->dwColor[i] = pDS1->dwColor[i];
  1290. }
  1291. pDS2->Initialized = TRUE;
  1292. return TRUE;
  1293. }