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.

588 lines
20 KiB

  1. /****************************************************************************
  2. *
  3. * File: ghost.cpp
  4. * Project: DxDiag (DirectX Diagnostic Tool)
  5. * Author: Mike Anderson (manders@microsoft.com)
  6. * Purpose: Allow user to remove/restore "ghost" display devices
  7. *
  8. * (C) Copyright 1998-1999 Microsoft Corp. All rights reserved.
  9. *
  10. ****************************************************************************/
  11. #include <tchar.h>
  12. #include <Windows.h>
  13. #include <multimon.h>
  14. #include "reginfo.h"
  15. #include "sysinfo.h"
  16. #include "dispinfo.h"
  17. #include "resource.h"
  18. // Structure for ghost display devices
  19. struct Ghost
  20. {
  21. TCHAR m_szKey[100];
  22. TCHAR m_szDesc[100];
  23. Ghost* m_pGhostPrev;
  24. Ghost* m_pGhostNext;
  25. };
  26. static VOID BuildGhostList(BOOL bBackedUp, DisplayInfo* pDisplayInfoFirst, Ghost** ppGhostFirst);
  27. static INT_PTR CALLBACK GhostDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  28. static VOID UpdateStuff(HWND hwnd);
  29. static VOID MoveSelectedItems(HWND hwnd, BOOL bBackup);
  30. static BOOL MoveGhost(HWND hwnd, Ghost* pGhost, BOOL bBackup);
  31. static DWORD RegCreateTree(HKEY hTree, HKEY hReplacement);
  32. static DWORD RegCreateValues(HKEY hReplacement, LPCTSTR lpSubKey, HKEY hNewKey);
  33. static VOID RemoveFromListBox(Ghost* pGhost, HWND hwndList);
  34. static VOID FreeGhostList(Ghost** ppGhostFirst);
  35. static Ghost* s_pGhostBackedUpFirst = NULL;
  36. static Ghost* s_pGhostRestoredFirst = NULL;
  37. /****************************************************************************
  38. *
  39. * AdjustGhostDevices
  40. *
  41. ****************************************************************************/
  42. VOID AdjustGhostDevices(HWND hwndMain, DisplayInfo* pDisplayInfoFirst)
  43. {
  44. HINSTANCE hinst = (HINSTANCE)GetWindowLongPtr(hwndMain, GWLP_HINSTANCE);
  45. BuildGhostList(TRUE, NULL, &s_pGhostBackedUpFirst);
  46. BuildGhostList(FALSE, pDisplayInfoFirst, &s_pGhostRestoredFirst);
  47. DialogBox(hinst, MAKEINTRESOURCE(IDD_GHOST), hwndMain, GhostDialogProc);
  48. FreeGhostList(&s_pGhostBackedUpFirst);
  49. FreeGhostList(&s_pGhostRestoredFirst);
  50. }
  51. /****************************************************************************
  52. *
  53. * BuildGhostList
  54. *
  55. ****************************************************************************/
  56. VOID BuildGhostList(BOOL bBackedUp, DisplayInfo* pDisplayInfoFirst, Ghost** ppGhostFirst)
  57. {
  58. HKEY hkey;
  59. HKEY hkey2;
  60. DisplayInfo* pDisplayInfo;
  61. TCHAR* pszCompare;
  62. TCHAR szName[100];
  63. LONG iKey;
  64. Ghost* pGhostNew;
  65. DWORD cbData = 100;
  66. DWORD dwType;
  67. BOOL bActive;
  68. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, bBackedUp ?
  69. TEXT("System\\CurrentControlSet\\Services\\Class\\DisplayBackup") :
  70. TEXT("System\\CurrentControlSet\\Services\\Class\\Display"), KEY_READ, NULL, &hkey))
  71. {
  72. return;
  73. }
  74. iKey = 0;
  75. while (ERROR_SUCCESS == RegEnumKey(hkey, iKey, szName, 100))
  76. {
  77. bActive = FALSE; // unless found TRUE below
  78. for (pDisplayInfo = pDisplayInfoFirst; pDisplayInfo != NULL; pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
  79. {
  80. pszCompare = pDisplayInfo->m_szKeyDeviceKey;
  81. if (lstrlen(pszCompare) > 4)
  82. {
  83. pszCompare += (lstrlen(pszCompare) - 4);
  84. if (lstrcmp(szName, pszCompare) == 0)
  85. {
  86. bActive = TRUE;
  87. break;
  88. }
  89. }
  90. }
  91. if (!bActive &&
  92. ERROR_SUCCESS == RegOpenKeyEx(hkey, szName, KEY_READ, NULL, &hkey2))
  93. {
  94. pGhostNew = new Ghost;
  95. if (pGhostNew != NULL)
  96. {
  97. ZeroMemory(pGhostNew, sizeof(Ghost));
  98. cbData = 100;
  99. RegQueryValueEx(hkey2, TEXT("DriverDesc"), 0, &dwType, (LPBYTE)pGhostNew->m_szDesc, &cbData);
  100. lstrcpy(pGhostNew->m_szKey, szName);
  101. pGhostNew->m_pGhostNext = *ppGhostFirst;
  102. if (pGhostNew->m_pGhostNext != NULL)
  103. pGhostNew->m_pGhostNext->m_pGhostPrev = pGhostNew;
  104. *ppGhostFirst = pGhostNew;
  105. }
  106. RegCloseKey(hkey2);
  107. }
  108. iKey++;
  109. }
  110. RegCloseKey(hkey);
  111. }
  112. /****************************************************************************
  113. *
  114. * GhostDialogProc
  115. *
  116. ****************************************************************************/
  117. INT_PTR CALLBACK GhostDialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
  118. {
  119. HWND hwndRList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
  120. HWND hwndBList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
  121. Ghost* pGhost;
  122. TCHAR sz[300];
  123. LRESULT iItem;
  124. switch (msg)
  125. {
  126. case WM_INITDIALOG:
  127. for (pGhost = s_pGhostRestoredFirst; pGhost != NULL; pGhost = pGhost->m_pGhostNext)
  128. {
  129. wsprintf(sz, TEXT("%s: %s"), pGhost->m_szKey, pGhost->m_szDesc);
  130. iItem = SendMessage(hwndRList, LB_ADDSTRING, 0, (LPARAM)sz);
  131. SendMessage(hwndRList, LB_SETITEMDATA, iItem, (LPARAM)pGhost);
  132. }
  133. for (pGhost = s_pGhostBackedUpFirst; pGhost != NULL; pGhost = pGhost->m_pGhostNext)
  134. {
  135. wsprintf(sz, TEXT("%s: %s"), pGhost->m_szKey, pGhost->m_szDesc);
  136. iItem = SendMessage(hwndBList, LB_ADDSTRING, 0, (LPARAM)sz);
  137. SendMessage(hwndBList, LB_SETITEMDATA, iItem, (LPARAM)pGhost);
  138. }
  139. UpdateStuff(hwnd);
  140. return TRUE;
  141. case WM_COMMAND:
  142. {
  143. WORD wID = LOWORD(wparam);
  144. switch(wID)
  145. {
  146. case IDCANCEL:
  147. EndDialog(hwnd, IDCANCEL);
  148. break;
  149. case IDOK:
  150. EndDialog(hwnd, IDOK);
  151. break;
  152. case IDC_RESTOREDLIST:
  153. if (HIWORD(wparam) == LBN_SELCHANGE)
  154. {
  155. if (SendMessage(hwndRList, LB_GETSELCOUNT, 0, 0) > 0)
  156. EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), TRUE);
  157. else
  158. EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), FALSE);
  159. }
  160. break;
  161. case IDC_BACKEDUPLIST:
  162. if (HIWORD(wparam) == LBN_SELCHANGE)
  163. {
  164. if (SendMessage(hwndBList, LB_GETSELCOUNT, 0, 0) > 0)
  165. EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), TRUE);
  166. else
  167. EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), FALSE);
  168. }
  169. break;
  170. case IDC_BACKUP:
  171. MoveSelectedItems(hwnd, TRUE);
  172. UpdateStuff(hwnd);
  173. break;
  174. case IDC_RESTORE:
  175. MoveSelectedItems(hwnd, FALSE);
  176. UpdateStuff(hwnd);
  177. break;
  178. }
  179. }
  180. return TRUE;
  181. }
  182. return FALSE;
  183. }
  184. /****************************************************************************
  185. *
  186. * UpdateStuff - Update some UI details based on lists.
  187. *
  188. ****************************************************************************/
  189. VOID UpdateStuff(HWND hwnd)
  190. {
  191. HWND hwndRList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
  192. HWND hwndBList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
  193. if (SendMessage(hwndRList, LB_GETCOUNT, 0, 0) > 0)
  194. {
  195. if (SendMessage(hwndRList, LB_GETSELCOUNT, 0, 0) == 0)
  196. SendMessage(hwndRList, LB_SETSEL, TRUE, 0); // Select first item
  197. EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), TRUE);
  198. }
  199. else
  200. {
  201. EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), FALSE);
  202. }
  203. if (SendMessage(hwndBList, LB_GETCOUNT, 0, 0) > 0)
  204. {
  205. if (SendMessage(hwndBList, LB_GETSELCOUNT, 0, 0) == 0)
  206. SendMessage(hwndBList, LB_SETSEL, TRUE, 0); // Select first item
  207. EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), TRUE);
  208. }
  209. else
  210. {
  211. EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), FALSE);
  212. }
  213. }
  214. /****************************************************************************
  215. *
  216. * MoveSelectedItems
  217. *
  218. ****************************************************************************/
  219. VOID MoveSelectedItems(HWND hwnd, BOOL bBackup)
  220. {
  221. HWND hwndFromList;
  222. HWND hwndToList;
  223. Ghost** ppGhostFromFirst;
  224. Ghost** ppGhostToFirst;
  225. LONG iItemArray[100];
  226. LONG iItem;
  227. Ghost* pGhost;
  228. Ghost* pGhost2;
  229. TCHAR sz[200];
  230. if (bBackup)
  231. {
  232. hwndFromList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
  233. hwndToList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
  234. ppGhostFromFirst = &s_pGhostRestoredFirst;
  235. ppGhostToFirst = &s_pGhostBackedUpFirst;
  236. }
  237. else
  238. {
  239. hwndFromList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
  240. hwndToList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
  241. ppGhostFromFirst = &s_pGhostBackedUpFirst;
  242. ppGhostToFirst = &s_pGhostRestoredFirst;
  243. }
  244. SendMessage(hwndFromList, LB_GETSELITEMS, 100, (LPARAM)iItemArray);
  245. for (iItem = (LONG) SendMessage(hwndFromList, LB_GETSELCOUNT, 0, 0) - 1; iItem >= 0; iItem--)
  246. {
  247. pGhost = (Ghost*)SendMessage(hwndFromList, LB_GETITEMDATA, iItemArray[iItem], 0);
  248. if (MoveGhost(hwnd, pGhost, bBackup))
  249. {
  250. // Remove from old list
  251. if (pGhost->m_pGhostNext != NULL)
  252. pGhost->m_pGhostNext->m_pGhostPrev = pGhost->m_pGhostPrev;
  253. if (pGhost->m_pGhostPrev == NULL)
  254. *ppGhostFromFirst = pGhost->m_pGhostNext;
  255. else
  256. pGhost->m_pGhostPrev->m_pGhostNext = pGhost->m_pGhostNext;
  257. // Add to new list
  258. pGhost->m_pGhostPrev = NULL;
  259. pGhost->m_pGhostNext = *ppGhostToFirst;
  260. if (pGhost->m_pGhostNext != NULL)
  261. pGhost->m_pGhostNext->m_pGhostPrev = pGhost;
  262. *ppGhostToFirst = pGhost;
  263. // Update list boxes:
  264. SendMessage(hwndFromList, LB_GETTEXT, iItemArray[iItem], (LPARAM)sz);
  265. SendMessage(hwndFromList, LB_DELETESTRING, iItemArray[iItem], 0);
  266. SendMessage(hwndToList, LB_SETITEMDATA, SendMessage(hwndToList, LB_ADDSTRING, 0, (LPARAM)sz), (LPARAM)pGhost);
  267. // If we overwrote another Ghost with the same key, remove it from dest list:
  268. for (pGhost2 = *ppGhostToFirst; pGhost2 != NULL; pGhost2 = pGhost2->m_pGhostNext)
  269. {
  270. if (pGhost2 != pGhost && lstrcmp(pGhost2->m_szKey, pGhost->m_szKey) == 0)
  271. {
  272. if (pGhost2->m_pGhostNext != NULL)
  273. pGhost2->m_pGhostNext->m_pGhostPrev = pGhost2->m_pGhostPrev;
  274. if (pGhost2->m_pGhostPrev == NULL)
  275. *ppGhostToFirst = pGhost2->m_pGhostNext;
  276. else
  277. pGhost2->m_pGhostPrev->m_pGhostNext = pGhost2->m_pGhostNext;
  278. RemoveFromListBox(pGhost2, hwndToList);
  279. delete pGhost2;
  280. break;
  281. }
  282. }
  283. }
  284. }
  285. }
  286. /****************************************************************************
  287. *
  288. * MoveGhost
  289. *
  290. ****************************************************************************/
  291. BOOL MoveGhost(HWND hwnd, Ghost* pGhost, BOOL bBackup)
  292. {
  293. HKEY hkeySrcParent = NULL;
  294. HKEY hkeySrc = NULL;
  295. HKEY hkeyDestParent = NULL;
  296. HKEY hkeyDest = NULL;
  297. DWORD dwDisposition;
  298. BOOL bRet = FALSE;
  299. // Open source key:
  300. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, bBackup ?
  301. TEXT("System\\CurrentControlSet\\Services\\Class\\Display") :
  302. TEXT("System\\CurrentControlSet\\Services\\Class\\DisplayBackup"),
  303. KEY_ALL_ACCESS, NULL, &hkeySrcParent))
  304. {
  305. goto LEnd;
  306. }
  307. if (ERROR_SUCCESS != RegOpenKeyEx(hkeySrcParent, pGhost->m_szKey,
  308. KEY_ALL_ACCESS, NULL, &hkeySrc))
  309. {
  310. goto LEnd;
  311. }
  312. // Create destination key:
  313. if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_LOCAL_MACHINE, bBackup ?
  314. TEXT("System\\CurrentControlSet\\Services\\Class\\DisplayBackup") :
  315. TEXT("System\\CurrentControlSet\\Services\\Class\\Display"),
  316. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyDestParent, &dwDisposition))
  317. {
  318. goto LEnd;
  319. }
  320. // Ensure key isn't already there:
  321. if (ERROR_SUCCESS == RegOpenKeyEx(hkeyDestParent, pGhost->m_szKey, KEY_ALL_ACCESS, NULL, &hkeyDest))
  322. {
  323. RegCloseKey(hkeyDest);
  324. hkeyDest = NULL;
  325. TCHAR szMessage[300];
  326. TCHAR szTitle[100];
  327. LoadString(NULL, IDS_APPFULLNAME, szTitle, 100);
  328. LoadString(NULL, IDS_REPLACEGHOST, szMessage, 300);
  329. if (IDYES == MessageBox(hwnd, szMessage, szTitle, MB_YESNO))
  330. {
  331. RegDeleteKey(hkeyDestParent, pGhost->m_szKey);
  332. }
  333. else
  334. {
  335. goto LEnd;
  336. }
  337. }
  338. if (ERROR_SUCCESS != RegCreateKeyEx(hkeyDestParent, pGhost->m_szKey, 0, NULL,
  339. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyDest, &dwDisposition))
  340. {
  341. goto LEnd;
  342. }
  343. // Copy tree:
  344. if (ERROR_SUCCESS != RegCreateValues(hkeySrc, NULL, hkeyDest))
  345. goto LEnd;
  346. if (ERROR_SUCCESS != RegCreateTree(hkeyDest, hkeySrc))
  347. goto LEnd;
  348. // Delete old tree
  349. RegDeleteKey(hkeySrcParent, pGhost->m_szKey);
  350. bRet = TRUE; // Everything succeeded
  351. LEnd:
  352. if (hkeySrcParent != NULL)
  353. RegCloseKey(hkeySrcParent);
  354. if (hkeySrc != NULL)
  355. RegCloseKey(hkeySrc);
  356. if (hkeyDestParent != NULL)
  357. RegCloseKey(hkeyDestParent);
  358. if (hkeyDest != NULL)
  359. RegCloseKey(hkeyDest);
  360. return bRet;
  361. }
  362. /****************************************************************************
  363. *
  364. * RegCreateTree
  365. *
  366. ****************************************************************************/
  367. DWORD RegCreateTree(HKEY hTree, HKEY hReplacement)
  368. {
  369. #define REGSTR_MAX_VALUE_LENGTH 300
  370. DWORD cdwClass, dwSubKeyLength, dwDisposition, dwKeyIndex = 0;
  371. LPTSTR pSubKey = NULL;
  372. TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
  373. TCHAR szClass[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
  374. HKEY hNewKey, hKey;
  375. DWORD lRet;
  376. for(;;)
  377. {
  378. dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
  379. cdwClass = REGSTR_MAX_VALUE_LENGTH;
  380. lRet=RegEnumKeyEx(
  381. hReplacement,
  382. dwKeyIndex,
  383. szSubKey,
  384. &dwSubKeyLength,
  385. NULL,
  386. szClass,
  387. &cdwClass,
  388. NULL
  389. );
  390. if(lRet == ERROR_NO_MORE_ITEMS)
  391. {
  392. lRet = ERROR_SUCCESS;
  393. break;
  394. }
  395. else if(lRet == ERROR_SUCCESS)
  396. {
  397. if ((lRet=RegCreateKeyEx(hTree, szSubKey,0, szClass,
  398. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  399. &hNewKey, &dwDisposition)) != ERROR_SUCCESS )
  400. break;
  401. else // add key values and recurse
  402. {
  403. if ((lRet=RegCreateValues( hReplacement, szSubKey, hNewKey))
  404. != ERROR_SUCCESS)
  405. {
  406. CloseHandle(hNewKey);
  407. break;
  408. }
  409. if ( (lRet=RegOpenKeyEx(hReplacement, szSubKey, 0,
  410. KEY_ALL_ACCESS, &hKey )) == ERROR_SUCCESS )
  411. {
  412. lRet=RegCreateTree(hNewKey, hKey);
  413. CloseHandle(hKey);
  414. CloseHandle(hNewKey);
  415. if ( lRet != ERROR_SUCCESS )
  416. break;
  417. }
  418. else
  419. {
  420. CloseHandle(hNewKey);
  421. break;
  422. }
  423. }
  424. }
  425. else
  426. break;
  427. ++dwKeyIndex;
  428. } // end for loop
  429. return lRet;
  430. }
  431. /****************************************************************************
  432. *
  433. * RegCreateValues
  434. *
  435. ****************************************************************************/
  436. DWORD RegCreateValues(HKEY hReplacement, LPCTSTR lpSubKey, HKEY hNewKey)
  437. {
  438. DWORD cbValue, dwSubKeyIndex=0, dwType, cdwBuf;
  439. DWORD dwValues, cbMaxValueData, i;
  440. LPTSTR pSubKey = NULL;
  441. TCHAR szValue[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
  442. HKEY hKey;
  443. DWORD lRet = ERROR_SUCCESS;
  444. LPBYTE pBuf;
  445. if (lstrlen(lpSubKey) == 0)
  446. {
  447. hKey = hReplacement;
  448. }
  449. else
  450. {
  451. if ((lRet = RegOpenKeyEx(hReplacement, lpSubKey, 0,
  452. KEY_ALL_ACCESS, &hKey )) != ERROR_SUCCESS)
  453. {
  454. return lRet;
  455. }
  456. }
  457. if ((lRet = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL,
  458. NULL, &dwValues,NULL, &cbMaxValueData,
  459. NULL, NULL)) == ERROR_SUCCESS)
  460. {
  461. if ( dwValues )
  462. {
  463. if ((pBuf = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
  464. cbMaxValueData )))
  465. {
  466. for (i = 0; i < dwValues ; i++)
  467. {
  468. // get values to create
  469. cbValue = REGSTR_MAX_VALUE_LENGTH;
  470. cdwBuf = cbMaxValueData;
  471. lRet = RegEnumValue(
  472. hKey, // handle of key to query
  473. i, // index of value to query
  474. szValue, // buffer for value string
  475. &cbValue, // address for size of buffer
  476. NULL, // reserved
  477. &dwType, // buffer address for type code
  478. pBuf, // address of buffer for value data
  479. &cdwBuf // address for size of buffer
  480. );
  481. if ( ERROR_SUCCESS == lRet )
  482. {
  483. if( (lRet = RegSetValueEx(hNewKey, szValue, 0,
  484. dwType, (CONST BYTE *)pBuf,
  485. cdwBuf))!= ERROR_SUCCESS)
  486. break;
  487. }
  488. else
  489. break;
  490. } // for loop
  491. }
  492. HeapFree(GetProcessHeap(), 0, pBuf);
  493. }
  494. }
  495. if (lstrlen(lpSubKey) != 0)
  496. {
  497. CloseHandle(hKey);
  498. }
  499. return lRet;
  500. }
  501. /****************************************************************************
  502. *
  503. * RemoveFromListBox
  504. *
  505. ****************************************************************************/
  506. VOID RemoveFromListBox(Ghost* pGhostRemove, HWND hwndList)
  507. {
  508. LONG iItem;
  509. Ghost* pGhost;
  510. for (iItem = (LONG) SendMessage(hwndList, LB_GETCOUNT, 0, 0) - 1; iItem >= 0; iItem--)
  511. {
  512. pGhost = (Ghost*)SendMessage(hwndList, LB_GETITEMDATA, iItem, 0);
  513. if (pGhost == pGhostRemove)
  514. {
  515. SendMessage(hwndList, LB_DELETESTRING, iItem, 0);
  516. break;
  517. }
  518. }
  519. }
  520. /****************************************************************************
  521. *
  522. * FreeGhostList
  523. *
  524. ****************************************************************************/
  525. VOID FreeGhostList(Ghost** ppGhostFirst)
  526. {
  527. Ghost* pGhostNext;
  528. while (*ppGhostFirst != NULL)
  529. {
  530. pGhostNext = (*ppGhostFirst)->m_pGhostNext;
  531. delete *ppGhostFirst;
  532. *ppGhostFirst = pGhostNext;
  533. }
  534. }