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.

549 lines
16 KiB

  1. //+---------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993 - 1997.
  5. //
  6. // File: creg.cpp
  7. //
  8. // Contents: Implements class CRegistry to wrap registry access
  9. //
  10. // Classes:
  11. //
  12. // Methods: CRegistry::CRegistry
  13. // CRegistry::~CRegistry
  14. // CRegistry::Init
  15. // CRegistry::InitGetItem
  16. // CRegistry::GetNextItem
  17. // CRegistry::GetItem
  18. // CRegistry::FindItem
  19. // CRegistry::FindAppid
  20. // CRegistry::AppendIndex
  21. // CRegistry::GetNumItems
  22. //
  23. // History: 23-Apr-96 BruceMa Created.
  24. //
  25. //----------------------------------------------------------------------
  26. #include "stdafx.h"
  27. #include "resource.h"
  28. #include "types.h"
  29. #include "cstrings.h"
  30. #include "creg.h"
  31. #ifdef _DEBUG
  32. #define new DEBUG_NEW
  33. #undef THIS_FILE
  34. static char BASED_CODE THIS_FILE[] = __FILE__;
  35. #endif
  36. CRegistry::CRegistry(void)
  37. {
  38. m_applications.RemoveAll();
  39. }
  40. CRegistry::~CRegistry(void)
  41. {
  42. }
  43. // Access and store all application names and associated appid's
  44. BOOL CRegistry::Init(void)
  45. {
  46. int err;
  47. HKEY hKey;
  48. DWORD dwSubKey;
  49. TCHAR szTitle[MAX_PATH];
  50. TCHAR szAppid[MAX_PATH];
  51. TCHAR szCLSID[MAX_PATH];
  52. TCHAR szBuffer[MAX_PATH];
  53. LONG lSize;
  54. DWORD dwType;
  55. DWORD dwDisposition;
  56. // Cleanup any previous run
  57. m_applications.RemoveAll();
  58. // First enumerate HKEY_CLASSES_ROOT\CLSID picking up all .exe
  59. // Open HKEY_CLASSES_ROOT\CLSID
  60. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_READ | KEY_WRITE,
  61. &hKey) != ERROR_SUCCESS)
  62. {
  63. return FALSE;
  64. }
  65. // Enumerate the CLSID subkeys
  66. dwSubKey = 0;
  67. while (RegEnumKey(hKey, dwSubKey, szCLSID, sizeof(szCLSID) / sizeof(TCHAR))
  68. == ERROR_SUCCESS)
  69. {
  70. TCHAR szPath[MAX_PATH];
  71. HKEY hKey2;
  72. SRVTYPE srvType;
  73. // Prepare for next key
  74. dwSubKey++;
  75. // Open this key
  76. if (RegOpenKeyEx(hKey, szCLSID, 0, KEY_READ | KEY_WRITE,
  77. &hKey2) == ERROR_SUCCESS)
  78. {
  79. // Check for subkeys "LocalServer32", "_LocalServer32",
  80. // "LocalServer", and "_LocalServer"
  81. lSize = MAX_PATH * sizeof(TCHAR);
  82. err = RegQueryValue(hKey2, TEXT("LocalServer32"), szPath,
  83. &lSize);
  84. srvType = LOCALSERVER32;
  85. if (err != ERROR_SUCCESS)
  86. {
  87. lSize = MAX_PATH * sizeof(TCHAR);
  88. err = RegQueryValue(hKey2, TEXT("_LocalServer32"), szPath,
  89. &lSize);
  90. srvType = _LOCALSERVER32;
  91. }
  92. if (err != ERROR_SUCCESS)
  93. {
  94. lSize = MAX_PATH * sizeof(TCHAR);
  95. err = RegQueryValue(hKey2, TEXT("LocalServer"), szPath,
  96. &lSize);
  97. srvType = LOCALSERVER;
  98. }
  99. if (err != ERROR_SUCCESS)
  100. {
  101. lSize = MAX_PATH * sizeof(TCHAR);
  102. err = RegQueryValue(hKey2, TEXT("_LocalServer"), szPath,
  103. &lSize);
  104. srvType = _LOCALSERVER;
  105. }
  106. if (err != ERROR_SUCCESS)
  107. {
  108. RegCloseKey(hKey2);
  109. continue;
  110. }
  111. // Strip off any command line parameters -
  112. // it's the executale path that determines an item. Because
  113. // of quotes, embedded spaces, etc. we scan for ".exe"
  114. int k = 0;
  115. // szPath is executable path
  116. while (szPath[k])
  117. {
  118. if (szPath[k] == TEXT('.') &&
  119. szPath[k + 1] && (szPath[k + 1] == TEXT('e') ||
  120. szPath[k + 1] == TEXT('E')) &&
  121. szPath[k + 2] && (szPath[k + 2] == TEXT('x') ||
  122. szPath[k + 2] == TEXT('X')) &&
  123. szPath[k + 3] && (szPath[k + 3] == TEXT('e') ||
  124. szPath[k + 3] == TEXT('E')))
  125. {
  126. break;
  127. }
  128. k++;
  129. }
  130. // Just continue if we don't have an .exe path
  131. if (!szPath[k])
  132. {
  133. RegCloseKey(hKey2);
  134. continue;
  135. }
  136. // Increment to the nominal end of the path
  137. k += 4;
  138. // In case the entire path is surrounded by quotes
  139. if (szPath[k] == TEXT('"'))
  140. {
  141. k++;
  142. }
  143. szPath[k] = TEXT('\0');
  144. // Read the AppID for this clsid (if any)
  145. BOOL fUseThisClsid = FALSE;
  146. lSize = MAX_PATH * sizeof(TCHAR);
  147. if (RegQueryValueEx(hKey2, TEXT("AppID"), NULL, &dwType,
  148. (UCHAR *) szAppid, (ULONG *) &lSize)
  149. != ERROR_SUCCESS)
  150. {
  151. // Use this clsid as the appid
  152. fUseThisClsid = TRUE;
  153. }
  154. // If this is a 16-bit server without an existing AppId
  155. // named value then skip it
  156. if ((srvType == LOCALSERVER || srvType == _LOCALSERVER) &&
  157. fUseThisClsid == TRUE)
  158. {
  159. RegCloseKey(hKey2);
  160. continue;
  161. }
  162. // Read the title for the item
  163. BOOL fNoTitle = FALSE;
  164. lSize = MAX_PATH * sizeof(TCHAR);
  165. if (RegQueryValueEx(hKey2, NULL, NULL, &dwType,
  166. (UCHAR *) szTitle, (ULONG *) &lSize)
  167. != ERROR_SUCCESS)
  168. {
  169. fNoTitle = TRUE;
  170. }
  171. else if (szTitle[0] == TEXT('\0'))
  172. {
  173. fNoTitle = TRUE;
  174. }
  175. // If both the item (the executable path) and the title
  176. // (the unnamed value on the CLSID) are empty, then skip
  177. // this entry
  178. if (szPath[0] == TEXT('\0') &&
  179. (fNoTitle || szTitle[0] == TEXT('\0')))
  180. {
  181. RegCloseKey(hKey2);
  182. continue;
  183. }
  184. // Check whether we already have this item in the table - we
  185. // search differently depending on whether this clsid already
  186. // has an associated appid
  187. SItem *pItem;
  188. if (fUseThisClsid)
  189. {
  190. // check if application is in list
  191. pItem = FindItem(szPath);
  192. }
  193. else
  194. {
  195. pItem = FindAppid(szAppid);
  196. }
  197. if (pItem == NULL)
  198. {
  199. // Create a new item
  200. // szPath is path, szCLSID is CLSID
  201. pItem = m_applications.PutItem(szPath[0] ? szPath : szCLSID,
  202. fNoTitle ? szCLSID : szTitle,
  203. fUseThisClsid ? szCLSID : szAppid);
  204. if (pItem == NULL)
  205. {
  206. RegCloseKey(hKey2);
  207. RegCloseKey(hKey);
  208. return FALSE;
  209. }
  210. // Note whether the clsid had an appid named value
  211. pItem->fHasAppid = !fUseThisClsid;
  212. }
  213. // Write the AppId for this class if it doesn't exist
  214. lSize = MAX_PATH * sizeof(TCHAR);
  215. if (RegQueryValueEx(hKey2, TEXT("AppID"), 0, &dwType,
  216. (BYTE *) szBuffer, (ULONG *) &lSize)
  217. != ERROR_SUCCESS)
  218. {
  219. if (RegSetValueEx(hKey2, TEXT("AppID"), 0, REG_SZ,
  220. (const BYTE *) (LPCTSTR)pItem->szAppid,
  221. (pItem->szAppid.GetLength() + 1) * sizeof(TCHAR))
  222. != ERROR_SUCCESS)
  223. {
  224. RegCloseKey(hKey2);
  225. RegCloseKey(hKey);
  226. return FALSE;
  227. }
  228. }
  229. // Now add this clsid to the table of clsid's for this .exe
  230. if (!m_applications.AddClsid(pItem, szCLSID))
  231. {
  232. RegCloseKey(hKey2);
  233. RegCloseKey(hKey);
  234. return FALSE;
  235. }
  236. // Close the key
  237. RegCloseKey(hKey2);
  238. }
  239. } // End of the enumeration over HKEY_CLASSES_ROOT\CLSID
  240. // Close the key on HKEY_CLASSES_ROOT\CLSID
  241. RegCloseKey(hKey);
  242. // Create or open the key "HKEY_CLASSES_ROOT\AppID"
  243. if (RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("AppID"), 0, NULL,
  244. REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey,
  245. &dwDisposition) != ERROR_SUCCESS)
  246. {
  247. return FALSE;
  248. }
  249. // Enumerate keys under HKEY_CLASSES_ROOT\AppID
  250. dwSubKey = 0;
  251. while (RegEnumKey(hKey, dwSubKey, szCLSID, sizeof(szCLSID) / sizeof(TCHAR)) == ERROR_SUCCESS)
  252. {
  253. // Prepare for next key
  254. dwSubKey++;
  255. // Only look at entries having an AppId format
  256. if (!(szCLSID[0] == TEXT('{') &&
  257. _tcslen(szCLSID) == GUIDSTR_MAX &&
  258. szCLSID[37] == TEXT('}')))
  259. {
  260. continue;
  261. }
  262. // Check if this appid is already in the table
  263. SItem *pItem = FindAppid(szCLSID);
  264. // read title
  265. TCHAR szTitle[MAX_PATH];
  266. long lSize = MAX_PATH * sizeof(TCHAR);
  267. // Read its unnamed value as the title
  268. szTitle[0] = TEXT('\0');
  269. err = RegQueryValue(hKey, szCLSID, szTitle, &lSize);
  270. // If not create an item entry so it can be displayed in the UI
  271. if (pItem == NULL)
  272. {
  273. // Store this item
  274. pItem = m_applications.PutItem(NULL,
  275. szTitle[0] ? szTitle : szCLSID,
  276. szCLSID);
  277. if (pItem == NULL)
  278. return FALSE;
  279. }
  280. else
  281. {
  282. // ronans - bugfix for raided bug
  283. // change existing item title to AppID title if there is one
  284. if ((err == ERROR_SUCCESS) && szTitle[0])
  285. {
  286. pItem -> szTitle = (LPCTSTR)szTitle;
  287. }
  288. }
  289. // Mark it so we don't rewrite it to HKEY_CLASSES_ROOT\AppID
  290. pItem->fMarked = TRUE;
  291. } // End enumeration of HKEY_CLASSES_ROOT\AppID
  292. // Enumerate through the table of items, writing to HKEY_CLASSES_ROOT\AppID
  293. // any items that are not marked
  294. SItem *pItem;
  295. m_applications.InitGetNext();
  296. for (pItem = GetNextItem(); pItem; pItem = GetNextItem())
  297. {
  298. HKEY hKey2;
  299. // If this item has an AppID but is unmarked, then ask the user
  300. // whether he really wants to create the AppID
  301. if (!pItem->fMarked && pItem->fHasAppid)
  302. {
  303. CString szMessage;
  304. CString szDCOM_;
  305. CString szNULL;
  306. TCHAR szText[MAX_PATH*2];
  307. TCHAR *szParms[3];
  308. szMessage.LoadString(IDS_CLSID_);
  309. szDCOM_.LoadString(IDS_DCOM_Configuration_Warning);
  310. szNULL.LoadString(IDS_NULL);
  311. szParms[0] = pItem->ppszClsids[0];
  312. szParms[1] = !pItem->szItem.IsEmpty() ? (TCHAR *) ((LPCTSTR)pItem->szItem)
  313. : (TCHAR *) ((LPCTSTR) szNULL);
  314. szParms[2] = !pItem->szTitle.IsEmpty() ? (TCHAR *) ((LPCTSTR)pItem->szTitle)
  315. : (TCHAR *) ((LPCTSTR) szNULL);
  316. FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  317. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  318. (TCHAR *) ((LPCTSTR) szMessage),
  319. 0,
  320. 0,
  321. szText,
  322. MAX_PATH*2 * sizeof(TCHAR),
  323. (va_list *) szParms);
  324. if (MessageBox(GetForegroundWindow(),
  325. szText,
  326. (TCHAR *) ((LPCTSTR) szDCOM_),
  327. MB_YESNO) == IDNO)
  328. {
  329. pItem->fMarked = TRUE;
  330. pItem->fDontDisplay = TRUE;
  331. }
  332. }
  333. // If this item is not marked then, then create an appid key for
  334. // it under HKEY_CLASSES_ROOT\AppID and, separately, write the
  335. // .exe name under HKEY_CLASSES_ROOT\AppID
  336. if (!pItem->fMarked)
  337. {
  338. if (RegCreateKeyEx(hKey, pItem->szAppid, 0, NULL,
  339. REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey2,
  340. &dwDisposition) == ERROR_SUCCESS)
  341. {
  342. // Write the item title as the unnamed value
  343. if (!pItem->szTitle.IsEmpty())
  344. {
  345. RegSetValueEx(hKey2, NULL, 0, REG_SZ,(BYTE *) (LPCTSTR) pItem->szTitle,
  346. (pItem->szTitle.GetLength() + 1) * sizeof(TCHAR));
  347. }
  348. // Close it
  349. RegCloseKey(hKey2);
  350. // Write the .exe name if it's not empty
  351. if (!(pItem->szItem.IsEmpty()))
  352. {
  353. // Extract the .exe name
  354. int k = pItem->szItem.ReverseFind(TEXT('\\'));
  355. CString szExe = pItem->szItem.Mid((k != -1) ? k+1 : 0);
  356. // remove trailing quotes on executable name if necessary
  357. k = szExe.GetLength();
  358. if (k && (szExe.GetAt(k-1) == TEXT('\"')))
  359. szExe = szExe.Left(k-1);
  360. // Write the .exe name as a key
  361. if (RegCreateKeyEx(hKey, (LPCTSTR)szExe, 0, NULL,
  362. REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey2,
  363. &dwDisposition) == ERROR_SUCCESS)
  364. {
  365. // Now write the associated AppId as a named value
  366. RegSetValueEx(hKey2, TEXT("AppId"), 0, REG_SZ,
  367. (BYTE *)(LPCTSTR) pItem->szAppid,
  368. (pItem->szAppid.GetLength() + 1) * sizeof(TCHAR));
  369. RegCloseKey(hKey2);
  370. }
  371. }
  372. }
  373. else // dont continue on failure
  374. break;
  375. }
  376. }
  377. // Close the key on HKEY_CLASSES_ROOT\AppID
  378. RegCloseKey(hKey);
  379. // We display applications by their titles (e.g. "Microsoft Word 6.0")
  380. // which have to be unique because we're going to uniquely associate
  381. // an entry in the list box with the index of its associated SItem
  382. // structure. So here we make sure all the titles are unique.
  383. DWORD cbItems = m_applications.GetNumItems();
  384. // Compare all non-empty titles of the same length. If they are
  385. // not unique, then append "(<index>)" to make them unique
  386. for (DWORD k = 0; k < cbItems; k++)
  387. {
  388. DWORD dwIndex = 1;
  389. SItem *pItem = m_applications.GetItem(k);
  390. if (!(pItem->szTitle.IsEmpty()) && !pItem->fChecked)
  391. {
  392. for (DWORD j = k + 1; j < cbItems; j++)
  393. {
  394. SItem *pItem2 = m_applications.GetItem(j);
  395. if (!pItem2->fChecked &&
  396. (pItem->szTitle == pItem2->szTitle))
  397. {
  398. if (dwIndex == 1)
  399. {
  400. AppendIndex(pItem, 1);
  401. dwIndex++;
  402. }
  403. AppendIndex(pItem2, dwIndex++);
  404. pItem2->fChecked = TRUE;
  405. }
  406. }
  407. }
  408. }
  409. // Prepare for the UI enumerating item entries
  410. m_applications.InitGetNext();
  411. return TRUE;
  412. }
  413. BOOL CRegistry::InitGetItem(void)
  414. {
  415. return m_applications.InitGetNext();
  416. }
  417. // Enumerate the next application name
  418. SItem *CRegistry::GetNextItem(void)
  419. {
  420. return m_applications.GetNextItem();
  421. }
  422. // Get a specific item
  423. SItem *CRegistry::GetItem(DWORD dwItem)
  424. {
  425. return m_applications.GetItem(dwItem);
  426. }
  427. SItem *CRegistry::FindItem(TCHAR *szPath)
  428. {
  429. return m_applications.FindItem(szPath);
  430. }
  431. SItem *CRegistry::FindAppid(TCHAR *szAppid)
  432. {
  433. return m_applications.FindAppid(szAppid);
  434. }
  435. void CRegistry::AppendIndex(SItem *pItem, DWORD dwIndex)
  436. {
  437. CString szTmp;
  438. szTmp.Format(TEXT(" (%d)"),dwIndex);
  439. pItem->szTitle += szTmp;
  440. }
  441. DWORD CRegistry::GetNumItems(void)
  442. {
  443. return m_applications.GetNumItems();
  444. }