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.

386 lines
9.6 KiB

  1. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  2. //
  3. // Helper routines that wrap called to functions in oleaut32. This enables us to
  4. // compile free from any dependency on oleaut32.dll. In this case, some functionality
  5. // is lost. For example, only certain types of VARIANT variables are handled correctly
  6. // in the abscence of oleaut32.
  7. //
  8. // Defining DMS_USE_OLEAUT allows oleaut32 to be used.
  9. //
  10. #include "stdinc.h"
  11. #include "oleaut.h"
  12. #ifndef DMS_ALWAYS_USE_OLEAUT
  13. #ifndef DMS_NEVER_USE_OLEAUT
  14. //////////////////////////////////////////////////////////////////////
  15. // Handling LoadLibrary of OleAut32
  16. bool g_fCalledLoadLibrary = false;
  17. HINSTANCE g_hinstOleAut = NULL;
  18. #define OLEAUTAPI_FUNC_PTR STDAPICALLTYPE *
  19. void (OLEAUTAPI_FUNC_PTR g_pfnVariantInit)(VARIANTARG *pvarg) = NULL;
  20. HRESULT (OLEAUTAPI_FUNC_PTR g_pfnVariantClear)(VARIANTARG *pvarg) = NULL;
  21. HRESULT (OLEAUTAPI_FUNC_PTR g_pfnVariantCopy)(VARIANTARG *pvargDest, VARIANTARG *pvargSrc) = NULL;
  22. HRESULT (OLEAUTAPI_FUNC_PTR g_pfnVariantChangeType)(VARIANTARG *pvargDest, VARIANTARG *pvarSrc, USHORT wFlags, VARTYPE vt) = NULL;
  23. BSTR (OLEAUTAPI_FUNC_PTR g_pfnSysAllocString)(const OLECHAR *) = NULL;
  24. void (OLEAUTAPI_FUNC_PTR g_pfnSysFreeString)(BSTR) = NULL;
  25. bool FEnsureOleAutLoaded()
  26. {
  27. if (!g_fCalledLoadLibrary)
  28. {
  29. Trace(4, "Loading oleaut32.\n");
  30. g_fCalledLoadLibrary = true;
  31. g_hinstOleAut = LoadLibrary("oleaut32");
  32. assert(g_hinstOleAut);
  33. if (g_hinstOleAut)
  34. {
  35. *reinterpret_cast<FARPROC*>(&g_pfnVariantInit) = GetProcAddress(g_hinstOleAut, "VariantInit");
  36. if (!g_pfnVariantInit)
  37. goto Fail;
  38. *reinterpret_cast<FARPROC*>(&g_pfnVariantClear) = GetProcAddress(g_hinstOleAut, "VariantClear");
  39. if (!g_pfnVariantClear)
  40. goto Fail;
  41. *reinterpret_cast<FARPROC*>(&g_pfnVariantCopy) = GetProcAddress(g_hinstOleAut, "VariantCopy");
  42. if (!g_pfnVariantCopy)
  43. goto Fail;
  44. *reinterpret_cast<FARPROC*>(&g_pfnVariantChangeType) = GetProcAddress(g_hinstOleAut, "VariantChangeType");
  45. if (!g_pfnVariantChangeType)
  46. goto Fail;
  47. *reinterpret_cast<FARPROC*>(&g_pfnSysAllocString) = GetProcAddress(g_hinstOleAut, "SysAllocString");
  48. if (!g_pfnSysAllocString)
  49. goto Fail;
  50. *reinterpret_cast<FARPROC*>(&g_pfnSysFreeString) = GetProcAddress(g_hinstOleAut, "SysFreeString");
  51. if (!g_pfnSysFreeString)
  52. goto Fail;
  53. return true;
  54. }
  55. }
  56. return !!g_hinstOleAut;
  57. Fail:
  58. Trace(1, "Error: Unable to load oleaut32.dll.\n");
  59. g_hinstOleAut = NULL;
  60. return false;
  61. }
  62. #endif
  63. //////////////////////////////////////////////////////////////////////
  64. // VARIANT functions
  65. // private functions
  66. inline bool FIsRefOrArray(VARTYPE vt)
  67. {
  68. return (vt & VT_BYREF) || (vt & VT_ARRAY);
  69. }
  70. // public functions
  71. void
  72. DMS_VariantInit(bool fUseOleAut, VARIANTARG *pvarg)
  73. {
  74. #ifndef DMS_NEVER_USE_OLEAUT
  75. if (fUseOleAut)
  76. {
  77. if (FEnsureOleAutLoaded())
  78. {
  79. g_pfnVariantInit(pvarg);
  80. return;
  81. }
  82. }
  83. #else
  84. assert(!fUseOleAut);
  85. #endif
  86. {
  87. V_INAME(DMS_VariantInit);
  88. assert(!IsBadWritePtr(pvarg, sizeof(VARIANTARG)));
  89. pvarg->vt = VT_EMPTY;
  90. }
  91. }
  92. HRESULT
  93. DMS_VariantClear(bool fUseOleAut, VARIANTARG * pvarg)
  94. {
  95. #ifndef DMS_NEVER_USE_OLEAUT
  96. if (fUseOleAut)
  97. {
  98. if (FEnsureOleAutLoaded())
  99. return g_pfnVariantClear(pvarg);
  100. else
  101. return DMUS_E_SCRIPT_CANTLOAD_OLEAUT32;
  102. }
  103. #else
  104. assert(!fUseOleAut);
  105. #endif
  106. V_INAME(DMS_VariantClear);
  107. V_PTR_WRITE(pvarg, VARIANTARG);
  108. if (FIsRefOrArray(pvarg->vt))
  109. {
  110. Trace(1, "Error: A varient was used that had a type that is not supported by AudioVBScript.\n");
  111. return DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE;
  112. }
  113. switch (pvarg->vt)
  114. {
  115. case VT_UNKNOWN:
  116. SafeRelease(pvarg->punkVal);
  117. break;
  118. case VT_DISPATCH:
  119. SafeRelease(pvarg->pdispVal);
  120. break;
  121. case VT_BSTR:
  122. DMS_SysFreeString(fUseOleAut, pvarg->bstrVal);
  123. pvarg->bstrVal = NULL;
  124. break;
  125. }
  126. pvarg->vt = VT_EMPTY;
  127. return S_OK;
  128. }
  129. HRESULT DMS_VariantCopy(bool fUseOleAut, VARIANTARG * pvargDest, const VARIANTARG * pvargSrc)
  130. {
  131. #ifndef DMS_NEVER_USE_OLEAUT
  132. if (fUseOleAut)
  133. {
  134. if (FEnsureOleAutLoaded())
  135. return g_pfnVariantCopy(pvargDest, const_cast<VARIANT*>(pvargSrc));
  136. else
  137. return DMUS_E_SCRIPT_CANTLOAD_OLEAUT32;
  138. }
  139. #else
  140. assert(!fUseOleAut);
  141. #endif
  142. V_INAME(DMS_VariantCopy);
  143. V_PTR_WRITE(pvargDest, VARIANTARG);
  144. V_PTR_READ(pvargSrc, VARIANTARG);
  145. if (pvargDest == pvargSrc)
  146. {
  147. assert(false);
  148. return E_INVALIDARG;
  149. }
  150. if (FIsRefOrArray(pvargSrc->vt))
  151. {
  152. Trace(1, "Error: A varient was used that had a type that is not supported by AudioVBScript.\n");
  153. return DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE;
  154. }
  155. HRESULT hr = DMS_VariantClear(fUseOleAut, pvargDest);
  156. if (FAILED(hr))
  157. return hr;
  158. switch (pvargSrc->vt)
  159. {
  160. case VT_UNKNOWN:
  161. if (pvargSrc->punkVal)
  162. pvargSrc->punkVal->AddRef();
  163. break;
  164. case VT_DISPATCH:
  165. if (pvargSrc->pdispVal)
  166. pvargSrc->pdispVal->AddRef();
  167. break;
  168. case VT_BSTR:
  169. pvargDest->vt = VT_BSTR;
  170. pvargDest->bstrVal = DMS_SysAllocString(fUseOleAut, pvargSrc->bstrVal);
  171. return S_OK;
  172. }
  173. *pvargDest = *pvargSrc;
  174. return S_OK;
  175. }
  176. HRESULT
  177. DMS_VariantChangeType(
  178. bool fUseOleAut,
  179. VARIANTARG * pvargDest,
  180. VARIANTARG * pvarSrc,
  181. USHORT wFlags,
  182. VARTYPE vt)
  183. {
  184. #ifndef DMS_NEVER_USE_OLEAUT
  185. if (fUseOleAut)
  186. {
  187. if (FEnsureOleAutLoaded())
  188. return g_pfnVariantChangeType(pvargDest, pvarSrc, wFlags, vt);
  189. else
  190. return DMUS_E_SCRIPT_CANTLOAD_OLEAUT32;
  191. }
  192. #else
  193. assert(!fUseOleAut);
  194. #endif
  195. V_INAME(DMS_VariantChangeType);
  196. V_PTR_WRITE(pvargDest, VARIANTARG);
  197. V_PTR_READ(pvarSrc, VARIANTARG);
  198. bool fConvertInPlace = pvarSrc == pvargDest;
  199. if (vt == pvarSrc->vt)
  200. {
  201. // No conversion necessary
  202. if (fConvertInPlace)
  203. return S_OK;
  204. return DMS_VariantCopy(fUseOleAut, pvargDest, pvarSrc);
  205. }
  206. if (FIsRefOrArray(vt) || FIsRefOrArray(pvarSrc->vt))
  207. {
  208. Trace(1, "Error: A varient was used that had a type that is not supported by AudioVBScript.\n");
  209. return DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE;
  210. }
  211. switch (vt)
  212. {
  213. case VT_I4:
  214. {
  215. // Get the value
  216. LONG lVal = 0;
  217. switch (pvarSrc->vt)
  218. {
  219. case VT_I2:
  220. lVal = pvarSrc->iVal;
  221. break;
  222. case VT_EMPTY:
  223. break;
  224. case VT_UNKNOWN:
  225. case VT_DISPATCH:
  226. case VT_BSTR:
  227. return DISP_E_TYPEMISMATCH;
  228. default:
  229. Trace(1, "Error: A varient was used that had a type that is not supported by AudioVBScript.\n");
  230. return DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE;
  231. }
  232. // Write the result
  233. pvargDest->vt = VT_I4;
  234. pvargDest->lVal = lVal;
  235. return S_OK;
  236. }
  237. case VT_DISPATCH:
  238. case VT_UNKNOWN:
  239. {
  240. // We can convert between IDispatch and IUnknown.
  241. bool fConvertToUnknown = vt == VT_UNKNOWN; // true if IUnknown is dest, false if IDispatch is dest
  242. // We'll assume that both fields (pdispVal/punkVal) are stored in the same slot in the VARIANT union.
  243. // This will make things simpler because we can just manipulate the same pointer now matter whether we're
  244. // converting to or from Dispatch/Unknown.
  245. assert(reinterpret_cast<void**>(&pvarSrc->pdispVal) == reinterpret_cast<void**>(&pvarSrc->punkVal));
  246. assert(reinterpret_cast<void**>(&pvargDest->pdispVal) == reinterpret_cast<void**>(&pvargDest->punkVal));
  247. IUnknown *punkCur = pvarSrc->punkVal; // Current value we're going to convert.
  248. void *pval = NULL; // New value result of conversion.
  249. switch (pvarSrc->vt)
  250. {
  251. case VT_DISPATCH:
  252. case VT_UNKNOWN:
  253. {
  254. if (!punkCur)
  255. return E_INVALIDARG;
  256. HRESULT hrDispQI = punkCur->QueryInterface(fConvertToUnknown ? IID_IUnknown : IID_IDispatch, &pval);
  257. if (FAILED(hrDispQI))
  258. return hrDispQI;
  259. break;
  260. }
  261. case VT_I4:
  262. case VT_I2:
  263. case VT_BSTR:
  264. case VT_EMPTY:
  265. return DISP_E_TYPEMISMATCH;
  266. default:
  267. Trace(1, "Error: A varient was used that had a type that is not supported by AudioVBScript.\n");
  268. return DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE;
  269. }
  270. // Write the result
  271. if (fConvertInPlace)
  272. punkCur->Release();
  273. pvargDest->vt = fConvertToUnknown ? VT_UNKNOWN : VT_DISPATCH;
  274. pvargDest->punkVal = reinterpret_cast<IUnknown*>(pval);
  275. return S_OK;
  276. }
  277. default:
  278. Trace(1, "Error: A varient was used that had a type that is not supported by AudioVBScript.\n");
  279. return DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE;
  280. }
  281. }
  282. //////////////////////////////////////////////////////////////////////
  283. // BSTR functions
  284. const UINT cwchCountPrefix = sizeof(DWORD) / sizeof(WCHAR);
  285. BSTR
  286. DMS_SysAllocString(bool fUseOleAut, const OLECHAR *pwsz)
  287. {
  288. #ifndef DMS_NEVER_USE_OLEAUT
  289. if (fUseOleAut)
  290. {
  291. if (FEnsureOleAutLoaded())
  292. {
  293. BSTR bstrReturn = g_pfnSysAllocString(pwsz);
  294. // Use this to trace memory being allocated in case you need to debug a corruption problem.
  295. TraceI(4, "DMS_SysAllocString: 0x%08x, \"%S\", %S\n", bstrReturn, bstrReturn ? bstrReturn : L"", L"oleaut");
  296. return bstrReturn;
  297. }
  298. else
  299. {
  300. return NULL;
  301. }
  302. }
  303. #else
  304. assert(!fUseOleAut);
  305. #endif
  306. if (!pwsz)
  307. return NULL;
  308. BSTR bstr = new WCHAR[wcslen(pwsz) + 1];
  309. if (!bstr)
  310. return NULL;
  311. wcscpy(bstr, pwsz);
  312. // Use this to trace memory being allocated in case you need to debug a corruption problem.
  313. TraceI(4, "DMS_SysAllocString: 0x%08x, \"%S\", %S\n", bstr, bstr ? bstr : L"", L"no oleaut");
  314. return bstr;
  315. }
  316. void
  317. DMS_SysFreeString(bool fUseOleAut, BSTR bstr)
  318. {
  319. // Use this to trace memory being deallocated in case you need to debug a corruption problem.
  320. // All DMS_SysAllocString with "no oleaut" should be neatly balanced by an opposing DMS_SysAllocFreeString.
  321. // There are some unbalanced calls with "oleaut" because we don't see the allocations and frees made by VBScript.
  322. TraceI(4, "DMS_SysFreeString: 0x%08x, \"%S\", %S\n", bstr, bstr ? bstr : L"", fUseOleAut ? L"oleaut" : L"no oleaut");
  323. #ifndef DMS_NEVER_USE_OLEAUT
  324. if (fUseOleAut)
  325. {
  326. if (FEnsureOleAutLoaded())
  327. g_pfnSysFreeString(bstr);
  328. return;
  329. }
  330. #else
  331. assert(!fUseOleAut);
  332. #endif
  333. delete[] bstr;
  334. }
  335. #endif