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.

1760 lines
53 KiB

  1. #include "general.h"
  2. #include "ParseInf.h"
  3. #include "resource.h"
  4. #include "FileNode.h"
  5. #include <shlwapi.h>
  6. #include <shlobj.h>
  7. //#define USE_SHORT_PATH_NAME 1
  8. // also defined in \nt\private\inet\urlmon\download\isctrl.cxx
  9. LPCTSTR g_lpszUpdateInfo = TEXT("UpdateInfo");
  10. LPCTSTR g_lpszCookieValue = TEXT("Cookie");
  11. LPCTSTR g_lpszSavedValue = TEXT("LastSpecifiedInterval");
  12. // This is a 'private' entry point into URLMON that we use
  13. // to convert paths from their current, possibly short-file-name
  14. // form to their canonical long-file-name form.
  15. extern "C" {
  16. #ifdef UNICODE
  17. #define STR_CDLGETLONGPATHNAME "CDLGetLongPathNameW"
  18. typedef DWORD (STDAPICALLTYPE *CDLGetLongPathNamePtr)(LPWSTR lpszLongPath, LPCWSTR lpszShortPath, DWORD cchBuffer);
  19. #else // not UNICODE
  20. #define STR_CDLGETLONGPATHNAME "CDLGetLongPathNameA"
  21. typedef DWORD (STDAPICALLTYPE *CDLGetLongPathNamePtr)(LPSTR lpszLong, LPCSTR lpszShort, DWORD cchBuffer);
  22. #endif // else not UNICODE
  23. }
  24. // given the typelib id, loop through HKEY_CLASSES_ROOT\Interface section and
  25. // remove those entries with "TypeLib" subkey equal to the given type lib id
  26. HRESULT CleanInterfaceEntries(LPCTSTR lpszTypeLibCLSID)
  27. {
  28. Assert(lpszTypeLibCLSID != NULL);
  29. if (lpszTypeLibCLSID == NULL || lpszTypeLibCLSID[0] == '\0')
  30. return HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  31. HRESULT hr = S_OK;
  32. HKEY hkey = NULL;
  33. DWORD cStrings = 0;
  34. LONG lResult = ERROR_SUCCESS, lSize = 0;
  35. TCHAR szKeyName[OLEUI_CCHKEYMAX];
  36. TCHAR szTmpID[MAX_PATH];
  37. // open key HKEY_CLASS_ROOT\Interface
  38. if (RegOpenKeyEx(
  39. HKEY_CLASSES_ROOT,
  40. HKCR_INTERFACE,
  41. 0,
  42. KEY_ALL_ACCESS,
  43. &hkey) == ERROR_SUCCESS)
  44. {
  45. // loop through all entries
  46. while ((lResult = RegEnumKey(
  47. hkey,
  48. cStrings,
  49. szKeyName,
  50. OLEUI_CCHKEYMAX)) == ERROR_SUCCESS)
  51. {
  52. lSize = MAX_PATH;
  53. lstrcat(szKeyName, TEXT("\\"));
  54. lstrcat(szKeyName, HKCR_TYPELIB);
  55. // if typelib id's match, remove the key
  56. if ((RegQueryValue(
  57. hkey,
  58. szKeyName,
  59. szTmpID,
  60. &lSize) == ERROR_SUCCESS) &&
  61. (lstrcmpi(szTmpID, lpszTypeLibCLSID) == 0))
  62. {
  63. hr = NullLastSlash(szKeyName, 0);
  64. if (SUCCEEDED(hr))
  65. {
  66. DeleteKeyAndSubKeys(hkey, szKeyName);
  67. }
  68. }
  69. else
  70. {
  71. cStrings += 1;
  72. }
  73. }
  74. RegCloseKey(hkey);
  75. if (SUCCEEDED(hr))
  76. {
  77. if (lResult != ERROR_NO_MORE_ITEMS)
  78. hr = HRESULT_FROM_WIN32(lResult);
  79. }
  80. }
  81. return hr;
  82. }
  83. // If the OCX file being removed does not exist, then we cannot prompt the control
  84. // to unregister itself. In this case, we call this function of clean up as many
  85. // registry entries as we could for the control.
  86. HRESULT CleanOrphanedRegistry(
  87. LPCTSTR szFileName,
  88. LPCTSTR szClientClsId,
  89. LPCTSTR szTypeLibCLSID)
  90. {
  91. HRESULT hr = S_OK;
  92. LONG lResult = 0;
  93. TCHAR szTmpID[MAX_PATH];
  94. TCHAR szTmpRev[MAX_PATH];
  95. TCHAR szKeyName[OLEUI_CCHKEYMAX+50];
  96. HKEY hkey = NULL, hkeyCLSID = NULL;
  97. int nKeyLen = 0;
  98. DWORD cStrings = 0;
  99. long lSize = MAX_PATH;
  100. Assert(lstrlen(szFileName) > 0);
  101. Assert(lstrlen(szClientClsId) > 0);
  102. // Delete CLSID keys
  103. CatPathStrN( szTmpID, HKCR_CLSID, szClientClsId, MAX_PATH );
  104. if (DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szTmpID) != ERROR_SUCCESS)
  105. hr = S_FALSE; // Keep going, but mark that there was a failure
  106. // Delete TypeLib info
  107. if (szTypeLibCLSID != NULL && szTypeLibCLSID[0] != '\0')
  108. {
  109. CatPathStrN( szTmpID, HKCR_TYPELIB, szTypeLibCLSID, MAX_PATH);
  110. if (DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szTmpID) != ERROR_SUCCESS)
  111. hr = S_FALSE;
  112. }
  113. // Delete ModuleUsage keys
  114. // The canonicalizer can fail if the target file isn't there, so in that case, fall back
  115. // on szFileName, which may well have come in canonical form from the DU file list.
  116. if ( OCCGetLongPathName(szTmpRev, szFileName, MAX_PATH) == 0 )
  117. lstrcpy( szTmpRev, szFileName );
  118. ReverseSlashes(szTmpRev);
  119. // Guard against the subkey name being empty, as this will cause us to nuke
  120. // the entire Module Usage subtree, which is a bad thing to do.
  121. if ( szTmpRev[0] != '\0' )
  122. {
  123. CatPathStrN(szTmpID, REGSTR_PATH_MODULE_USAGE, szTmpRev, MAX_PATH);
  124. if (DeleteKeyAndSubKeys(HKEY_LOCAL_MACHINE, szTmpID) != ERROR_SUCCESS)
  125. hr = S_FALSE;
  126. // Delete SharedDLL value
  127. if (RegOpenKeyEx(
  128. HKEY_LOCAL_MACHINE,
  129. REGSTR_PATH_SHAREDDLLS,
  130. 0,
  131. KEY_ALL_ACCESS,
  132. &hkey) == ERROR_SUCCESS)
  133. {
  134. hr = (RegDeleteValue(hkey, szFileName) == ERROR_SUCCESS ? hr : S_FALSE);
  135. RegCloseKey(hkey);
  136. }
  137. else
  138. {
  139. hr = S_FALSE;
  140. }
  141. }
  142. // loop through entries under HKEY_CLASSES_ROOT to clear entries
  143. // whose CLSID subsection is equal to the CLSID of the control
  144. // being removed
  145. while ((lResult = RegEnumKey(
  146. HKEY_CLASSES_ROOT,
  147. cStrings++,
  148. szKeyName,
  149. OLEUI_CCHKEYMAX)) == ERROR_SUCCESS)
  150. {
  151. lSize = MAX_PATH;
  152. nKeyLen = lstrlen(szKeyName);
  153. lstrcat(szKeyName, "\\");
  154. lstrcat(szKeyName, HKCR_CLSID);
  155. if ((RegQueryValue(
  156. HKEY_CLASSES_ROOT,
  157. szKeyName,
  158. szTmpID, &lSize) == ERROR_SUCCESS) &&
  159. (lstrcmpi(szTmpID, szClientClsId) == 0))
  160. {
  161. szKeyName[nKeyLen] = '\0';
  162. DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szKeyName);
  163. lResult = ERROR_NO_MORE_ITEMS;
  164. break;
  165. }
  166. }
  167. Assert(lResult == ERROR_NO_MORE_ITEMS);
  168. if (lResult != ERROR_NO_MORE_ITEMS)
  169. hr = S_FALSE;
  170. // loop through all HKEY_CLASSES_ROOT\CLSID entries and remove
  171. // those with InprocServer32 subsection equal to the name of
  172. // the OCX file being removed
  173. if (RegOpenKeyEx(
  174. HKEY_CLASSES_ROOT,
  175. HKCR_CLSID,
  176. 0,
  177. KEY_ALL_ACCESS,
  178. &hkey) == ERROR_SUCCESS)
  179. {
  180. cStrings = 0;
  181. while ((lResult = RegEnumKey(
  182. hkey,
  183. cStrings,
  184. szKeyName,
  185. OLEUI_CCHKEYMAX)) == ERROR_SUCCESS)
  186. {
  187. // check InprocServer32
  188. lSize = MAX_PATH;
  189. lstrcat(szKeyName, "\\");
  190. lstrcat(szKeyName, INPROCSERVER32);
  191. if ((RegQueryValue(
  192. hkey,
  193. szKeyName,
  194. szTmpID,
  195. &lSize) == ERROR_SUCCESS) &&
  196. (lstrcmpi(szTmpID, szFileName) == 0))
  197. {
  198. hr = NullLastSlash(szKeyName, 0);
  199. if (SUCCEEDED(hr))
  200. {
  201. DeleteKeyAndSubKeys(hkey, szKeyName);
  202. }
  203. continue;
  204. }
  205. // check LocalServer32
  206. hr = NullLastSlash(szKeyName, 1);
  207. if (SUCCEEDED(hr))
  208. {
  209. lstrcat(szKeyName, LOCALSERVER32);
  210. if ((RegQueryValue(
  211. hkey,
  212. szKeyName,
  213. szTmpID,
  214. &lSize) == ERROR_SUCCESS) &&
  215. (lstrcmpi(szTmpID, szFileName) == 0))
  216. {
  217. hr = NullLastSlash(szKeyName, 0);
  218. if (SUCCEEDED(hr))
  219. {
  220. DeleteKeyAndSubKeys(hkey, szKeyName);
  221. }
  222. continue;
  223. }
  224. }
  225. // check LocalServerX86
  226. hr = NullLastSlash(szKeyName, 1);
  227. if (SUCCEEDED(hr))
  228. {
  229. lstrcat(szKeyName, LOCALSERVERX86);
  230. if ((RegQueryValue(
  231. hkey,
  232. szKeyName,
  233. szTmpID,
  234. &lSize) == ERROR_SUCCESS) &&
  235. (lstrcmpi(szTmpID, szFileName) == 0))
  236. {
  237. hr = NullLastSlash(szKeyName, 0);
  238. if (SUCCEEDED(hr))
  239. {
  240. DeleteKeyAndSubKeys(hkey, szKeyName);
  241. }
  242. continue;
  243. }
  244. }
  245. // check InProcServerX86
  246. hr = NullLastSlash(szKeyName, 1);
  247. if (SUCCEEDED(hr))
  248. {
  249. lstrcat(szKeyName, INPROCSERVERX86);
  250. if ((RegQueryValue(
  251. hkey,
  252. szKeyName,
  253. szTmpID,
  254. &lSize) == ERROR_SUCCESS) &&
  255. (lstrcmpi(szTmpID, szFileName) == 0))
  256. {
  257. hr = NullLastSlash(szKeyName, 0);
  258. if (SUCCEEDED(hr))
  259. {
  260. DeleteKeyAndSubKeys(hkey, szKeyName);
  261. }
  262. continue;
  263. }
  264. }
  265. cStrings += 1;
  266. }
  267. RegCloseKey(hkey);
  268. Assert(lResult == ERROR_NO_MORE_ITEMS);
  269. if (lResult != ERROR_NO_MORE_ITEMS)
  270. hr = S_FALSE;
  271. }
  272. return hr;
  273. }
  274. // Get from a abbreviated filename its full, long name
  275. // eg. from C:\DOC\MyMath~1.txt to C:\DOC\MyMathFile.txt
  276. // lpszShortFileName must has in it both the file name and its full path
  277. // if bToUpper is TRUE, the name returned will be in uppercase
  278. HRESULT ConvertToLongFileName(
  279. LPTSTR lpszShortFileName,
  280. BOOL bToUpper /* = FALSE */)
  281. {
  282. Assert(lpszShortFileName != NULL);
  283. if (lpszShortFileName == NULL)
  284. return HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  285. HRESULT hr = S_OK;
  286. WIN32_FIND_DATA filedata;
  287. TCHAR *pEndPath = NULL;
  288. HANDLE h = FindFirstFile(lpszShortFileName, &filedata);
  289. if (h != INVALID_HANDLE_VALUE)
  290. {
  291. FindClose(h);
  292. // separate filename from path
  293. pEndPath = ReverseStrchr(lpszShortFileName, '\\');
  294. if (pEndPath != NULL)
  295. {
  296. *(++pEndPath) = '\0';
  297. lstrcat(pEndPath, filedata.cFileName);
  298. }
  299. else
  300. {
  301. lstrcpy(lpszShortFileName, filedata.cFileName);
  302. }
  303. // to upper case if requested
  304. if (bToUpper)
  305. CharUpper(lpszShortFileName);
  306. }
  307. else
  308. {
  309. hr = HRESULT_FROM_WIN32(GetLastError());
  310. }
  311. return hr;
  312. }
  313. //=--------------------------------------------------------------------------=
  314. // DeleteKeyAndSubKeys
  315. //=--------------------------------------------------------------------------=
  316. // delete's a key and all of it's subkeys.
  317. //
  318. // Parameters:
  319. // HKEY - [in] delete the descendant specified
  320. // LPSTR - [in] i'm the descendant specified
  321. //
  322. // Output:
  323. // LONG - ERROR_SUCCESS if successful
  324. // - else, a nonzero error code defined in WINERROR.H
  325. //
  326. // Notes:
  327. // - I don't feel too bad about implementing this recursively, since the
  328. // depth isn't likely to get all the great.
  329. // - Manually removing subkeys is needed for NT. Win95 does that
  330. // automatically
  331. //
  332. // This code was stolen from the ActiveX framework (util.cpp).
  333. LONG DeleteKeyAndSubKeys(HKEY hkIn, LPCTSTR pszSubKey)
  334. {
  335. HKEY hk;
  336. TCHAR szTmp[MAX_PATH];
  337. DWORD dwTmpSize;
  338. LONG lResult;
  339. lResult = RegOpenKeyEx(hkIn, pszSubKey, 0, KEY_ALL_ACCESS, &hk);
  340. if (lResult != ERROR_SUCCESS)
  341. return lResult;
  342. // loop through all subkeys, blowing them away.
  343. for (/* DWORD c = 0 */; lResult == ERROR_SUCCESS; /* c++ */)
  344. {
  345. dwTmpSize = MAX_PATH;
  346. lResult = RegEnumKeyEx(hk, 0, szTmp, &dwTmpSize, 0, NULL, NULL, NULL);
  347. if (lResult == ERROR_NO_MORE_ITEMS)
  348. break;
  349. lResult = DeleteKeyAndSubKeys(hk, szTmp);
  350. }
  351. // there are no subkeys left, [or we'll just generate an error and return FALSE].
  352. // let's go blow this dude away.
  353. //
  354. dwTmpSize = MAX_PATH;
  355. Assert(RegEnumKeyEx(hk, 0, szTmp, &dwTmpSize, 0, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS);
  356. RegCloseKey(hk);
  357. lResult = RegDeleteKey(hkIn, pszSubKey);
  358. return lResult;
  359. }
  360. // return TRUE if file szFileName exists, FALSE otherwise
  361. BOOL FileExist(LPCTSTR lpszFileName)
  362. {
  363. DWORD dwErrMode;
  364. BOOL fResult;
  365. dwErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  366. fResult = ((UINT)GetFileAttributes(lpszFileName) != (UINT)-1);
  367. SetErrorMode(dwErrMode);
  368. return fResult;
  369. }
  370. // given a flag, return the appropriate directory
  371. // possible flags are:
  372. // GD_WINDOWDIR : return WINDOWS directory
  373. // GD_SYSTEMDIR : return SYSTEM directory
  374. // GD_CONTAINERDIR : return directory of app used to view control (ie IE)
  375. // GD_CACHEDIR : return OCX cache directory, read from registry
  376. // GD_CONFLICTDIR : return OCX conflict directory, read from registry
  377. // GD_EXTRACTDIR : require an extra parameter szOCXFullName,
  378. // extract and return its path
  379. HRESULT GetDirectory(
  380. UINT nDirType,
  381. LPTSTR szDirBuffer,
  382. int nBufSize,
  383. LPCTSTR szOCXFullName /* = NULL */)
  384. {
  385. LONG lResult = 0;
  386. TCHAR *pCh = NULL, *pszKeyName = NULL;
  387. HRESULT hr = S_OK;
  388. HKEY hkeyIntSetting = NULL;
  389. unsigned long ulSize = nBufSize;
  390. switch (nDirType)
  391. {
  392. case GD_WINDOWSDIR:
  393. if (GetWindowsDirectory(szDirBuffer, nBufSize) == 0)
  394. hr = HRESULT_FROM_WIN32(GetLastError());
  395. break;
  396. case GD_SYSTEMDIR:
  397. if (GetSystemDirectory(szDirBuffer, nBufSize) == 0)
  398. hr = HRESULT_FROM_WIN32(GetLastError());
  399. break;
  400. case GD_EXTRACTDIR:
  401. if (szOCXFullName == NULL)
  402. {
  403. hr = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  404. break;
  405. }
  406. lstrcpy(szDirBuffer, szOCXFullName);
  407. pCh = ReverseStrchr(szDirBuffer, '\\');
  408. if (pCh == NULL)
  409. hr = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  410. else
  411. pCh[0] = '\0';
  412. break;
  413. case GD_CONTAINERDIR:
  414. pszKeyName = new TCHAR[MAX_PATH];
  415. if (pszKeyName == NULL)
  416. {
  417. hr = E_OUTOFMEMORY;
  418. break;
  419. }
  420. CatPathStrN(pszKeyName, REGSTR_PATH_IE, CONTAINER_APP, MAX_PATH);
  421. if ((lResult = RegOpenKeyEx(
  422. HKEY_LOCAL_MACHINE,
  423. pszKeyName,
  424. 0x0,
  425. KEY_READ,
  426. &hkeyIntSetting)) == ERROR_SUCCESS)
  427. {
  428. lResult = RegQueryValueEx(
  429. hkeyIntSetting,
  430. VALUE_PATH,
  431. NULL,
  432. NULL,
  433. (unsigned char*)szDirBuffer,
  434. &ulSize);
  435. }
  436. if (lResult != ERROR_SUCCESS)
  437. hr = HRESULT_FROM_WIN32(lResult);
  438. else
  439. szDirBuffer[lstrlen(szDirBuffer)-1] = '\0'; // take away the ending ';'
  440. delete [] pszKeyName;
  441. break;
  442. case GD_CACHEDIR:
  443. case GD_CONFLICTDIR:
  444. if ((lResult = RegOpenKeyEx(
  445. HKEY_LOCAL_MACHINE,
  446. REGSTR_PATH_IE_SETTINGS,
  447. 0x0,
  448. KEY_READ,
  449. &hkeyIntSetting)) == ERROR_SUCCESS)
  450. {
  451. lResult = RegQueryValueEx(
  452. hkeyIntSetting,
  453. VALUE_ACTIVEXCACHE,
  454. NULL,
  455. NULL,
  456. (unsigned char*)szDirBuffer,
  457. &ulSize);
  458. }
  459. hr = (lResult == ERROR_SUCCESS ? S_OK : HRESULT_FROM_WIN32(lResult));
  460. // if looking for cache dir, append "\\CONFLICT"
  461. if (SUCCEEDED(hr) && nDirType == GD_CONFLICTDIR)
  462. lstrcat(szDirBuffer, DEFAULT_CONFLICT);
  463. break;
  464. default:
  465. Assert(FALSE);
  466. hr = E_UNEXPECTED;
  467. }
  468. if (hkeyIntSetting != NULL)
  469. RegCloseKey(hkeyIntSetting);
  470. if (FAILED(hr))
  471. szDirBuffer[0] = '\0';
  472. return hr;
  473. }
  474. // retrieve file size for file szFile. Size returne in pSize.
  475. HRESULT GetSizeOfFile(LPCTSTR lpszFile, LPDWORD lpSize)
  476. {
  477. HANDLE hFile = NULL;
  478. WIN32_FIND_DATA fileData;
  479. *lpSize = 0;
  480. Assert(lpszFile != NULL);
  481. hFile = FindFirstFile(lpszFile, &fileData);
  482. if (hFile == INVALID_HANDLE_VALUE)
  483. return HRESULT_FROM_WIN32(GetLastError());
  484. FindClose(hFile);
  485. *lpSize = fileData.nFileSizeLow;
  486. // Get cluster size to calculate the real # of bytes
  487. // taken up by the file
  488. DWORD dwSectorPerCluster, dwBytePerSector;
  489. DWORD dwFreeCluster, dwTotalCluster;
  490. TCHAR szRoot[4];
  491. lstrcpyn(szRoot, lpszFile, 4);
  492. if (!GetDiskFreeSpace(
  493. szRoot, &dwSectorPerCluster, &dwBytePerSector,
  494. &dwFreeCluster, &dwTotalCluster))
  495. return HRESULT_FROM_WIN32(GetLastError());
  496. DWORD dwClusterSize = dwSectorPerCluster * dwBytePerSector;
  497. *lpSize = ((*lpSize/dwClusterSize) * dwClusterSize +
  498. (*lpSize % dwClusterSize ? dwClusterSize : 0));
  499. return S_OK;
  500. }
  501. // Return S_OK is lpszCLSID is in ModuleUsage section of lpszFileName.
  502. // Return E_... otherwise.
  503. // lpszCLSID can be NULL, in this case it does not search for the CLSID.
  504. // If lpszOwner is not NULL, it must point to a buffer which will be
  505. // used to store the owner of the ModuleUsage section for lpszFileName
  506. // dwOwnerSize is the size of the buffer pointed to by lpszOwner .
  507. HRESULT LookUpModuleUsage(
  508. LPCTSTR lpszFileName,
  509. LPCTSTR lpszCLSID,
  510. LPTSTR lpszOwner /* = NULL */,
  511. DWORD dwOwnerSize /* = 0 */)
  512. {
  513. HKEY hkey = NULL, hkeyMod = NULL;
  514. HRESULT hr = S_OK;
  515. TCHAR szBuf[MAX_PATH];
  516. LONG lResult = ERROR_SUCCESS;
  517. if ((lResult = RegOpenKeyEx(
  518. HKEY_LOCAL_MACHINE,
  519. REGSTR_PATH_MODULE_USAGE,
  520. 0,
  521. KEY_READ,
  522. &hkeyMod)) != ERROR_SUCCESS)
  523. {
  524. hr = HRESULT_FROM_WIN32(lResult);
  525. goto EXITLOOKUPMODULEUSAGE;
  526. }
  527. if ( OCCGetLongPathName(szBuf, lpszFileName, MAX_PATH) == 0 )
  528. lstrcpyn( szBuf, lpszFileName, MAX_PATH );
  529. szBuf[256] = '\0'; // truncate if longer than 255 ude to win95 registry bug
  530. lResult = RegOpenKeyEx(
  531. hkeyMod,
  532. szBuf,
  533. 0,
  534. KEY_READ,
  535. &hkey);
  536. if (lResult != ERROR_SUCCESS)
  537. {
  538. ReverseSlashes(szBuf);
  539. lResult = RegOpenKeyEx(hkeyMod, szBuf, 0, KEY_READ, &hkey);
  540. if (lResult != ERROR_SUCCESS)
  541. {
  542. hr = HRESULT_FROM_WIN32(lResult);
  543. goto EXITLOOKUPMODULEUSAGE;
  544. }
  545. }
  546. // Get owner if requested
  547. if (lpszOwner != NULL)
  548. {
  549. DWORD dwSize = dwOwnerSize;
  550. lResult = RegQueryValueEx(
  551. hkey,
  552. VALUE_OWNER,
  553. NULL,
  554. NULL,
  555. (unsigned char*)lpszOwner,
  556. &dwSize);
  557. if (lResult != ERROR_SUCCESS)
  558. {
  559. hr = HRESULT_FROM_WIN32(lResult);
  560. lpszOwner[0] = '\0';
  561. goto EXITLOOKUPMODULEUSAGE;
  562. }
  563. }
  564. // see if lpszCLSID is a client of this module usage section
  565. if (lpszCLSID != NULL)
  566. {
  567. lResult = RegQueryValueEx(
  568. hkey,
  569. lpszCLSID,
  570. NULL,
  571. NULL,
  572. NULL,
  573. NULL);
  574. if (lResult != ERROR_SUCCESS)
  575. {
  576. hr = HRESULT_FROM_WIN32(lResult);
  577. goto EXITLOOKUPMODULEUSAGE;
  578. }
  579. }
  580. EXITLOOKUPMODULEUSAGE:
  581. if (hkey)
  582. RegCloseKey(hkey);
  583. if (hkeyMod)
  584. RegCloseKey(hkeyMod);
  585. return hr;
  586. }
  587. // ReverseSlashes() takes a string, that's assumed to be pointing to a
  588. // valid string and is null-terminated, and reverses all forward slashes
  589. // to backslashes and all backslashes to forward slashes.
  590. void ReverseSlashes(LPTSTR pszStr)
  591. {
  592. while (*pszStr)
  593. {
  594. if (*pszStr == '\\') *pszStr = '/';
  595. else if (*pszStr == '/') *pszStr = '\\';
  596. pszStr++;
  597. }
  598. }
  599. // find the last occurance of ch in string szString
  600. TCHAR* ReverseStrchr(LPCTSTR szString, TCHAR ch)
  601. {
  602. if (szString == NULL || szString[0] == '\0')
  603. return NULL;
  604. TCHAR *pCh = (TCHAR*)(szString + lstrlen(szString));
  605. for (;pCh != szString && *pCh != ch; pCh--);
  606. return (*pCh == ch ? pCh : NULL);
  607. }
  608. // set the last backslash (or the character offset from that by 1) to NULL
  609. // returns S_OK if fine, E_FAIL if last backslash not found
  610. HRESULT NullLastSlash(LPTSTR pszString, UINT uiOffset)
  611. {
  612. LPTSTR pszLastSlash;
  613. HRESULT hr;
  614. ASSERT(pszString);
  615. ASSERT((uiOffset == 0) || (uiOffset == 1));
  616. pszLastSlash = ReverseStrchr(pszString, TEXT('\\'));
  617. if (!pszLastSlash)
  618. {
  619. hr = E_FAIL;
  620. }
  621. else
  622. {
  623. *(pszLastSlash + uiOffset) = TEXT('\0');
  624. hr = S_OK;
  625. }
  626. return hr;
  627. }
  628. // If lpszGUID is an owner of the module lpszFileName in Module Usage,
  629. // remove it, updating the .Owner as necessary. If we remove an owner,
  630. // then decrement the SharedDlls count. Never drop the SharedDlls count
  631. // below 1 if the owner is 'Unknown Owner'.
  632. // If modules usage drops to zero, remove MU. If SharedDlls count drops
  633. // to zero, remove that value.
  634. // Return the resulting owner count.
  635. DWORD SubtractModuleOwner( LPCTSTR lpszFileName, LPCTSTR lpszGUID )
  636. {
  637. LONG cRef = 0;
  638. HRESULT hr = S_OK;
  639. LONG lResult;
  640. HKEY hkeyMU = NULL;
  641. HKEY hkeyMod = NULL;
  642. TCHAR szBuf[MAX_PATH];
  643. TCHAR szOwner[MAX_PATH];
  644. DWORD dwSize = MAX_PATH;
  645. BOOL bHasUnknownOwner;
  646. BOOL bGUIDIsOwner;
  647. Assert(lpszFileName != NULL);
  648. Assert(lpszGUID != NULL);
  649. // Get the current ref count, passing -1 to set is a get. Go figure.
  650. hr = SetSharedDllsCount( lpszFileName, -1, &cRef );
  651. if ( FAILED(hr) )
  652. return 1; // in event of failure, say something safe
  653. // check if Usage section is present for this dll
  654. // open the file's section we are concerned with
  655. if ((lResult = RegOpenKeyEx(
  656. HKEY_LOCAL_MACHINE,
  657. REGSTR_PATH_MODULE_USAGE,
  658. 0,
  659. KEY_ALL_ACCESS,
  660. &hkeyMU)) != ERROR_SUCCESS)
  661. {
  662. hr = HRESULT_FROM_WIN32(lResult);
  663. goto ExitSubtractModuleOwner;
  664. }
  665. if ( OCCGetLongPathName(szBuf, lpszFileName, MAX_PATH) == 0 )
  666. lstrcpyn( szBuf, lpszFileName, MAX_PATH );
  667. szBuf[256] = '\0'; // truncate if longer than 255 ude to win95 registry bug
  668. ReverseSlashes(szBuf);
  669. // open section for szFileName under ModuleUsage
  670. if ((lResult = RegOpenKeyEx(
  671. hkeyMU,
  672. szBuf,
  673. 0,
  674. KEY_ALL_ACCESS,
  675. &hkeyMod)) != ERROR_SUCCESS)
  676. {
  677. goto ExitSubtractModuleOwner;
  678. }
  679. dwSize = MAX_PATH;
  680. if ((lResult = RegQueryValueEx(
  681. hkeyMod,
  682. VALUE_OWNER,
  683. NULL,
  684. NULL,
  685. (unsigned char*)szOwner,
  686. &dwSize)) != ERROR_SUCCESS)
  687. {
  688. goto ExitSubtractModuleOwner;
  689. }
  690. bHasUnknownOwner = lstrcmp( szOwner, MODULE_UNKNOWN_OWNER ) == 0;
  691. bGUIDIsOwner = lstrcmp( szOwner, lpszGUID ) == 0;
  692. // remove the owner value entry, if any.
  693. lResult = RegDeleteValue(hkeyMod, lpszGUID);
  694. // if this worked, then we'll need to drop the SharedDlls count,
  695. // being careful not to let it fall below 1 if bHasUnknownOwner
  696. if ( lResult == ERROR_SUCCESS )
  697. {
  698. if ( !bHasUnknownOwner || cRef > 1 )
  699. SetSharedDllsCount( lpszFileName, --cRef, NULL );
  700. if ( cRef > 0 && bGUIDIsOwner )
  701. {
  702. DWORD dwEnumIndex;
  703. // lpszGUID was the .Owner, now that it's gone, replace it
  704. // with another owner
  705. for ( dwEnumIndex = 0, dwSize = MAX_PATH;
  706. RegEnumValue(hkeyMod, dwEnumIndex, (char *)szOwner,
  707. &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
  708. dwEnumIndex++, dwSize = MAX_PATH )
  709. {
  710. if (szOwner[0] != '.')
  711. {
  712. lResult = RegSetValueEx( hkeyMod,VALUE_OWNER, 0,
  713. REG_SZ, (LPBYTE)szOwner,
  714. (lstrlen( szOwner ) + 1) * sizeof(TCHAR) );
  715. break; // we've done our job
  716. }
  717. } // for find a new owner
  718. } // if there are still owners, but we've nuked the owner of record.
  719. else if ( cRef == 0 )
  720. {
  721. // that was the last ref, so nuke the MU entry
  722. RegCloseKey( hkeyMod );
  723. hkeyMod = NULL;
  724. RegDeleteKey( hkeyMU, szBuf ); // note - we assume this key has no subkeys.
  725. // Take out the shared DLL's value
  726. HKEY hkey;
  727. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  728. REGSTR_PATH_SHAREDDLLS, 0, KEY_ALL_ACCESS,
  729. &hkey);
  730. if ( lResult == ERROR_SUCCESS )
  731. {
  732. ReverseSlashes(szBuf); // revert to file sys
  733. lResult = RegDeleteValue( hkey, szBuf );
  734. RegCloseKey( hkey );
  735. } // if opened SharedDlls
  736. } // else last reference
  737. } // if removed an owner
  738. ExitSubtractModuleOwner:
  739. if (hkeyMU)
  740. RegCloseKey(hkeyMU);
  741. if (hkeyMod)
  742. RegCloseKey(hkeyMod);
  743. return cRef;
  744. }
  745. // Set manually the count in SharedDlls.
  746. // If dwCount is < 0, nothing is set.
  747. // If pdwOldCount is non-null, the old count is returned
  748. HRESULT SetSharedDllsCount(
  749. LPCTSTR lpszFileName,
  750. LONG cRef,
  751. LONG *pcRefOld /* = NULL */)
  752. {
  753. HRESULT hr = S_OK;
  754. LONG lResult = ERROR_SUCCESS;
  755. DWORD dwSize = 0;
  756. HKEY hkey = NULL;
  757. Assert(lpszFileName != NULL);
  758. if (lpszFileName == NULL)
  759. {
  760. hr = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  761. goto EXITSETSHAREDDLLSCOUNT;
  762. }
  763. if (cRef < 0 && pcRefOld == NULL)
  764. {
  765. goto EXITSETSHAREDDLLSCOUNT;
  766. }
  767. // open HKLM, Microsoft\Windows\CurrentVersion\SharedDlls
  768. lResult = RegOpenKeyEx(
  769. HKEY_LOCAL_MACHINE,
  770. REGSTR_PATH_SHAREDDLLS, 0, KEY_ALL_ACCESS,
  771. &hkey);
  772. if (lResult != ERROR_SUCCESS)
  773. {
  774. hr = HRESULT_FROM_WIN32(lResult);
  775. goto EXITSETSHAREDDLLSCOUNT;
  776. }
  777. // if pdwOldCount is not NULL, save the old count in it
  778. if (pcRefOld != NULL)
  779. {
  780. dwSize = sizeof(DWORD);
  781. lResult = RegQueryValueEx(
  782. hkey,
  783. lpszFileName,
  784. 0,
  785. NULL,
  786. (unsigned char*)pcRefOld,
  787. &dwSize);
  788. if (lResult != ERROR_SUCCESS)
  789. {
  790. *pcRefOld = 0;
  791. hr = S_FALSE;
  792. goto EXITSETSHAREDDLLSCOUNT;
  793. }
  794. }
  795. // if dwCount >= 0, set it as the new count
  796. if (cRef >= 0)
  797. {
  798. lResult = RegSetValueEx(
  799. hkey,
  800. lpszFileName,
  801. 0,
  802. REG_DWORD,
  803. (unsigned char*)&cRef,
  804. sizeof(DWORD));
  805. if (lResult != ERROR_SUCCESS)
  806. {
  807. hr = S_FALSE;
  808. goto EXITSETSHAREDDLLSCOUNT;
  809. }
  810. }
  811. EXITSETSHAREDDLLSCOUNT:
  812. if (hkey != NULL)
  813. RegCloseKey(hkey);
  814. return hr;
  815. }
  816. // UnregisterOCX() attempts to unregister a DLL or OCX by calling LoadLibrary
  817. // and then DllUnregisterServer if the LoadLibrary succeeds. This function
  818. // returns TRUE if the DLL or OCX could be unregistered or if the file isn't
  819. // a loadable module.
  820. HRESULT UnregisterOCX(LPCTSTR pszFile)
  821. {
  822. HINSTANCE hLib;
  823. HRESULT hr = S_OK;
  824. HRESULT (FAR STDAPICALLTYPE * pUnregisterEntry)(void);
  825. hLib = LoadLibrary(pszFile);
  826. if (hLib == NULL)
  827. {
  828. hr = HRESULT_FROM_WIN32(GetLastError());
  829. }
  830. else
  831. {
  832. (FARPROC &) pUnregisterEntry = GetProcAddress(
  833. hLib,
  834. "DllUnregisterServer"
  835. );
  836. if (pUnregisterEntry != NULL)
  837. {
  838. hr = (*pUnregisterEntry)();
  839. }
  840. FreeLibrary(hLib);
  841. }
  842. return hr;
  843. }
  844. // Return S_OK if dll can be removed, or S_FALSE if it cannot.
  845. // Return E_... if an error has occured
  846. HRESULT UpdateSharedDlls(LPCTSTR szFileName, BOOL bUpdate)
  847. {
  848. HKEY hkeySD = NULL;
  849. HRESULT hr = S_OK;
  850. DWORD dwType;
  851. DWORD dwRef = 1;
  852. DWORD dwSize = sizeof(DWORD);
  853. LONG lResult;
  854. // get the main SHAREDDLLS key ready; this is never freed!
  855. if ((lResult = RegOpenKeyEx(
  856. HKEY_LOCAL_MACHINE, REGSTR_PATH_SHAREDDLLS,
  857. 0, KEY_ALL_ACCESS, &hkeySD)) != ERROR_SUCCESS)
  858. {
  859. hkeySD = NULL;
  860. hr = HRESULT_FROM_WIN32(lResult);
  861. goto ExitUpdateSharedDlls;
  862. }
  863. // now look for szFileName
  864. lResult = RegQueryValueEx(hkeySD, szFileName, NULL, &dwType,
  865. (unsigned char*)&dwRef, &dwSize);
  866. if (lResult != ERROR_SUCCESS)
  867. {
  868. hr = S_FALSE;
  869. goto ExitUpdateSharedDlls;
  870. }
  871. // decrement reference count by 1.
  872. //
  873. // if (count equals to 0)
  874. // if (bUpdate is TRUE)
  875. // remove the key from SharedDlls
  876. // return S_OK
  877. // otherwise
  878. // if (bUpdate is TRUE)
  879. // update the count
  880. // return S_FALSE
  881. if ((--dwRef) > 0)
  882. {
  883. hr = S_FALSE;
  884. if (bUpdate &&
  885. (lResult = RegSetValueEx(hkeySD, szFileName, 0, REG_DWORD,
  886. (unsigned char *)&dwRef, sizeof(DWORD))) != ERROR_SUCCESS)
  887. {
  888. hr = HRESULT_FROM_WIN32(lResult);
  889. }
  890. goto ExitUpdateSharedDlls;
  891. }
  892. Assert(dwRef == 0);
  893. // remove entry from SharedDlls
  894. if (bUpdate &&
  895. (lResult = RegDeleteValue(hkeySD, szFileName)) != ERROR_SUCCESS)
  896. {
  897. hr = HRESULT_FROM_WIN32(lResult);
  898. goto ExitUpdateSharedDlls;
  899. }
  900. ExitUpdateSharedDlls:
  901. if (hkeySD)
  902. RegCloseKey(hkeySD);
  903. return hr;
  904. }
  905. void RemoveList(LPCLSIDLIST_ITEM lpListHead)
  906. {
  907. LPCLSIDLIST_ITEM lpItemPtr = NULL;
  908. while (TRUE)
  909. {
  910. lpItemPtr = lpListHead;
  911. if (lpItemPtr == NULL)
  912. break;
  913. lpListHead = lpItemPtr->pNext;
  914. delete lpItemPtr;
  915. }
  916. lpListHead = NULL;
  917. }
  918. BOOL ReadInfFileNameFromRegistry(
  919. LPCTSTR lpszCLSID,
  920. LPTSTR lpszInf,
  921. LONG nBufLen)
  922. {
  923. if (lpszCLSID == NULL || lpszInf == NULL)
  924. return FALSE;
  925. HKEY hkey = NULL;
  926. TCHAR szKey[100];
  927. LONG lResult = ERROR_SUCCESS;
  928. CatPathStrN( szKey, HKCR_CLSID, lpszCLSID, 100);
  929. CatPathStrN( szKey, szKey, INFFILE, 100);
  930. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
  931. return FALSE;
  932. lResult = RegQueryValue(hkey, NULL, lpszInf, &nBufLen);
  933. RegCloseKey(hkey);
  934. if (lResult != ERROR_SUCCESS)
  935. {
  936. lpszInf[0] = '\0';
  937. }
  938. if (lpszInf[0] == '\0')
  939. return FALSE;
  940. return TRUE;
  941. }
  942. BOOL WriteInfFileNameToRegistry(LPCTSTR lpszCLSID, LPTSTR lpszInf)
  943. {
  944. if (lpszCLSID == NULL)
  945. return FALSE;
  946. HKEY hkey = NULL;
  947. LONG lResult = ERROR_SUCCESS;
  948. TCHAR szKey[100];
  949. CatPathStrN(szKey, HKCR_CLSID, lpszCLSID, 100);
  950. CatPathStrN(szKey, szKey, INFFILE, 100);
  951. if (RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hkey) != ERROR_SUCCESS)
  952. return FALSE;
  953. lResult = RegSetValue(
  954. hkey,
  955. NULL,
  956. REG_SZ,
  957. (lpszInf == NULL ? TEXT("") : lpszInf),
  958. (lpszInf == NULL ? 0 : lstrlen(lpszInf)));
  959. RegCloseKey(hkey);
  960. return (lResult == ERROR_SUCCESS);
  961. }
  962. // Define a macro to make life easier
  963. #define QUIT_IF_FAIL if (FAILED(hr)) goto Exit
  964. HRESULT
  965. ExpandVar(
  966. LPCSTR& pchSrc, // passed by ref!
  967. LPSTR& pchOut, // passed by ref!
  968. DWORD& cbLen, // passed by ref!
  969. DWORD cbBuffer,
  970. const char * szVars[],
  971. const char * szValues[])
  972. {
  973. HRESULT hr = S_FALSE;
  974. int cbvar = 0;
  975. Assert (*pchSrc == '%');
  976. for (int i=0; szVars[i] && (cbvar = lstrlen(szVars[i])) ; i++) { // for each variable
  977. int cbneed = 0;
  978. if ( (szValues[i] == NULL) || !(cbneed = lstrlen(szValues[i])))
  979. continue;
  980. cbneed++; // add for nul
  981. if (0 == strncmp(szVars[i], pchSrc, cbvar)) {
  982. // found something we can expand
  983. if ((cbLen + cbneed) >= cbBuffer) {
  984. // out of buffer space
  985. *pchOut = '\0'; // term
  986. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  987. goto Exit;
  988. }
  989. lstrcpy(pchOut, szValues[i]);
  990. cbLen += (cbneed -1); //don't count the nul
  991. pchSrc += cbvar; // skip past the var in pchSrc
  992. pchOut += (cbneed -1); // skip past dir in pchOut
  993. hr = S_OK;
  994. goto Exit;
  995. }
  996. }
  997. Exit:
  998. return hr;
  999. }
  1000. // from urlmon\download\hooks.cxx (ExpandCommandLine and ExpandVars)
  1001. // used to expand variables
  1002. HRESULT
  1003. ExpandCommandLine(
  1004. LPCSTR szSrc,
  1005. LPSTR szBuf,
  1006. DWORD cbBuffer,
  1007. const char * szVars[],
  1008. const char * szValues[])
  1009. {
  1010. Assert(cbBuffer);
  1011. HRESULT hr = S_FALSE;
  1012. LPCSTR pchSrc = szSrc; // start parsing at begining of cmdline
  1013. LPSTR pchOut = szBuf; // set at begin of out buffer
  1014. DWORD cbLen = 0;
  1015. while (*pchSrc) {
  1016. // look for match of any of our env vars
  1017. if (*pchSrc == '%') {
  1018. HRESULT hr1 = ExpandVar(pchSrc, pchOut, cbLen, // all passed by ref!
  1019. cbBuffer, szVars, szValues);
  1020. if (FAILED(hr1)) {
  1021. hr = hr1;
  1022. goto Exit;
  1023. }
  1024. if (hr1 == S_OK) { // expand var expanded this
  1025. hr = hr1;
  1026. continue;
  1027. }
  1028. }
  1029. // copy till the next % or nul
  1030. if ((cbLen + 1) < cbBuffer) {
  1031. *pchOut++ = *pchSrc++;
  1032. cbLen++;
  1033. } else {
  1034. // out of buffer space
  1035. *pchOut = '\0'; // term
  1036. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1037. goto Exit;
  1038. }
  1039. }
  1040. *pchOut = '\0'; // term
  1041. Exit:
  1042. return hr;
  1043. }
  1044. // Find dependent DLLs in ModuleUsage
  1045. // given the clsid it will enumerate all the DLLs in the ModuleUsage
  1046. // that were used by this clsid
  1047. HRESULT FindDLLInModuleUsage(
  1048. LPTSTR lpszFileName,
  1049. LPCTSTR lpszCLSID,
  1050. DWORD &iSubKey)
  1051. {
  1052. HKEY hkey = NULL, hkeyMod = NULL;
  1053. HRESULT hr = S_OK;
  1054. TCHAR szBuf[MAX_PATH];
  1055. LONG lResult = ERROR_SUCCESS;
  1056. if (lpszCLSID == NULL) {
  1057. hr = E_INVALIDARG; // req clsid
  1058. goto Exit;
  1059. }
  1060. // get the main MODULEUSAGE key
  1061. if ((lResult = RegOpenKeyEx(
  1062. HKEY_LOCAL_MACHINE,
  1063. REGSTR_PATH_MODULE_USAGE,
  1064. 0,
  1065. KEY_READ,
  1066. &hkeyMod)) != ERROR_SUCCESS)
  1067. {
  1068. hr = HRESULT_FROM_WIN32(lResult);
  1069. goto Exit;
  1070. }
  1071. while ( ((lResult = RegEnumKey(
  1072. hkeyMod,
  1073. iSubKey++,
  1074. szBuf,
  1075. MAX_PATH)) == ERROR_SUCCESS) ) {
  1076. lResult = RegOpenKeyEx(
  1077. hkeyMod,
  1078. szBuf,
  1079. 0,
  1080. KEY_READ,
  1081. &hkey);
  1082. if (lResult != ERROR_SUCCESS)
  1083. break;
  1084. // see if lpszCLSID is a client of this module usage section
  1085. lResult = RegQueryValueEx(
  1086. hkey,
  1087. lpszCLSID,
  1088. NULL,
  1089. NULL,
  1090. NULL,
  1091. NULL);
  1092. if (lResult == ERROR_SUCCESS)
  1093. {
  1094. // got the filename, return it
  1095. lstrcpy(lpszFileName, szBuf);
  1096. goto Exit;
  1097. }
  1098. if (hkey) {
  1099. RegCloseKey(hkey);
  1100. hkey = NULL;
  1101. }
  1102. } // while
  1103. if (lResult != ERROR_SUCCESS) {
  1104. hr = HRESULT_FROM_WIN32(lResult);
  1105. }
  1106. Exit:
  1107. if (hkey)
  1108. RegCloseKey(hkey);
  1109. if (hkeyMod)
  1110. RegCloseKey(hkeyMod);
  1111. return hr;
  1112. }
  1113. BOOL PatternMatch(LPCTSTR szModName, LPTSTR szSectionName)
  1114. {
  1115. LPCTSTR pch = ReverseStrchr(szModName, '/');
  1116. DWORD len = 0;
  1117. if (!pch)
  1118. pch = szModName;
  1119. else
  1120. pch++;
  1121. // pch points at base name of module
  1122. if ((len = lstrlen(pch)) != (DWORD)lstrlen(szSectionName))
  1123. return FALSE;
  1124. LPTSTR pchSecStar = StrChr(szSectionName, '*');
  1125. Assert(pchSecStar);
  1126. DWORD cbLen1 = (DWORD) (pchSecStar - szSectionName);
  1127. // compare upto '*'
  1128. if (StrCmpNI(szSectionName, pch, cbLen1) != 0)
  1129. return FALSE;
  1130. // compare after the 3 stars
  1131. if ( (cbLen1 + 3) < len) // *s not at end
  1132. if (StrCmpNI(pchSecStar+3, pch + (cbLen1+3), len -(cbLen1+3)) != 0)
  1133. return FALSE;
  1134. // simlar strings but for the stars.
  1135. // modify the szSectionName to hold the value for the stars
  1136. // in-effect this will substitute the original variable with
  1137. // the value that was used when installing the OCX
  1138. lstrcpy(pchSecStar, pch + cbLen1);
  1139. return TRUE;
  1140. }
  1141. DWORD OCCGetLongPathName( LPTSTR szLong, LPCTSTR szShort, DWORD cchBuffer )
  1142. {
  1143. DWORD dwLen = 0;
  1144. HMODULE hmodUrlMon;
  1145. CDLGetLongPathNamePtr pfnGetLongPathName = NULL;
  1146. hmodUrlMon = LoadLibrary( "URLMON.DLL" );
  1147. // Set up our globals with short and long versions of the base cache path
  1148. if ( hmodUrlMon != NULL ) {
  1149. pfnGetLongPathName = (CDLGetLongPathNamePtr)GetProcAddress(hmodUrlMon, (LPCSTR)STR_CDLGETLONGPATHNAME );
  1150. if ( pfnGetLongPathName != NULL ) {
  1151. dwLen = pfnGetLongPathName( szLong, szShort, cchBuffer );
  1152. }
  1153. FreeLibrary( hmodUrlMon );
  1154. }
  1155. return dwLen;
  1156. }
  1157. TCHAR *CatPathStrN( TCHAR *szDst, const TCHAR *szHead, const TCHAR *szTail, int cchDst )
  1158. {
  1159. TCHAR *szRet = szDst;
  1160. int cchHead = lstrlen(szHead);
  1161. int cchTail = lstrlen(szTail);
  1162. if ( cchHead + cchTail >= (cchDst - 2) ) {// - 2 for / and null
  1163. Assert(FALSE);
  1164. szRet = NULL;
  1165. *szDst = 0;
  1166. }
  1167. else { // we know the whole thing is safe
  1168. lstrcpy(szDst, szHead);
  1169. lstrcpy(&szDst[cchHead], TEXT("\\"));
  1170. lstrcpy(&szDst[cchHead + 1], szTail);
  1171. }
  1172. return szRet;
  1173. }
  1174. BOOL IsCanonicalName( LPTSTR szName )
  1175. {
  1176. // simple test - if there's a ~ in it, it has a contraction in it
  1177. // and is therefore non-canonical
  1178. for ( ; *szName != '\0' && *szName != '~'; szName++ );
  1179. return *szName != '~';
  1180. };
  1181. struct RegPathName {
  1182. LPTSTR m_szName;
  1183. LPTSTR m_szCanonicalName;
  1184. RegPathName(void) : m_szName(NULL), m_szCanonicalName(NULL)
  1185. {};
  1186. ~RegPathName()
  1187. {
  1188. if ( m_szName )
  1189. delete m_szName;
  1190. if ( m_szCanonicalName )
  1191. delete m_szCanonicalName;
  1192. };
  1193. void MakeRegFriendly( LPTSTR szName )
  1194. {
  1195. TCHAR *pch;
  1196. // If szName is going to be a reg key name, we can't have it lookin' like a path
  1197. for ( pch = szName; *pch != '\0'; pch++ )
  1198. if ( *pch == '\\' ) *pch = '/';
  1199. }
  1200. void MakeFileSysFriendly( LPTSTR szName )
  1201. {
  1202. TCHAR *pch;
  1203. // change the slashes back into DOS
  1204. // directory \'s
  1205. for ( pch = szName; *pch != '\0'; pch++ )
  1206. if ( *pch == '/' ) *pch = '\\';
  1207. }
  1208. BOOL FSetCanonicalName(void)
  1209. {
  1210. BOOL fSet = FALSE;
  1211. TCHAR *szT = new TCHAR[MAX_PATH];
  1212. if ( m_szName != NULL && szT != NULL ) {
  1213. LPITEMIDLIST pidl = NULL;
  1214. // WE jump through some hoops to get the all-long
  1215. // name version of szName. First we convert it to
  1216. // an ITEMIDLIST.
  1217. // but first, we must change the slashes back into DOS
  1218. // directory \'s
  1219. MakeFileSysFriendly( m_szName );
  1220. if ( OCCGetLongPathName( szT, m_szName, MAX_PATH ) != 0 ) {
  1221. m_szCanonicalName = szT;
  1222. fSet = TRUE;
  1223. } else
  1224. delete [] szT;
  1225. // restore m_szName to it's registry-friendly form
  1226. MakeRegFriendly( m_szName );
  1227. } // if we can get our temp string
  1228. if ( fSet ) { // whatever its source, our canonical form has reversed slashes
  1229. MakeRegFriendly( m_szCanonicalName );
  1230. }
  1231. return fSet;
  1232. };
  1233. BOOL FSetName( LPTSTR szName, int cchName )
  1234. {
  1235. BOOL fSet = FALSE;
  1236. if ( m_szName != NULL ) {
  1237. delete m_szName;
  1238. m_szName = NULL;
  1239. }
  1240. if ( m_szCanonicalName != NULL ) {
  1241. delete m_szCanonicalName;
  1242. m_szCanonicalName = NULL;
  1243. }
  1244. // we got a short name, so szName is the short name
  1245. m_szName = new TCHAR[cchName + 1];
  1246. if ( m_szName != NULL ) {
  1247. lstrcpy( m_szName, szName );
  1248. fSet = FSetCanonicalName();
  1249. }
  1250. return fSet;
  1251. };
  1252. };
  1253. struct ModuleUsageKeys : public RegPathName {
  1254. ModuleUsageKeys *m_pmukNext;
  1255. HKEY m_hkeyShort; // key with the short file name name
  1256. ModuleUsageKeys(void) : m_pmukNext(NULL), m_hkeyShort(NULL) {};
  1257. ~ModuleUsageKeys(void)
  1258. {
  1259. if ( m_hkeyShort )
  1260. RegCloseKey( m_hkeyShort );
  1261. };
  1262. HRESULT MergeMU( HKEY hkeyCanon, HKEY hkeyMU )
  1263. {
  1264. HRESULT hr = E_FAIL;
  1265. DWORD dwIndex = 0;
  1266. DWORD cchNameMax;
  1267. DWORD cbValueMax;
  1268. if ( RegQueryInfoKey( m_hkeyShort,
  1269. NULL, NULL, NULL, NULL, NULL, NULL,
  1270. &dwIndex, &cchNameMax, &cbValueMax,
  1271. NULL, NULL ) == ERROR_SUCCESS ) {
  1272. LPTSTR szName = new TCHAR[cchNameMax + 1];
  1273. if (szName != NULL)
  1274. {
  1275. LPBYTE lpbValue = new BYTE[cbValueMax];
  1276. if (lpbValue != NULL)
  1277. {
  1278. // Examine each value.
  1279. for ( dwIndex--, hr = S_OK; (LONG)dwIndex >= 0 && SUCCEEDED(hr); dwIndex-- ) {
  1280. LONG lResult;
  1281. DWORD cchName = cchNameMax + 1;
  1282. DWORD dwType;
  1283. DWORD dwSize = cbValueMax;
  1284. // fetch key and value
  1285. lResult = RegEnumValue( m_hkeyShort,
  1286. dwIndex,
  1287. szName,
  1288. &cchName,
  1289. 0,
  1290. &dwType,
  1291. lpbValue,
  1292. &dwSize );
  1293. if ( lResult == ERROR_SUCCESS ) {
  1294. // Do not replace if the canonical entry already has a
  1295. // .Owner value that is "Unknown Owner"
  1296. if ( lstrcmp( szName, ".Owner" ) == 0 ) {
  1297. TCHAR szCanonValue[MAX_PATH];
  1298. DWORD dwType;
  1299. DWORD lcbCanonValue = MAX_PATH;
  1300. if ( RegQueryValueEx( hkeyCanon, ".Owner", NULL, &dwType,
  1301. (LPBYTE)szCanonValue, &lcbCanonValue ) == ERROR_SUCCESS &&
  1302. lstrcmp( szCanonValue, "Unknown Owner" ) == 0 )
  1303. continue;
  1304. }
  1305. // Add the value to the canonical version of the key
  1306. if ( RegSetValueEx( hkeyCanon, szName, NULL, dwType,
  1307. lpbValue, dwSize ) != ERROR_SUCCESS )
  1308. hr = E_FAIL;
  1309. } else
  1310. hr = E_FAIL;
  1311. } // for each value in the non-canoncical key
  1312. // Now we are finished with the non-canonical key
  1313. if ( SUCCEEDED(hr) &&
  1314. RegDeleteKey( hkeyMU, m_szName ) != ERROR_SUCCESS )
  1315. hr = E_FAIL;
  1316. }
  1317. else // lpbValue.
  1318. {
  1319. delete [] szName;
  1320. hr = E_OUTOFMEMORY;
  1321. }
  1322. }
  1323. else // szName
  1324. {
  1325. hr = E_OUTOFMEMORY;
  1326. }
  1327. }
  1328. return hr;
  1329. };
  1330. HRESULT MergeSharedDlls( HKEY hkeySD )
  1331. {
  1332. HRESULT hr = E_FAIL;
  1333. DWORD dwShortVal = 0;
  1334. DWORD dwCanonicalVal = 0;
  1335. DWORD dwType;
  1336. DWORD dwSize;
  1337. // The value names under shared DLLs are raw paths
  1338. MakeFileSysFriendly( m_szName );
  1339. MakeFileSysFriendly( m_szCanonicalName );
  1340. dwSize = sizeof(DWORD);
  1341. if ( RegQueryValueEx( hkeySD, m_szName, NULL,
  1342. &dwType, (LPBYTE)&dwShortVal, &dwSize ) == ERROR_SUCCESS &&
  1343. dwType == REG_DWORD ) {
  1344. dwCanonicalVal = 0;
  1345. dwSize = sizeof(DWORD);
  1346. // the canonical form may not be there, so we don't care if this
  1347. // fails.
  1348. RegQueryValueEx( hkeySD, m_szCanonicalName, NULL,
  1349. &dwType, (LPBYTE)&dwCanonicalVal, &dwSize );
  1350. dwCanonicalVal += dwShortVal;
  1351. dwSize = sizeof(DWORD);
  1352. if ( RegSetValueEx( hkeySD, m_szCanonicalName, NULL, REG_DWORD,
  1353. (LPBYTE)&dwCanonicalVal, dwSize ) == ERROR_SUCCESS ) {
  1354. RegDeleteValue( hkeySD, m_szName );
  1355. }
  1356. } else {
  1357. dwCanonicalVal = 1;
  1358. dwSize = sizeof(DWORD);
  1359. if ( RegSetValueEx( hkeySD, m_szCanonicalName, NULL, REG_DWORD,
  1360. (LPBYTE)&dwCanonicalVal, dwSize ) == ERROR_SUCCESS )
  1361. hr = S_OK;
  1362. }
  1363. MakeRegFriendly( m_szName );
  1364. MakeRegFriendly( m_szCanonicalName );
  1365. return hr;
  1366. }
  1367. HRESULT CanonicalizeMU( HKEY hkeyMU, HKEY hkeySD )
  1368. {
  1369. HRESULT hr = E_FAIL;
  1370. HKEY hkeyCanon;
  1371. LONG lResult = RegOpenKeyEx( hkeyMU, m_szCanonicalName, 0, KEY_ALL_ACCESS, &hkeyCanon);
  1372. if ( lResult != ERROR_SUCCESS )
  1373. lResult = RegCreateKey( hkeyMU,
  1374. m_szCanonicalName,
  1375. &hkeyCanon );
  1376. if ( lResult == ERROR_SUCCESS ) {
  1377. hr = MergeMU( hkeyCanon, hkeyMU );
  1378. if ( SUCCEEDED(hr) )
  1379. hr = MergeSharedDlls( hkeySD );
  1380. RegCloseKey( hkeyCanon );
  1381. } else
  1382. hr = E_FAIL;
  1383. return S_OK;
  1384. };
  1385. };
  1386. // FAddModuleUsageKeys adds a module usage key to the list.
  1387. BOOL FAddModuleUsageKeys( ModuleUsageKeys*&pmuk, // head of ModuleUsageKeys list
  1388. LPTSTR szName, // name of key value
  1389. DWORD cchName, // length of szName, minus null terminator
  1390. HKEY hkeyMU // hkey of parent
  1391. )
  1392. {
  1393. BOOL fAdd = FALSE;
  1394. ModuleUsageKeys* pmukNew;
  1395. HKEY hkeySub = NULL;
  1396. LRESULT lr;
  1397. pmukNew = new ModuleUsageKeys;
  1398. if ( pmukNew &&
  1399. (lr = RegOpenKeyEx( hkeyMU, szName, 0, KEY_ALL_ACCESS, &hkeySub)) == ERROR_SUCCESS ) {
  1400. fAdd = pmukNew->FSetName( szName, cchName );
  1401. if ( fAdd ) {
  1402. // append to head of the list
  1403. pmukNew->m_hkeyShort = hkeySub;
  1404. pmukNew->m_pmukNext = pmuk;
  1405. pmuk = pmukNew;
  1406. }
  1407. }
  1408. if ( !fAdd ) {
  1409. if ( hkeySub )
  1410. RegCloseKey( hkeySub );
  1411. if ( pmukNew != NULL )
  1412. delete pmukNew;
  1413. }
  1414. return fAdd;
  1415. }
  1416. EXTERN_C HRESULT
  1417. CanonicalizeModuleUsage(void)
  1418. {
  1419. HKEY hkeyMU = NULL;
  1420. HKEY hkeySD = NULL;
  1421. HRESULT hr = S_OK;
  1422. LONG lResult;
  1423. // get the main SHAREDDLLS key ready; this is never freed!
  1424. if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_SHAREDDLLS,
  1425. 0, KEY_ALL_ACCESS, &hkeySD)) == ERROR_SUCCESS &&
  1426. (lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_MODULE_USAGE,
  1427. 0, KEY_ALL_ACCESS, &hkeyMU)) == ERROR_SUCCESS )
  1428. {
  1429. DWORD dwIndex = 0;
  1430. ModuleUsageKeys *pmukUpdate = NULL; // records for values we want to update.
  1431. ModuleUsageKeys *pmuk;
  1432. ModuleUsageKeys *pmukNext;
  1433. // Examine each value.
  1434. do {
  1435. TCHAR szName[MAX_PATH]; // Value name
  1436. DWORD cchName = MAX_PATH;
  1437. FILETIME ftT;
  1438. // fetch key and value
  1439. lResult = RegEnumKeyEx( hkeyMU, dwIndex, szName, &cchName,
  1440. 0, NULL, NULL, &ftT );
  1441. if ( lResult == ERROR_SUCCESS ) {
  1442. if ( !IsCanonicalName( szName ) )
  1443. if ( !FAddModuleUsageKeys( pmukUpdate, szName, cchName, hkeyMU ) )
  1444. hr = E_OUTOFMEMORY;
  1445. dwIndex++;
  1446. } else if ( lResult == ERROR_NO_MORE_ITEMS )
  1447. hr = S_FALSE;
  1448. else
  1449. hr = E_FAIL;
  1450. } while ( hr == S_OK );
  1451. if ( SUCCEEDED(hr) ) {
  1452. hr = S_OK; // don't need S_FALSE any longer
  1453. for ( pmuk = pmukUpdate; pmuk != NULL; pmuk = pmukNext ) {
  1454. HRESULT hr2 = pmuk->CanonicalizeMU( hkeyMU, hkeySD );
  1455. if ( FAILED(hr2) )
  1456. hr = hr2;
  1457. pmukNext = pmuk->m_pmukNext;
  1458. delete pmuk;
  1459. } // for
  1460. } // if enumeration succeeded
  1461. } // if keys opened
  1462. if (hkeyMU)
  1463. RegCloseKey(hkeyMU);
  1464. if ( hkeySD )
  1465. RegCloseKey( hkeySD );
  1466. return hr;
  1467. }