Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
18 KiB

  1. //+============================================================================
  2. //
  3. // File: dllmain.cxx
  4. //
  5. // Purpose: This file provides the registration and deregistration
  6. // functions for the IProp DLL: DllRegisterServer and
  7. // DllUnregisterServer. These two functions register/
  8. // deregister the property set marshaling code:
  9. // IPropertySetStorage, IPropertyStorage, IEnumSTATPROPSETSTG,
  10. // and IEnumSTATPROPSTG. Note that this registration is
  11. // different from the typical server registration in that
  12. // it only registers the marshaling code, it does not
  13. // register an instantiable COM server. Also, no registration
  14. // takes place if OLE32 is already registered to perform
  15. // this marshaling.
  16. //
  17. // The actual DllRegisterServer and DllUnregisterServer
  18. // implementations are at the end of this file. First,
  19. // several helper functions are defined.
  20. //
  21. //+============================================================================
  22. // --------
  23. // Includes
  24. // --------
  25. #include <pch.cxx>
  26. #include <tchar.h>
  27. // The following is from "olectl.h". That file couldn't simply
  28. // be included, however, because it isn't compatible with the
  29. // special objidl.h and wtypes.h used by IProp DLL.
  30. #define SELFREG_E_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x0200)
  31. #define SELFREG_E_LAST MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x020F)
  32. #define SELFREG_S_FIRST MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_ITF, 0x0200)
  33. #define SELFREG_S_LAST MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_ITF, 0x020F)
  34. #define SELFREG_E_TYPELIB (SELFREG_E_FIRST+0)
  35. #define SELFREG_E_CLASS (SELFREG_E_FIRST+1)
  36. // -------
  37. // Globals
  38. // -------
  39. // Important DLL names.
  40. const LPTSTR tszNameDll = TEXT( "IProp.dll" );
  41. // Registry entry descriptions
  42. const LPTSTR tszOle32PSFactoryClsid = TEXT( "{00000320-0000-0000-C000-000000000046}" );
  43. const LPTSTR tszNamePropertySetStorage = TEXT( "IPropertySetStorage" );
  44. const LPTSTR tszNamePropertyStorage = TEXT( "IPropertyStorage" );
  45. const LPTSTR tszNameIEnumSTATPROPSETSTG = TEXT( "IEnumSTATPROPSETSTG" );
  46. const LPTSTR tszNameIEnumSTATPROPSTG = TEXT( "IEnumSTATPROPSTG" );
  47. // GUIDs in Registry format
  48. const LPTSTR tszGuidPropertySetStorage = TEXT( "{0000013A-0000-0000-C000-000000000046}" );
  49. const LPTSTR tszGuidPropertyStorage = TEXT( "{00000138-0000-0000-C000-000000000046}" );
  50. const LPTSTR tszGuidIEnumSTATPROPSETSTG = TEXT( "{0000013B-0000-0000-C000-000000000046}" );
  51. const LPTSTR tszGuidIEnumSTATPROPSTG = TEXT( "{00000139-0000-0000-C000-000000000046}" );
  52. //+----------------------------------------------------------------------------
  53. //
  54. // Function: UpdateKeyAndSubKey
  55. //
  56. // Synopsis: This function either creates or deletes first
  57. // a key and un-named value under HKEY_CLASSES_ROOT,
  58. // then a sub-key and associated un-named value. The
  59. // caller indicates whether a create or delete should occur.
  60. //
  61. // However, the caller may specify that nothing be done
  62. // if the sub-key exists and already has a specific
  63. // un-named REG_SZ value.
  64. //
  65. // Inputs: [const LPTSTR] tszMainKey (in)
  66. // The name of the key under HKEY_CLASSES_ROOT.
  67. // [const LPTSTR] tszMainKeyDescription (in)
  68. // The un-named REG_SZ value under this key (not necessary
  69. // if fDelete is true).
  70. // [const LPTSTR] tszSubKey (in)
  71. // The name of the key under the first key.
  72. // [const LPTSTR] tszSubKeyDescription (in)
  73. // The un-named REG_SZ value to write under this sub-key
  74. // (not necessary if fDelete is true).
  75. // [const LPTSTR] tszSubKeyCheck (in)
  76. // If non-NULL, and the subkey already exists, see if
  77. // this string matches an un-named REG_SZ value in
  78. // the sub-key. If so, abort the operation and return
  79. // ERROR_ALREADY_EXISTS.
  80. // [BOOL] fDelete
  81. // If TRUE, delete the keys, if FALSE, create them.
  82. // But this is ignored if tszSubKeyCheck matches
  83. // (in which case nothing happens).
  84. //
  85. // Returns: [long] A GetLastError value.
  86. //
  87. //+----------------------------------------------------------------------------
  88. long
  89. UpdateKeyAndSubKey( const LPTSTR tszMainKey,
  90. const LPTSTR tszMainKeyDescription,
  91. const LPTSTR tszSubKey,
  92. const LPTSTR tszSubKeyDescription,
  93. const LPTSTR tszSubKeyCheck,
  94. BOOL fDelete )
  95. {
  96. // ------
  97. // Locals
  98. // ------
  99. long lResult = ERROR_SUCCESS;
  100. DWORD dwDisposition;
  101. HKEY hkeyMain = NULL; // E.g. "HKEY_CLASSES_ROOT\\CLSID\\{.....}"
  102. HKEY hkeySub = NULL; // E.g. ..."InProcServer32"
  103. // -------------
  104. // Open the keys
  105. // -------------
  106. // Are we opening for delete?
  107. if( fDelete )
  108. {
  109. // Yes - we're deleting. We'll just attempt to do an Open.
  110. dwDisposition = REG_OPENED_EXISTING_KEY;
  111. lResult = RegOpenKeyEx( HKEY_CLASSES_ROOT,
  112. tszMainKey,
  113. 0L,
  114. KEY_ALL_ACCESS,
  115. &hkeyMain );
  116. if( ERROR_SUCCESS == lResult )
  117. {
  118. lResult = RegOpenKeyEx( hkeyMain,
  119. tszSubKey,
  120. 0L,
  121. KEY_ALL_ACCESS,
  122. &hkeySub );
  123. }
  124. if( ERROR_FILE_NOT_FOUND == lResult )
  125. lResult = ERROR_SUCCESS;
  126. else if( ERROR_SUCCESS != lResult )
  127. goto Exit;
  128. } // if( fDelete )
  129. else
  130. {
  131. // We're not opening for delete. So we'll use RegCreateKey,
  132. // which does an Open if the key exists, and a Create otherwise.
  133. lResult = RegCreateKeyEx( HKEY_CLASSES_ROOT,
  134. tszMainKey,
  135. 0L,
  136. NULL,
  137. 0,
  138. KEY_ALL_ACCESS,
  139. NULL,
  140. &hkeyMain,
  141. &dwDisposition );
  142. if( lResult != ERROR_SUCCESS ) goto Exit;
  143. // Open the sub-key.
  144. lResult = RegCreateKeyEx( hkeyMain,
  145. tszSubKey,
  146. 0L,
  147. NULL,
  148. 0,
  149. KEY_ALL_ACCESS,
  150. NULL,
  151. &hkeySub,
  152. &dwDisposition );
  153. if( ERROR_SUCCESS != lResult ) goto Exit;
  154. } // if( fDelete ) ... else
  155. // --------------------------
  156. // Do we need to do anything?
  157. // --------------------------
  158. // Does it look like we might not need to do anything?
  159. if( NULL != tszSubKeyCheck // The caller said to check first
  160. &&
  161. NULL != hkeySub // We Created or Opened a sub-key
  162. && // Specifically, it was an Open.
  163. REG_OPENED_EXISTING_KEY == dwDisposition )
  164. {
  165. // Yes - we need to see if the key already contains
  166. // tszSubKeyCheck. If so, then we're done.
  167. DWORD dwType = 0;
  168. TCHAR tszData[ MAX_PATH ];
  169. DWORD dwDataSize = sizeof( tszData );
  170. // Is there an un-named value in this key?
  171. lResult = RegQueryValueEx( hkeySub,
  172. NULL, // Name
  173. NULL, // Reserved
  174. &dwType, // E.g. REG_SZ
  175. (LPBYTE) tszData,// Return value
  176. &dwDataSize ); // In: size of buf. Out: size of value
  177. // We should have gotten a success-code or a not-extant code
  178. if( ERROR_SUCCESS != lResult
  179. &&
  180. ERROR_FILE_NOT_FOUND != lResult )
  181. {
  182. goto Exit;
  183. }
  184. // If we got an extant SZ value that matches tszSubKeyCheck,
  185. // then there's nothing we need do.
  186. if( ERROR_SUCCESS == lResult
  187. &&
  188. REG_SZ == dwType
  189. &&
  190. !_tcsicmp( tszData, tszSubKeyCheck )
  191. )
  192. {
  193. lResult = ERROR_ALREADY_EXISTS;
  194. goto Exit;
  195. }
  196. } // if( REG_OPENED_EXISTING_KEY == dwDisposition ...
  197. // --------------------------
  198. // Delete keys, or set values
  199. // --------------------------
  200. if( fDelete )
  201. {
  202. // Reset the result code, since the code below may not set it.
  203. lResult = ERROR_SUCCESS;
  204. // We're doing a delete. First, delete the sub-key, which
  205. // will delete any values. If there was no subkey, hkeySub will
  206. // be NULL.
  207. if( NULL != hkeySub )
  208. {
  209. CloseHandle( hkeySub );
  210. hkeySub = NULL;
  211. lResult = RegDeleteKey( hkeyMain,
  212. tszSubKey );
  213. if( ERROR_SUCCESS != lResult ) goto Exit;
  214. }
  215. // Second, delete the main key
  216. if( NULL != hkeyMain )
  217. {
  218. CloseHandle( hkeyMain );
  219. hkeyMain = NULL;
  220. lResult = RegDeleteKey( HKEY_CLASSES_ROOT,
  221. tszMainKey );
  222. if( ERROR_SUCCESS != lResult ) goto Exit;
  223. }
  224. } // if( fDelete )
  225. else
  226. {
  227. // We're adding to the Registry. The two keys are now
  228. // created & opened, so we can add the REG_SZ values.
  229. // The REG_SZ value for the main key.
  230. lResult = RegSetValueEx(hkeyMain,
  231. NULL,
  232. 0L,
  233. REG_SZ,
  234. (const BYTE *) tszMainKeyDescription,
  235. sizeof(TCHAR) * (1 + _tcslen(tszMainKeyDescription) ));
  236. if( ERROR_SUCCESS != lResult ) goto Exit;
  237. // The REG_SZ value for the sub-key.
  238. lResult = RegSetValueEx(hkeySub,
  239. NULL, 0L,
  240. REG_SZ,
  241. (const BYTE *) tszSubKeyDescription,
  242. sizeof(TCHAR) * (1 + _tcslen(tszSubKeyDescription) ));
  243. if( ERROR_SUCCESS != lResult ) goto Exit;
  244. } // if( fDelete ) ... else
  245. // ----
  246. // Exit
  247. // ----
  248. Exit:
  249. if( NULL != hkeySub )
  250. CloseHandle( hkeySub );
  251. if( NULL != hkeyMain )
  252. CloseHandle( hkeyMain );
  253. return( lResult );
  254. } // WriteKeyAndSubKey()
  255. //+----------------------------------------------------------------------------
  256. //
  257. // Function: RegisterForMarshaling
  258. //
  259. // Synopsis: This function takes the GUID ane name of an interface
  260. // for which MIDL-generated marshaling code exists in the
  261. // caller-specified DLL. First we try to update the
  262. // CLSID entries, but we'll fail this if the entries already
  263. // exist and reference OLE32 (OLE32 has better marshaling
  264. // code). If this doesn't fail, then we'll update the
  265. // Interface entries.
  266. //
  267. // The caller specifies if this "update" of the registry
  268. // is a write or a delete. This this routine can be used
  269. // in either a registration or a de-registration.
  270. //
  271. // Inputs: [const LPTSTR] tszGuid (in)
  272. // The GUID in registery format ("{...-...-...}")
  273. // [const LPTSTR] tszName (in)
  274. // The name of the interface
  275. // [const LPTSTR] tszDllPath (in)
  276. // The complete path and filename of the DLL which contains
  277. // the marshaling code.
  278. // [BOOL] fDelete (in)
  279. // Determines if we add to the Registry or delete from it.
  280. //
  281. // Returns: [long] a GetLastError() value
  282. //
  283. //+----------------------------------------------------------------------------
  284. long
  285. RegisterForMarshaling( const LPTSTR tszGuid,
  286. const LPTSTR tszName,
  287. const LPTSTR tszDllPath,
  288. BOOL fDelete )
  289. {
  290. // ------
  291. // Locals
  292. // ------
  293. long lResult;
  294. TCHAR tszMainKey[ MAX_PATH ];
  295. // -----------------------------------
  296. // Update HKEY_CLASSES_ROOT\Interfaces
  297. // -----------------------------------
  298. // Calculate the key name name
  299. _tcscpy( tszMainKey, TEXT( "Interface\\" ));
  300. _tcscat( tszMainKey, tszGuid );
  301. // Update the registry, but only if there isn't a current
  302. // entry pointing to OLE32's proxy/stub factory.
  303. lResult = UpdateKeyAndSubKey( tszMainKey,
  304. tszName,
  305. TEXT( "ProxyStubClsid32" ),
  306. tszGuid,
  307. tszOle32PSFactoryClsid,
  308. fDelete );
  309. if( ERROR_SUCCESS != lResult ) goto Exit;
  310. // ------------------------------
  311. // Update HKEY_CLASSES_ROOT\CLSID
  312. // ------------------------------
  313. // Calculate the name.
  314. _tcscpy( tszMainKey, TEXT( "CLSID\\" ));
  315. _tcscat( tszMainKey, tszGuid );
  316. // Update the entries. This will add the path (if !fDelete) or remove
  317. // the registry entry (if fDelete) regardless of the current state
  318. // of the key; if we weren't supposed to remove it, the previous
  319. // call to UpdateKeyAndSubKey would have returned an error.
  320. lResult = UpdateKeyAndSubKey( tszMainKey,
  321. tszName,
  322. TEXT( "InprocServer32" ),
  323. tszDllPath,
  324. NULL, // Add/delete, regardless of what exists
  325. fDelete );
  326. if( ERROR_SUCCESS != lResult ) goto Exit;
  327. // ----
  328. // Exit
  329. // ----
  330. Exit:
  331. if( ERROR_ALREADY_EXISTS == lResult )
  332. {
  333. propDbg(( DEB_WARN, "IProp DLL UpdateKeyAndSubKey: Entry already exists\n" ));
  334. lResult = ERROR_SUCCESS;
  335. }
  336. return( lResult );
  337. } // RegisterForMarshaling()
  338. //+----------------------------------------------------------------------------
  339. //
  340. // Function: RegisterServer
  341. //
  342. // Synopsis: This routine can be used with both DllRegisterServer and
  343. // DllUnregisterServer. It adds/deletes IPropertySetStorage
  344. // IPropertyStorage, IEnumSTATPROPSETSTG, and IEnumSTATPROPSTG.
  345. //
  346. // Inputs: [BOOL] fDelete (in)
  347. // Indicates whether the registry entries should be added
  348. // or removed.
  349. //
  350. // Returns: [HRESULT]
  351. //
  352. //+----------------------------------------------------------------------------
  353. STDAPI RegisterServer( BOOL fDelete )
  354. {
  355. // ------
  356. // Locals
  357. // ------
  358. LONG lResult;
  359. // -----
  360. // Begin
  361. // -----
  362. // Register IPropertySetStorage
  363. lResult = RegisterForMarshaling( tszGuidPropertySetStorage,
  364. tszNamePropertySetStorage,
  365. tszNameDll,
  366. fDelete );
  367. if( ERROR_SUCCESS != lResult ) goto Exit;
  368. // Register IPropertyStorage
  369. lResult = RegisterForMarshaling( tszGuidPropertyStorage,
  370. tszNamePropertyStorage,
  371. tszNameDll,
  372. fDelete );
  373. if( ERROR_SUCCESS != lResult ) goto Exit;
  374. // Register IEnumSTATPROPSETSTG
  375. lResult = RegisterForMarshaling( tszGuidIEnumSTATPROPSETSTG,
  376. tszNameIEnumSTATPROPSETSTG,
  377. tszNameDll,
  378. fDelete );
  379. if( ERROR_SUCCESS != lResult ) goto Exit;
  380. // Register IEnumSTATPROPSTG
  381. lResult = RegisterForMarshaling( tszGuidIEnumSTATPROPSTG,
  382. tszNameIEnumSTATPROPSTG,
  383. tszNameDll,
  384. fDelete );
  385. if( ERROR_SUCCESS != lResult ) goto Exit;
  386. // ----
  387. // Exit
  388. // ----
  389. Exit:
  390. if( ERROR_SUCCESS != lResult )
  391. {
  392. propDbg(( DEB_ERROR, "IProp DLL RegisterServer failed (%lu)\n", lResult ));
  393. return( SELFREG_E_CLASS );
  394. }
  395. else
  396. {
  397. return( S_OK );
  398. }
  399. } // RegisterServer()
  400. //+----------------------------------------------------------------------------
  401. //
  402. // Function: DllRegisterServer & DllUnregisterServer
  403. //
  404. // Synopsis: These routines are the standard DLL registration entry
  405. // points for a self-registering in-proc COM server. They
  406. // are used to register the property set marshaling code.
  407. // These routines are called, for example,
  408. // by a setup program during installation and de-installation,
  409. // respectively.
  410. //
  411. //+----------------------------------------------------------------------------
  412. STDAPI DllRegisterServer()
  413. {
  414. return( RegisterServer( FALSE ));
  415. }
  416. STDAPI DllUnregisterServer()
  417. {
  418. return( RegisterServer( TRUE ));
  419. }
  420. void InitializeDebugging();
  421. void UnInitializeDebugging();
  422. BOOL WINAPI
  423. DllMain( HANDLE hinst, DWORD dwReason, LPVOID lpv )
  424. {
  425. #if DBG == 1
  426. {
  427. if( DLL_PROCESS_ATTACH == dwReason )
  428. InitializeDebugging();
  429. else if( DLL_PROCESS_DETACH == dwReason )
  430. UnInitializeDebugging();
  431. }
  432. #endif // #if DBG == 1
  433. return( TRUE );
  434. }