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.

600 lines
20 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // File: tdllhost.cxx
  4. //
  5. // Contents: test for dll hosting
  6. //
  7. //--------------------------------------------------------------------
  8. #include <tstmain.hxx>
  9. #include "tdllhost.h"
  10. // BUGBUG: these should be in a public place somewhere.
  11. DEFINE_OLEGUID(CLSID_Balls, 0x0000013a, 1, 8);
  12. DEFINE_OLEGUID(CLSID_Cubes, 0x0000013b, 1, 8);
  13. DEFINE_OLEGUID(CLSID_LoopSrv, 0x0000013c, 1, 8);
  14. DEFINE_OLEGUID(CLSID_QI, 0x00000140, 0, 8);
  15. const GUID CLSID_QI =
  16. {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
  17. const GUID CLSID_QIHANDLER1 =
  18. {0x00000141,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
  19. const TCHAR *pszRegValThreadModel = TEXT("ThreadingModel");
  20. const TCHAR *pszSingleModel = TEXT("Single");
  21. const TCHAR *pszApartmentModel = TEXT("Apartment");
  22. const TCHAR *pszMultiThreadedModel = TEXT("Free");
  23. const TCHAR *pszBothModel = TEXT("Both");
  24. BOOL gfApt;
  25. // ----------------------------------------------------------------------
  26. //
  27. // Structures and Function Prototypes
  28. //
  29. // ----------------------------------------------------------------------
  30. typedef struct tagLoadDLLParams
  31. {
  32. DWORD dwCallingTID; // tid of calling thread
  33. DWORD dwCoInitFlag; // flag to initialize OLE with
  34. DWORD dwItfFlag; // flag if the resulting object should be a proxy
  35. BOOL RetVal; // return value
  36. HANDLE hEvent; // thread completion event
  37. } SLoadDLLParam;
  38. typedef enum tagITFFLAGS
  39. {
  40. ITF_REAL = 1, // expect ptr to real object
  41. ITF_PROXY = 2 // expect ptr to proxy object
  42. } ITFFLAGS;
  43. // worker subroutines
  44. BOOL SpinThread(DWORD dwInitFlag, DWORD dwItfFlag);
  45. DWORD _stdcall LoadDLLOnThread(void *param);
  46. BOOL LoadClassObject(DWORD dwItfFlag);
  47. BOOL SetRegForDll(REFCLSID rclsid, const TCHAR *pszThreadModel);
  48. // test routines - return value of TRUE return means the test passed
  49. BOOL TestLoadSingleThreaded(void);
  50. BOOL TestLoadApartmentThreaded(void);
  51. BOOL TestLoadMultiThreaded(void);
  52. BOOL TestLoadBothThreaded(void);
  53. // ----------------------------------------------------------------------
  54. //
  55. // TestDllHost - main test driver. read the ini file to determine
  56. // which tests to run.
  57. //
  58. // ----------------------------------------------------------------------
  59. BOOL TestDllHost(void)
  60. {
  61. BOOL RetVal = TRUE;
  62. gfApt = (gInitFlag == COINIT_APARTMENTTHREADED) ? TRUE : FALSE;
  63. // the driver did a CoInitialize, we dont want one so do CoUninit.
  64. CoUninitialize();
  65. if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadSingleThreaded"),1))
  66. RetVal &= TestLoadSingleThreaded();
  67. if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadApartmentThreaded"),1))
  68. RetVal &= TestLoadApartmentThreaded();
  69. if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadMultiThreaded"),1))
  70. RetVal &= TestLoadMultiThreaded();
  71. if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadBothThreaded"),1))
  72. RetVal &= TestLoadBothThreaded();
  73. // re-initialize so we dont get a complaint from OLE in debug builds
  74. // about an unbalanced call to Uninitialize.
  75. CoInitializeEx(NULL, gInitFlag);
  76. return RetVal;
  77. }
  78. // ----------------------------------------------------------------------
  79. //
  80. // TestLoadSingleThreaded
  81. //
  82. // Tests loading a single-threaded DLL
  83. //
  84. // ----------------------------------------------------------------------
  85. BOOL TestLoadSingleThreaded(void)
  86. {
  87. BOOL RetVal = TRUE, RetVal2 = TRUE;
  88. HRESULT hRes = S_OK;
  89. OUTPUT ("\n\nStarting TestLoadSingleThreaded\n");
  90. // First, mark the DLL appropriately in the registry.
  91. RetVal2 = SetRegForDll(CLSID_QI, pszSingleModel);
  92. TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
  93. hRes = CoInitializeEx(NULL, gInitFlag);
  94. TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
  95. // ----------------------------------------------------------------------
  96. OUTPUT ("\n Load Single-Threaded DLL on Main Thread\n");
  97. RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
  98. TEST_FAILED(!RetVal2, "SingleThreadedDLL on Main Thread Failed\n");
  99. OUTPUT (" Done Load Single-Threaded DLL on Main Thread\n");
  100. OUTPUT ("\n Load Single-Threaded DLL on Main Thread\n");
  101. RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
  102. TEST_FAILED(!RetVal2, "SingleThreadedDLL on Main Thread Failed\n");
  103. OUTPUT (" Done Load Single-Threaded DLL on Main Thread\n");
  104. // ----------------------------------------------------------------------
  105. OUTPUT ("\n Load Single-Threaded DLL on Different Apartment Thread\n");
  106. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
  107. TEST_FAILED(!RetVal2, "SingleThreadedDLL on Apartment Thread Failed\n");
  108. OUTPUT (" Done Load Single-Threaded DLL on Different Apartment Thread\n");
  109. OUTPUT ("\n Second Load Single-Threaded DLL on Different Apartment Thread\n");
  110. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
  111. TEST_FAILED(!RetVal2, "Single-ThreadedDLL on Apartment Thread Failed\n");
  112. OUTPUT (" Second Done Load Single-Threaded DLL on Different Apartment Thread\n");
  113. // ----------------------------------------------------------------------
  114. OUTPUT ("\n Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
  115. hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
  116. TEST_FAILED(!RetVal2, "SingleThreadedDLL on Multi Thread Failed\n");
  117. OUTPUT (" Done Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
  118. OUTPUT ("\n Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
  119. hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
  120. TEST_FAILED(!RetVal2, "SingleThreadedDLL on Multi Thread Failed\n");
  121. OUTPUT (" Done Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
  122. // ----------------------------------------------------------------------
  123. OUTPUT (" - Test Complete. Doing Cleanup\n");
  124. CoUninitialize();
  125. BOOL fResult = TestResult(RetVal, "TestLoadSingleThreaded");
  126. Sleep(2000);
  127. return fResult;
  128. }
  129. // ----------------------------------------------------------------------
  130. //
  131. // TestLoadApartmentThreaded
  132. //
  133. // Tests loading an apartment-threaded DLL
  134. //
  135. // ----------------------------------------------------------------------
  136. BOOL TestLoadApartmentThreaded(void)
  137. {
  138. BOOL RetVal = TRUE, RetVal2 = FALSE;
  139. HRESULT hRes = S_OK;
  140. OUTPUT ("\n\nStarting TestLoadApartmentThreaded\n");
  141. // First, mark the DLL appropriately in the registry.
  142. RetVal2 = SetRegForDll(CLSID_QI, pszApartmentModel);
  143. TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
  144. hRes = CoInitializeEx(NULL, gInitFlag);
  145. TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
  146. // ----------------------------------------------------------------------
  147. OUTPUT ("\n Load Apartment-Threaded DLL on Main Thread\n");
  148. RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
  149. TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Main Thread Failed\n");
  150. OUTPUT (" Done Load Apartment-Threaded DLL on Main Thread\n");
  151. OUTPUT ("\n Load Apartment-Threaded DLL on Main Thread\n");
  152. RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
  153. TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Main Thread Failed\n");
  154. OUTPUT (" Done Load Apartment-Threaded DLL on Main Thread\n");
  155. // ----------------------------------------------------------------------
  156. OUTPUT ("\n Load Apartment-Threaded DLL on Different Apartment Thread\n");
  157. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
  158. TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Apartment Thread Failed\n");
  159. OUTPUT (" Done Load Apartment-Threaded DLL on Different Apartment Thread\n");
  160. OUTPUT ("\n Second Load Apartment-Threaded DLL on Different Apartment Thread\n");
  161. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
  162. TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Apartment Thread Failed\n");
  163. OUTPUT (" Second Done Load Apartment-Threaded DLL on Different Apartment Thread\n");
  164. // ----------------------------------------------------------------------
  165. OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  166. hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
  167. TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Multi Thread Failed\n");
  168. OUTPUT (" Done Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  169. OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  170. hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
  171. TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Multi Thread Failed\n");
  172. OUTPUT (" Done Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  173. // ----------------------------------------------------------------------
  174. OUTPUT (" - Test Complete. Doing Cleanup\n");
  175. CoUninitialize();
  176. BOOL fResult = TestResult(RetVal, "TestLoadApartmentThreaded");
  177. Sleep(2000);
  178. return fResult;
  179. }
  180. // ----------------------------------------------------------------------
  181. //
  182. // TestLoadMultiThreaded
  183. //
  184. // Tests loading a multi-threaded DLL
  185. //
  186. // ----------------------------------------------------------------------
  187. BOOL TestLoadMultiThreaded(void)
  188. {
  189. BOOL RetVal = TRUE, RetVal2 = FALSE;;
  190. HRESULT hRes = S_OK;
  191. OUTPUT ("\n\nStarting TestLoadMultiThreaded\n");
  192. // First, mark the DLL appropriately in the registry.
  193. RetVal2 = SetRegForDll(CLSID_QI, pszMultiThreadedModel);
  194. TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
  195. hRes = CoInitializeEx(NULL, gInitFlag);
  196. TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
  197. // ----------------------------------------------------------------------
  198. OUTPUT ("\n Load Free-Threaded DLL on Main Thread\n");
  199. RetVal2 = LoadClassObject((gfApt) ? ITF_PROXY : ITF_REAL);
  200. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Main Thread Failed\n");
  201. OUTPUT (" Done Load Free-Threaded DLL on Main Thread\n");
  202. OUTPUT ("\n Load Free-Threaded DLL on Main Thread\n");
  203. RetVal2 = LoadClassObject((gfApt) ? ITF_PROXY : ITF_REAL);
  204. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Main Thread Failed\n");
  205. OUTPUT (" Done Load Free-Threaded DLL on Main Thread\n");
  206. // ----------------------------------------------------------------------
  207. OUTPUT ("\n Load Free-Threaded DLL on Different Apartment Thread\n");
  208. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
  209. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
  210. OUTPUT (" Done Load Free-Threaded DLL on Different Apartment Thread\n");
  211. OUTPUT ("\n Second Load Free-Threaded DLL on Different Apartment Thread\n");
  212. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
  213. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
  214. OUTPUT (" Second Done Load Apartment-Threaded DLL on Different Apartment Thread\n");
  215. // ----------------------------------------------------------------------
  216. OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  217. hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
  218. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
  219. OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
  220. OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  221. hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
  222. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
  223. OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
  224. // ----------------------------------------------------------------------
  225. OUTPUT (" - Test Complete. Doing Cleanup\n");
  226. CoUninitialize();
  227. BOOL fResult = TestResult(RetVal, "TestLoadMultiThreaded");
  228. Sleep(2000);
  229. return fResult;
  230. }
  231. // ----------------------------------------------------------------------
  232. //
  233. // TestLoadBothThreaded
  234. //
  235. // Tests loading a both-threaded DLL
  236. //
  237. // ----------------------------------------------------------------------
  238. BOOL TestLoadBothThreaded(void)
  239. {
  240. BOOL RetVal = TRUE, RetVal2 = FALSE;;
  241. HRESULT hRes = S_OK;
  242. OUTPUT ("\n\nStarting TestLoadBothThreaded\n");
  243. // First, mark the DLL appropriately in the registry.
  244. RetVal2 = SetRegForDll(CLSID_QI, pszBothModel);
  245. TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
  246. hRes = CoInitializeEx(NULL, gInitFlag);
  247. TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
  248. // ----------------------------------------------------------------------
  249. OUTPUT ("\n Load Both-Threaded DLL on Main Thread\n");
  250. RetVal2 = LoadClassObject(ITF_REAL);
  251. TEST_FAILED(!RetVal2, "Both-ThreadedDLL on Main Thread Failed\n");
  252. OUTPUT (" Done Load Both-Threaded DLL on Main Thread\n");
  253. // ----------------------------------------------------------------------
  254. OUTPUT ("\n Load Both-Threaded DLL on Different Apartment Thread\n");
  255. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
  256. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
  257. OUTPUT (" Done Load Free-Threaded DLL on Different Apartment Thread\n");
  258. OUTPUT ("\n Second Load Free-Threaded DLL on Different Apartment Thread\n");
  259. hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
  260. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
  261. OUTPUT (" Second Done Load Free-Threaded DLL on Different Apartment Thread\n");
  262. // ----------------------------------------------------------------------
  263. OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  264. hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
  265. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
  266. OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
  267. OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
  268. hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
  269. TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
  270. OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
  271. // ----------------------------------------------------------------------
  272. OUTPUT (" - Test Complete. Doing Cleanup\n");
  273. CoUninitialize();
  274. BOOL fResult = TestResult(RetVal, "TestLoadBothThreaded");
  275. Sleep(2000);
  276. return fResult;
  277. }
  278. // ----------------------------------------------------------------------
  279. //
  280. // Function: SpinThread
  281. //
  282. // Synopsis: Creates a thread to do some work for us. Waits for it to
  283. // complete. Returns the results.
  284. //
  285. // ----------------------------------------------------------------------
  286. BOOL SpinThread(DWORD dwInitFlag, DWORD dwItfFlag)
  287. {
  288. BOOL RetVal = FALSE;
  289. // set up paramters to pass to the thread
  290. SLoadDLLParam LoadParam;
  291. LoadParam.dwCallingTID = GetCurrentThreadId();
  292. LoadParam.dwCoInitFlag = dwInitFlag;
  293. LoadParam.dwItfFlag = dwItfFlag;
  294. LoadParam.RetVal = FALSE;
  295. LoadParam.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  296. // create the thread
  297. DWORD dwThrdId = 0;
  298. HANDLE hThrd = CreateThread(NULL, 0,
  299. LoadDLLOnThread,
  300. &LoadParam, 0, &dwThrdId);
  301. if (hThrd)
  302. {
  303. // enter a message loop and wait for the other thread to run
  304. // We stay here until the thread posts a QUIT message.
  305. MSG msg;
  306. while (GetMessage(&msg, NULL, 0, 0))
  307. {
  308. DispatchMessage(&msg);
  309. }
  310. // close the thread handle
  311. CloseHandle(hThrd);
  312. }
  313. else
  314. {
  315. HRESULT hRes = GetLastError();
  316. TEST_FAILED(hRes, "CreateThread failed\n")
  317. LoadParam.RetVal = RetVal;
  318. }
  319. // wait for the other thread to complete
  320. WaitForSingleObject(LoadParam.hEvent, 0xffffffff);
  321. CloseHandle(LoadParam.hEvent);
  322. return LoadParam.RetVal;
  323. }
  324. // ----------------------------------------------------------------------
  325. //
  326. // Function: LoadDLLOnThread
  327. //
  328. // Synopsis: Initializes COM, loads the class object and creates an
  329. // instance, releases them, Posts a message to wake up the
  330. // calling thread, Uninitializes COM, then exits.
  331. //
  332. // ----------------------------------------------------------------------
  333. DWORD _stdcall LoadDLLOnThread(void *param)
  334. {
  335. BOOL RetVal = TRUE;
  336. HRESULT hRes = S_OK;
  337. SLoadDLLParam *pLoadParam = (SLoadDLLParam *)param;
  338. OUTPUT (" - LoadDLLOnThread Entered\n");
  339. hRes = CoInitializeEx(NULL, pLoadParam->dwCoInitFlag);
  340. TEST_FAILED(FAILED(hRes), "CoInitialize failed\n")
  341. if (SUCCEEDED(hRes))
  342. {
  343. // attempt to load the class object on this thread.
  344. pLoadParam->RetVal = LoadClassObject(pLoadParam->dwItfFlag);
  345. CoUninitialize();
  346. }
  347. // post a message to the server thread to exit now that we are done.
  348. PostThreadMessage(pLoadParam->dwCallingTID, WM_QUIT, 0, 0);
  349. SetEvent(pLoadParam->hEvent);
  350. OUTPUT (" - LoadDLLOnThread Exit\n");
  351. return RetVal;
  352. }
  353. // ----------------------------------------------------------------------
  354. //
  355. // Function: LoadClassObject
  356. //
  357. // Synopsis: Loads the class object, creates an instance, releases
  358. // them, returns the results.
  359. //
  360. // ----------------------------------------------------------------------
  361. BOOL LoadClassObject(DWORD dwItfFlag)
  362. {
  363. BOOL RetVal = TRUE;
  364. IClassFactory *pICF = NULL;
  365. IUnknown *pIPM = NULL;
  366. // try to load the dll class object
  367. HRESULT hRes = CoGetClassObject(CLSID_QI, CLSCTX_INPROC_SERVER, NULL,
  368. IID_IClassFactory, (void **)&pICF);
  369. TEST_FAILED(FAILED(hRes), "CoGetClassObject failed\n");
  370. if (SUCCEEDED(hRes))
  371. {
  372. hRes = pICF->QueryInterface(IID_IProxyManager, (void **)&pIPM);
  373. if (SUCCEEDED(hRes))
  374. {
  375. pIPM->Release();
  376. TEST_FAILED(dwItfFlag != ITF_PROXY, "Got Proxy when expected Real\n");
  377. }
  378. else
  379. {
  380. TEST_FAILED(dwItfFlag != ITF_REAL, "Got Real when expected Proxy\n");
  381. }
  382. // CODEWORK: create an instance, then release them
  383. // release the class object.
  384. OUTPUT (" - CoGetClassObject succeeded\n");
  385. ULONG ulRefCnt = pICF->Release();
  386. TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
  387. pICF = NULL;
  388. OUTPUT (" - Released ClassObject\n");
  389. }
  390. return RetVal;
  391. }
  392. //+-------------------------------------------------------------------
  393. //
  394. // Function: SetRegForDll, private
  395. //
  396. // Synopsis: Set registry entry for a DLL
  397. //
  398. // Arguments: [rclsid] - clsid for reg entry
  399. // [pszThreadModel] - threading model can be NULL.
  400. //
  401. // Returns: TRUE - Registry entry set successfully.
  402. // FALSE - Registry entry set successfully.
  403. //
  404. // History: 01-Nov-94 Ricksa Created
  405. //
  406. //--------------------------------------------------------------------
  407. BOOL SetRegForDll(REFCLSID rclsid, const TCHAR *pszThreadModel)
  408. {
  409. BOOL fResult = FALSE;
  410. HKEY hKeyClass = NULL;
  411. HKEY hKeyDll = NULL;
  412. TCHAR aszWkBuf[MAX_PATH]; // String buffer used for various purposes
  413. // Build clsid registry key
  414. wsprintf(aszWkBuf,
  415. TEXT("CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
  416. rclsid.Data1, rclsid.Data2, rclsid.Data3,
  417. rclsid.Data4[0], rclsid.Data4[1],
  418. rclsid.Data4[2], rclsid.Data4[3],
  419. rclsid.Data4[4], rclsid.Data4[5],
  420. rclsid.Data4[6], rclsid.Data4[7]);
  421. // Create the key for the class
  422. if (RegCreateKey(HKEY_CLASSES_ROOT, aszWkBuf, &hKeyClass) == ERROR_SUCCESS)
  423. {
  424. // Create the key for the DLL
  425. if (RegCreateKey(hKeyClass, TEXT("InprocServer32"), &hKeyDll) == ERROR_SUCCESS)
  426. {
  427. // Set the value for the Threading Model
  428. if (RegSetValueEx(hKeyDll, pszRegValThreadModel, 0,
  429. REG_SZ,
  430. (const unsigned char*) pszThreadModel,
  431. (wcslen(pszThreadModel) + 1) * sizeof(WCHAR))
  432. == ERROR_SUCCESS)
  433. {
  434. fResult = TRUE;
  435. }
  436. RegCloseKey(hKeyDll);
  437. }
  438. RegCloseKey(hKeyClass);
  439. }
  440. return fResult;
  441. }