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.

2399 lines
69 KiB

  1. #include <cdlpch.h>
  2. #pragma hdrstop
  3. #include "verp.h"
  4. #include <mstask.h>
  5. #include <pkgguid.h>
  6. extern LCID g_lcidBrowser; // default to english
  7. extern char g_szBrowserPrimaryLang[];
  8. // global that encapsulates delay-loaded version.dll
  9. CVersion g_versiondll;
  10. extern BOOL g_bRunOnWin95;
  11. HRESULT NeedForceLanguageCheck(HKEY hkeyCLSID, CLocalComponentInfo *plci);
  12. BOOL SniffStringFileInfo( LPSTR szFileName, LPCTSTR lpszSubblock, DWORD *pdw = NULL );
  13. HRESULT IsDistUnitLocallyInstalledSxS(LPCWSTR wszDistUnit, LPCWSTR wszClsid, DWORD dwFileVersionMS, DWORD dwFileVersionLS, CLocalComponentInfo * plci);
  14. void ExtractVersion(char *pszDistUnit, DWORD *pdwVerMS, DWORD *pdwVerLS);
  15. DWORD SearchPathA_Wrap(
  16. LPCSTR lpPath, // search path
  17. LPCSTR lpFileName, // file name
  18. LPCSTR lpExtension, // file extension
  19. DWORD nBufferLength, // size of buffer
  20. LPSTR lpBuffer, // found file name buffer
  21. LPSTR *lpFilePart // file component
  22. )
  23. {
  24. DWORD dwRet = SearchPath(lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart);
  25. //Trap the possible failures.
  26. if (dwRet && (dwRet < nBufferLength))
  27. {
  28. ASSERT(lpFilePart); //All the current calls to this definitely pass this in.
  29. if (! *lpFilePart)
  30. {
  31. //IE6 bug 19001
  32. // If a dir is passed in in lpFileName terminating with a "/", then this happens ->
  33. // to avoid the subsequent crash in MakeDestDir, make this point to the terminating
  34. // NULL character. This return value would have made better sense from SearchPath, methinx.
  35. *lpFilePart = lpBuffer+dwRet;
  36. }
  37. }
  38. else
  39. {
  40. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  41. dwRet = 0; //simulate failure even for insufficient buffer. Unlikely with INTERNET_MAX_PATH,
  42. // since we would have failed much before this in urlmon download code, but be safe
  43. // and not assume success as the code does prior to this.
  44. }
  45. return dwRet;
  46. }
  47. // ---------------------------------------------------------------------------
  48. // %%Function: CLocalComponentInfo::CLocalComponentInfo
  49. // ---------------------------------------------------------------------------
  50. CLocalComponentInfo::CLocalComponentInfo()
  51. {
  52. DEBUG_ENTER((DBG_DOWNLOAD,
  53. None,
  54. "CLocalComponentInfo::CLocalComponentInfo",
  55. "this=%#x",
  56. this
  57. ));
  58. szExistingFileName[0] = '\0';
  59. pBaseExistingFileName = NULL;
  60. lpDestDir = NULL;
  61. dwLocFVMS = 0;
  62. dwLocFVLS = 0;
  63. ftLastModified.dwLowDateTime = 0;
  64. ftLastModified.dwHighDateTime = 0;
  65. lcid = g_lcidBrowser;
  66. bForceLangGetLatest = FALSE;
  67. pbEtag = NULL;
  68. dwAvailMS = 0;
  69. dwAvailLS = 0;
  70. DEBUG_LEAVE(0);
  71. } // CLocalComponentInfo
  72. // ---------------------------------------------------------------------------
  73. // %%Function: CLocalComponentInfo::~CLocalComponentInfo
  74. // ---------------------------------------------------------------------------
  75. CLocalComponentInfo::~CLocalComponentInfo()
  76. {
  77. DEBUG_ENTER((DBG_DOWNLOAD,
  78. None,
  79. "CLocalComponentInfo::~CLocalComponentInfo",
  80. "this=%#x",
  81. this
  82. ));
  83. SAFEDELETE(lpDestDir);
  84. SAFEDELETE(pbEtag);
  85. DEBUG_LEAVE(0);
  86. } // ~CLocalComponentInfo
  87. // ---------------------------------------------------------------------------
  88. // %%Function: CLocalComponentInfo::MakeDestDir
  89. // ---------------------------------------------------------------------------
  90. HRESULT
  91. CLocalComponentInfo::MakeDestDir()
  92. {
  93. DEBUG_ENTER((DBG_DOWNLOAD,
  94. Hresult,
  95. "CLocalComponentInfo::MakeDestDir",
  96. "this=%#x",
  97. this
  98. ));
  99. HRESULT hr = S_OK;
  100. ASSERT(pBaseExistingFileName);
  101. if (szExistingFileName[0]) {
  102. DWORD cbLen = (DWORD) (pBaseExistingFileName - szExistingFileName);
  103. lpDestDir = new char[cbLen + 1];
  104. if (lpDestDir) {
  105. StrNCpy(lpDestDir, szExistingFileName, cbLen);
  106. } else {
  107. hr = E_OUTOFMEMORY;
  108. }
  109. }
  110. DEBUG_LEAVE(hr);
  111. return hr;
  112. } // ~MakeDestDir
  113. // ---------------------------------------------------------------------------
  114. // %%Function: CModuleUsage::CModuleUsage
  115. // CModuleUsage is the basic download obj.
  116. // ---------------------------------------------------------------------------
  117. CModuleUsage::CModuleUsage(LPCSTR szFileName, DWORD muflags, HRESULT *phr)
  118. {
  119. DEBUG_ENTER((DBG_DOWNLOAD,
  120. None,
  121. "CModuleUsage::CModuleUsage",
  122. "this=%#x, %.80q, %x, %#x",
  123. this, szFileName, muflags, phr
  124. ));
  125. m_szFileName = NULL;
  126. if (szFileName) {
  127. CHAR szCanonical[MAX_PATH];
  128. if ( CDLGetLongPathNameA( szCanonical, szFileName, MAX_PATH ) != 0 )
  129. m_szFileName = new char [lstrlen(szCanonical)+1];
  130. if (m_szFileName) {
  131. lstrcpy(m_szFileName, szCanonical);
  132. }
  133. else
  134. {
  135. // CDLGetLongPathName failed, so we are on a platform that
  136. // doesn't support it, and we can't guess what the right long
  137. // pathname is. Just use the short one
  138. m_szFileName = new char [lstrlen(szFileName)+1];
  139. if (m_szFileName) {
  140. lstrcpy(m_szFileName, szFileName);
  141. }
  142. else {
  143. *phr = E_OUTOFMEMORY;
  144. }
  145. }
  146. }
  147. m_dwFlags = muflags;
  148. DEBUG_LEAVE(0);
  149. } // CModuleUsage
  150. // ---------------------------------------------------------------------------
  151. // %%Function: CModuleUsage::~CModuleUsage
  152. // ---------------------------------------------------------------------------
  153. CModuleUsage::~CModuleUsage()
  154. {
  155. DEBUG_ENTER((DBG_DOWNLOAD,
  156. None,
  157. "CModuleUsage::~CModuleUsage",
  158. "this=%#x",
  159. this
  160. ));
  161. if (m_szFileName)
  162. SAFEDELETE(m_szFileName);
  163. DEBUG_LEAVE(0);
  164. } // ~CModuleUsage
  165. // ---------------------------------------------------------------------------
  166. // %%Function: CModuleUsage::Update(LPCSTR lpClientName)
  167. // ---------------------------------------------------------------------------
  168. HRESULT
  169. CModuleUsage::Update(LPCSTR lpClientName)
  170. {
  171. DEBUG_ENTER((DBG_DOWNLOAD,
  172. None,
  173. "CModuleUsage::Update",
  174. "this=%#x, %.80q",
  175. this, lpClientName
  176. ));
  177. HRESULT hr = ::UpdateModuleUsage(m_szFileName,
  178. lpClientName, NULL,
  179. m_dwFlags);
  180. DEBUG_LEAVE(hr);
  181. return hr;
  182. } // ~CModuleUsage
  183. HRESULT
  184. GetVersionHint(HKEY hkeyVersion, DWORD *pdwVersionMS, DWORD *pdwVersionLS)
  185. {
  186. DEBUG_ENTER((DBG_DOWNLOAD,
  187. Hresult,
  188. "GetVersionHint",
  189. "%#x, %#x, %#x",
  190. hkeyVersion, pdwVersionMS, pdwVersionLS
  191. ));
  192. DWORD Size = MAX_PATH;
  193. char szVersionBuf[MAX_PATH];
  194. DWORD dwType;
  195. HRESULT hr = S_OK;
  196. *pdwVersionMS = 0;
  197. *pdwVersionLS = 0;
  198. DWORD lResult = ::RegQueryValueEx(hkeyVersion, NULL, NULL, &dwType,
  199. (unsigned char *)szVersionBuf, &Size);
  200. if (lResult != ERROR_SUCCESS) {
  201. // value not found, consider this is always with bad/low version
  202. // of InstalledVersion
  203. hr = S_FALSE;
  204. goto Exit;
  205. }
  206. if ( FAILED(GetVersionFromString(szVersionBuf, pdwVersionMS, pdwVersionLS))){
  207. hr = S_FALSE;
  208. }
  209. Exit:
  210. DEBUG_LEAVE(hr);
  211. return hr;
  212. }
  213. /*******************************************************************
  214. NAME: CheckInstalledVersionHint
  215. SYNOPSIS: Checks for key InstalledVersion under {...}
  216. If no key then we fail
  217. once key is present we check version numbers
  218. S_OK: local version is good enough
  219. S_FALSE: need update:
  220. ERROR: not applicable, caller proceeds with InProcServer32
  221. check.
  222. [HKCR:clsid]
  223. [{...}]
  224. [InstalledVersion]
  225. Deafult "1,0,0,1"
  226. Path "c:\foo\foo.ocx"
  227. The Path is optional, if find we will req update id
  228. file pointed to by path is missing on client. This is a
  229. way to robustify if user deletes the file on disk but
  230. not the regsitry (unclean uninstall)
  231. In this case update is needed
  232. ********************************************************************/
  233. HRESULT
  234. CheckInstalledVersionHint(
  235. HKEY hKeyEmbedding,
  236. CLocalComponentInfo *plci,
  237. DWORD dwFileVersionMS,
  238. DWORD dwFileVersionLS)
  239. {
  240. DEBUG_ENTER((DBG_DOWNLOAD,
  241. Hresult,
  242. "CheckInstalledVersionHint",
  243. "%#x, %#x, %x, %x",
  244. hKeyEmbedding, plci, dwFileVersionMS, dwFileVersionLS
  245. ));
  246. HRESULT hr = S_OK;
  247. DWORD Size = MAX_PATH;
  248. DWORD dwType =0;
  249. LONG lResult = ERROR_SUCCESS;
  250. const static char * szInstalledVersion = "InstalledVersion";
  251. const static char * szAvailableVersion = "AvailableVersion";
  252. const static char * szPATH = "Path";
  253. const static char * szLASTMODIFIED = "LastModified";
  254. const static char * szETAG = "Etag";
  255. char szVersionBuf[MAX_PATH];
  256. char szFileName[MAX_PATH];
  257. HKEY hKeyVersion = 0;
  258. HKEY hkeyAvailableVersion = 0;
  259. DWORD dwLocFVMS = 0;
  260. DWORD dwLocFVLS = 0;
  261. char szLastMod[INTERNET_RFC1123_BUFSIZE+1];
  262. if (RegOpenKeyEx(hKeyEmbedding, szAvailableVersion, 0,
  263. KEY_READ, &hkeyAvailableVersion) == ERROR_SUCCESS) {
  264. DWORD dwAvailMS = 0;
  265. DWORD dwAvailLS = 0;
  266. if ( GetVersionHint(hkeyAvailableVersion, &dwAvailMS, &dwAvailLS) == S_OK){
  267. plci->dwAvailMS = dwAvailMS;
  268. plci->dwAvailLS = dwAvailLS;
  269. }
  270. }
  271. lResult = ::RegOpenKeyEx(hKeyEmbedding, szInstalledVersion, 0,
  272. KEY_READ, &hKeyVersion);
  273. if (lResult != ERROR_SUCCESS) {
  274. // key not found, consider this is regular ActiveX with no hint
  275. // of InstalledVersion
  276. hr = HRESULT_FROM_WIN32(lResult);
  277. goto Exit;
  278. }
  279. if ( GetVersionHint(hKeyVersion, &dwLocFVMS, &dwLocFVLS) == S_FALSE){
  280. hr = S_FALSE;
  281. goto Exit;
  282. }
  283. plci->dwLocFVMS = dwLocFVMS;
  284. plci->dwLocFVLS = dwLocFVLS;
  285. Size = INTERNET_RFC1123_BUFSIZE + 1;
  286. lResult = ::RegQueryValueEx(hKeyVersion, szLASTMODIFIED, NULL, &dwType,
  287. (unsigned char *)szLastMod, &Size);
  288. if (lResult == ERROR_SUCCESS) {
  289. SYSTEMTIME st;
  290. FILETIME ft;
  291. // convert intenet time to file time
  292. if (InternetTimeToSystemTimeA(szLastMod, &st, 0) &&
  293. SystemTimeToFileTime(&st, &ft) ) {
  294. memcpy(&(plci->ftLastModified), &ft, sizeof(FILETIME));
  295. }
  296. }
  297. Size = 0;
  298. lResult = ::RegQueryValueEx(hKeyVersion, szETAG, NULL, &dwType,
  299. (unsigned char *)NULL, &Size);
  300. if (lResult == ERROR_SUCCESS) {
  301. char *pbEtag = new char [Size];
  302. if (pbEtag) {
  303. lResult = ::RegQueryValueEx(hKeyVersion, szETAG, NULL, &dwType,
  304. (unsigned char *)pbEtag, &Size);
  305. if (lResult == ERROR_SUCCESS)
  306. plci->pbEtag = pbEtag;
  307. else
  308. delete pbEtag;
  309. }
  310. }
  311. // check file versions
  312. if ((dwFileVersionMS > dwLocFVMS) ||
  313. ((dwFileVersionMS == dwLocFVMS) &&
  314. (dwFileVersionLS > dwLocFVLS)))
  315. hr = S_FALSE;
  316. if (hr == S_OK) {
  317. // if we seem to have the right version
  318. // check if the file physically exists on disk
  319. // the software can specify this by having a PATH="c:\foo\foo.class"
  320. // if present we will check for physical file existance
  321. dwType = 0;
  322. Size = MAX_PATH;
  323. lResult = ::SHQueryValueEx(hKeyVersion, szPATH, NULL, &dwType,
  324. (unsigned char *)szFileName, &Size);
  325. if (lResult != ERROR_SUCCESS)
  326. goto Exit;
  327. // value present, check if file is present
  328. if (GetFileAttributes(szFileName) == -1) {
  329. // if file is not physically present then clear out our
  330. // local file version. this comes in the way of doing
  331. // get latest. (ie get latest will assume that if a local file
  332. // is present then do If-Modified-Since
  333. plci->dwLocFVMS = 0;
  334. plci->dwLocFVLS = 0;
  335. hr = S_FALSE;
  336. }
  337. }
  338. Exit:
  339. if (hKeyVersion)
  340. ::RegCloseKey(hKeyVersion);
  341. if (hkeyAvailableVersion)
  342. ::RegCloseKey(hkeyAvailableVersion);
  343. DEBUG_LEAVE(hr);
  344. return hr;
  345. }
  346. HRESULT
  347. CreateJavaPackageManager(IJavaPackageManager **ppPackageManager)
  348. {
  349. DEBUG_ENTER((DBG_DOWNLOAD,
  350. Hresult,
  351. "CreateJavaPackageManager",
  352. "%#x",
  353. ppPackageManager
  354. ));
  355. HRESULT hr = S_OK;
  356. Assert(ppPackageManager);
  357. if (!(*ppPackageManager)) {
  358. ICreateJavaPackageMgr *picjpm;
  359. hr=CoCreateInstance(CLSID_JavaPackageManager,NULL,(CLSCTX_INPROC_SERVER),
  360. IID_ICreateJavaPackageMgr,(LPVOID *) &picjpm);
  361. if (SUCCEEDED(hr)) {
  362. hr = picjpm->GetPackageManager(ppPackageManager);
  363. picjpm->Release();
  364. }
  365. }
  366. DEBUG_LEAVE(hr);
  367. return hr;
  368. }
  369. HRESULT
  370. IsPackageLocallyInstalled(IJavaPackageManager **ppPackageManager, LPCWSTR szPackageName,
  371. LPCWSTR szNameSpace, DWORD dwVersionMS, DWORD dwVersionLS)
  372. {
  373. DEBUG_ENTER((DBG_DOWNLOAD,
  374. Hresult,
  375. "IsPackageLocallyInstalled",
  376. "%#x, %.80wq, %.80wq, %x, %x",
  377. ppPackageManager, szPackageName, szNameSpace, dwVersionMS, dwVersionLS
  378. ));
  379. HRESULT hr = S_OK; // assume Ok!
  380. IJavaPackage *pJavaPkg = NULL;
  381. DWORD dwLocMS = 0;
  382. DWORD dwLocLS = 0;
  383. Assert(ppPackageManager);
  384. if (!(*ppPackageManager)) {
  385. hr = CreateJavaPackageManager(ppPackageManager);
  386. if (FAILED(hr))
  387. goto Exit;
  388. }
  389. if (SUCCEEDED((*ppPackageManager)->GetPackage(szPackageName, szNameSpace, &pJavaPkg))) {
  390. Assert(pJavaPkg);
  391. pJavaPkg->GetVersion(&dwLocMS, &dwLocLS);
  392. if ((dwVersionMS > dwLocMS) ||
  393. ((dwVersionMS == dwLocMS) &&
  394. (dwVersionLS > dwLocLS)))
  395. hr = S_FALSE;
  396. BSTR bstrFileName = NULL;
  397. if (SUCCEEDED(pJavaPkg->GetFilePath(&bstrFileName))) {
  398. // check if file really exists
  399. LPSTR szFileName = NULL;
  400. if (SUCCEEDED(Unicode2Ansi(bstrFileName, &szFileName))) {
  401. if (GetFileAttributes(szFileName) == -1)
  402. hr = S_FALSE;
  403. } else {
  404. hr = S_FALSE;
  405. }
  406. } else {
  407. hr = S_FALSE;
  408. }
  409. SAFESYSFREESTRING(bstrFileName);
  410. SAFERELEASE(pJavaPkg);
  411. } else {
  412. hr = S_FALSE;
  413. }
  414. Exit:
  415. DEBUG_LEAVE(hr);
  416. return hr;
  417. }
  418. HRESULT
  419. AreNameSpacePackagesIntact(HKEY hkeyJava, LPCWSTR lpwszNameSpace, IJavaPackageManager **ppPackageManager)
  420. {
  421. DEBUG_ENTER((DBG_DOWNLOAD,
  422. Hresult,
  423. "AreNameSpacePackagesIntact",
  424. "%#x, %.80wq, %#x",
  425. hkeyJava, lpwszNameSpace, ppPackageManager
  426. ));
  427. int iValue = 0;
  428. DWORD dwType = REG_SZ;
  429. DWORD dwValueSize = MAX_PATH;
  430. char szPkgName[MAX_PATH];
  431. HRESULT hr = S_OK;
  432. while (
  433. RegEnumValue(hkeyJava, iValue++, szPkgName, &dwValueSize, 0,
  434. &dwType, NULL, NULL) == ERROR_SUCCESS) {
  435. LPWSTR lpwszPkgName = NULL;
  436. dwValueSize = MAX_PATH; // reset
  437. if ( (Ansi2Unicode(szPkgName,&lpwszPkgName) == S_OK)
  438. && ((IsPackageLocallyInstalled
  439. (ppPackageManager, lpwszPkgName, lpwszNameSpace, 0,0) != S_OK)) ) {
  440. hr = S_FALSE;
  441. SAFEDELETE(lpwszPkgName);
  442. break;
  443. }
  444. SAFEDELETE(lpwszPkgName);
  445. }
  446. DEBUG_LEAVE(hr);
  447. return hr;
  448. }
  449. HRESULT
  450. ArePackagesIntact(HKEY hkeyContains)
  451. {
  452. DEBUG_ENTER((DBG_DOWNLOAD,
  453. Hresult,
  454. "ArePackagesIntact",
  455. "%#x",
  456. hkeyContains
  457. ));
  458. HRESULT hr = S_OK;
  459. HKEY hkeyJava = 0;
  460. const static char * szJava = "Java";
  461. IJavaPackageManager *pPackageManager = NULL;
  462. DWORD iSubKey = 0;
  463. DWORD dwSize = MAX_PATH;
  464. DWORD lResult;
  465. char szNameSpace[MAX_PATH];
  466. // first validate pkgs in the global namespace
  467. if (RegOpenKeyEx( hkeyContains, szJava,
  468. 0, KEY_READ, &hkeyJava) == ERROR_SUCCESS) {
  469. hr = AreNameSpacePackagesIntact(hkeyJava, NULL, &pPackageManager);
  470. if (hr != S_OK)
  471. goto Exit;
  472. } else {
  473. goto Exit;
  474. }
  475. // validate pkgs in each of other namespaces, if any
  476. while ( (lResult = RegEnumKeyEx(hkeyJava, iSubKey++, szNameSpace, &dwSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) {
  477. dwSize = MAX_PATH;
  478. HKEY hkeyNameSpace = 0;
  479. if (RegOpenKeyEx( hkeyJava, szNameSpace,
  480. 0, KEY_READ, &hkeyNameSpace) == ERROR_SUCCESS) {
  481. LPWSTR lpwszNameSpace = NULL;
  482. if (Ansi2Unicode(szNameSpace,&lpwszNameSpace) == S_OK)
  483. hr = AreNameSpacePackagesIntact(hkeyNameSpace, lpwszNameSpace,
  484. &pPackageManager);
  485. SAFEDELETE(lpwszNameSpace);
  486. RegCloseKey(hkeyNameSpace);
  487. if (hr != S_OK)
  488. goto Exit;
  489. }
  490. }
  491. if (lResult != ERROR_NO_MORE_ITEMS) {
  492. hr = HRESULT_FROM_WIN32(lResult);
  493. //FALLTHRU goto Exit;
  494. }
  495. Exit:
  496. SAFERELEASE(pPackageManager);
  497. if (hkeyJava)
  498. RegCloseKey(hkeyJava);
  499. DEBUG_LEAVE(hr);
  500. return hr;
  501. }
  502. /*******************************************************************
  503. NAME: IsDistUnitLocallyInstalled
  504. SYNOPSIS: S_OK - distribution is installed correctly
  505. S_FALSE - distribution unit entry exists, but not installed
  506. or installed incorrectly
  507. E_FAIL - distribution unit doesn't exit (no entry for it)
  508. ********************************************************************/
  509. HRESULT
  510. IsDistUnitLocallyInstalled(
  511. LPCWSTR szDistUnit,
  512. DWORD dwFileVersionMS,
  513. DWORD dwFileVersionLS,
  514. CLocalComponentInfo *plci,
  515. LPSTR szDestDirHint,
  516. LPBOOL pbParanoidCheck,
  517. DWORD flags)
  518. {
  519. DEBUG_ENTER((DBG_DOWNLOAD,
  520. Hresult,
  521. "IsDistUnitLocallyInstalled",
  522. "%.80wq, %x, %x, %#x, %.80q, %#x, %x",
  523. szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, pbParanoidCheck, flags
  524. ));
  525. LPSTR pszDist = NULL;
  526. HRESULT hr = S_FALSE;
  527. HKEY hkeyDist = 0, hkeyThisDist = 0;
  528. HKEY hkeyContains = 0;
  529. HKEY hkeyFiles = 0;
  530. HKEY hkeyDepends = 0;
  531. const static char * szContains = "Contains";
  532. const static char * szFiles = "Files";
  533. const static char * szDistUnitStr = "Distribution Units";
  534. LONG lResult = ERROR_SUCCESS;
  535. char szFileName[MAX_PATH];
  536. ULONG cbSize = MAX_PATH;
  537. DWORD dwType = REG_SZ;
  538. if (pbParanoidCheck) {
  539. *pbParanoidCheck = FALSE;
  540. }
  541. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DIST_UNITS,
  542. 0, KEY_READ, &hkeyDist);
  543. if (lResult != ERROR_SUCCESS)
  544. {
  545. hr = HRESULT_FROM_WIN32(REGDB_E_KEYMISSING);
  546. goto Exit;
  547. }
  548. if (FAILED((hr=::Unicode2Ansi(szDistUnit, &pszDist))))
  549. {
  550. goto Exit;
  551. }
  552. hr = S_FALSE; // reset to NOT found
  553. // Open the key for this embedding:
  554. lResult = ::RegOpenKeyEx(hkeyDist, pszDist, 0, KEY_READ,
  555. &hkeyThisDist);
  556. if (lResult == ERROR_SUCCESS) {
  557. hr = CheckInstalledVersionHint( hkeyThisDist, plci,
  558. dwFileVersionMS, dwFileVersionLS);
  559. }
  560. else
  561. {
  562. hr = HRESULT_FROM_WIN32(REGDB_E_KEYMISSING);
  563. goto Exit;
  564. }
  565. if (hr == S_OK || (SUCCEEDED(hr) && dwFileVersionMS == -1 && dwFileVersionLS == -1)) {
  566. if (RegOpenKeyEx( hkeyThisDist, szContains,
  567. 0, KEY_READ, &hkeyContains) == ERROR_SUCCESS) {
  568. if (pbParanoidCheck) {
  569. *pbParanoidCheck = TRUE;
  570. }
  571. // BUGBUG: only do if paranoid flag on?
  572. // assert dependency state installed correctly on machine
  573. // this is where we would have to walk the dependecy tree
  574. // as well as make sure the contained packages and files
  575. // are indeed availabel on the client machine
  576. // BUGBUG: maybe we should only do this in paranoid mode
  577. // instead of all the time.
  578. if (RegOpenKeyEx( hkeyContains, szDistUnitStr,
  579. 0, KEY_READ, &hkeyDepends) == ERROR_SUCCESS ) {
  580. int iSubKey = 0;
  581. while (RegEnumValue(hkeyDepends, iSubKey++,
  582. szFileName, &cbSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  583. CLocalComponentInfo lci;
  584. LPWSTR wszFileName = 0;
  585. CLSID clsidTemp;
  586. if (FAILED(Ansi2Unicode(szFileName, &wszFileName)))
  587. break;
  588. clsidTemp = CLSID_NULL;
  589. if (wszFileName)
  590. CLSIDFromString(wszFileName, &clsidTemp);
  591. // if above call fails DistUnit is not clsid
  592. if (IsControlLocallyInstalled(NULL, &clsidTemp, wszFileName, 0,0, &lci, NULL) != S_OK) {
  593. SAFEDELETE(wszFileName);
  594. plci->dwLocFVMS = 0;
  595. plci->dwLocFVLS = 0;
  596. hr = S_FALSE;
  597. goto Exit;
  598. }
  599. SAFEDELETE(wszFileName);
  600. cbSize = MAX_PATH;
  601. }
  602. }
  603. if (RegOpenKeyEx( hkeyContains, szFiles,
  604. 0, KEY_READ, &hkeyFiles) == ERROR_SUCCESS) {
  605. int iValue = 0;
  606. DWORD dwType = REG_SZ;
  607. DWORD dwValueSize = MAX_PATH;
  608. while (RegEnumValue(hkeyFiles, iValue++,
  609. szFileName, &dwValueSize, 0, &dwType, NULL, NULL) == ERROR_SUCCESS) {
  610. dwValueSize = MAX_PATH; // reset
  611. if (GetFileAttributes(szFileName) == -1) {
  612. // if file is not physically present then clear out our
  613. // local file version. this comes in the way of doing
  614. // get latest. (get latest will assume that if a local
  615. // file is present then do If-Modified-Since
  616. plci->dwLocFVMS = 0;
  617. plci->dwLocFVLS = 0;
  618. hr = S_FALSE;
  619. goto Exit;
  620. }
  621. }
  622. }
  623. if (ArePackagesIntact(hkeyContains) == S_FALSE) {
  624. plci->dwLocFVMS = 0;
  625. plci->dwLocFVLS = 0;
  626. hr = S_FALSE;
  627. goto Exit;
  628. }
  629. }
  630. } else {
  631. hr = S_FALSE; // mark not present, don't error out
  632. }
  633. Exit:
  634. if (pszDist)
  635. delete pszDist;
  636. if (hkeyDepends)
  637. ::RegCloseKey(hkeyDepends);
  638. if (hkeyFiles)
  639. ::RegCloseKey(hkeyFiles);
  640. if (hkeyContains)
  641. ::RegCloseKey(hkeyContains);
  642. if (hkeyThisDist)
  643. ::RegCloseKey(hkeyThisDist);
  644. if (hkeyDist)
  645. ::RegCloseKey(hkeyDist);
  646. DEBUG_LEAVE(hr);
  647. return hr;
  648. }
  649. HRESULT
  650. IsFileLocallyInstalled(
  651. LPSTR lpCurCode,
  652. DWORD dwFileVersionMS,
  653. DWORD dwFileVersionLS,
  654. CLocalComponentInfo *plci,
  655. LPSTR szDestDirHint,
  656. BOOL bExactVersion
  657. )
  658. {
  659. DEBUG_ENTER((DBG_DOWNLOAD,
  660. Hresult,
  661. "IsFileLocallyInstalled",
  662. "%.80q, %x, %x, %#x, %.80q, %B",
  663. lpCurCode, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, bExactVersion
  664. ));
  665. HRESULT hr = S_FALSE;
  666. // no clsid, but we have a file name
  667. // first check for a file of the same name in DestDirHint.
  668. // This is the directory that the main OCX file existed on
  669. // and so should be checked first.
  670. // In case this is a new install this will point to the
  671. // suggested destination dir for the DLL.
  672. if (szDestDirHint) {
  673. if (SearchPathA_Wrap( szDestDirHint,
  674. lpCurCode, NULL, MAX_PATH,
  675. plci->szExistingFileName, &(plci->pBaseExistingFileName))) {
  676. // check fileversion to see if update reqd.
  677. hr = LocalVersionOK(0,plci,dwFileVersionMS, dwFileVersionLS, bExactVersion);
  678. goto Exit;
  679. }
  680. }
  681. // file not found in suggested destination. Look in system searchpath
  682. // SearchPath for this filename
  683. if (!(SearchPathA_Wrap( NULL, lpCurCode, NULL, MAX_PATH,
  684. plci->szExistingFileName, &(plci->pBaseExistingFileName)))) {
  685. hr = S_FALSE;
  686. goto Exit;
  687. }
  688. // check fileversion to see if update reqd.
  689. hr = LocalVersionOK(0,plci,dwFileVersionMS, dwFileVersionLS, bExactVersion);
  690. Exit:
  691. DEBUG_LEAVE(hr);
  692. return hr;
  693. }
  694. BOOL GetEXEName(LPSTR szCmdLine)
  695. {
  696. DEBUG_ENTER((DBG_DOWNLOAD,
  697. Bool,
  698. "GetEXEName",
  699. "%.80q",
  700. szCmdLine
  701. ));
  702. Assert(szCmdLine);
  703. LPSTR pchStartBaseName = szCmdLine;
  704. BOOL bFullyQualified = FALSE;
  705. BOOL bHasSpaces = FALSE;
  706. char *pch;
  707. if (*szCmdLine == '"') {
  708. szCmdLine++;
  709. char *pszEnd = StrStrA(szCmdLine, "\"");
  710. ASSERT(pszEnd);
  711. *pszEnd = '\0';
  712. if (GetFileAttributes(szCmdLine) != -1) {
  713. //found the EXE name, but got to get rid of the first quote
  714. szCmdLine--; // step back to the "
  715. while (*szCmdLine) {
  716. *szCmdLine = *(szCmdLine + 1);
  717. szCmdLine++;
  718. }
  719. DEBUG_LEAVE(TRUE);
  720. return TRUE;
  721. }
  722. szCmdLine--; // step back to the "
  723. while (*szCmdLine) {
  724. *szCmdLine = *(szCmdLine + 1);
  725. szCmdLine++;
  726. }
  727. DEBUG_LEAVE(FALSE);
  728. return FALSE;
  729. }
  730. // skip past the directory if fully qualified.
  731. for (pch = szCmdLine; *pch; pch++) {
  732. if (*pch == '\\')
  733. pchStartBaseName = pch;
  734. if ( (*pch == ' ') || (*pch == '\t') )
  735. bHasSpaces = TRUE;
  736. }
  737. if (!bHasSpaces) {
  738. if (GetFileAttributes(szCmdLine) != -1) {
  739. //found the EXE name, it is already in szCmdLine
  740. DEBUG_LEAVE(TRUE);
  741. return TRUE;
  742. }
  743. DEBUG_LEAVE(FALSE);
  744. return FALSE;
  745. }
  746. // pchStartBaseName now points at the last '\\' if any
  747. if (*pchStartBaseName == '\\') {
  748. pchStartBaseName++;
  749. bFullyQualified = TRUE;
  750. }
  751. // pchStartBaseName no points at the base name of the EXE.
  752. // Now look for spaces. When we find a space we will
  753. // replace with a '\0' and check if the cmd line is valid.
  754. // if valid, this must be the EXE name, return
  755. // if not valid, march on to do the same. when we finish
  756. // examining all of the cmd line, or no more spaces, likely the
  757. // EXE is missing.
  758. for (pch = pchStartBaseName; *pch != '\0'; pch++) {
  759. if ( (*pch == ' ') || (*pch == '\t') ) {
  760. char chTemp = *pch; // sacve the white spc char
  761. *pch = '\0'; // stomp the spc with nul. now we have in szCmdLine
  762. // what could be the full EXE name
  763. if (bFullyQualified) {
  764. if (GetFileAttributes(szCmdLine) != -1) {
  765. //found the EXE name, it is already in szCmdLine
  766. DEBUG_LEAVE(TRUE);
  767. return TRUE;
  768. }
  769. } else {
  770. char szBuf[MAX_PATH];
  771. LPSTR pBaseFileName;
  772. if (SearchPathA_Wrap( NULL, szCmdLine, NULL, MAX_PATH,
  773. szBuf, &pBaseFileName)) {
  774. //found the EXE name, it is already in szCmdLine
  775. DEBUG_LEAVE(TRUE);
  776. return TRUE;
  777. }
  778. }
  779. *pch = chTemp; // restore the while spc and move past.
  780. }
  781. }
  782. DEBUG_LEAVE(FALSE);
  783. return FALSE;
  784. }
  785. BOOL
  786. AdviseForceDownload(const LPCLSID lpclsid, DWORD dwClsContext)
  787. {
  788. DEBUG_ENTER((DBG_DOWNLOAD,
  789. Bool,
  790. "AdviseForceDownload",
  791. "%#x, %x",
  792. lpclsid, dwClsContext
  793. ));
  794. HRESULT hr = S_OK;
  795. BOOL bNullClsid = lpclsid?IsEqualGUID(*lpclsid , CLSID_NULL):TRUE;
  796. HKEY hKeyClsid = 0;
  797. HKEY hKeyEmbedding = 0;
  798. HKEY hkeyDist = 0;
  799. BOOL bForceDownload = TRUE;
  800. LPOLESTR pwcsClsid = NULL;
  801. DWORD dwType;
  802. LONG lResult = ERROR_SUCCESS;
  803. static char * szAppID = "AppID";
  804. LPSTR pszClsid = NULL;
  805. CLocalComponentInfo lci;
  806. static char * szInprocServer32 = "InProcServer32";
  807. static char * szLocalServer32 = "LocalServer32";
  808. if (bNullClsid)
  809. goto Exit;
  810. // return if we can't get a valid string representation of the CLSID
  811. if (FAILED((hr=StringFromCLSID(*lpclsid, &pwcsClsid))))
  812. goto Exit;
  813. Assert(pwcsClsid != NULL);
  814. if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &pszClsid))))
  815. {
  816. goto Exit;
  817. }
  818. // Open root HKEY_CLASSES_ROOT\CLSID key
  819. lResult = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hKeyClsid);
  820. if (lResult == ERROR_SUCCESS)
  821. {
  822. // Open the key for this embedding:
  823. lResult = ::RegOpenKeyEx(hKeyClsid, pszClsid, 0, KEY_READ,
  824. &hKeyEmbedding);
  825. if (lResult == ERROR_SUCCESS) {
  826. // check for hint of FileVersion before actually getting FileVersion
  827. // This way non-PE files, like Java, random data etc. can be
  828. // accomodated with CODEBASE= with proper version checking.
  829. // If they are not really COM object then they can't be
  830. // instantiated by COM or us (if object needed). But if they
  831. // use AsyncGetClassBits(no object instantiated) or from the
  832. // browser give height=0 width=0, the browser will not
  833. // report placeholders with errors, so they can work gracefully
  834. // overloading the object tag to do version checking and
  835. // random stuff
  836. hr = CheckInstalledVersionHint( hKeyEmbedding, &lci,
  837. 0, 0);
  838. // if the key is found and
  839. // if the latest version is not available then
  840. // return now with false, if right version is already
  841. // present return. If the key is missing then we
  842. // proceed with checks for InprocServer32/LocalServer32
  843. if (SUCCEEDED(hr)) {
  844. // if using installed version hint and the verdict is
  845. // local good enough
  846. if (hr == S_OK)
  847. bForceDownload = FALSE;
  848. goto Exit;
  849. }
  850. hr = S_OK; // reset
  851. // ckeck if DCOM
  852. HKEY hKeyAppID;
  853. lResult = ::RegOpenKeyEx(hKeyEmbedding, szAppID, 0,
  854. KEY_READ, &hKeyAppID);
  855. if (lResult == ERROR_SUCCESS) {
  856. // DCOM
  857. // just assume that this is the latest version already
  858. // we never attempt code download for dcom
  859. bForceDownload = FALSE; // no force download for DCOM
  860. RegCloseKey(hKeyAppID);
  861. goto Exit;
  862. }
  863. HKEY hKeyInProc;
  864. lResult = ::RegOpenKeyEx(hKeyEmbedding, szInprocServer32, 0,
  865. KEY_READ, &hKeyInProc);
  866. if (lResult != ERROR_SUCCESS) {
  867. if (RegOpenKeyEx(hKeyEmbedding, szLocalServer32, 0,
  868. KEY_READ, &hKeyInProc) == ERROR_SUCCESS) {
  869. // specific look for vb doc obj hack where they just use
  870. // the OBJECT tag to do code download, but not hosting
  871. // no inproc but we have localserver
  872. // we could have failed because we pass the wrong clsctx
  873. RegCloseKey(hKeyInProc);
  874. if (!(dwClsContext & CLSCTX_LOCAL_SERVER))
  875. bForceDownload = FALSE;
  876. }
  877. } else {
  878. RegCloseKey(hKeyInProc);
  879. }
  880. }
  881. }
  882. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DIST_UNITS,
  883. 0, KEY_READ, &hkeyDist);
  884. if (lResult == ERROR_SUCCESS)
  885. {
  886. // Open the key for this embedding:
  887. HKEY hkeyThisDist = 0;
  888. if (RegOpenKeyEx(hkeyDist, pszClsid, 0, KEY_READ,
  889. &hkeyThisDist) == ERROR_SUCCESS) {
  890. HKEY hkeyJava = 0;
  891. if (RegOpenKeyEx(hkeyThisDist, "Contains\\Java", 0, KEY_READ,
  892. &hkeyJava) == ERROR_SUCCESS) {
  893. bForceDownload = FALSE;
  894. RegCloseKey(hkeyJava);
  895. }
  896. RegCloseKey(hkeyThisDist);
  897. }
  898. RegCloseKey(hkeyDist);
  899. }
  900. Exit:
  901. if (pwcsClsid)
  902. delete pwcsClsid;
  903. if (pszClsid)
  904. delete pszClsid;
  905. if (hKeyClsid)
  906. ::RegCloseKey(hKeyClsid);
  907. if (hKeyEmbedding)
  908. ::RegCloseKey(hKeyEmbedding);
  909. DEBUG_LEAVE(bForceDownload);
  910. return bForceDownload;
  911. }
  912. /*******************************************************************
  913. NAME: IsControlLocallyInstalled
  914. SYNOPSIS: Indicates whether the provided CLSID represents an
  915. OLE control.
  916. If no clsid provided then checks to see if lpCurCode
  917. exists in system and checks file version to verify if
  918. update is needed
  919. ********************************************************************/
  920. HRESULT
  921. IsControlLocallyInstalled(LPSTR lpCurCode, const LPCLSID lpclsid,
  922. LPCWSTR szDistUnit,
  923. DWORD dwFileVersionMS, DWORD dwFileVersionLS,
  924. CLocalComponentInfo *plci,
  925. LPSTR szDestDirHint,
  926. BOOL bExactVersion)
  927. {
  928. DEBUG_ENTER((DBG_DOWNLOAD,
  929. Hresult,
  930. "IsControlLocallyInstalled",
  931. "%.80q, %#x, %.80wq, %x, %x, %#x, %.80q, %B",
  932. lpCurCode, lpclsid, szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, bExactVersion
  933. ));
  934. HRESULT hr1, hr2, hrResult, hr = S_FALSE;
  935. BOOL bNullClsid = lpclsid?IsEqualGUID(*lpclsid , CLSID_NULL):TRUE;
  936. BOOL bParanoidCheck = FALSE;
  937. if ( bNullClsid && (lpCurCode == NULL) && (szDistUnit == NULL) ) {
  938. hr = E_INVALIDARG;
  939. goto Exit;
  940. }
  941. // hr1: HRESULT for whether the dist unit is installed
  942. // hr2: HRESULT for whether the particular clsid is installed
  943. // hrResult: HRESULT for whether the particular clsid is present (but not necessarily installed correctly)
  944. if (szDistUnit) {
  945. hr1 = IsDistUnitLocallyInstalled( szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, &bParanoidCheck, 0);
  946. } else {
  947. if (bNullClsid)
  948. {
  949. hr1 = IsFileLocallyInstalled( lpCurCode, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, bExactVersion);
  950. // if no dist unit name or clsid and this is
  951. // clearly just checking for dependent file then
  952. // no need to fall thru and check the com br as well
  953. hr = hr1;
  954. goto Exit;
  955. }
  956. else
  957. {
  958. hr1 = E_FAIL;
  959. }
  960. }
  961. hr2 = IsCLSIDLocallyInstalled( lpCurCode, lpclsid, szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, &hrResult , bExactVersion);
  962. if (hr2 != S_OK)
  963. {
  964. // if HKLM\CLSID\{CLSID} existed, but control wasn't there, we fail with that error
  965. // otherwise we fail with hr1.
  966. if (SUCCEEDED(hrResult))
  967. {
  968. hr = hr2;
  969. }
  970. else
  971. {
  972. // if DU check returned S_FALSE or S_OK we return that, otherwise return from CLSID check.
  973. if (SUCCEEDED(hr1))
  974. {
  975. hr = hr1;
  976. }
  977. else
  978. {
  979. hr = hr2;
  980. }
  981. }
  982. }
  983. else
  984. {
  985. if (hr1 == S_FALSE)
  986. {
  987. // COM branch says we are OK, but Distribution unit says we are lacking.
  988. // if we did paranoid checking and then failed the DU then
  989. // really fail. But if we just looked at the InstalledVersion
  990. // in the registry and concluded that our DU is no good then we
  991. // should go by the COM br and succeed the call as the user
  992. // could have obtained a newer version thru a mechanism other than
  993. // code download and so we have no business trying to update this
  994. // BUGBUG: do we at this point try to correct our registry
  995. // record of the version? need to ship tomorrow!
  996. if (bParanoidCheck)
  997. hr = hr1;
  998. else
  999. hr = hr2;
  1000. }
  1001. else
  1002. {
  1003. hr = hr2;
  1004. }
  1005. }
  1006. Exit:
  1007. DEBUG_LEAVE(hr);
  1008. return hr;
  1009. }
  1010. /*******************************************************************
  1011. NAME: IsCLSIDLocallyInstalled
  1012. SYNOPSIS: Indicates whether the provided CLSID represents an
  1013. OLE control.
  1014. If no clsid provided then checks to see if lpCurCode
  1015. exists in system and checks file version to verify if
  1016. update is needed
  1017. ********************************************************************/
  1018. HRESULT
  1019. IsCLSIDLocallyInstalled(LPSTR lpCurCode, const LPCLSID lpclsid,
  1020. LPCWSTR szDistUnit,
  1021. DWORD dwFileVersionMS, DWORD dwFileVersionLS,
  1022. CLocalComponentInfo *plci,
  1023. LPSTR szDestDirHint,
  1024. HRESULT *pHrExtra,
  1025. BOOL bExactVersion
  1026. )
  1027. {
  1028. DEBUG_ENTER((DBG_DOWNLOAD,
  1029. Hresult,
  1030. "IsCLSIDLocallyInstalled",
  1031. "%.80q, %#x, %.80wq, %x, %x, %#x, %.80q, %#x, %B",
  1032. lpCurCode, lpclsid, szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, szDestDirHint, pHrExtra, bExactVersion
  1033. ));
  1034. LPSTR pszClsid = NULL;
  1035. LPOLESTR pwcsClsid = NULL;
  1036. HRESULT hr = S_FALSE;
  1037. DWORD dwType;
  1038. LONG lResult = ERROR_SUCCESS;
  1039. static char * szInprocServer32 = "InProcServer32";
  1040. static char * szLocalServer32 = "LocalServer32";
  1041. static char * szAppID = "AppID";
  1042. HKEY hKeyClsid = 0;
  1043. DWORD Size = MAX_PATH;
  1044. if (pHrExtra)
  1045. *pHrExtra = E_FAIL;
  1046. // return if we can't get a valid string representation of the CLSID
  1047. if (FAILED((hr=StringFromCLSID(*lpclsid, &pwcsClsid))))
  1048. goto Exit;
  1049. Assert(pwcsClsid != NULL);
  1050. // Open root HKEY_CLASSES_ROOT\CLSID key
  1051. lResult = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hKeyClsid);
  1052. if (lResult == ERROR_SUCCESS)
  1053. {
  1054. if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &pszClsid))))
  1055. {
  1056. goto Exit;
  1057. }
  1058. // Open the key for this embedding:
  1059. HKEY hKeyEmbedding;
  1060. HKEY hKeyInProc;
  1061. lResult = ::RegOpenKeyEx(hKeyClsid, pszClsid, 0, KEY_READ,
  1062. &hKeyEmbedding);
  1063. if (lResult == ERROR_SUCCESS) {
  1064. // check for hint of FileVersion before actually getting FileVersion
  1065. // This way non-PE files, like Java, random data etc. can be
  1066. // accomodated with CODEBASE= with proper version checking.
  1067. // If they are not really COM object then they can't be
  1068. // instantiated by COM or us (if object needed). But if they
  1069. // use AsyncGetClassBits(no object instantiated) or from the
  1070. // browser give height=0 width=0, the browser will not
  1071. // report placeholders with errors, so they can work gracefully
  1072. // overloading the object tag to do version checking and
  1073. // random stuff
  1074. if (pHrExtra)
  1075. {
  1076. // indicate that CLSID reg key exists, so any failures after this
  1077. // imply the control is not registered correctly
  1078. *pHrExtra = S_OK;
  1079. }
  1080. hr = CheckInstalledVersionHint( hKeyEmbedding, plci,
  1081. dwFileVersionMS, dwFileVersionLS);
  1082. // if the key is found and
  1083. // if the latest version is not available then
  1084. // return now with false, if right version is already
  1085. // present return. If the key is missing then we
  1086. // proceed with checks for InprocServer32/LocalServer32
  1087. if (SUCCEEDED(hr))
  1088. goto finish_all;
  1089. hr = S_OK; // reset
  1090. // ckeck if DCOM
  1091. HKEY hKeyAppID;
  1092. lResult = ::RegOpenKeyEx(hKeyEmbedding, szAppID, 0,
  1093. KEY_READ, &hKeyAppID);
  1094. if (lResult == ERROR_SUCCESS) {
  1095. // DCOM
  1096. // just assume that this is the latest version already
  1097. // we never attempt code download for dcom
  1098. ::RegCloseKey(hKeyAppID);
  1099. goto finish_all;
  1100. }
  1101. lResult = ::RegOpenKeyEx(hKeyEmbedding, szInprocServer32, 0,
  1102. KEY_READ, &hKeyInProc);
  1103. if (lResult == ERROR_SUCCESS) {
  1104. Size = MAX_PATH;
  1105. lResult = ::SHQueryValueEx(hKeyInProc, NULL, NULL, &dwType,
  1106. (unsigned char *)plci->szExistingFileName, &Size);
  1107. if (lResult == ERROR_SUCCESS) {
  1108. if (!(SearchPathA_Wrap( NULL,
  1109. plci->szExistingFileName, NULL, MAX_PATH,
  1110. plci->szExistingFileName, &(plci->pBaseExistingFileName)))) {
  1111. hr = S_FALSE;
  1112. goto finish_verchecks;
  1113. }
  1114. // check fileversion to see if update reqd.
  1115. hr = LocalVersionOK(hKeyEmbedding, plci,
  1116. dwFileVersionMS, dwFileVersionLS, bExactVersion);
  1117. if (plci->bForceLangGetLatest) {
  1118. hr = NeedForceLanguageCheck(hKeyEmbedding, plci);
  1119. }
  1120. goto finish_verchecks;
  1121. } else {
  1122. hr = S_FALSE; // problem: can't locate file
  1123. goto finish_verchecks;
  1124. }
  1125. } else {
  1126. lResult = ::RegOpenKeyEx(hKeyEmbedding, szLocalServer32, 0,
  1127. KEY_READ, &hKeyInProc);
  1128. if (lResult != ERROR_SUCCESS) {
  1129. hr = S_FALSE; // problem :have a clsid but, can't locate it
  1130. goto finish_all;
  1131. }
  1132. Size = MAX_PATH;
  1133. lResult = ::SHQueryValueEx(hKeyInProc, NULL, NULL, &dwType,
  1134. (unsigned char *)plci->szExistingFileName, &Size);
  1135. if (lResult == ERROR_SUCCESS) {
  1136. // strip out args if any for this localserver32
  1137. // and extract only the EXE name
  1138. GetEXEName(plci->szExistingFileName);
  1139. if (!(SearchPathA_Wrap( NULL,
  1140. plci->szExistingFileName, NULL, MAX_PATH,
  1141. plci->szExistingFileName, &(plci->pBaseExistingFileName)))) {
  1142. hr = S_FALSE;
  1143. goto finish_verchecks;
  1144. }
  1145. // check fileversion to see if update reqd.
  1146. hr = LocalVersionOK(hKeyEmbedding, plci, dwFileVersionMS, dwFileVersionLS, bExactVersion);
  1147. if (plci->bForceLangGetLatest)
  1148. hr = NeedForceLanguageCheck(hKeyEmbedding, plci);
  1149. goto finish_verchecks;
  1150. } else {
  1151. hr = S_FALSE; // problem: can't locate file
  1152. goto finish_verchecks;
  1153. }
  1154. }
  1155. finish_verchecks:
  1156. ::RegCloseKey(hKeyInProc);
  1157. finish_all:
  1158. ::RegCloseKey(hKeyEmbedding);
  1159. } else {
  1160. // here if we could not find the embedding in HKCR\CLSID
  1161. hr = S_FALSE;
  1162. }
  1163. } else
  1164. hr = S_FALSE;
  1165. Exit:
  1166. // release the string allocated by StringFromCLSID
  1167. if (pwcsClsid)
  1168. delete pwcsClsid;
  1169. if (pszClsid)
  1170. delete pszClsid;
  1171. if (hKeyClsid)
  1172. ::RegCloseKey(hKeyClsid);
  1173. DEBUG_LEAVE(hr);
  1174. return hr;
  1175. }
  1176. BOOL SupportsSelfRegister(LPSTR szFileName)
  1177. {
  1178. DEBUG_ENTER((DBG_DOWNLOAD,
  1179. Bool,
  1180. "SupportsSelfRegister",
  1181. "%.80q",
  1182. szFileName
  1183. ));
  1184. HRESULT hr = SniffStringFileInfo( szFileName, TEXT("OLESelfRegister") );
  1185. DEBUG_LEAVE(hr);
  1186. return hr;
  1187. }
  1188. BOOL WantsAutoExpire(LPSTR szFileName, DWORD *pnExpireDays)
  1189. {
  1190. DEBUG_ENTER((DBG_DOWNLOAD,
  1191. Bool,
  1192. "WantsAutoExpire",
  1193. "%.80q, %#x",
  1194. szFileName, pnExpireDays
  1195. ));
  1196. HRESULT hr = SniffStringFileInfo( szFileName, TEXT("Expire"), pnExpireDays );
  1197. DEBUG_LEAVE(hr);
  1198. return hr;
  1199. }
  1200. HRESULT GetFileVersion(CLocalComponentInfo *plci, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS)
  1201. {
  1202. DEBUG_ENTER((DBG_DOWNLOAD,
  1203. Hresult,
  1204. "GetFileVersion",
  1205. "%#x, %#x, %#x",
  1206. plci, pdwFileVersionMS, pdwFileVersionLS
  1207. ));
  1208. DWORD handle;
  1209. UINT uiInfoSize;
  1210. UINT uiVerSize ;
  1211. UINT uiSize ;
  1212. BYTE* pbData = NULL ;
  1213. VS_FIXEDFILEINFO *lpVSInfo;;
  1214. HRESULT hr = S_OK;
  1215. LPVOID lpVerBuffer = NULL;
  1216. #ifdef UNIX
  1217. // We don't have version.dll
  1218. DebugBreak();
  1219. DEBUG_LEAVE(E_INVALIDARG);
  1220. return E_INVALIDARG;
  1221. #endif
  1222. if (!pdwFileVersionMS || !pdwFileVersionLS) {
  1223. hr = E_INVALIDARG;
  1224. goto Exit;
  1225. }
  1226. *pdwFileVersionMS = 0;
  1227. *pdwFileVersionLS = 0;
  1228. // Get the size of the version information.
  1229. uiInfoSize = g_versiondll.GetFileVersionInfoSize( (char *)plci->szExistingFileName, &handle);
  1230. if (uiInfoSize == 0) {
  1231. hr = S_FALSE;
  1232. goto Exit;
  1233. }
  1234. // Allocate a buffer for the version information.
  1235. pbData = new BYTE[uiInfoSize] ;
  1236. if (!pbData)
  1237. {
  1238. DEBUG_LEAVE(E_OUTOFMEMORY);
  1239. return E_OUTOFMEMORY;
  1240. }
  1241. // Fill the buffer with the version information.
  1242. if (!g_versiondll.GetFileVersionInfo((char *)plci->szExistingFileName, handle, uiInfoSize, pbData)) {
  1243. hr = HRESULT_FROM_WIN32(GetLastError());
  1244. goto Exit ;
  1245. }
  1246. // Get the translation information.
  1247. if (!g_versiondll.VerQueryValue( pbData, "\\", (void**)&lpVSInfo, &uiVerSize)) {
  1248. hr = HRESULT_FROM_WIN32(GetLastError());
  1249. goto Exit ;
  1250. }
  1251. if (!uiVerSize) {
  1252. hr = E_FAIL;
  1253. goto Exit ;
  1254. }
  1255. *pdwFileVersionMS = lpVSInfo->dwFileVersionMS;
  1256. *pdwFileVersionLS = lpVSInfo->dwFileVersionLS;
  1257. // Get the translation information.
  1258. if (!g_versiondll.VerQueryValue( pbData, "\\VarFileInfo\\Translation", &lpVerBuffer, &uiVerSize)) {
  1259. hr = HRESULT_FROM_WIN32(GetLastError());
  1260. goto Exit ;
  1261. }
  1262. if (!uiVerSize) {
  1263. hr = E_FAIL;
  1264. goto Exit ;
  1265. }
  1266. plci->lcid = LOWORD(*((DWORD *) lpVerBuffer)); // Language ID
  1267. Exit:
  1268. if (pbData)
  1269. delete [] pbData ;
  1270. DEBUG_LEAVE(hr);
  1271. return hr;
  1272. }
  1273. DWORD
  1274. GetLanguageCheckInterval(HKEY hkeyCheckPeriod)
  1275. {
  1276. DEBUG_ENTER((DBG_DOWNLOAD,
  1277. Dword,
  1278. "GetLanguageCheckInterval",
  1279. "%#x",
  1280. hkeyCheckPeriod
  1281. ));
  1282. DWORD dwMagicDays = 30;
  1283. DWORD dwType = REG_DWORD;
  1284. DWORD dwSize = sizeof(DWORD);
  1285. char szLangString[MAX_PATH];
  1286. LCID lcidPriOverride = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()));
  1287. LCID lcidPriBrowser = PRIMARYLANGID(LANGIDFROMLCID(g_lcidBrowser));
  1288. if (SUCCEEDED(GetLangString(lcidPriOverride, szLangString, sizeof(szLangString)))) {
  1289. if (RegQueryValueEx(hkeyCheckPeriod, szLangString, NULL, &dwType,
  1290. (unsigned char *)&dwMagicDays, &dwSize) == ERROR_SUCCESS) {
  1291. DEBUG_LEAVE(dwMagicDays);
  1292. return dwMagicDays;
  1293. }
  1294. }
  1295. if ( (lcidPriOverride != lcidPriBrowser) &&
  1296. SUCCEEDED(GetLangString(lcidPriBrowser, szLangString, sizeof(szLangString)))) {
  1297. if (RegQueryValueEx(hkeyCheckPeriod, szLangString, NULL, &dwType,
  1298. (unsigned char *)&dwMagicDays, &dwSize) == ERROR_SUCCESS) {
  1299. DEBUG_LEAVE(dwMagicDays);
  1300. return dwMagicDays;
  1301. }
  1302. }
  1303. DEBUG_LEAVE(dwMagicDays);
  1304. return dwMagicDays;
  1305. }
  1306. // returns:
  1307. // S_OK: local version OK or local version lang check not reqd now
  1308. // S_FALSE: localversion not of right lang force lang check now
  1309. // ERROR: fail
  1310. HRESULT NeedForceLanguageCheck(HKEY hkeyCLSID, CLocalComponentInfo *plci)
  1311. {
  1312. DEBUG_ENTER((DBG_DOWNLOAD,
  1313. Hresult,
  1314. "NeedForceLanguageCheck",
  1315. "%#x, %#x",
  1316. hkeyCLSID, plci
  1317. ));
  1318. HRESULT hr = S_OK;
  1319. DWORD lResult;
  1320. const char *szCHECKPERIOD = "LanguageCheckPeriod";
  1321. const char *szLASTCHECKEDHI = "LastCheckedHi";
  1322. DWORD dwMagicPerDay = 201;
  1323. DWORD dwMagicDays;
  1324. DWORD dwType;
  1325. DWORD dwSize;
  1326. FILETIME ftlast, ftnow;
  1327. SYSTEMTIME st;
  1328. HKEY hkeyCheckPeriod = 0;
  1329. char szLangEnable[MAX_PATH];
  1330. if (!plci->bForceLangGetLatest)
  1331. {
  1332. DEBUG_LEAVE(hr);
  1333. return hr;
  1334. }
  1335. // lang is mismatched for this browser
  1336. // check when was the last time we checked for the right lang
  1337. if ((lResult = RegOpenKeyEx( hkeyCLSID, szCHECKPERIOD,
  1338. 0, KEY_READ, &hkeyCheckPeriod)) != ERROR_SUCCESS) {
  1339. plci->bForceLangGetLatest = FALSE;
  1340. goto Exit;
  1341. }
  1342. szLangEnable[0] = '\0';
  1343. dwType = REG_SZ;
  1344. dwSize = MAX_PATH;
  1345. if ( (RegQueryValueEx(hkeyCheckPeriod, NULL, NULL, &dwType,
  1346. (unsigned char *)szLangEnable, &dwSize) != ERROR_SUCCESS) ||
  1347. lstrcmpi(szLangEnable, "Enabled") != 0 ) {
  1348. plci->bForceLangGetLatest = FALSE;
  1349. goto Exit;
  1350. }
  1351. // see if lang check interval is specified for this lang
  1352. dwMagicDays = GetLanguageCheckInterval(hkeyCheckPeriod);
  1353. GetSystemTime(&st);
  1354. SystemTimeToFileTime(&st, &ftnow);
  1355. ftnow.dwLowDateTime = 0;
  1356. memset(&ftlast, 0, sizeof(FILETIME));
  1357. dwType = REG_DWORD;
  1358. dwSize = sizeof(DWORD);
  1359. if (RegQueryValueEx(hkeyCheckPeriod, szLASTCHECKEDHI, NULL, &dwType,
  1360. (unsigned char *)&ftlast.dwHighDateTime, &dwSize) == ERROR_SUCCESS) {
  1361. ftlast.dwHighDateTime += (dwMagicPerDay * dwMagicDays);
  1362. }
  1363. if (CompareFileTime(&ftlast, &ftnow) > 0) {
  1364. plci->bForceLangGetLatest = FALSE;
  1365. }
  1366. Exit:
  1367. SAFEREGCLOSEKEY(hkeyCheckPeriod);
  1368. if (FAILED(hr))
  1369. plci->bForceLangGetLatest = FALSE;
  1370. hr = plci->bForceLangGetLatest?S_FALSE:S_OK;
  1371. DEBUG_LEAVE(hr);
  1372. return hr;
  1373. }
  1374. HRESULT IsRightLanguageLocallyInstalled(CLocalComponentInfo *plci)
  1375. {
  1376. DEBUG_ENTER((DBG_DOWNLOAD,
  1377. Hresult,
  1378. "IsRightLanguageLocallyInstalled",
  1379. "%#x",
  1380. plci
  1381. ));
  1382. HRESULT hr = S_OK;
  1383. LCID lcidLocalVersion;
  1384. LCID lcidNeeded;
  1385. if (!plci->lcid) // lang neutral?
  1386. goto Exit;
  1387. // make sure that the browser locale and lang strings are
  1388. // initialized at this point
  1389. hr = InitBrowserLangStrings();
  1390. if (FAILED(hr))
  1391. goto Exit;
  1392. // BUGBUG: we are using threadlocale here instead of the
  1393. // bindopts from the bindctx passed in
  1394. if (plci->lcid == GetThreadLocale()) // full match with override?
  1395. goto Exit;
  1396. if (plci->lcid == g_lcidBrowser) // full match with browser?
  1397. goto Exit;
  1398. // get primary lang of local version
  1399. lcidLocalVersion = PRIMARYLANGID(LANGIDFROMLCID(plci->lcid));
  1400. // check with primary language of override
  1401. lcidNeeded = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()));
  1402. if (lcidLocalVersion == lcidNeeded) // same primary lang?
  1403. goto Exit;
  1404. // check with primary language of browser
  1405. lcidNeeded = PRIMARYLANGID(LANGIDFROMLCID(g_lcidBrowser));
  1406. if (lcidLocalVersion == lcidNeeded) // same primary lang?
  1407. goto Exit;
  1408. // BUGBUG: how to detect language neutral or multiligual OCX
  1409. // we have a mismatch
  1410. // check when was the last time we check and if past the
  1411. // interval to check for new language availability
  1412. // force a download now.
  1413. hr = S_FALSE;
  1414. plci->bForceLangGetLatest = TRUE;
  1415. Exit:
  1416. DEBUG_LEAVE(hr);
  1417. return hr;
  1418. }
  1419. //
  1420. HRESULT LocalVersionOK(HKEY hkeyCLSID, CLocalComponentInfo *plci, DWORD dwFileVersionMS,
  1421. DWORD dwFileVersionLS, BOOL bExactVersion)
  1422. {
  1423. DEBUG_ENTER((DBG_DOWNLOAD,
  1424. Hresult,
  1425. "LocalVersionOK",
  1426. "%#x, %#x, %x, %x, %B",
  1427. hkeyCLSID, plci, dwFileVersionMS, dwFileVersionLS, bExactVersion
  1428. ));
  1429. DWORD handle;
  1430. HRESULT hr = S_OK; // assume local version OK.
  1431. DWORD dwLocFVMS = 0;
  1432. DWORD dwLocFVLS = 0;
  1433. HKEY hkeyCheckPeriod = 0;
  1434. const char *szCHECKPERIOD = "LanguageCheckPeriod";
  1435. if (FAILED(hr = plci->MakeDestDir()) ) {
  1436. goto Exit;
  1437. }
  1438. #ifdef UNIX
  1439. DEBUG_LEAVE(S_OK);
  1440. return S_OK;
  1441. #endif
  1442. if ((dwFileVersionMS == 0) && (dwFileVersionLS == 0)) {
  1443. // for dlls that don't require lang support and have no version req
  1444. // don't check version numbers
  1445. // this is to boost perf on system/IE dlls
  1446. // One can also avoid such checks
  1447. // by adding a [InstalledVersion] key under the clsid
  1448. if (!hkeyCLSID || RegOpenKeyEx( hkeyCLSID, szCHECKPERIOD,
  1449. 0, KEY_READ, &hkeyCheckPeriod) != ERROR_SUCCESS) {
  1450. goto Exit;
  1451. }
  1452. }
  1453. hr = GetFileVersion( plci, &dwLocFVMS, &dwLocFVLS);
  1454. if (hr == S_OK) {
  1455. plci->dwLocFVMS = dwLocFVMS;
  1456. plci->dwLocFVLS = dwLocFVLS;
  1457. if (bExactVersion) {
  1458. if (dwFileVersionMS != dwLocFVMS || dwFileVersionLS != dwLocFVLS) {
  1459. hr = S_FALSE;
  1460. } else {
  1461. // check language
  1462. // sets the plci->bForcelangGetLatest if reqd
  1463. IsRightLanguageLocallyInstalled(plci);
  1464. }
  1465. }
  1466. else {
  1467. if ((dwFileVersionMS > dwLocFVMS) ||
  1468. ((dwFileVersionMS == dwLocFVMS) &&
  1469. (dwFileVersionLS > dwLocFVLS))) {
  1470. hr = S_FALSE;
  1471. } else {
  1472. // check language
  1473. // sets the plci->bForcelangGetLatest if reqd
  1474. IsRightLanguageLocallyInstalled(plci);
  1475. }
  1476. }
  1477. }
  1478. if ((dwFileVersionMS == 0) && (dwFileVersionLS == 0)) {
  1479. hr = S_OK;
  1480. }
  1481. if ((dwFileVersionMS == -1) && (dwFileVersionLS == -1)) {
  1482. hr = S_FALSE;
  1483. }
  1484. Exit:
  1485. if (hkeyCheckPeriod)
  1486. RegCloseKey(hkeyCheckPeriod);
  1487. DEBUG_LEAVE(hr);
  1488. return hr;
  1489. }
  1490. /*
  1491. *
  1492. * UpdateSharedDlls
  1493. *
  1494. * the SharedDlls section looks like this
  1495. *
  1496. * [SharedDlls]
  1497. * C:\Windows\System\foo.ocx = <ref count>
  1498. *
  1499. * Parameters:
  1500. *
  1501. * szFileName full file name of module we want to use
  1502. *
  1503. * Returns:
  1504. *
  1505. * S_OK incremented tge shared dlls ref count.
  1506. *
  1507. * Error the error encountered
  1508. */
  1509. HRESULT
  1510. UpdateSharedDlls( LPCSTR szFileName)
  1511. {
  1512. DEBUG_ENTER((DBG_DOWNLOAD,
  1513. Hresult,
  1514. "UpdateSharedDlls",
  1515. "%.80q",
  1516. szFileName
  1517. ));
  1518. HKEY hKeySD = NULL;
  1519. HRESULT hr = S_OK;
  1520. DWORD dwType;
  1521. DWORD dwRef = 1;
  1522. DWORD dwSize = sizeof(DWORD);
  1523. LONG lResult;
  1524. // get the main SHAREDDLLS key ready; this is never freed!
  1525. if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_SHAREDDLLS,
  1526. 0, KEY_ALL_ACCESS, &hKeySD)) != ERROR_SUCCESS) {
  1527. if ((lResult = RegCreateKey( HKEY_LOCAL_MACHINE,
  1528. REGSTR_PATH_SHAREDDLLS, &hKeySD)) != ERROR_SUCCESS) {
  1529. hKeySD = NULL;
  1530. hr = HRESULT_FROM_WIN32(lResult);
  1531. goto Exit;
  1532. }
  1533. }
  1534. // now look for szFileName
  1535. lResult = SHQueryValueEx(hKeySD, szFileName, NULL, &dwType,
  1536. (unsigned char *)&dwRef, &dwSize);
  1537. if (lResult == ERROR_SUCCESS)
  1538. dwRef++;
  1539. // does not exist. Create one and initialize to 1
  1540. if ((lResult = RegSetValueEx (hKeySD, szFileName, 0, REG_DWORD,
  1541. (unsigned char *)&dwRef,
  1542. sizeof(DWORD))) != ERROR_SUCCESS) {
  1543. hr = HRESULT_FROM_WIN32(lResult);
  1544. goto Exit;
  1545. }
  1546. Exit:
  1547. if (hKeySD)
  1548. RegCloseKey(hKeySD);
  1549. DEBUG_LEAVE(hr);
  1550. return hr;
  1551. }
  1552. /*
  1553. *
  1554. * UpdateModuleUsage
  1555. *
  1556. * the module usage section in the regitry looks like this
  1557. *
  1558. * [ModuleUsage]
  1559. * [c:/windows/occache/foo.ocx]
  1560. * Owner = Internet Code Downloader
  1561. * FileVersion = <optional text version of 64-bit fileversion of ocx
  1562. * [clients]
  1563. * Internet Code Downloader = <this client's ref count>
  1564. * To allow for full path names without using the backslash we convert
  1565. * backslahes to forward slashes.
  1566. *
  1567. *
  1568. * Parameters:
  1569. *
  1570. * szFileName full file name of module we want to use
  1571. *
  1572. * szClientName name of or stringfromclsid of client.
  1573. *
  1574. * szClientPath optional (if present we can detect if client is gone)
  1575. *
  1576. * muFlags:
  1577. * MU_CLIENT mark ourselves client
  1578. * MU_OWNER mark ourselves owner
  1579. *
  1580. * Returns:
  1581. * S_OK we updated the module usage section,
  1582. * and if that was previously absent then we also upped the
  1583. * shared dlls count.
  1584. *
  1585. * Error the error encountered
  1586. */
  1587. HRESULT
  1588. UpdateModuleUsage(
  1589. LPCSTR szFileName,
  1590. LPCSTR szClientName,
  1591. LPCSTR szClientPath,
  1592. LONG muFlags)
  1593. {
  1594. DEBUG_ENTER((DBG_DOWNLOAD,
  1595. Hresult,
  1596. "UpdateModuleUsage",
  1597. "%.80q, %.80q, %.80q, %x",
  1598. szFileName, szClientName, szClientPath, muFlags
  1599. ));
  1600. HRESULT hr = S_OK;
  1601. LONG lResult = 0;
  1602. BOOL fUpdateSharedDlls = TRUE;
  1603. DWORD dwType;
  1604. HKEY hKeyMod = NULL;
  1605. DWORD dwSize = MAX_PATH;
  1606. char szBuf[MAX_PATH];
  1607. const char *pchSrc;
  1608. char *pchDest;
  1609. static const LPCSTR szCLIENTPATHDEFAULT = "";
  1610. LPCSTR lpClientPath = (szClientPath)?szClientPath:szCLIENTPATHDEFAULT;
  1611. HKEY hKeyMU = NULL;
  1612. static const char szOWNER[] = ".Owner";
  1613. static const char szUNKNOWN[] = "Unknown Owner";
  1614. Assert(szClientName);
  1615. DWORD cbClientName = lstrlen(szClientName);
  1616. DWORD cbUnknown = sizeof(szUNKNOWN);
  1617. char szShortFileName[MAX_PATH];
  1618. #ifdef SHORTEN
  1619. if (!GetShortPathName(szFileName, szShortFileName, MAX_PATH)) {
  1620. hr = HRESULT_FROM_WIN32(GetLastError());
  1621. goto Exit;
  1622. }
  1623. #else
  1624. StrNCpy(szShortFileName, szFileName, sizeof(szShortFileName));
  1625. #endif
  1626. if (g_bRunOnWin95) {
  1627. char szCharFileName[MAX_PATH];
  1628. OemToCharBuff(szShortFileName, szCharFileName, sizeof(szCharFileName) / sizeof(szCharFileName[0]));
  1629. StrNCpy(szShortFileName, szCharFileName, sizeof(szShortFileName));
  1630. }
  1631. // get the main MODULEUSAGE key ready; this is never freed!
  1632. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_MODULE_USAGE,
  1633. 0, KEY_ALL_ACCESS, &hKeyMU) != ERROR_SUCCESS)
  1634. if ((lResult = RegCreateKey( HKEY_LOCAL_MACHINE,
  1635. REGSTR_PATH_MODULE_USAGE, &hKeyMU)) != ERROR_SUCCESS) {
  1636. hKeyMU = NULL;
  1637. hr = HRESULT_FROM_WIN32(lResult);
  1638. goto Exit;
  1639. }
  1640. // check if Usage section is present for this dll
  1641. // open the file's section we are concerned with
  1642. // if absent create it
  1643. // BUGBUG: win95 registry bug does not allow keys to be > 255
  1644. // MAX_PATH for filename is 260
  1645. pchDest = szBuf;
  1646. for (pchSrc = szShortFileName; *pchSrc != '\0'; pchSrc++, pchDest++) {
  1647. if ((*pchDest = *pchSrc) == '\\')
  1648. *pchDest = '/';
  1649. }
  1650. *pchDest = '\0'; // null terminate
  1651. szBuf[256] = '\0'; // truncate if longer than 255 ude to win95 registry bug
  1652. if (RegOpenKeyEx( hKeyMU, szBuf,
  1653. 0, KEY_ALL_ACCESS, &hKeyMod) != ERROR_SUCCESS) {
  1654. if ((lResult = RegCreateKey( hKeyMU,
  1655. szBuf, &hKeyMod)) != ERROR_SUCCESS) {
  1656. hr = HRESULT_FROM_WIN32(lResult);
  1657. goto Exit;
  1658. }
  1659. }
  1660. // now look for '.Owner='
  1661. dwSize = MAX_PATH;
  1662. szBuf[0] = '\0';
  1663. if (RegQueryValueEx(hKeyMod, szOWNER, NULL, &dwType,
  1664. (unsigned char *)szBuf, &dwSize) == ERROR_SUCCESS) {
  1665. if ((lstrcmpi(szBuf, szClientName) != 0) && (muFlags & MU_OWNER)) {
  1666. // if we are the not the owner we can't make ourselves the owner
  1667. hr = E_INVALIDARG;
  1668. goto Exit;
  1669. }
  1670. } else {
  1671. // '.Owner =' does not exist. Create one and initialize to us
  1672. // if muFlags & MU_OWNER
  1673. if (((lResult = RegSetValueEx (hKeyMod, szOWNER, 0, REG_SZ,
  1674. (UCHAR *)((muFlags & MU_OWNER)?szClientName:szUNKNOWN),
  1675. ((muFlags & MU_OWNER)?cbClientName:cbUnknown)))) != ERROR_SUCCESS) {
  1676. hr = HRESULT_FROM_WIN32(lResult);
  1677. goto Exit;
  1678. }
  1679. }
  1680. // look for szClientName already marked as a client
  1681. dwSize = MAX_PATH;
  1682. if (SHQueryValueEx(hKeyMod, szClientName, NULL, &dwType,
  1683. (unsigned char *)szBuf, &dwSize) == ERROR_SUCCESS) {
  1684. // signal that we have already registered as a
  1685. // client and so don't up ref count in shareddlls
  1686. fUpdateSharedDlls = FALSE;
  1687. } else {
  1688. // add ourselves as a client
  1689. if ((lResult =RegSetValueEx(hKeyMod, szClientName, 0, REG_SZ,
  1690. (unsigned char *)lpClientPath, lstrlen(lpClientPath)+1 )) != ERROR_SUCCESS) {
  1691. hr = HRESULT_FROM_WIN32(lResult);
  1692. goto Exit;
  1693. }
  1694. }
  1695. Exit:
  1696. if (hKeyMod)
  1697. RegCloseKey(hKeyMod);
  1698. if (hKeyMU)
  1699. RegCloseKey(hKeyMU);
  1700. // Update ref count in SharedDlls only if usage section was not
  1701. // already updated. This will ensure that the code downloader has
  1702. // just one ref count represented in SharedDlls
  1703. if ( fUpdateSharedDlls)
  1704. hr = UpdateSharedDlls(szShortFileName);
  1705. DEBUG_LEAVE(hr);
  1706. return hr;
  1707. }
  1708. // Name: SniffStringFileInfo
  1709. // Parameters:
  1710. // szFileName - full path to file whose StringFileInfo we want to sniff
  1711. // lpszSubblock - sub block of the StringFileInfo to look for
  1712. // pdw - place to put the string, interpreted as a number
  1713. // Returns:
  1714. // TRUE - if the subblock is present.
  1715. // FALSE - if the subblock is absent.
  1716. // Notes:
  1717. // This function implements stuff common to SupportsSelfRegister and WantsAutoExpire
  1718. BOOL SniffStringFileInfo( LPSTR szFileName, LPCTSTR lpszSubblock, DWORD *pdw )
  1719. {
  1720. DEBUG_ENTER((DBG_DOWNLOAD,
  1721. Bool,
  1722. "SniffStringFileInfo",
  1723. "%.80q, %#x, %#x",
  1724. szFileName, lpszSubblock, pdw
  1725. ));
  1726. BOOL bResult = FALSE;
  1727. DWORD handle;
  1728. UINT uiInfoSize;
  1729. UINT uiVerSize ;
  1730. UINT uiSize ;
  1731. BYTE* pbData = NULL ;
  1732. DWORD* lpBuffer;
  1733. TCHAR szName[512] ;
  1734. LPTSTR szExpire;
  1735. if ( pdw )
  1736. *pdw = 0;
  1737. #ifdef UNIX
  1738. // Don't have version.dll
  1739. DebugBreak();
  1740. DEBUG_LEAVE(FALSE);
  1741. return FALSE;
  1742. #endif
  1743. // Get the size of the version information.
  1744. uiInfoSize = g_versiondll.GetFileVersionInfoSize( szFileName, &handle);
  1745. if (uiInfoSize == 0)
  1746. {
  1747. DEBUG_LEAVE(FALSE);
  1748. return FALSE ;
  1749. }
  1750. // Allocate a buffer for the version information.
  1751. pbData = new BYTE[uiInfoSize] ;
  1752. if (!pbData)
  1753. {
  1754. DEBUG_LEAVE(TRUE);
  1755. return TRUE; // nothing nasty, just quirky
  1756. }
  1757. // Fill the buffer with the version information.
  1758. bResult = g_versiondll.GetFileVersionInfo( szFileName, handle, uiInfoSize, pbData);
  1759. if (!bResult) goto Exit ;
  1760. // Get the translation information.
  1761. bResult = g_versiondll.VerQueryValue( pbData, "\\VarFileInfo\\Translation",
  1762. (void**)&lpBuffer, &uiVerSize);
  1763. if (!bResult) goto Exit ;
  1764. if (!uiVerSize) goto Exit ;
  1765. // Build the path to the OLESelfRegister key
  1766. // using the translation information.
  1767. wnsprintf( szName, ARRAY_ELEMENTS(szName)-1, "\\StringFileInfo\\%04hX%04hX\\%s",
  1768. LOWORD(*lpBuffer), HIWORD(*lpBuffer), lpszSubblock) ;
  1769. // Search for the key.
  1770. bResult = g_versiondll.VerQueryValue( pbData, szName, (void**)&szExpire, &uiSize);
  1771. // If there's a string there, we need to convert it to a count of days.
  1772. if ( bResult && pdw && uiSize )
  1773. {
  1774. DWORD dwExpire = 0;
  1775. for ( ; *szExpire; szExpire++ )
  1776. {
  1777. if ( (*szExpire >= TEXT('0') && *szExpire <= TEXT('9')) )
  1778. dwExpire = dwExpire * 10 + *szExpire - TEXT('0');
  1779. else
  1780. break;
  1781. }
  1782. if (dwExpire > MAX_EXPIRE_DAYS)
  1783. dwExpire = MAX_EXPIRE_DAYS;
  1784. *pdw = dwExpire;
  1785. }
  1786. Exit:
  1787. delete [] pbData ;
  1788. DEBUG_LEAVE(bResult);
  1789. return bResult ;
  1790. }
  1791. void ExtractVersion(char *pszDistUnit, DWORD *pdwVerMS, DWORD *pdwVerLS)
  1792. {
  1793. DEBUG_ENTER((DBG_DOWNLOAD,
  1794. None,
  1795. "ExtractVersion",
  1796. "%.80q, %#x, %#x",
  1797. pszDistUnit, pdwVerMS, pdwVerLS
  1798. ));
  1799. char *pszCopy = NULL;
  1800. char *pszPtr = NULL;
  1801. int iLen = 0;
  1802. if (!pszDistUnit)
  1803. {
  1804. DEBUG_LEAVE(0);
  1805. return;
  1806. }
  1807. iLen = lstrlen(pszDistUnit) + 1;
  1808. pszCopy = new char[iLen];
  1809. if (!pszCopy) {
  1810. DEBUG_LEAVE(0);
  1811. return;
  1812. }
  1813. StrNCpy(pszCopy, pszDistUnit, iLen);
  1814. pszPtr = pszCopy;
  1815. // Convert _ to , for GetVersionFromString()
  1816. while (*pszPtr)
  1817. {
  1818. if (*pszPtr == '_')
  1819. {
  1820. *pszPtr = ',';
  1821. }
  1822. pszPtr++;
  1823. }
  1824. pszPtr = StrStrA(pszCopy, "!");
  1825. if (pszPtr) {
  1826. pszPtr++;
  1827. GetVersionFromString(pszPtr, pdwVerMS, pdwVerLS);
  1828. }
  1829. SAFEDELETE(pszCopy);
  1830. DEBUG_LEAVE(0);
  1831. }