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.

2236 lines
74 KiB

  1. //=--------------------------------------------------------------------------=
  2. // Util.C
  3. //=--------------------------------------------------------------------------=
  4. // Copyright 1995 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  9. // PARTICULAR PURPOSE.
  10. //=--------------------------------------------------------------------------=
  11. //
  12. // contains routines that we will find useful.
  13. //
  14. #include "pch.h"
  15. #include <comcat.h>
  16. // for ASSERT and FAIL
  17. //
  18. SZTHISFILE
  19. BOOL g_bDllVerChecked = FALSE;
  20. // VERSION.DLL functions
  21. //
  22. HINSTANCE g_hinstVersion = NULL;
  23. PVERQUERYVALUE g_pVerQueryValue = NULL;
  24. PGETFILEVERSIONINFO g_pGetFileVersionInfo = NULL;
  25. PGETFILEVERSIONINFOSIZE g_pGetFileVersionInfoSize = NULL;
  26. // temporary until we get an updated ComCat.H
  27. //
  28. EXTERN_C const CATID CATID_SimpleFrameControl = {0xD40C2700,0xFFA1,0x11cf,{0x82,0x34,0x00,0xaa,0x00,0xC1,0xAB,0x85}};
  29. // These are externals for registering the control CATID's
  30. extern const CATID *g_rgCATIDImplemented[];
  31. extern const CATID *g_rgCATIDRequired[];
  32. extern const int g_ctCATIDImplemented;
  33. extern const int g_ctCATIDRequired;
  34. #define CATID_ARRAY_SIZE 10
  35. //=---------------------------------------------------------------------------=
  36. // this table is used for copying data around, and persisting properties.
  37. // basically, it contains the size of a given data type
  38. //
  39. const BYTE g_rgcbDataTypeSize[] = {
  40. 0, // VT_EMPTY= 0,
  41. 0, // VT_NULL= 1,
  42. sizeof(short), // VT_I2= 2,
  43. sizeof(long), // VT_I4 = 3,
  44. sizeof(float), // VT_R4 = 4,
  45. sizeof(double), // VT_R8= 5,
  46. sizeof(CURRENCY), // VT_CY= 6,
  47. sizeof(DATE), // VT_DATE = 7,
  48. sizeof(BSTR), // VT_BSTR = 8,
  49. sizeof(IDispatch *), // VT_DISPATCH = 9,
  50. sizeof(SCODE), // VT_ERROR = 10,
  51. sizeof(VARIANT_BOOL), // VT_BOOL = 11,
  52. sizeof(VARIANT), // VT_VARIANT= 12,
  53. sizeof(IUnknown *), // VT_UNKNOWN= 13,
  54. };
  55. #ifndef MDAC_BUILD
  56. //=---------------------------------------------------------------------------=
  57. // overloaded new
  58. //=---------------------------------------------------------------------------=
  59. //
  60. // Please use New instead of new by inheriting from the class CtlNewDelete
  61. // in Macros.H
  62. //
  63. inline void * _cdecl operator new
  64. (
  65. size_t size
  66. )
  67. {
  68. if (!g_hHeap)
  69. {
  70. g_hHeap = GetProcessHeap();
  71. return g_hHeap ? CtlHeapAlloc(g_hHeap, 0, size) : NULL;
  72. }
  73. return CtlHeapAlloc(g_hHeap, 0, size);
  74. }
  75. //=---------------------------------------------------------------------------=
  76. // overloaded delete
  77. //=---------------------------------------------------------------------------=
  78. // retail case just uses win32 Local* heap mgmt functions
  79. //
  80. // Parameters:
  81. // void * - [in] free me!
  82. //
  83. // Notes:
  84. //
  85. void _cdecl operator delete ( void *ptr)
  86. {
  87. if (ptr)
  88. CtlHeapFree(g_hHeap, 0, ptr);
  89. }
  90. #endif
  91. //=--------------------------------------------------------------------------=
  92. // MakeWideFromAnsi
  93. //=--------------------------------------------------------------------------=
  94. // given a string, make a BSTR out of it.
  95. //
  96. // Parameters:
  97. // LPSTR - [in]
  98. // BYTE - [in]
  99. //
  100. // Output:
  101. // LPWSTR - needs to be cast to final desired result
  102. //
  103. // Notes:
  104. //
  105. LPWSTR MakeWideStrFromAnsi
  106. (
  107. LPSTR psz,
  108. BYTE bType
  109. )
  110. {
  111. LPWSTR pwsz;
  112. int i;
  113. // arg checking.
  114. //
  115. if (!psz)
  116. return NULL;
  117. // compute the length of the required BSTR
  118. //
  119. i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  120. if (i <= 0) return NULL;
  121. // allocate the widestr
  122. //
  123. switch (bType) {
  124. case STR_BSTR:
  125. // -1 since it'll add it's own space for a NULL terminator
  126. //
  127. pwsz = (LPWSTR) SysAllocStringLen(NULL, i - 1);
  128. break;
  129. case STR_OLESTR:
  130. pwsz = (LPWSTR) CoTaskMemAlloc(i * sizeof(WCHAR));
  131. break;
  132. default:
  133. FAIL("Bogus String Type.");
  134. }
  135. if (!pwsz) return NULL;
  136. MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i);
  137. pwsz[i - 1] = 0;
  138. return pwsz;
  139. }
  140. //=--------------------------------------------------------------------------=
  141. // MakeWideStrFromResId
  142. //=--------------------------------------------------------------------------=
  143. // given a resource ID, load it, and allocate a wide string for it.
  144. //
  145. // Parameters:
  146. // WORD - [in] resource id.
  147. // BYTE - [in] type of string desired.
  148. //
  149. // Output:
  150. // LPWSTR - needs to be cast to desired string type.
  151. //
  152. // Notes:
  153. //
  154. LPWSTR MakeWideStrFromResourceId
  155. (
  156. WORD wId,
  157. BYTE bType
  158. )
  159. {
  160. int i;
  161. char szTmp[512];
  162. // load the string from the resources.
  163. //
  164. i = LoadString(GetResourceHandle(), wId, szTmp, 512);
  165. if (!i) return NULL;
  166. return MakeWideStrFromAnsi(szTmp, bType);
  167. }
  168. //=--------------------------------------------------------------------------=
  169. // MakeWideStrFromWide
  170. //=--------------------------------------------------------------------------=
  171. // given a wide string, make a new wide string with it of the given type.
  172. //
  173. // Parameters:
  174. // LPWSTR - [in] current wide str.
  175. // BYTE - [in] desired type of string.
  176. //
  177. // Output:
  178. // LPWSTR
  179. //
  180. // Notes:
  181. //
  182. LPWSTR MakeWideStrFromWide
  183. (
  184. LPWSTR pwsz,
  185. BYTE bType
  186. )
  187. {
  188. LPWSTR pwszTmp;
  189. int i;
  190. if (!pwsz) return NULL;
  191. // just copy the string, depending on what type they want.
  192. //
  193. switch (bType) {
  194. case STR_OLESTR:
  195. i = lstrlenW(pwsz);
  196. pwszTmp = (LPWSTR)CoTaskMemAlloc((i * sizeof(WCHAR)) + sizeof(WCHAR));
  197. if (!pwszTmp) return NULL;
  198. memcpy(pwszTmp, pwsz, (sizeof(WCHAR) * i) + sizeof(WCHAR));
  199. break;
  200. case STR_BSTR:
  201. pwszTmp = (LPWSTR)SysAllocString(pwsz);
  202. break;
  203. }
  204. return pwszTmp;
  205. }
  206. //=--------------------------------------------------------------------------=
  207. // StringFromGuidA
  208. //=--------------------------------------------------------------------------=
  209. // returns an ANSI string from a CLSID or GUID
  210. //
  211. // Parameters:
  212. // REFIID - [in] clsid to make string out of.
  213. // LPSTR - [in] buffer in which to place resultant GUID.
  214. //
  215. // Output:
  216. // int - number of chars written out.
  217. //
  218. // Notes:
  219. //
  220. int StringFromGuidA
  221. (
  222. REFIID riid,
  223. LPSTR pszBuf
  224. )
  225. {
  226. return wsprintf((char *)pszBuf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", riid.Data1,
  227. riid.Data2, riid.Data3, riid.Data4[0], riid.Data4[1], riid.Data4[2],
  228. riid.Data4[3], riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
  229. }
  230. //=--------------------------------------------------------------------------=
  231. // RegisterUnknownObject
  232. //=--------------------------------------------------------------------------=
  233. // registers a simple CoCreatable object. nothing terribly serious.
  234. // we add the following information to the registry:
  235. //
  236. // HKEY_CLASSES_ROOT\CLSID\<CLSID> = <ObjectName> Object
  237. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 = <path to local server>
  238. //
  239. // Parameters:
  240. // LPCSTR - [in] Object Name
  241. // REFCLSID - [in] CLSID of the object
  242. //
  243. // Output:
  244. // BOOL - FALSE means couldn't register it all
  245. //
  246. // Notes:
  247. //
  248. BOOL RegisterUnknownObject
  249. (
  250. LPCSTR pszObjectName,
  251. LPCSTR pszLabelName,
  252. REFCLSID riidObject,
  253. BOOL fAptThreadSafe
  254. )
  255. {
  256. HKEY hk = NULL, hkSub = NULL;
  257. char szGuidStr[GUID_STR_LEN];
  258. DWORD dwPathLen, dwDummy;
  259. char szScratch[MAX_PATH];
  260. long l;
  261. // HKEY_CLASSES_ROOT\CLSID\<CLSID> = <ObjectName> Object
  262. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 = <path to local server>
  263. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 @ThreadingModel = Apartment
  264. //
  265. // If someone has added Implemented Categories for our control, then
  266. // don't blow away the entire CLSID section as we will blow away
  267. // these keys. Ideally we should clean up all other keys, but
  268. // implemented categories, but this would be expensive.
  269. //
  270. if (!ExistImplementedCategories(riidObject))
  271. // clean out any garbage
  272. //
  273. UnregisterUnknownObject(riidObject, NULL);
  274. if (!StringFromGuidA(riidObject, szGuidStr))
  275. goto CleanUp;
  276. wsprintf(szScratch, "CLSID\\%s", szGuidStr);
  277. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  278. KEY_READ | KEY_WRITE, NULL, &hk, &dwDummy);
  279. CLEANUP_ON_ERROR(l);
  280. if (!pszLabelName)
  281. wsprintf(szScratch, "%s Object", pszObjectName);
  282. else
  283. lstrcpy(szScratch, pszLabelName);
  284. l = RegSetValueEx(hk, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  285. CLEANUP_ON_ERROR(l);
  286. l = RegCreateKeyEx(hk, "InprocServer32", 0, "", REG_OPTION_NON_VOLATILE,
  287. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  288. CLEANUP_ON_ERROR(l);
  289. dwPathLen = GetModuleFileName(g_hInstance, szScratch, sizeof(szScratch));
  290. if (!dwPathLen) goto CleanUp;
  291. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, dwPathLen + 1);
  292. CLEANUP_ON_ERROR(l);
  293. if (fAptThreadSafe)
  294. {
  295. l = RegSetValueEx(hkSub, "ThreadingModel", 0, REG_SZ, (BYTE *)"Apartment", sizeof("Apartment"));
  296. CLEANUP_ON_ERROR(l);
  297. }
  298. else
  299. {
  300. // Blow away any existing key that would say we're Apartment model threaded
  301. //
  302. RegDeleteValue(hkSub, "ThreadingModel");
  303. }
  304. RegCloseKey(hkSub);
  305. RegCloseKey(hk);
  306. return TRUE;
  307. // we are not very happy!
  308. //
  309. CleanUp:
  310. if (hk) RegCloseKey(hk);
  311. if (hkSub) RegCloseKey(hkSub);
  312. return FALSE;
  313. }
  314. //=--------------------------------------------------------------------------=
  315. // RegisterAutomationObject
  316. //=--------------------------------------------------------------------------=
  317. // given a little bit of information about an automation object, go and put it
  318. // in the registry.
  319. // we add the following information in addition to that set up in
  320. // RegisterUnknownObject:
  321. //
  322. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName> = <ObjectName> Object
  323. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CLSID = <CLSID>
  324. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CurVer = <ObjectName>.Object.<VersionNumber>
  325. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\Version = <VERSION>
  326. //
  327. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber> = <ObjectName> Object
  328. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber>\CLSID = <CLSID>
  329. //
  330. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\TypeLib = <LibidOfTypeLibrary>
  331. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\ProgID = <LibraryName>.<ObjectName>.<VersionNumber>
  332. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\VersionIndependentProgID = <LibraryName>.<ObjectName>
  333. //
  334. // Parameters:
  335. // LPCSTR - [in] Library Name
  336. // LPCSTR - [in] Object Name
  337. // long - [in] Object Version Number
  338. // long - [in] typelib major ver
  339. // long - [in] typelib minor ver
  340. // REFCLSID - [in] LIBID of type library
  341. // REFCLSID - [in] CLSID of the object
  342. //
  343. // Output:
  344. // BOOL - FALSE means not all of it was registered
  345. //
  346. // Notes:
  347. //
  348. BOOL RegisterAutomationObject
  349. (
  350. LPCSTR pszLibName,
  351. LPCSTR pszObjectName,
  352. LPCSTR pszLabelName,
  353. long lVersion,
  354. long lTLMajor,
  355. long lTLMinor,
  356. REFCLSID riidLibrary,
  357. REFCLSID riidObject,
  358. BOOL fAptThreadSafe
  359. )
  360. {
  361. ICatRegister *pCatRegister;
  362. HRESULT hr;
  363. HKEY hk = NULL, hkSub = NULL;
  364. char szGuidStr[GUID_STR_LEN];
  365. char szScratch[MAX_PATH];
  366. long l;
  367. DWORD dwDummy;
  368. // This is a warning assert. If you've tripped this, then your current component
  369. // is within VERSION_DELTA versions of exceeding MAX_VERSION. Consider bumping up MAX_VERSION
  370. // or change the delta to a smaller number. Reasonable settings for these
  371. // depend on how often you do a major version change of your component.
  372. //
  373. ASSERT(MAX_VERSION > VERSION_DELTA, "The MAX_VERSION setting is not in line with what we expect it to be.");
  374. ASSERT(lVersion <= MAX_VERSION - VERSION_DELTA, "Version number of component is approaching or exceeds limit of checked range. Consider increasing MAX_VERSION value.");
  375. // first register the simple Unknown stuff.
  376. //
  377. if (!RegisterUnknownObject(pszObjectName, pszLabelName, riidObject, fAptThreadSafe)) return FALSE;
  378. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName> = <ObjectName> Object
  379. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CLSID = <CLSID>
  380. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CurVer = <ObjectName>.Object.<VersionNumber>
  381. //
  382. lstrcpy(szScratch, pszLibName);
  383. lstrcat(szScratch, ".");
  384. lstrcat(szScratch, pszObjectName);
  385. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0L, "",
  386. REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  387. NULL, &hk, &dwDummy);
  388. CLEANUP_ON_ERROR(l);
  389. if (!pszLabelName)
  390. wsprintf(szScratch, "%s Object", pszObjectName);
  391. else
  392. lstrcpy(szScratch, pszLabelName);
  393. l = RegSetValueEx(hk, NULL, 0L, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch)+1);
  394. CLEANUP_ON_ERROR(l);
  395. l = RegCreateKeyEx(hk, "CLSID", 0L, "", REG_OPTION_NON_VOLATILE,
  396. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  397. CLEANUP_ON_ERROR(l);
  398. if (!StringFromGuidA(riidObject, szGuidStr))
  399. goto CleanUp;
  400. l = RegSetValueEx(hkSub, NULL, 0L, REG_SZ, (BYTE *)szGuidStr, lstrlen(szGuidStr) + 1);
  401. CLEANUP_ON_ERROR(l);
  402. RegCloseKey(hkSub);
  403. l = RegCreateKeyEx(hk, "CurVer", 0, "", REG_OPTION_NON_VOLATILE,
  404. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  405. CLEANUP_ON_ERROR(l);
  406. ASSERT(pszObjectName, "Object name is NULL");
  407. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  408. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  409. CLEANUP_ON_ERROR(l);
  410. RegCloseKey(hkSub);
  411. RegCloseKey(hk);
  412. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber> = <ObjectName> Object
  413. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber>\CLSID = <CLSID>
  414. //
  415. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  416. KEY_READ | KEY_WRITE, NULL, &hk, &dwDummy);
  417. CLEANUP_ON_ERROR(l);
  418. if (!pszLabelName)
  419. wsprintf(szScratch, "%s Object", pszObjectName);
  420. else
  421. lstrcpy(szScratch, pszLabelName);
  422. l = RegSetValueEx(hk, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  423. CLEANUP_ON_ERROR(l);
  424. l = RegCreateKeyEx(hk, "CLSID", 0, "", REG_OPTION_NON_VOLATILE,
  425. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  426. CLEANUP_ON_ERROR(l);
  427. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szGuidStr, lstrlen(szGuidStr) + 1);
  428. CLEANUP_ON_ERROR(l);
  429. RegCloseKey(hkSub);
  430. RegCloseKey(hk);
  431. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\ProgID = <LibraryName>.<ObjectName>.<VersionNumber>
  432. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\VersionIndependentProgID = <LibraryName>.<ObjectName>
  433. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\TypeLib = <LibidOfTypeLibrary>
  434. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\Version = "<TLMajor>.<TLMinor>"
  435. //
  436. if (!StringFromGuidA(riidObject, szGuidStr)) goto CleanUp;
  437. wsprintf(szScratch, "CLSID\\%s", szGuidStr);
  438. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  439. KEY_READ|KEY_WRITE, NULL, &hk, &dwDummy);
  440. CLEANUP_ON_ERROR(l);
  441. l = RegCreateKeyEx(hk, "VersionIndependentProgID", 0, "", REG_OPTION_NON_VOLATILE,
  442. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  443. CLEANUP_ON_ERROR(l);
  444. wsprintf(szScratch, "%s.%s", pszLibName, pszObjectName);
  445. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  446. CLEANUP_ON_ERROR(l);
  447. RegCloseKey(hkSub);
  448. l = RegCreateKeyEx(hk, "ProgID", 0, "", REG_OPTION_NON_VOLATILE,
  449. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  450. CLEANUP_ON_ERROR(l);
  451. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  452. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  453. CLEANUP_ON_ERROR(l);
  454. RegCloseKey(hkSub);
  455. l = RegCreateKeyEx(hk, "TypeLib", 0, "", REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  456. NULL, &hkSub, &dwDummy);
  457. if (!StringFromGuidA(riidLibrary, szGuidStr)) goto CleanUp;
  458. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szGuidStr, lstrlen(szGuidStr) + 1);
  459. CLEANUP_ON_ERROR(l);
  460. // now set up the version information
  461. //
  462. RegCloseKey(hkSub);
  463. l = RegCreateKeyEx(hk, "Version", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  464. CLEANUP_ON_ERROR(l);
  465. wsprintf(szScratch, "%ld.%ld", lTLMajor, lTLMinor);
  466. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  467. // now, finally, register ourselves with component categories
  468. //
  469. hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
  470. CLSCTX_INPROC_SERVER, IID_ICatRegister,
  471. (void **)&pCatRegister);
  472. if (SUCCEEDED(hr)) {
  473. pCatRegister->RegisterClassImplCategories(riidObject, 1,
  474. (GUID *)&CATID_Programmable);
  475. pCatRegister->Release();
  476. }
  477. RegCloseKey(hkSub);
  478. RegCloseKey(hk);
  479. return TRUE;
  480. CleanUp:
  481. if (hk) RegCloseKey(hkSub);
  482. if (hk) RegCloseKey(hk);
  483. return FALSE;
  484. }
  485. //=--------------------------------------------------------------------------=
  486. // RegisterControlObject.
  487. //=--------------------------------------------------------------------------=
  488. // in addition to writing out automation object information, this function
  489. // writes out some values specific to a control.
  490. //
  491. // What we add here:
  492. //
  493. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\Control
  494. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\MiscStatus\1 = <MISCSTATUSBITS>
  495. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\ToolboxBitmap32 = <PATH TO BMP>
  496. //
  497. // Parameters:
  498. // LPCSTR - [in] Library Name
  499. // LPCSTR - [in] Object Name
  500. // long - [in] Object Major Version Number
  501. // long - [in] Object Minor Vesrion Number
  502. // long - [in] TypeLib Major Version Number
  503. // long - [in] Typelib minor version number
  504. // REFCLSID - [in] LIBID of type library
  505. // REFCLSID - [in] CLSID of the object
  506. // DWORD - [in] misc status flags for ctl
  507. // WORD - [in] toolbox id for control
  508. // BOOL - [in] Apartment thread safe flag
  509. // BOOL - [in] Control bit:Flag to tell whether to add the Control key or not.
  510. //
  511. // Output:
  512. // BOOL
  513. //
  514. // Notes:
  515. // - not the most terribly efficient routine.
  516. //
  517. BOOL RegisterControlObject
  518. (
  519. LPCSTR pszLibName,
  520. LPCSTR pszObjectName,
  521. LPCSTR pszLabelName,
  522. long lMajorVersion,
  523. long lMinorVersion,
  524. long lTLMajor,
  525. long lTLMinor,
  526. REFCLSID riidLibrary,
  527. REFCLSID riidObject,
  528. DWORD dwMiscStatus,
  529. WORD wToolboxBitmapId,
  530. BOOL fAptThreadSafe,
  531. BOOL fControl
  532. )
  533. {
  534. ICatRegister *pCatRegister;
  535. HRESULT hr;
  536. HKEY hk, hkSub = NULL, hkSub2 = NULL;
  537. char szTmp[MAX_PATH];
  538. char szGuidStr[GUID_STR_LEN];
  539. DWORD dwDummy;
  540. CATID rgCatid[CATID_ARRAY_SIZE];
  541. LONG l;
  542. // first register all the automation information for this sucker.
  543. //
  544. if (!RegisterAutomationObject(pszLibName, pszObjectName, pszLabelName, lMajorVersion, lTLMajor, lTLMinor, riidLibrary, riidObject, fAptThreadSafe)) return FALSE;
  545. // then go and register the control specific stuff.
  546. //
  547. StringFromGuidA(riidObject, szGuidStr);
  548. wsprintf(szTmp, "CLSID\\%s", szGuidStr);
  549. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, szTmp, 0, KEY_ALL_ACCESS, &hk);
  550. if (l != ERROR_SUCCESS) return FALSE;
  551. // create the control flag.
  552. //
  553. if (fControl)
  554. {
  555. l = RegCreateKeyEx(hk, "Control", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  556. CLEANUP_ON_ERROR(l);
  557. RegCloseKey(hkSub);
  558. hkSub = NULL;
  559. }
  560. // now set up the MiscStatus Bits...
  561. //
  562. l = RegCreateKeyEx(hk, "MiscStatus", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  563. CLEANUP_ON_ERROR(l);
  564. szTmp[0] = '0';
  565. szTmp[1] = '\0';
  566. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szTmp, 2);
  567. CLEANUP_ON_ERROR(l);
  568. l = RegCreateKeyEx(hkSub, "1", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub2, &dwDummy);
  569. CLEANUP_ON_ERROR(l);
  570. wsprintf(szTmp, "%d", dwMiscStatus);
  571. l = RegSetValueEx(hkSub2, NULL, 0, REG_SZ, (BYTE *)szTmp, lstrlen(szTmp) + 1);
  572. RegCloseKey(hkSub2);
  573. CLEANUP_ON_ERROR(l);
  574. RegCloseKey(hkSub);
  575. hkSub = NULL;
  576. // Don't need Toolbox bitmap for designers and other non-controls
  577. //
  578. if (fControl)
  579. {
  580. // now set up the toolbox bitmap
  581. //
  582. GetModuleFileName(g_hInstance, szTmp, MAX_PATH);
  583. wsprintf(szGuidStr, ", %d", wToolboxBitmapId);
  584. lstrcat(szTmp, szGuidStr);
  585. l = RegCreateKeyEx(hk, "ToolboxBitmap32", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  586. CLEANUP_ON_ERROR(l);
  587. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szTmp, lstrlen(szTmp) + 1);
  588. CLEANUP_ON_ERROR(l);
  589. }
  590. // now, finally, register ourselves with component categories
  591. //
  592. hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
  593. CLSCTX_INPROC_SERVER, IID_ICatRegister,
  594. (void **)&pCatRegister);
  595. if (SUCCEEDED(hr)) {
  596. int iCounter;
  597. ASSERT(g_ctCATIDImplemented <= CATID_ARRAY_SIZE &&
  598. g_ctCATIDRequired <= CATID_ARRAY_SIZE,
  599. "Array for CATID's is too small. Need to adjust.");
  600. // Register all the implemented CATID's of the control.
  601. if(g_ctCATIDImplemented > 0)
  602. {
  603. for(iCounter = 0; iCounter < g_ctCATIDImplemented &&
  604. iCounter < CATID_ARRAY_SIZE; iCounter++)
  605. memcpy(&(rgCatid[iCounter]), g_rgCATIDImplemented[iCounter], sizeof(CATID));
  606. pCatRegister->RegisterClassImplCategories(riidObject,
  607. g_ctCATIDImplemented,
  608. (GUID *)rgCatid);
  609. } //if
  610. // Register all the Required CATID's of the control.
  611. if(g_ctCATIDRequired > 0)
  612. {
  613. for(iCounter = 0; iCounter < g_ctCATIDRequired &&
  614. iCounter < CATID_ARRAY_SIZE; iCounter++)
  615. memcpy(&(rgCatid[iCounter]), g_rgCATIDRequired[iCounter], sizeof(CATID));
  616. pCatRegister->RegisterClassReqCategories(riidObject,
  617. g_ctCATIDRequired,
  618. (GUID *)rgCatid);
  619. } //if
  620. pCatRegister->Release();
  621. }
  622. CleanUp:
  623. if (hk)
  624. RegCloseKey(hk);
  625. if (hkSub)
  626. RegCloseKey(hkSub);
  627. return (l == ERROR_SUCCESS) ? TRUE : FALSE;
  628. }
  629. //=--------------------------------------------------------------------------=
  630. // UnregisterUnknownObject
  631. //=--------------------------------------------------------------------------=
  632. // cleans up all the stuff that RegisterUnknownObject puts in the
  633. // registry.
  634. //
  635. // Parameters:
  636. // REFCLSID - [in] CLSID of the object
  637. // BOOL - [out] Returns TRUE if all keys were deleted for the
  638. // given CLSID. Returns FALSE if only the
  639. // InprocServer32 key or no keys were deleted.
  640. // The caller can pass NULL if they don't care
  641. // about what set of keys were removed.
  642. //
  643. // Output:
  644. // BOOL - FALSE means not all of it was registered
  645. //
  646. // Notes:
  647. // WARNING! This routine assumes that all framework built components
  648. // and their predessors are in-process server 32-bit DLLs.
  649. // If other server types exist for control's CLSID
  650. // the CLSID entry will be blown away for these server types.
  651. //
  652. // If the framework and the control are built as 16-bit components
  653. // and you unregister the control, the information will be left
  654. // in the registry. You're on your own to make this work for 16-bit.
  655. //
  656. // This routine *only* preserves the CLSID section if
  657. // a 16-bit InprocServer key is found.
  658. //
  659. BOOL UnregisterUnknownObject
  660. (
  661. REFCLSID riidObject,
  662. BOOL *pfAllRemoved
  663. )
  664. {
  665. char szScratch[MAX_PATH];
  666. HKEY hk;
  667. BOOL f;
  668. long l;
  669. // Start on the assumption that we are going to blow away the entire section
  670. // for the given CLSID. If this turns out to be a false assumption we'll
  671. // reset this to FALSE.
  672. //
  673. if (pfAllRemoved)
  674. *pfAllRemoved = TRUE;
  675. // delete everybody of the form
  676. // HKEY_CLASSES_ROOT\CLSID\<CLSID> [\] *
  677. //
  678. if (!StringFromGuidA(riidObject, szScratch))
  679. return FALSE;
  680. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_ALL_ACCESS, &hk);
  681. if (l != ERROR_SUCCESS) return FALSE;
  682. // See if a 16-bit in-proc server is register for this object
  683. // If so, then we don't want to disturb any of the keys except
  684. // the 32-bit in-proc server key
  685. //
  686. if (ExistInprocServer(hk, szScratch))
  687. {
  688. // Move one more level down to the InprocServer32 key and only delete it
  689. // We need to preserve the other keys for the InprocServer.
  690. //
  691. lstrcat(szScratch, "\\InprocServer32");
  692. if (pfAllRemoved)
  693. *pfAllRemoved = FALSE;
  694. }
  695. f = DeleteKeyAndSubKeys(hk, szScratch);
  696. RegCloseKey(hk);
  697. return f;
  698. }
  699. //=--------------------------------------------------------------------------=
  700. // UnregisterAutomationObject
  701. //=--------------------------------------------------------------------------=
  702. // unregisters an automation object, including all of it's unknown object
  703. // information.
  704. //
  705. // Parameters:
  706. // LPCSTR - [in] Library Name
  707. // LPCSTR - [in] Object Name
  708. // long - [in] Version Number
  709. // REFCLSID - [in] CLSID of the object
  710. //
  711. // Output:
  712. // BOOL - FALSE means couldn't get it all unregistered.
  713. //
  714. // Notes:
  715. //
  716. BOOL UnregisterAutomationObject
  717. (
  718. LPCSTR pszLibName,
  719. LPCSTR pszObjectName,
  720. long lVersion,
  721. REFCLSID riidObject
  722. )
  723. {
  724. char szScratch[MAX_PATH];
  725. HKEY hk;
  726. BOOL f, fAllRemoved, fFailure;
  727. long l, lVersionFound;
  728. DWORD dwDummy;
  729. BOOL bSuccess;
  730. // first thing -- unregister Unknown information
  731. //
  732. f = UnregisterUnknownObject(riidObject, &fAllRemoved);
  733. if (!f) return FALSE;
  734. if (fAllRemoved)
  735. {
  736. // delete everybody of the form
  737. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber> [\] *
  738. //
  739. // Note: It's important we unregister the version dependent progid first
  740. // otherwise, if another version of the component was unregistered
  741. // it will have blown away the version independent progid, we'd
  742. // fail and never blow away the version dependent progid
  743. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  744. f = DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szScratch);
  745. if (!f) return FALSE;
  746. // Before we blow away the version independent ProgId, make sure there are
  747. // no version dependent ProgIds out there
  748. //
  749. if (!QueryOtherVersionProgIds(pszLibName, pszObjectName, lVersion, &lVersionFound, &fFailure))
  750. {
  751. ASSERT(!fFailure, "QueryOtherVersionProgIds failed");
  752. // If a failure occurred such that we don't know if there was another version,
  753. // error on the side of leaving the version dependent ProgId in the registry.
  754. //
  755. if (!fFailure)
  756. {
  757. // delete everybody of the form:
  758. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName> [\] *
  759. //
  760. wsprintf(szScratch, "%s.%s", pszLibName, pszObjectName);
  761. f = DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szScratch);
  762. if (!f) return FALSE;
  763. }
  764. }
  765. else
  766. {
  767. // This is here to fix a bug in the previous version of the framework
  768. // In the previous version we'd blindly blow away the progid for the
  769. // component without looking for other versions. To help
  770. // resolve this, we'll restore the progid if we found other
  771. // version dependent progids.
  772. //
  773. ASSERT(lVersionFound > 0, "Version number found is 0");
  774. bSuccess = CopyVersionDependentProgIdToIndependentProgId(pszLibName, pszObjectName, lVersionFound);
  775. ASSERT(bSuccess, "Failed to copy version dependent ProgId to version independent ProgId");
  776. // The previous version of the framework didn't write out the CurVer sub-key so
  777. // we need to take care of that here.
  778. //
  779. wsprintf(szScratch, "%s.%s\\CurVer", pszLibName, pszObjectName);
  780. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, KEY_ALL_ACCESS, &hk);
  781. if (ERROR_SUCCESS != l)
  782. {
  783. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  784. KEY_READ | KEY_WRITE, NULL, &hk, &dwDummy);
  785. ASSERT(ERROR_SUCCESS == l, "Failed to create reg key");
  786. if (ERROR_SUCCESS == l)
  787. {
  788. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersionFound);
  789. l = RegSetValueEx(hk, NULL, 0, REG_SZ, (BYTE *)szScratch, lstrlen(szScratch) + 1);
  790. ASSERT(ERROR_SUCCESS == l, "Failed to set key value");
  791. l = RegCloseKey(hk);
  792. ASSERT(ERROR_SUCCESS == l, "Failed to close key");
  793. }
  794. }
  795. else
  796. {
  797. l = RegCloseKey(hk);
  798. }
  799. }
  800. }
  801. return TRUE;
  802. }
  803. //=--------------------------------------------------------------------------=
  804. // UnregisterTypeLibrary
  805. //=--------------------------------------------------------------------------=
  806. // blows away the type library keys for a given libid.
  807. //
  808. // Parameters:
  809. // REFCLSID - [in] libid to blow away.
  810. //
  811. // Output:
  812. // BOOL - TRUE OK, FALSE bad.
  813. //
  814. // Notes:
  815. // - WARNING: this function just blows away the entire type library section,
  816. // including all localized versions of the type library. mildly anti-
  817. // social, but not killer.
  818. //
  819. BOOL UnregisterTypeLibrary
  820. (
  821. REFCLSID riidLibrary
  822. )
  823. {
  824. HKEY hk;
  825. char szScratch[GUID_STR_LEN];
  826. long l;
  827. BOOL f;
  828. // convert the libid into a string.
  829. //
  830. if (!StringFromGuidA(riidLibrary, szScratch))
  831. return FALSE;
  832. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, "TypeLib", 0, KEY_ALL_ACCESS, &hk);
  833. if (l != ERROR_SUCCESS) return FALSE;
  834. f = DeleteKeyAndSubKeys(hk, szScratch);
  835. RegCloseKey(hk);
  836. return f;
  837. }
  838. //=--------------------------------------------------------------------------=
  839. // DeleteKeyAndSubKeys
  840. //=--------------------------------------------------------------------------=
  841. // deletes a key and all of its subkeys.
  842. //
  843. // Parameters:
  844. // HKEY - [in] delete the descendant specified
  845. // LPCSTR - [in] i'm the descendant specified
  846. //
  847. // Output:
  848. // BOOL - TRUE OK, FALSE baaaad.
  849. //
  850. // Notes:
  851. // - I don't feel too bad about implementing this recursively, since the
  852. // depth isn't likely to get all the great.
  853. // - Despite the win32 docs claiming it does, RegDeleteKey doesn't seem to
  854. // work with sub-keys under windows 95.
  855. //
  856. BOOL DeleteKeyAndSubKeys
  857. (
  858. HKEY hkIn,
  859. LPCSTR pszSubKey
  860. )
  861. {
  862. HKEY hk;
  863. char szTmp[MAX_PATH];
  864. DWORD dwTmpSize;
  865. long l;
  866. BOOL f;
  867. l = RegOpenKeyEx(hkIn, pszSubKey, 0, KEY_ALL_ACCESS, &hk);
  868. if (l != ERROR_SUCCESS) return FALSE;
  869. // loop through all subkeys, blowing them away.
  870. //
  871. f = TRUE;
  872. while (f) {
  873. dwTmpSize = MAX_PATH;
  874. // We're deleting keys, so always enumerate the 0th
  875. l = RegEnumKeyEx(hk, 0, szTmp, &dwTmpSize, 0, NULL, NULL, NULL);
  876. if (l != ERROR_SUCCESS) break;
  877. f = DeleteKeyAndSubKeys(hk, szTmp);
  878. }
  879. // there are no subkeys left, [or we'll just generate an error and return FALSE].
  880. // let's go blow this dude away.
  881. //
  882. RegCloseKey(hk);
  883. l = RegDeleteKey(hkIn, pszSubKey);
  884. return (l == ERROR_SUCCESS) ? TRUE : FALSE;
  885. }
  886. //=--------------------------------------------------------------------------=
  887. // QueryOtherVersionProgIds [RegisterTypeLib helper]
  888. //=--------------------------------------------------------------------------=
  889. // Searches for other version dependent ProgIds for a component
  890. //
  891. // Parameters:
  892. // pszLibName - [in] lib name portion of ProgId <libname.coclass>
  893. // pszObjectName - [in] coclass portion of ProgId <libname.coclass>
  894. // lVersion - [in] Major version number of our component
  895. // plFoundVersion - [out] The largest version number found not equal to our own.
  896. // The version number will be less than or equal to MAX_VERSION
  897. // pfFailure - [out] Flag indicating that a failure occurred preventing
  898. // us from knowing if there are any other ProgIds
  899. // Output:
  900. // BOOL - TRUE: One or more other version dependent progids exist
  901. // FALSE: No other version dependent progids exist
  902. //
  903. // Notes:
  904. // - If a version dependent ProgId exceeds MAX_VERSION we won't find it.
  905. // - ASSUMPTION: Major versions are checked for starting at MAX_VERSION and working
  906. // down to 1. An assert will occur if your component
  907. // approaches MAX_VERSION allowing you to bump up MAX_VERSION.
  908. // The assumption is that major version changes on components
  909. // built with the framework are rare. It should take many
  910. // dev cycles and many years to approach this limit.
  911. // Once you get near the limit the assert fires and you
  912. // can modify the value to anticipate future versions.
  913. // This will allow components built today to successfully
  914. // find ProgIds for other components built in the future.
  915. // However, at some point a component built today won't
  916. // be able to find other controls that exceed today's
  917. // MAX_VERSION value. If this is a concern, re-write
  918. // this routine to use RegEnumKey and look for any
  919. // version dependent ProgId independent of it's version number.
  920. // We chose not to implement it this way, since there may be
  921. // several hundred calls to RegEnumKey to find the ProgId
  922. // you're looking for. It's cheaper to make at most MAX_VERSION
  923. // calls.
  924. //
  925. BOOL QueryOtherVersionProgIds
  926. (
  927. LPCSTR pszLibName,
  928. LPCSTR pszObjectName,
  929. long lVersion,
  930. long *plFoundVersion,
  931. BOOL *pfFailure
  932. )
  933. {
  934. BOOL fFound;
  935. char szTmp[MAX_PATH];
  936. long lVer;
  937. long l;
  938. HKEY hk, hkVersion;
  939. CHECK_POINTER(pszLibName);
  940. CHECK_POINTER(pszObjectName);
  941. // This is a warning assert. If you've tripped this, then your current component
  942. // is within VERSION_DELTA versions of exceeding MAX_VERSION. Consider bumping up MAX_VERSION
  943. // or change the delta to a smaller number. Reasonable settings for these
  944. // depend on how often you do a major version change of your component.
  945. //
  946. ASSERT(MAX_VERSION > VERSION_DELTA, "The MAX_VERSION setting is not in line with what we expect it to be.");
  947. ASSERT(lVersion <= MAX_VERSION - VERSION_DELTA, "Version number of component is approaching or exceeds limit of checked range. Consider increasing MAX_VERSION value.");
  948. // Initialize out params
  949. //
  950. if (plFoundVersion)
  951. *plFoundVersion = 0;
  952. if (pfFailure)
  953. *pfFailure = TRUE;
  954. fFound = FALSE;
  955. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, "", 0, KEY_ALL_ACCESS, &hk);
  956. ASSERT(l == ERROR_SUCCESS, "Failed to open HKEY_CLASSES_ROOT");
  957. if (l != ERROR_SUCCESS) return FALSE; // Note: If this fails we don't know whether a version dependent ProgId exists or not.
  958. // We need to walk backwards down from MAX_VERSION so that we end up with the largest version number
  959. // not equaling our own
  960. // PERF: It's cheaper to look for a realistic set of versions than it is to enumerate all registry keys
  961. // looking for a partial match on the ProgId to figure out what versions are available.
  962. //
  963. for (lVer = MAX_VERSION; lVer > 0; lVer--)
  964. {
  965. // We know about our version number, skip it.
  966. //
  967. if (lVersion == lVer)
  968. continue;
  969. // Create version dependent ProgId
  970. //
  971. wsprintf(szTmp, "%s.%s.%ld", pszLibName, pszObjectName, lVer);
  972. l = RegOpenKeyEx(hk, szTmp, 0, KEY_ALL_ACCESS, &hkVersion);
  973. if (ERROR_SUCCESS == l)
  974. {
  975. // We found another version dependent ProgId other than our own - bail out
  976. //
  977. fFound = TRUE;
  978. if (plFoundVersion)
  979. *plFoundVersion = lVer;
  980. l = RegCloseKey(hkVersion);
  981. ASSERT(l == ERROR_SUCCESS, "Failed to close version dependent key");
  982. goto CleanUp;
  983. }
  984. }
  985. CleanUp:
  986. // If we made it this far, then we know for certain whether there were other
  987. // version dependent progids or not. Reflect back to the caller there
  988. // was no general failure that led to us not know whether there were
  989. // any version dependent ProgIds
  990. //
  991. if (pfFailure)
  992. *pfFailure = FALSE;
  993. l = RegCloseKey(hk);
  994. ASSERT(l == ERROR_SUCCESS, "Failed closing HKEY_CLASSES_ROOT key");
  995. return fFound;
  996. }
  997. //=--------------------------------------------------------------------------=
  998. // CopyVersionDependentProgIdToIndependentProgId [RegisterTypeLib helper]
  999. //=--------------------------------------------------------------------------=
  1000. // Copies the contents of the version dependent ProgId to a version
  1001. // independent ProgId
  1002. //
  1003. // Parameters:
  1004. // pszLibName - [in] lib name portion of ProgId <libname.coclass>
  1005. // pszObjectName - [in] coclass portion of ProgId <libname.coclass>
  1006. // lVersion - [in] Major version number of our component
  1007. //
  1008. // Output:
  1009. // BOOL - TRUE: ProgId was copied successfully
  1010. // FALSE: ProgId was not copied successfully
  1011. //
  1012. // Notes:
  1013. //
  1014. BOOL CopyVersionDependentProgIdToIndependentProgId
  1015. (
  1016. LPCSTR pszLibName,
  1017. LPCSTR pszObjectName,
  1018. long lVersion
  1019. )
  1020. {
  1021. CHECK_POINTER(pszLibName);
  1022. CHECK_POINTER(pszObjectName);
  1023. HKEY hkVerDependent, hkVerIndependent;
  1024. char szTmp[MAX_PATH];
  1025. long l, lTmp;
  1026. BOOL bSuccess;
  1027. DWORD dwDummy;
  1028. // Get a handle to the version dependent ProgId
  1029. //
  1030. wsprintf(szTmp, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  1031. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, szTmp, 0, KEY_ALL_ACCESS, &hkVerDependent);
  1032. ASSERT(ERROR_SUCCESS == l, "Failed to open the version dependent ProgId");
  1033. if (ERROR_SUCCESS != l)
  1034. return FALSE;
  1035. // Blow away the version independent ProgId
  1036. //
  1037. wsprintf(szTmp, "%s.%s", pszLibName, pszObjectName);
  1038. DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szTmp);
  1039. // Create the initial key for the version independent ProgId
  1040. //
  1041. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szTmp, 0, "", REG_OPTION_NON_VOLATILE,
  1042. KEY_READ | KEY_WRITE, NULL, &hkVerIndependent, &dwDummy);
  1043. if (ERROR_SUCCESS != l)
  1044. goto CleanUp;
  1045. // Copy the contents of the version dependent ProgId to the version independent ProgId
  1046. //
  1047. bSuccess = CopyRegistrySection(hkVerDependent, hkVerIndependent);
  1048. l = (bSuccess) ? ERROR_SUCCESS : !ERROR_SUCCESS;
  1049. CleanUp:
  1050. lTmp = RegCloseKey(hkVerDependent);
  1051. ASSERT(ERROR_SUCCESS == lTmp, "Failed to close registry key");
  1052. lTmp = RegCloseKey(hkVerIndependent);
  1053. ASSERT(ERROR_SUCCESS == lTmp, "Failed to close registry key");
  1054. return (ERROR_SUCCESS == l) ? TRUE : FALSE;
  1055. }
  1056. //=--------------------------------------------------------------------------=
  1057. // CopyRegistrySection
  1058. //=--------------------------------------------------------------------------=
  1059. // Recursively copies a section of the registry to another section of the
  1060. // registry
  1061. //
  1062. // Parameters:
  1063. // hkSource - [in] The source key to copy from
  1064. // hkDest - [in] The dest key to copy to
  1065. //
  1066. // Output:
  1067. // BOOL - TRUE: Registry section was copied successfully
  1068. // FALSE: Registry section was not copied successfully
  1069. //
  1070. // Notes:
  1071. // - In order for this to work, only the top-level destination key should exist.
  1072. // We assume that there are no sub-keys under the destination key.
  1073. //
  1074. BOOL CopyRegistrySection(HKEY hkSource, HKEY hkDest)
  1075. {
  1076. char szTmp[MAX_PATH];
  1077. long l, lTmp;
  1078. DWORD dwKey, dwDummy, cbData;
  1079. HKEY hkSrcSub, hkDestSub;
  1080. BOOL bSuccess;
  1081. FILETIME ft;
  1082. DWORD dwType;
  1083. // Copy the value of the source key to the destination key
  1084. //
  1085. cbData = sizeof(szTmp);
  1086. l = RegQueryValueEx(hkSource, NULL, NULL, &dwType, (BYTE *) szTmp, &cbData);
  1087. if (ERROR_SUCCESS != l)
  1088. return FALSE;
  1089. l = RegSetValueEx(hkDest, NULL, NULL, dwType, (const BYTE *) szTmp, cbData);
  1090. if (ERROR_SUCCESS != l)
  1091. return FALSE;
  1092. dwKey = 0;
  1093. // Enumerate through all of the sub-keys underneath the source key
  1094. //
  1095. while (ERROR_SUCCESS == RegEnumKeyEx(hkSource, dwKey, szTmp, &cbData, NULL, NULL, NULL, &ft))
  1096. {
  1097. ASSERT(cbData > 0, "RegEnumKeyEx returned 0 length string");
  1098. // Open the registry source sub-key
  1099. //
  1100. l = RegOpenKeyEx(hkSource, szTmp, 0, KEY_ALL_ACCESS, &hkSrcSub);
  1101. ASSERT(ERROR_SUCCESS == l, "Failed to open reg key");
  1102. if (ERROR_SUCCESS != l)
  1103. break;
  1104. // Create the registry dest sub-key
  1105. //
  1106. l = RegCreateKeyEx(hkDest, szTmp, 0, "", REG_OPTION_NON_VOLATILE,
  1107. KEY_READ | KEY_WRITE, NULL, &hkDestSub, &dwDummy);
  1108. ASSERT(ERROR_SUCCESS == l, "Failed to create reg key");
  1109. if (ERROR_SUCCESS != l)
  1110. {
  1111. lTmp = RegCloseKey(hkSrcSub);
  1112. ASSERT(ERROR_SUCCESS == lTmp, "Failed to close reg key");
  1113. break;
  1114. }
  1115. // Recursively call ourselves copying all sub-entries from the source key to the dest key
  1116. //
  1117. bSuccess = CopyRegistrySection(hkSrcSub, hkDestSub);
  1118. ASSERT(bSuccess, "Recursive call to CopyRegistrySection failed");
  1119. // Cleanup
  1120. //
  1121. lTmp = RegCloseKey(hkSrcSub);
  1122. ASSERT(ERROR_SUCCESS == l, "Failed to close reg key");
  1123. lTmp = RegCloseKey(hkDestSub);
  1124. ASSERT(ERROR_SUCCESS == l, "Failed to close reg key");
  1125. dwKey++;
  1126. }
  1127. return (ERROR_SUCCESS == l ? TRUE : FALSE);
  1128. }
  1129. //=--------------------------------------------------------------------------=
  1130. // GetHelpFilePath [RegisterTypeLib helper]
  1131. //=--------------------------------------------------------------------------=
  1132. // Returns the path to the Windows\Help directory
  1133. //
  1134. // Parameters:
  1135. // char * - [in/out] Pointer to buffer that will contain
  1136. // the HELP path we will return to the caller
  1137. // UINT - [in] Number of bytes in the buffer
  1138. //
  1139. // Output:
  1140. // UINT - Returns the number of bytes actually copied to the buffer
  1141. //
  1142. UINT GetHelpFilePath(char *pszPath, UINT cbPath)
  1143. {
  1144. UINT cb;
  1145. char szHelp[] = "\\HELP";
  1146. ASSERT(pszPath, "Path pointer is NULL");
  1147. // No need to continue if specified buffer size is zero or less
  1148. //
  1149. if (cbPath == 0)
  1150. return 0;
  1151. cb = GetWindowsDirectory(pszPath, cbPath);
  1152. ASSERT(cb > 0, "Windows path is zero length");
  1153. // Concatenate "\HELP" onto the Windows directory
  1154. //
  1155. cb += lstrlen(szHelp);
  1156. if (cb < cbPath)
  1157. lstrcat(pszPath, szHelp);
  1158. else
  1159. FAIL("Unable to add HELP path to Windows, buffer too small");
  1160. return cb;
  1161. }
  1162. //=--------------------------------------------------------------------------=
  1163. // ExistInprocServer [RegisterUnknownObject Helper]
  1164. //=--------------------------------------------------------------------------=
  1165. // Checks for the Implemented Categories key under a given key
  1166. //
  1167. // Parameters:
  1168. // riid - [in] CLSID of object to be examined
  1169. //
  1170. // Output:
  1171. // BOOL - Returns TRUE if Implemented Categories exists
  1172. // Returns FALSE if Implemented Categories doesn't exist
  1173. //
  1174. BOOL ExistImplementedCategories(REFCLSID riid)
  1175. {
  1176. char szGuidStr[MAX_PATH];
  1177. char szScratch[MAX_PATH];
  1178. long l;
  1179. DWORD dwDummy;
  1180. HKEY hkCLSID, hkImplementedCategories;
  1181. if (!StringFromGuidA(riid, szGuidStr))
  1182. return FALSE;
  1183. wsprintf(szScratch, "CLSID\\%s", szGuidStr);
  1184. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  1185. KEY_READ, NULL, &hkCLSID, &dwDummy);
  1186. if (l != ERROR_SUCCESS) return FALSE;
  1187. l = RegOpenKeyEx(hkCLSID, "Implemented Categories", 0, KEY_ALL_ACCESS, &hkImplementedCategories);
  1188. RegCloseKey(hkCLSID);
  1189. if (l != ERROR_SUCCESS) return FALSE;
  1190. RegCloseKey(hkImplementedCategories);
  1191. // If we made it this far, then the 'Implemented Categories' key must have been found
  1192. //
  1193. return TRUE;
  1194. }
  1195. //=--------------------------------------------------------------------------=
  1196. // ExistInprocServer [UnregisterUnknownObject Helper]
  1197. //=--------------------------------------------------------------------------=
  1198. // Checks for other servers such as (16-bit) InProcServer under the
  1199. // CLSID section for a given CLSID guid.
  1200. //
  1201. // Parameters:
  1202. // HKEY - [in] HKEY top-level key where to look for the given
  1203. // CLSID
  1204. // char * - [in] CLSID of server that we want to see if there
  1205. // is an (16-bit) InProcServer registered.
  1206. //
  1207. // Output:
  1208. // BOOL - Returns TRUE if a 16-bit in-proc server is registered
  1209. // Returns FALSE if no 16-bit in-proc server is registered
  1210. //
  1211. BOOL ExistInprocServer(HKEY hkCLSID, char *pszCLSID)
  1212. {
  1213. HKEY hkInProcServer;
  1214. LONG l;
  1215. char szInprocServer[MAX_PATH];
  1216. wsprintf(szInprocServer, "%s\\InprocServer", pszCLSID);
  1217. // Attempt to open the 16-bit 'InProcServer' key
  1218. //
  1219. l = RegOpenKeyEx(hkCLSID, szInprocServer, 0, KEY_ALL_ACCESS, &hkInProcServer);
  1220. if (l != ERROR_SUCCESS) return FALSE;
  1221. RegCloseKey(hkInProcServer);
  1222. // If we made it this far, then the 'InProcServer' key must have been found
  1223. //
  1224. return TRUE;
  1225. }
  1226. //=--------------------------------------------------------------------------=
  1227. // FileExtension
  1228. //=--------------------------------------------------------------------------=
  1229. // Given a filename returns the file extension without the preceeded period.
  1230. //
  1231. char *FileExtension(const char *pszFilename)
  1232. {
  1233. char *pPeriod;
  1234. ASSERT(pszFilename, "Passed in filename is NULL");
  1235. // Start at the end of the string and work backwards looking for a period
  1236. //
  1237. pPeriod = (char *) pszFilename + lstrlen(pszFilename) - 1;
  1238. while (pPeriod >= pszFilename)
  1239. {
  1240. if (*pPeriod == '.')
  1241. return ++pPeriod;
  1242. pPeriod--;
  1243. }
  1244. // No extension name was found
  1245. //
  1246. return NULL;
  1247. }
  1248. //=--------------------------------------------------------------------------=
  1249. // Conversion Routines
  1250. //=--------------------------------------------------------------------------=
  1251. // the following stuff is stuff used for the various conversion routines.
  1252. //
  1253. #define HIMETRIC_PER_INCH 2540
  1254. #define MAP_PIX_TO_LOGHIM(x,ppli) ( (HIMETRIC_PER_INCH*(x) + ((ppli)>>1)) / (ppli) )
  1255. #define MAP_LOGHIM_TO_PIX(x,ppli) ( ((ppli)*(x) + HIMETRIC_PER_INCH/2) / HIMETRIC_PER_INCH )
  1256. static int s_iXppli; // Pixels per logical inch along width
  1257. static int s_iYppli; // Pixels per logical inch along height
  1258. static BYTE s_fGotScreenMetrics; // Are above valid?
  1259. //=--------------------------------------------------------------------------=
  1260. // GetScreenMetrics
  1261. //=--------------------------------------------------------------------------=
  1262. // private function we call to set up various metrics the conversion routines
  1263. // will use.
  1264. //
  1265. // Notes:
  1266. //
  1267. static void GetScreenMetrics
  1268. (
  1269. void
  1270. )
  1271. {
  1272. HDC hDCScreen;
  1273. // we have to critical section this in case two threads are converting
  1274. // things at the same time
  1275. //
  1276. ENTERCRITICALSECTION1(&g_CriticalSection);
  1277. if (s_fGotScreenMetrics)
  1278. goto Done;
  1279. // we want the metrics for the screen
  1280. //
  1281. hDCScreen = GetDC(NULL);
  1282. ASSERT(hDCScreen, "couldn't get a DC for the screen.");
  1283. s_iXppli = GetDeviceCaps(hDCScreen, LOGPIXELSX);
  1284. s_iYppli = GetDeviceCaps(hDCScreen, LOGPIXELSY);
  1285. ReleaseDC(NULL, hDCScreen);
  1286. s_fGotScreenMetrics = TRUE;
  1287. // we're done with our critical seciton. clean it up
  1288. //
  1289. Done:
  1290. LEAVECRITICALSECTION1(&g_CriticalSection);
  1291. }
  1292. //=--------------------------------------------------------------------------=
  1293. // HiMetricToPixel
  1294. //=--------------------------------------------------------------------------=
  1295. // converts from himetric to Pixels.
  1296. //
  1297. // Parameters:
  1298. // const SIZEL * - [in] dudes in himetric
  1299. // SIZEL * - [out] size in pixels.
  1300. //
  1301. // Notes:
  1302. //
  1303. void HiMetricToPixel(const SIZEL * lpSizeInHiMetric, LPSIZEL lpSizeInPix)
  1304. {
  1305. GetScreenMetrics();
  1306. // We got logical HIMETRIC along the display, convert them to pixel units
  1307. //
  1308. lpSizeInPix->cx = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cx, s_iXppli);
  1309. lpSizeInPix->cy = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cy, s_iYppli);
  1310. }
  1311. //=--------------------------------------------------------------------------=
  1312. // PixelToHiMetric
  1313. //=--------------------------------------------------------------------------=
  1314. // converts from pixels to himetric.
  1315. //
  1316. // Parameters:
  1317. // const SIZEL * - [in] size in pixels
  1318. // SIZEL * - [out] size in himetric
  1319. //
  1320. // Notes:
  1321. //
  1322. void PixelToHiMetric(const SIZEL * lpSizeInPix, LPSIZEL lpSizeInHiMetric)
  1323. {
  1324. GetScreenMetrics();
  1325. // We got pixel units, convert them to logical HIMETRIC along the display
  1326. //
  1327. lpSizeInHiMetric->cx = MAP_PIX_TO_LOGHIM(lpSizeInPix->cx, s_iXppli);
  1328. lpSizeInHiMetric->cy = MAP_PIX_TO_LOGHIM(lpSizeInPix->cy, s_iYppli);
  1329. }
  1330. //=--------------------------------------------------------------------------=
  1331. // _MakePath
  1332. //=--------------------------------------------------------------------------=
  1333. // little helper routine for RegisterLocalizedTypeLibs and GetResourceHandle.
  1334. // not terrilby efficient or smart, but it's registration code, so we don't
  1335. // really care.
  1336. //
  1337. // Notes:
  1338. //
  1339. void _MakePath
  1340. (
  1341. LPSTR pszFull,
  1342. const char * pszName,
  1343. LPSTR pszOut
  1344. )
  1345. {
  1346. LPSTR psz;
  1347. LPSTR pszLast;
  1348. lstrcpy(pszOut, pszFull);
  1349. psz = pszLast = pszOut;
  1350. while (*psz) {
  1351. if (*psz == '\\')
  1352. pszLast = AnsiNext(psz);
  1353. psz = AnsiNext(psz);
  1354. }
  1355. // got the last \ character, so just go and replace the name.
  1356. //
  1357. lstrcpy(pszLast, pszName);
  1358. }
  1359. // from Globals.C
  1360. //
  1361. extern HINSTANCE g_hInstResources;
  1362. //=--------------------------------------------------------------------------=
  1363. // GetResourceHandle
  1364. //=--------------------------------------------------------------------------=
  1365. // returns the resource handle. we use the host's ambient Locale ID to
  1366. // determine, from a table in the DLL, which satellite DLL to load for
  1367. // localized resources. If a satellite .DLL is not supported or not found
  1368. // the instance handle of the object is returned.
  1369. //
  1370. // Input:
  1371. // lcid = 0 - [in, optional] Locale id that caller wants resource handle for
  1372. // This overrides the default lcid. If no lcid
  1373. // is provided or its 0, then the default lcid is used.
  1374. //
  1375. // Output:
  1376. // HINSTANCE
  1377. //
  1378. // Notes:
  1379. // The localized .DLL must be at the same location as the client object or control.
  1380. // If the .DLL is not in the same location it will not be found and the resource
  1381. // handle of the client object or control will be returned.
  1382. //
  1383. // If a localized .DLL containing the full language abbreviation is not found,
  1384. // the language abbreviation is truncated to two characters and the satellite
  1385. // DLL with that name is attempted. For example, the name MyCtlJPN.DLL and
  1386. // MyCtlJP.DLL are both valid.
  1387. //
  1388. // If an lcid is passed in then we will attempt to find a satellite DLL matching
  1389. // the desired lcid. If the lcid is not 0, doesn't match the default lcid and a
  1390. // library is found and loaded for it, we don't cache the library's instance handle.
  1391. // Its up to the caller to call FreeLibrary on the returned handle. The caller should
  1392. // compare the returned handle against g_hInstResources and g_hInstance. If its not
  1393. // equal to either of these handles then call FreeLibrary on it. If it is equal to
  1394. // either of these handles then the call must *not* call FreeLibrary on it.
  1395. //
  1396. HINSTANCE _stdcall GetResourceHandle
  1397. (
  1398. LCID lcid /* = 0 */
  1399. )
  1400. {
  1401. int i;
  1402. char szExtension[5], szModuleName[MAX_PATH];
  1403. char szDllName[MAX_PATH], szFinalName[MAX_PATH];
  1404. char szBaseName[MAX_PATH];
  1405. HINSTANCE hInstResources;
  1406. int iCompare;
  1407. #if DEBUG
  1408. int iReCompare;
  1409. char szEnvironValue[MAX_PATH];
  1410. char szMessage[5 * MAX_PATH]; // The message includes 4 file references plus message text
  1411. DWORD dwLength;
  1412. DWORD dwSuccess = 0;
  1413. #endif
  1414. // crit sect this so that we don't screw anything up.
  1415. //
  1416. ENTERCRITICALSECTION1(&g_CriticalSection);
  1417. // If we fall out, we need to make sure we're returning the cached resource handle
  1418. //
  1419. hInstResources = g_hInstResources;
  1420. // don't do anything if we don't have to
  1421. // If the resource handle has already been cached and the passed in lcid matches the
  1422. // cached lcid or its the default, we just use the saved instance.
  1423. //
  1424. if ((hInstResources && (lcid == 0 || lcid == g_lcidLocale)) || !g_fSatelliteLocalization)
  1425. goto CleanUp;
  1426. if (lcid == 0)
  1427. // Passed in LCID is zero so we want the instance for the default lcid.
  1428. lcid = g_lcidLocale;
  1429. // we're going to call GetLocaleInfo to get the abbreviated name for the
  1430. // LCID we've got.
  1431. //
  1432. i = GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, szExtension, sizeof(szExtension));
  1433. if (!i) goto CleanUp;
  1434. // we've got the language extension. go and load the DLL name from the
  1435. // resources and then tack on the extension.
  1436. // please note that all inproc sers -must- have the string resource 1001
  1437. // defined to the base name of the server if they wish to support satellite
  1438. // localization.
  1439. //
  1440. i = LoadString(g_hInstance, 1001, szBaseName, sizeof(szBaseName));
  1441. ASSERT(i, "This server doesn't have IDS_SERVERBASENAME defined in their resources!");
  1442. if (!i) goto CleanUp;
  1443. #ifdef MDAC_BUILD
  1444. if (g_fSatelliteLangExtension)
  1445. #endif
  1446. {
  1447. // got the basename and the extention. go and combine them, and then add
  1448. // on the .DLL for them.
  1449. //
  1450. wsprintf(szDllName, "%s%s.DLL", szBaseName, szExtension);
  1451. // try to load in the DLL
  1452. //
  1453. #if DEBUG
  1454. dwLength =
  1455. #endif
  1456. GetModuleFileName(g_hInstance, szModuleName, MAX_PATH);
  1457. ASSERT(dwLength > 0, "GetModuleFileName failed");
  1458. _MakePath(szModuleName, szDllName, szFinalName);
  1459. hInstResources = LoadLibrary(szFinalName);
  1460. #if DEBUG
  1461. // This will help diagnose problems where a machine may contain two satellite .DLLs
  1462. // one using the long extension name and the other the short extension name.
  1463. // We'll at least get a warning under DEBUG that we've got two plausible satellite
  1464. // DLLs hanging around, but we're only going to use one of them: the one with the long name.
  1465. //
  1466. if (hInstResources && lstrlen(szExtension) > 2)
  1467. {
  1468. HINSTANCE hinstTemp;
  1469. char szExtTemp[MAX_PATH];
  1470. // Truncate the language extension to the first two characters
  1471. lstrcpy(szExtTemp, szExtension); // Don't want to whack the extension as this will cause
  1472. // the next if statement to always fail if we truncate it here.
  1473. // Make a copy and use it.
  1474. szExtTemp[2] = '\0';
  1475. wsprintf(szDllName, "%s%s.DLL", szBaseName, szExtTemp);
  1476. _MakePath(szModuleName, szDllName, szFinalName);
  1477. // Try loading the localized .DLL using the truncated lang abbreviation
  1478. hinstTemp = LoadLibrary(szFinalName);
  1479. ASSERT(hinstTemp == NULL, "Satellite DLLs with both long and short language abbreviations found. Using long abbreviation.");
  1480. }
  1481. #endif // DEBUG
  1482. if (!hInstResources && lstrlen(szExtension) > 2)
  1483. {
  1484. // Truncate the language extension to the first two characters
  1485. szExtension[2] = '\0';
  1486. wsprintf(szDllName, "%s%s.DLL", szBaseName, szExtension);
  1487. _MakePath(szModuleName, szDllName, szFinalName);
  1488. // Try loading the localized .DLL using the truncated lang abbreviation
  1489. hInstResources = LoadLibrary(szFinalName);
  1490. }
  1491. // if we couldn't find it with the entire LCID, try it with just the primary
  1492. // langid
  1493. //
  1494. if (!hInstResources)
  1495. {
  1496. LPSTR psz;
  1497. LCID lcid;
  1498. lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(g_lcidLocale)), SUBLANG_DEFAULT), SORT_DEFAULT);
  1499. i = GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, szExtension, sizeof(szExtension));
  1500. if (!i) goto CleanUp;
  1501. // reconstruct the DLL name. the -7 is the length of XXX.DLL. mildly
  1502. // hacky, but it should be fine. there are no DBCS lang identifiers.
  1503. // finally, retry the load
  1504. //
  1505. psz = szFinalName + lstrlen(szFinalName);
  1506. memcpy((LPBYTE)psz - 7, szExtension, 3);
  1507. hInstResources = LoadLibrary(szFinalName);
  1508. }
  1509. //try under the <base path>\LCID\<sxBaseName.dll>
  1510. if (!hInstResources)
  1511. {
  1512. wsprintf(szDllName, "%u\\%s.dll", lcid, szBaseName);
  1513. _MakePath(szModuleName, szDllName, szFinalName);
  1514. hInstResources = LoadLibrary(szFinalName);
  1515. }
  1516. }
  1517. #ifdef MDAC_BUILD
  1518. else
  1519. {
  1520. char *psz;
  1521. GetModuleFileName(g_hInstance, szModuleName, MAX_PATH);
  1522. psz = strrchr(szModuleName, '\\');
  1523. *psz = NULL;
  1524. // szModuleName should now contain the path for the DLL
  1525. // now concatenate the resource location
  1526. strcat(szModuleName, "\\resources\\");
  1527. wsprintf(szDllName, "%s%d", szModuleName, lcid);
  1528. strcat(szDllName, "\\");
  1529. strcat(szDllName, szBaseName);
  1530. strcat(szDllName, ".DLL");
  1531. // try to load in the DLL
  1532. //
  1533. hInstResources = LoadLibrary(szDllName);
  1534. }
  1535. #endif
  1536. CleanUp:
  1537. // if we couldn't load the DLL for some reason, then just return the
  1538. // current resource handle, which is good enough.
  1539. //
  1540. if (!hInstResources)
  1541. hInstResources = g_hInstance;
  1542. if (!g_hInstResources && (lcid == 0 || lcid == g_lcidLocale))
  1543. // We only cache the instance handle for the default LCID.
  1544. // For all other passed in lcid values we will LoadLibrary on the satellite DLL each time.
  1545. // Its recommended that the calling app cache the returned instance handle for the given
  1546. // lcid passed in.
  1547. //
  1548. g_hInstResources = hInstResources;
  1549. ASSERT(hInstResources, "Resource handle is NULL");
  1550. // =-------------------------------------------------------------------
  1551. // Satellite .DLL version check
  1552. // =-------------------------------------------------------------------
  1553. // The satellite .DLL version must exactly match the version of the
  1554. //
  1555. if ((!g_bDllVerChecked) ||
  1556. (lcid != g_lcidLocale && lcid != 0))
  1557. {
  1558. // If we're using a satellite .DLL
  1559. // (hInstResources != g_hInstance), do a version check.
  1560. //
  1561. // If the passed in lcid is different than what we've cached and we're
  1562. // using a satellite .DLL, do the version check.
  1563. //
  1564. // Make sure we have a satellite .DLL
  1565. //
  1566. if (hInstResources != g_hInstance)
  1567. {
  1568. #if DEBUG
  1569. dwLength =
  1570. #endif
  1571. GetModuleFileName(hInstResources, szFinalName, MAX_PATH);
  1572. ASSERT(dwLength > 0, "GetModuleFileName failed");
  1573. iCompare = CompareDllVersion(szFinalName, TRUE);
  1574. #if DEBUG
  1575. if (VERSION_LESS_THAN == iCompare)
  1576. {
  1577. wsprintf(szMessage, "Major version compare: VERSION resource info in %s is less than VERSION info in %s. Non-localized resources will be used. In order to see localized resources, you need to obtain a version of %s that matches %s.", szFinalName, szModuleName, szFinalName, szModuleName);
  1578. DisplayAssert(szMessage, "", _szThisFile, __LINE__);
  1579. }
  1580. else if (VERSION_GREATER_THAN == iCompare)
  1581. {
  1582. wsprintf(szMessage, "Major version compare: VERSION resource info in %s is greater than VERSION info in %s. Non-localized resources will be used. In order to see localized resources, you need to obtain a version of %s that matches %s.", szFinalName, szModuleName, szFinalName, szModuleName);
  1583. DisplayAssert(szMessage, "", _szThisFile, __LINE__);
  1584. }
  1585. else if (VERSION_EQUAL == iCompare)
  1586. {
  1587. // Vegas #29024: Only enable full version assert if environment variable is set.
  1588. //
  1589. dwSuccess = GetEnvironmentVariable("INTL_VERSION_COMPARE", szEnvironValue, MAX_PATH);
  1590. if (dwSuccess > 0)
  1591. {
  1592. // Re-do the comparison using a full-version compare
  1593. //
  1594. // Note: Don't use iCompare here otherwise DEBUG builds will default to non-localized resources
  1595. // when major version comparison succeeds, but full version compare fails.
  1596. //
  1597. iReCompare = CompareDllVersion(szFinalName, FALSE);
  1598. if (VERSION_LESS_THAN == iReCompare)
  1599. {
  1600. wsprintf(szMessage, "Warning: Full version compare: VERSION resource info in %s is less than VERSION info in %s. Localized resources will continue to be used, but may not be in sync.", szFinalName, szModuleName);
  1601. DisplayAssert(szMessage, "", _szThisFile, __LINE__);
  1602. }
  1603. else if (VERSION_GREATER_THAN == iReCompare)
  1604. {
  1605. wsprintf(szMessage, "Warning: Full version compare: VERSION resource info in %s is greater than VERSION info in %s. Localized resources will continue to be used, but may not be in sync.", szFinalName, szModuleName);
  1606. DisplayAssert(szMessage, "", _szThisFile, __LINE__);
  1607. }
  1608. }
  1609. }
  1610. #endif
  1611. // If CompareDllVersion ever returns NOT_EQUAL it means it didn't get far enough
  1612. // to figure out if the version was less than or greater than. It must have failed.
  1613. //
  1614. // Note: In this case, we go ahead and use the satellite .DLL anyway. It may be that
  1615. // the satellite .DLL doesn't contain VERSION info.
  1616. //
  1617. ASSERT(VERSION_NOT_EQUAL != iCompare, "Failure attempting to compare satellite .DLL version");
  1618. if (VERSION_LESS_THAN == iCompare || VERSION_GREATER_THAN == iCompare)
  1619. {
  1620. // If the check fails, return the instance of ourself, not the
  1621. // satellite .DLL. Resources will be displayed in English.
  1622. //
  1623. hInstResources = g_hInstance;
  1624. if (lcid == 0 || lcid == g_lcidLocale)
  1625. {
  1626. g_hInstResources = g_hInstance;
  1627. }
  1628. }
  1629. }
  1630. if (lcid == 0 || lcid == g_lcidLocale)
  1631. g_bDllVerChecked = TRUE;
  1632. }
  1633. LEAVECRITICALSECTION1(&g_CriticalSection);
  1634. return hInstResources;
  1635. }
  1636. //=--------------------------------------------------------------------------=
  1637. // CompareDllVersion
  1638. //=--------------------------------------------------------------------------=
  1639. // Given a pointer to an external filename, compare the version info in the
  1640. // file with the version info in our own binary (.DLL or .OCX).
  1641. //
  1642. // Parameters:
  1643. //
  1644. // Returns: S_OK if type flags are successfully found, otherwise an error code
  1645. //
  1646. VERSIONRESULT _stdcall CompareDllVersion(const char * pszFilename, BOOL bCompareMajorVerOnly)
  1647. {
  1648. // Default to not equal. The only time we're not equal is if something failed.
  1649. //
  1650. VERSIONRESULT vrResult = VERSION_NOT_EQUAL;
  1651. BOOL bResult;
  1652. VS_FIXEDFILEINFO ffiMe, ffiDll;
  1653. char szModuleName[MAX_PATH];
  1654. WORD wMajorVerMe;
  1655. WORD wMajorVerDll;
  1656. DWORD dwLength;
  1657. // Get VERSION info for our own .DLL/.OCX (aka Me)
  1658. //
  1659. ASSERT(g_hInstance, "hInstance is NULL");
  1660. dwLength = GetModuleFileName(g_hInstance, szModuleName, MAX_PATH);
  1661. ASSERT(dwLength > 0, "GetModuleFilename failed");
  1662. if (0 == dwLength)
  1663. goto CleanUp;
  1664. // Make sure we're not comparing the same file
  1665. //
  1666. ASSERT(0 != lstrcmpi(szModuleName, pszFilename), "The same file is being compared");
  1667. bResult = GetVerInfo(szModuleName, &ffiMe);
  1668. ASSERT(bResult, "GetVerInfo failed");
  1669. if (!bResult)
  1670. goto CleanUp;
  1671. ASSERT(0xFEEF04BD == ffiMe.dwSignature, "Bad VS_FIXEDFILEINFO signature for Me");
  1672. // Get version info for the passed in .DLL name
  1673. //
  1674. bResult = GetVerInfo(pszFilename, &ffiDll);
  1675. ASSERT(bResult, "GetVerInfo failed");
  1676. if (!bResult)
  1677. goto CleanUp;
  1678. ASSERT(0xFEEF04BD == ffiDll.dwSignature, "Bad VS_FIXEDFILEINFO signature for Me");
  1679. if (bCompareMajorVerOnly)
  1680. {
  1681. // Major version compare
  1682. //
  1683. wMajorVerMe = HIWORD(ffiMe.dwFileVersionMS);
  1684. wMajorVerDll = HIWORD(ffiDll.dwFileVersionMS);
  1685. if (wMajorVerMe == wMajorVerDll)
  1686. return VERSION_EQUAL;
  1687. else if (wMajorVerMe > wMajorVerDll)
  1688. return VERSION_LESS_THAN;
  1689. else
  1690. return VERSION_GREATER_THAN;
  1691. }
  1692. else
  1693. {
  1694. // Full version compare
  1695. //
  1696. // Compare the version with our build version set by constants in DWINVERS.H
  1697. //
  1698. if (ffiMe.dwFileVersionMS == ffiDll.dwFileVersionMS &&
  1699. ffiMe.dwFileVersionLS == ffiDll.dwFileVersionLS)
  1700. {
  1701. vrResult = VERSION_EQUAL;
  1702. }
  1703. else if (ffiMe.dwFileVersionMS == ffiDll.dwFileVersionMS)
  1704. {
  1705. if (ffiMe.dwFileVersionLS > ffiDll.dwFileVersionLS)
  1706. vrResult = VERSION_LESS_THAN;
  1707. else
  1708. vrResult = VERSION_GREATER_THAN;
  1709. }
  1710. else if (ffiMe.dwFileVersionMS < ffiDll.dwFileVersionMS)
  1711. {
  1712. vrResult = VERSION_LESS_THAN;
  1713. }
  1714. else
  1715. {
  1716. vrResult = VERSION_GREATER_THAN;
  1717. }
  1718. }
  1719. CleanUp:
  1720. return vrResult;
  1721. }
  1722. //=--------------------------------------------------------------------------=
  1723. // GetVerInfo
  1724. //=--------------------------------------------------------------------------=
  1725. // Returns the VERSION resource fixed file info struct for a given file.
  1726. //
  1727. // Parameters:
  1728. // pszFilename - [in] Filename to return version info for
  1729. // pffi - [out] Version info
  1730. //
  1731. BOOL _stdcall GetVerInfo(const char * pszFilename, VS_FIXEDFILEINFO *pffi)
  1732. {
  1733. DWORD dwHandle = 0;
  1734. DWORD dwVersionSize = 0;
  1735. UINT uiLength = 0;
  1736. VS_FIXEDFILEINFO * pffiTemp;
  1737. #if DEBUG
  1738. DWORD dwGetLastError;
  1739. #endif
  1740. BYTE *pVersionInfo = NULL;
  1741. BOOL bResult = FALSE;
  1742. memset(pffi, 0, sizeof(VS_FIXEDFILEINFO));
  1743. dwVersionSize = CallGetFileVersionInfoSize((char *) pszFilename, &dwHandle);
  1744. #if DEBUG
  1745. dwGetLastError = GetLastError();
  1746. #endif
  1747. ASSERT(dwVersionSize > 0, "GetFileVersionInfoSize failed");
  1748. if (0 == dwVersionSize)
  1749. goto CleanUp;
  1750. pVersionInfo = (BYTE *) HeapAlloc(g_hHeap, 0, dwVersionSize);
  1751. ASSERT(pVersionInfo, "pVersionInfo is NULL");
  1752. if (NULL == pVersionInfo)
  1753. goto CleanUp;
  1754. bResult = CallGetFileVersionInfo((char *) pszFilename, dwHandle, dwVersionSize, pVersionInfo);
  1755. ASSERT(bResult, "GetFileVersionInfo failed");
  1756. if (!bResult)
  1757. goto CleanUp;
  1758. bResult = CallVerQueryValue(pVersionInfo, "\\", (void **) &pffiTemp, &uiLength);
  1759. ASSERT(bResult, "VerQueryValue failed");
  1760. if (!bResult)
  1761. goto CleanUp;
  1762. ASSERT(sizeof(VS_FIXEDFILEINFO) == uiLength, "Returned length is invalid");
  1763. memcpy(pffi, pffiTemp, uiLength);
  1764. CleanUp:
  1765. if (pVersionInfo)
  1766. HeapFree(g_hHeap, 0, pVersionInfo);
  1767. return bResult;
  1768. }
  1769. //=--------------------------------------------------------------------------=
  1770. // CallGetFileVersionInfoSize [VERSION.DLL API wrapper]
  1771. //=--------------------------------------------------------------------------=
  1772. // This does a dynamic call to the GetFileVersionInfoSize API function. If
  1773. // VERSION.DLL isn't loaded, then this function loads it.
  1774. //
  1775. BOOL CallGetFileVersionInfoSize
  1776. (
  1777. LPTSTR lptstrFilename,
  1778. LPDWORD lpdwHandle
  1779. )
  1780. {
  1781. EnterCriticalSection(&g_CriticalSection);
  1782. // One-time setup of VERSION.DLL and function pointer
  1783. //
  1784. if (!g_pGetFileVersionInfoSize)
  1785. {
  1786. if (!g_hinstVersion)
  1787. {
  1788. g_hinstVersion = LoadLibrary(DLL_VERSION);
  1789. ASSERT(g_hinstVersion, "Failed to load VERSION.DLL");
  1790. if (!g_hinstVersion)
  1791. return FALSE;
  1792. }
  1793. g_pGetFileVersionInfoSize = (PGETFILEVERSIONINFOSIZE) GetProcAddress(g_hinstVersion, FUNC_GETFILEVERSIONINFOSIZE);
  1794. ASSERT(g_pGetFileVersionInfoSize, "Failed to get proc address for GetFileVersionInfoSize");
  1795. if (!g_pGetFileVersionInfoSize)
  1796. return FALSE;
  1797. }
  1798. LeaveCriticalSection(&g_CriticalSection);
  1799. // Call GetFileVersionInfoSize
  1800. //
  1801. return g_pGetFileVersionInfoSize(lptstrFilename, lpdwHandle);
  1802. }
  1803. //=--------------------------------------------------------------------------=
  1804. // CallGetFileVersionInfo [VERSION.DLL API wrapper]
  1805. //=--------------------------------------------------------------------------=
  1806. // This does a dynamic call to the GetFileVersionInfo API function. If
  1807. // VERSION.DLL isn't loaded, then this function loads it.
  1808. //
  1809. BOOL CallGetFileVersionInfo
  1810. (
  1811. LPTSTR lpststrFilename,
  1812. DWORD dwHandle,
  1813. DWORD dwLen,
  1814. LPVOID lpData
  1815. )
  1816. {
  1817. EnterCriticalSection(&g_CriticalSection);
  1818. // One-time setup of VERSION.DLL and function pointer
  1819. //
  1820. if (!g_pGetFileVersionInfo)
  1821. {
  1822. if (!g_hinstVersion)
  1823. {
  1824. g_hinstVersion = LoadLibrary(DLL_VERSION);
  1825. ASSERT(g_hinstVersion, "Failed to load VERSION.DLL");
  1826. if (!g_hinstVersion)
  1827. return FALSE;
  1828. }
  1829. g_pGetFileVersionInfo = (PGETFILEVERSIONINFO) GetProcAddress(g_hinstVersion, FUNC_GETFILEVERSIONINFO);
  1830. ASSERT(g_pGetFileVersionInfo, "Failed to get proc address for GetFileVersionInfo");
  1831. if (!g_pGetFileVersionInfo)
  1832. return FALSE;
  1833. }
  1834. LeaveCriticalSection(&g_CriticalSection);
  1835. // Call GetFileVersionInfo
  1836. //
  1837. return g_pGetFileVersionInfo(lpststrFilename, dwHandle, dwLen, lpData);
  1838. }
  1839. //=--------------------------------------------------------------------------=
  1840. // CallVerQueryValue [VERSION.DLL API wrapper]
  1841. //=--------------------------------------------------------------------------=
  1842. // This does a dynamic call to the VerQueryValue API function. If
  1843. // VERSION.DLL isn't loaded, then this function loads it.
  1844. //
  1845. BOOL CallVerQueryValue
  1846. (
  1847. const LPVOID pBlock,
  1848. LPTSTR lpSubBlock,
  1849. LPVOID *lplpBuffer,
  1850. PUINT puLen
  1851. )
  1852. {
  1853. EnterCriticalSection(&g_CriticalSection);
  1854. // One-time setup of VERSION.DLL and function pointer
  1855. //
  1856. if (!g_pVerQueryValue)
  1857. {
  1858. if (!g_hinstVersion)
  1859. {
  1860. g_hinstVersion = LoadLibrary(DLL_VERSION);
  1861. ASSERT(g_hinstVersion, "Failed to load VERSION.DLL");
  1862. if (!g_hinstVersion)
  1863. return FALSE;
  1864. }
  1865. g_pVerQueryValue = (PVERQUERYVALUE) GetProcAddress(g_hinstVersion, FUNC_VERQUERYVALUE);
  1866. ASSERT(g_pVerQueryValue, "Failed to get proc address for VerQueryValue");
  1867. if (!g_pVerQueryValue)
  1868. return FALSE;
  1869. }
  1870. LeaveCriticalSection(&g_CriticalSection);
  1871. // Call VerQueryValue
  1872. //
  1873. return g_pVerQueryValue(pBlock, lpSubBlock, lplpBuffer, puLen);
  1874. }
  1875. //=--------------------------------------------------------------------------=
  1876. // GetTypeInfoFlagsForGuid
  1877. //=--------------------------------------------------------------------------=
  1878. // Given a pointer to a TypeLib and a TypeInfo guid, returns the TYPEFLAGS
  1879. // associated with the TypeInfo
  1880. //
  1881. // Parameters:
  1882. // pTypeLib - [in] Pointer of TypeLib to find typeinfo type flags
  1883. // guidTypeInfo - [in] Guid of TypeInfo we're looking for
  1884. // pwFlags - [out] TYPEFLAGS associated with the typeinfo
  1885. //
  1886. // Returns: S_OK if type flags are successfully found, otherwise an error code
  1887. //
  1888. HRESULT GetTypeFlagsForGuid(ITypeLib *pTypeLib, REFGUID guidTypeInfo, WORD *pwFlags)
  1889. {
  1890. ITypeInfo *pTypeInfo;
  1891. TYPEATTR *pTypeAttr;
  1892. HRESULT hr;
  1893. if (!pTypeLib || !pwFlags)
  1894. return E_POINTER;
  1895. *pwFlags = 0;
  1896. // Search for the given guid in the TypeLib
  1897. //
  1898. hr = pTypeLib->GetTypeInfoOfGuid(guidTypeInfo, &pTypeInfo);
  1899. if (SUCCEEDED(hr))
  1900. {
  1901. // Get the type attributes for the found TypeInfo
  1902. //
  1903. hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
  1904. ASSERT(SUCCEEDED(hr), "Failed to get ctl TypeInfo TypeAttr");
  1905. if (SUCCEEDED(hr))
  1906. {
  1907. // Return TYPEFLAGS
  1908. //
  1909. *pwFlags = pTypeAttr->wTypeFlags;
  1910. pTypeInfo->ReleaseTypeAttr(pTypeAttr);
  1911. }
  1912. pTypeInfo->Release();
  1913. }
  1914. return hr;
  1915. }