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.

346 lines
8.5 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: comutil.cpp
  6. * Content: Contains implementation of COM helper functions for DPLAY8 project.
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 06/07/00 rmt Created
  12. * 06/15/2000 rmt Fixed small bug in COM_CoCreateInstance which was causing AV
  13. * 06/27/00 rmt Added abstraction for COM_Co(Un)Initialize
  14. * 07/06/00 rmt Modified to match updated creg usage
  15. * 08/08/2000 rmt Bug #41736 - AV in call to lstrcpy by COM_GetDllName
  16. * 01/11/2001 rmt MANBUG #48487 - DPLAY: Crashes if CoCreate() isn't called.
  17. * 03/14/2001 rmt WINBUG #342420 - Restore COM emulation layer to operation.
  18. *@@END_MSINTERNAL
  19. *
  20. ***************************************************************************/
  21. #include "dncmni.h"
  22. #include "comutil.h"
  23. #undef DPF_SUBCOMP
  24. #define DPF_SUBCOMP DN_SUBCOMP_COMMON
  25. typedef HRESULT (WINAPI *PFNDLLGETCLASSOBJECT)(REFCLSID rclsid,REFIID riid,LPVOID *ppvObj );
  26. typedef HRESULT (WINAPI *PFNDLLCANUNLOADNOW)(void);
  27. CBilink g_blComEntriesGlobal;
  28. DNCRITICAL_SECTION csComEntriesLock;
  29. typedef struct _COMDLL_ENTRY
  30. {
  31. HMODULE hDLL;
  32. CHAR szFileName[_MAX_PATH];
  33. GUID clsid;
  34. PFNDLLGETCLASSOBJECT pfnGetClassObject;
  35. PFNDLLCANUNLOADNOW pfnCanUnloadNow;
  36. CBilink blComEntries;
  37. } COMDLL_ENTRY, *PCOMDLL_ENTRY;
  38. #undef DPF_MODNAME
  39. #define DPF_MODNAME "COM_Init"
  40. HRESULT COM_Init()
  41. {
  42. g_blComEntriesGlobal.Initialize();
  43. if (DNInitializeCriticalSection( &csComEntriesLock ) == FALSE)
  44. {
  45. return DPNERR_OUTOFMEMORY;
  46. }
  47. return DPN_OK;
  48. }
  49. #undef DPF_MODNAME
  50. #define DPF_MODNAME "COM_Free"
  51. HRESULT COM_Free()
  52. {
  53. CBilink *pblSearch;
  54. PCOMDLL_ENTRY pEntry;
  55. pblSearch = g_blComEntriesGlobal.GetNext();
  56. while( pblSearch != &g_blComEntriesGlobal )
  57. {
  58. pEntry = CONTAINING_RECORD( pblSearch, COMDLL_ENTRY, blComEntries );
  59. pblSearch = pblSearch->GetNext();
  60. FreeLibrary( pEntry->hDLL );
  61. delete pEntry;
  62. }
  63. DNDeleteCriticalSection( &csComEntriesLock );
  64. return DPN_OK;
  65. }
  66. #undef DPF_MODNAME
  67. #define DPF_MODNAME "COM_CoInitialize"
  68. HRESULT COM_CoInitialize( void * pvParam )
  69. {
  70. return CoInitializeEx( pvParam, COINIT_MULTITHREADED );
  71. }
  72. #undef DPF_MODNAME
  73. #define DPF_MODNAME "COM_CoUninitialize"
  74. void COM_CoUninitialize()
  75. {
  76. CoUninitialize();
  77. }
  78. #undef DPF_MODNAME
  79. #define DPF_MODNAME "COM_GetEntry"
  80. HRESULT COM_GetEntry( GUID clsid, PCOMDLL_ENTRY *ppEntry )
  81. {
  82. CBilink *pblSearch;
  83. PCOMDLL_ENTRY pEntry;
  84. HRESULT hr;
  85. DWORD dwSize;
  86. DNEnterCriticalSection( &csComEntriesLock );
  87. pblSearch = g_blComEntriesGlobal.GetNext();
  88. while( pblSearch != &g_blComEntriesGlobal )
  89. {
  90. pEntry = CONTAINING_RECORD( pblSearch, COMDLL_ENTRY, blComEntries );
  91. // This should never happen, but makes prefix happy
  92. if( !pEntry )
  93. {
  94. DNASSERT( FALSE );
  95. DNLeaveCriticalSection( &csComEntriesLock );
  96. return DPNERR_GENERIC;
  97. }
  98. if( pEntry->clsid == clsid )
  99. {
  100. *ppEntry = pEntry;
  101. DNLeaveCriticalSection( &csComEntriesLock );
  102. return DPN_OK;
  103. }
  104. pblSearch = pblSearch->GetNext();
  105. }
  106. pEntry = new COMDLL_ENTRY;
  107. if (pEntry == NULL)
  108. {
  109. DPFERR( "Error allocating COM entry" );
  110. hr = DPNERR_OUTOFMEMORY;
  111. goto LOAD_FAILED;
  112. }
  113. memset( pEntry, 0x00, sizeof( COMDLL_ENTRY ) );
  114. pEntry->clsid = clsid;
  115. pEntry->blComEntries.Initialize();
  116. dwSize = _MAX_PATH;
  117. hr = COM_GetDLLName( clsid, pEntry->szFileName, &dwSize );
  118. if( FAILED( hr ) )
  119. {
  120. DPFERR( "Unable to find DLL name for COM object" );
  121. goto LOAD_FAILED;
  122. }
  123. pEntry->hDLL = LoadLibraryA( pEntry->szFileName );
  124. if( !pEntry->hDLL )
  125. {
  126. hr = GetLastError();
  127. DPFX(DPFPREP, 0, "Unable to load libary err=0x%x", hr );
  128. goto LOAD_FAILED;
  129. }
  130. pEntry->pfnGetClassObject = (PFNDLLGETCLASSOBJECT) GetProcAddress( pEntry->hDLL, "DllGetClassObject" );
  131. pEntry->pfnCanUnloadNow = (PFNDLLCANUNLOADNOW) GetProcAddress( pEntry->hDLL, "DllCanUnloadNow" );
  132. pEntry->blComEntries.InsertBefore( &g_blComEntriesGlobal );
  133. DNLeaveCriticalSection( &csComEntriesLock );
  134. *ppEntry = pEntry;
  135. return DPN_OK;
  136. LOAD_FAILED:
  137. if( pEntry != NULL )
  138. {
  139. if( pEntry->hDLL != NULL )
  140. {
  141. FreeLibrary( pEntry->hDLL );
  142. }
  143. delete pEntry;
  144. }
  145. DNLeaveCriticalSection( &csComEntriesLock );
  146. return hr;
  147. }
  148. #undef DPF_MODNAME
  149. #define DPF_MODNAME "COM_GetDLLName"
  150. HRESULT COM_GetDLLName( GUID guidCLSID, CHAR *szPath, DWORD *pdwSize )
  151. {
  152. CRegistry cregRoot;
  153. CRegistry cregCLSID;
  154. CRegistry cregInProc;
  155. HRESULT hr = DPN_OK;
  156. BOOL fSuccess;
  157. WCHAR *wszTmpPath = NULL;
  158. DWORD dwTmpSize = 0;
  159. fSuccess = cregRoot.Open( HKEY_CLASSES_ROOT, L"CLSID", TRUE, FALSE );
  160. if( !fSuccess )
  161. {
  162. DPFX(DPFPREP, 0, "Error opening HKEY_CLASSES_ROOT\\CLSID" );
  163. hr = E_FAIL;
  164. goto COM_GETDLLNAME_ERROR;
  165. }
  166. fSuccess = cregCLSID.Open( cregRoot, &guidCLSID, TRUE, FALSE );
  167. if( !fSuccess )
  168. {
  169. DPFX(DPFPREP, 0, "Error opening specified CLSID" );
  170. hr = E_FAIL;
  171. goto COM_GETDLLNAME_ERROR;
  172. }
  173. fSuccess = cregInProc.Open( cregCLSID, L"InprocServer32", TRUE, FALSE );
  174. if( !fSuccess )
  175. {
  176. DPFX(DPFPREP, 0, "Error opening inprocserver key" );
  177. hr = E_FAIL;
  178. goto COM_GETDLLNAME_ERROR;
  179. }
  180. cregCLSID.Close();
  181. cregRoot.Close();
  182. fSuccess = cregInProc.ReadString( L"", wszTmpPath, &dwTmpSize );
  183. if( !dwTmpSize )
  184. {
  185. DPFX(DPFPREP, 0, "Error opening default key" );
  186. hr = E_FAIL;
  187. goto COM_GETDLLNAME_ERROR;
  188. }
  189. if( dwTmpSize > *pdwSize )
  190. {
  191. DPFX(DPFPREP, 0, "Buffer too small" );
  192. hr = DPNERR_BUFFERTOOSMALL;
  193. *pdwSize = dwTmpSize;
  194. goto COM_GETDLLNAME_ERROR;
  195. }
  196. *pdwSize = dwTmpSize;
  197. wszTmpPath = new WCHAR[dwTmpSize];
  198. if( !wszTmpPath )
  199. {
  200. DPFX(DPFPREP, 0, "Error allocating memory" );
  201. hr = DPNERR_OUTOFMEMORY;
  202. goto COM_GETDLLNAME_ERROR;
  203. }
  204. fSuccess = cregInProc.ReadString( L"", wszTmpPath, &dwTmpSize );
  205. if( !fSuccess )
  206. {
  207. DPFX(DPFPREP, 0, "Error opening default key" );
  208. hr = E_FAIL;
  209. goto COM_GETDLLNAME_ERROR;
  210. }
  211. if( FAILED( hr = STR_jkWideToAnsi(szPath,wszTmpPath, *pdwSize ) ) )
  212. {
  213. DPFX(DPFPREP, 0, "Error converting path to DLL to ANSI hr=0x%x", hr );
  214. hr = E_FAIL;
  215. }
  216. delete [] wszTmpPath;
  217. return hr;
  218. COM_GETDLLNAME_ERROR:
  219. if( wszTmpPath )
  220. delete [] wszTmpPath;
  221. return hr;
  222. }
  223. // DP_CoCreateInstance
  224. //
  225. // This CoCreateInstance can be used instead of CoCreateInstance and will manually perform the
  226. // steps neccessary to do a CoCreateInstance if COM has not been initialized.
  227. //
  228. #undef DPF_MODNAME
  229. #define DPF_MODNAME "COM_CoCreateInstance"
  230. STDAPI COM_CoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv, BOOL fWarnUser )
  231. {
  232. HRESULT hr;
  233. CHAR *szFileName = NULL;
  234. DWORD dwFileNameSize = 0;
  235. PCOMDLL_ENTRY pEntry;
  236. IClassFactory *pClassFactory;
  237. hr = CoCreateInstance( rclsid, pUnkOuter, dwClsContext, riid, ppv );
  238. if( hr == CO_E_NOTINITIALIZED )
  239. {
  240. if( fWarnUser )
  241. {
  242. DPFX(DPFPREP, 0, "=====================================================================================" );
  243. DPFX(DPFPREP, 0, "" );
  244. DPFX(DPFPREP, 0, "The DirectPlay8/Voice create functions are no longer supported. It is recommended" );
  245. DPFX(DPFPREP, 0, "that your application be updated to use CoCreateInstance instead." );
  246. DPFX(DPFPREP, 0, "" );
  247. DPFX(DPFPREP, 0, "=====================================================================================" );
  248. }
  249. hr = COM_GetEntry( rclsid, &pEntry );
  250. if( FAILED( hr ) )
  251. return hr;
  252. hr = (*pEntry->pfnGetClassObject)( rclsid, IID_IClassFactory, (void **) &pClassFactory );
  253. if( FAILED( hr ) )
  254. {
  255. DPFX(DPFPREP, 0, "Failed getting class object on dynamic entry hr=0x%x", hr );
  256. return hr;
  257. }
  258. hr = pClassFactory->lpVtbl->CreateInstance( pClassFactory, pUnkOuter, riid, ppv );
  259. if( FAILED( hr ) )
  260. {
  261. DPFX(DPFPREP, 0, "Class factory returned an error hr=0x%x", hr );
  262. }
  263. pClassFactory->lpVtbl->Release(pClassFactory);
  264. return hr;
  265. }
  266. return hr;
  267. }