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.

583 lines
12 KiB

  1. /*
  2. File: Dispatch.cpp
  3. Copyright (c) 1997-1999 Microsoft Corporation. All Rights Reserved.
  4. Abstract:
  5. Dispatch helpers. stolen from HTMED tree
  6. */
  7. #include "stdafx.h"
  8. #include "resource.h"
  9. #include "dispatch.h"
  10. //#include "viewhdrs.h"
  11. #define RETURN return
  12. #define SetLastError(x,y) SetLastError(x)
  13. HRESULT
  14. CallDispatchMethod(
  15. IDispatch * pDisp,
  16. DISPID dispid,
  17. VARIANT * pvarFirst,
  18. char * pstrSig,
  19. va_list val)
  20. {
  21. HRESULT hr;
  22. int c;
  23. int i;
  24. VARIANT * pvar;
  25. VARIANT * pvarOut = NULL;
  26. VARIANT avar[10];
  27. VARIANT varOut;
  28. void * pvOut = NULL;
  29. DISPPARAMS dp;
  30. EXCEPINFO ei;
  31. UINT uArgErr;
  32. _ASSERTE(pDisp);
  33. VariantInit(&varOut);
  34. if (pstrSig)
  35. {
  36. c = strlen(pstrSig);
  37. //_ASSERTE(c > 0);
  38. //_ASSERTE(c <= DIM(avar));
  39. if (pstrSig[c - 1] & VTS_RETURN_FLAG)
  40. {
  41. pvarOut = &varOut;
  42. c--;
  43. }
  44. for (i = 0, pvar = avar + c - 1; i < c; i++, pvar--)
  45. {
  46. pvar->vt = pstrSig[i];
  47. switch (pstrSig[i])
  48. {
  49. case VT_I2:
  50. pvar->iVal = va_arg(val, short);
  51. break;
  52. case VT_I4:
  53. pvar->lVal = va_arg(val, long);
  54. break;
  55. case VT_BSTR:
  56. pvar->bstrVal = va_arg(val, BSTR);
  57. break;
  58. case VT_DISPATCH:
  59. pvar->pdispVal = va_arg(val, IDispatch *);
  60. break;
  61. case VT_UNKNOWN:
  62. pvar->punkVal = va_arg(val, IUnknown *);
  63. break;
  64. case VT_BOOL:
  65. pvar->boolVal = va_arg(val, VARIANT_BOOL);
  66. break;
  67. case VT_BSTR | VTS_BYREF_FLAG:
  68. case VT_DISPATCH | VTS_BYREF_FLAG:
  69. case VT_UNKNOWN | VTS_BYREF_FLAG:
  70. pvar->vt = (VARTYPE)((pstrSig[i] & (VTS_BYREF_FLAG - 1)) | VT_BYREF);
  71. pvar->ppdispVal = va_arg(val, IDispatch **);
  72. // Passing an uninitialized BSTR or object will crash when the callee
  73. // frees the existing value as it's supposed to.
  74. // This has been a common source of hard-to-find bugs, but
  75. // this _ASSERTE can be removed if we need to pass an in/out string.
  76. _ASSERTE(*pvar->ppdispVal == NULL);
  77. break;
  78. case VT_I2 | VTS_BYREF_FLAG:
  79. case VT_I4 | VTS_BYREF_FLAG:
  80. case VT_BOOL | VTS_BYREF_FLAG:
  81. case VT_VARIANT | VTS_BYREF_FLAG:
  82. pvar->vt = (VARTYPE)((pstrSig[i] & (VTS_BYREF_FLAG - 1)) | VT_BYREF);
  83. pvar->ppdispVal = va_arg(val, IDispatch **);
  84. break;
  85. default:
  86. _ASSERTE(FALSE && "Unsupported variant type");
  87. break;
  88. }
  89. }
  90. if (pvarOut)
  91. {
  92. pvOut = va_arg(val, void *);
  93. }
  94. }
  95. else
  96. {
  97. c = 0;
  98. }
  99. if (pvarFirst)
  100. {
  101. // _ASSERTE(c >= 0);
  102. // _ASSERTE(c < DIM(avar));
  103. avar[c++] = *pvarFirst;
  104. }
  105. dp.rgvarg = avar;
  106. dp.cArgs = c;
  107. dp.rgdispidNamedArgs = NULL;
  108. dp.cNamedArgs = 0;
  109. memset(&ei, 0, sizeof (ei));
  110. hr = pDisp->Invoke(
  111. dispid,
  112. IID_NULL,
  113. LOCALE_SYSTEM_DEFAULT,
  114. DISPATCH_METHOD,
  115. &dp,
  116. pvarOut,
  117. &ei,
  118. &uArgErr);
  119. if (hr)
  120. {
  121. SetLastError(hr, &ei);
  122. goto Error;
  123. }
  124. // If we're returning a value, coerce it to the correct
  125. // type
  126. if (pvarOut)
  127. {
  128. #pragma warning(disable: 4310) // cast truncates constant value
  129. hr = VariantChangeTypeEx(
  130. &varOut,
  131. &varOut,
  132. LOCALE_SYSTEM_DEFAULT,
  133. 0,
  134. (VARTYPE)(pstrSig[c] & (char) ~VTS_RETURN_FLAG));
  135. #pragma warning(default: 4310) // cast truncates constant value
  136. if (hr)
  137. goto Error;
  138. #pragma warning(disable: 4310) // cast truncates constant value
  139. switch (pstrSig[c] & (char) ~VTS_RETURN_FLAG)
  140. #pragma warning(default: 4310) // cast truncates constant value
  141. {
  142. case VT_I2:
  143. * (short *) pvOut = varOut.iVal;
  144. break;
  145. case VT_I4:
  146. * (long *) pvOut = varOut.lVal;
  147. break;
  148. case VT_BSTR:
  149. * (BSTR *) pvOut = varOut.bstrVal;
  150. break;
  151. case VT_DISPATCH:
  152. * (IDispatch **) pvOut = varOut.pdispVal;
  153. break;
  154. case VT_UNKNOWN:
  155. * (IUnknown **) pvOut = varOut.punkVal;
  156. break;
  157. case VT_BOOL:
  158. * (VARIANT_BOOL *) pvOut = varOut.boolVal;
  159. break;
  160. default:
  161. _ASSERTE(FALSE && "Unsupported type");
  162. break;
  163. }
  164. varOut.vt = VT_EMPTY;
  165. }
  166. Error:
  167. VariantClear(&varOut);
  168. RETURN(hr);
  169. }
  170. HRESULT __cdecl
  171. CallDispatchMethod(IDispatch * pDisp, DISPID dispid, char * pstrSig, ...)
  172. {
  173. HRESULT hr;
  174. va_list val;
  175. va_start(val, pstrSig);
  176. hr = CallDispatchMethod(pDisp, dispid, NULL, pstrSig, val);
  177. va_end(val);
  178. return hr;
  179. }
  180. HRESULT
  181. CallDispatchMethod(
  182. IDispatch * pDisp,
  183. WCHAR * pstrMethod,
  184. VARIANT * pvarFirst,
  185. char * pstrSig,
  186. va_list val)
  187. {
  188. HRESULT hr;
  189. DISPID dispid;
  190. // NOTE that depending on the dispatch implementation, this
  191. // method call can fail with more than one error code
  192. // (notably DISP_E_MEMBERNOTFOUND and TYPE_E_ELEMENTNOTFOUND,
  193. // including others). Since we want to reliably detect a
  194. // missing method, we map all errors to DISP_E_MEMBERNOTFOUND.
  195. hr = pDisp->GetIDsOfNames(
  196. IID_NULL,
  197. &pstrMethod,
  198. 1,
  199. LOCALE_SYSTEM_DEFAULT,
  200. &dispid);
  201. if (hr)
  202. {
  203. #if DBG == 1
  204. switch (hr)
  205. {
  206. case DISP_E_MEMBERNOTFOUND:
  207. case DISP_E_UNKNOWNNAME:
  208. case TYPE_E_ELEMENTNOTFOUND:
  209. case E_NOTIMPL:
  210. case RPC_E_SERVER_DIED:
  211. break;
  212. default:
  213. _ASSERTE(FALSE && "Unexpected error code from GetIDsOfNames.");
  214. break;
  215. }
  216. #endif
  217. hr = DISP_E_MEMBERNOTFOUND;
  218. goto Error;
  219. }
  220. hr = CallDispatchMethod(pDisp, dispid, pvarFirst, pstrSig, val);
  221. if (hr)
  222. goto Error;
  223. Error:
  224. return hr;
  225. }
  226. HRESULT __cdecl
  227. CallDispatchMethod(
  228. IDispatch * pDisp,
  229. WCHAR * pstrMethod,
  230. char * pstrSig,
  231. ...)
  232. {
  233. HRESULT hr;
  234. va_list val;
  235. va_start(val, pstrSig);
  236. hr = CallDispatchMethod(pDisp, pstrMethod, NULL, pstrSig, val);
  237. va_end(val);
  238. return hr;
  239. }
  240. HRESULT __cdecl
  241. CallDispatchMethod(
  242. IDispatch * pDisp,
  243. WCHAR * pstrMethod,
  244. VARIANT * pvarFirst,
  245. char * pstrSig,
  246. ...)
  247. {
  248. HRESULT hr;
  249. va_list val;
  250. va_start(val, pstrSig);
  251. hr = CallDispatchMethod(pDisp, pstrMethod, pvarFirst, pstrSig, val);
  252. va_end(val);
  253. return hr;
  254. }
  255. HRESULT
  256. GetDispatchProperty(
  257. IDispatch * pDisp,
  258. WCHAR * pstrProperty,
  259. VARENUM vt,
  260. void * pv)
  261. {
  262. HRESULT hr;
  263. DISPID dispid;
  264. hr = pDisp->GetIDsOfNames(
  265. IID_NULL,
  266. &pstrProperty,
  267. 1,
  268. LOCALE_SYSTEM_DEFAULT,
  269. &dispid);
  270. if (hr)
  271. {
  272. #if DBG == 1
  273. switch (hr)
  274. {
  275. case DISP_E_MEMBERNOTFOUND:
  276. case DISP_E_UNKNOWNNAME:
  277. case TYPE_E_ELEMENTNOTFOUND:
  278. case E_NOTIMPL:
  279. break;
  280. default:
  281. _ASSERTE(FALSE && "Unexpected error code from GetIDsOfNames.");
  282. break;
  283. }
  284. #endif
  285. RETURN(DISP_E_MEMBERNOTFOUND);
  286. }
  287. return GetDispatchProperty(pDisp, dispid, vt, pv);
  288. }
  289. HRESULT
  290. GetDispatchProperty(
  291. IDispatch * pDisp,
  292. DISPID dispidProperty,
  293. VARENUM vt,
  294. void * pv)
  295. {
  296. HRESULT hr;
  297. VARIANT var;
  298. DISPPARAMS dp = { NULL, NULL, 0, 0 };
  299. EXCEPINFO ei;
  300. UINT uArgErr;
  301. #if DBG == 1
  302. switch (vt)
  303. {
  304. case VT_I4:
  305. case VT_DISPATCH:
  306. case VT_UNKNOWN:
  307. case VT_BSTR:
  308. break;
  309. }
  310. #endif
  311. VariantInit(&var);
  312. hr = pDisp->Invoke(
  313. dispidProperty,
  314. IID_NULL,
  315. LOCALE_SYSTEM_DEFAULT,
  316. DISPATCH_PROPERTYGET|DISPATCH_METHOD,
  317. &dp,
  318. &var,
  319. &ei,
  320. &uArgErr);
  321. if (hr)
  322. goto Error;
  323. if (vt != VT_VARIANT)
  324. {
  325. hr = VariantChangeTypeEx(
  326. &var,
  327. &var,
  328. LOCALE_SYSTEM_DEFAULT,
  329. 0,
  330. (VARTYPE)vt);
  331. if (hr)
  332. goto Error;
  333. }
  334. switch (vt)
  335. {
  336. case VT_I2:
  337. * (short *) pv = var.iVal;
  338. break;
  339. case VT_I4:
  340. * (int *) pv = var.lVal;
  341. break;
  342. case VT_DISPATCH:
  343. * (IDispatch **) pv = var.pdispVal;
  344. break;
  345. case VT_UNKNOWN:
  346. * (IUnknown **) pv = var.punkVal;
  347. break;
  348. case VT_BSTR:
  349. * (BSTR *) pv = var.bstrVal;
  350. break;
  351. case VT_BOOL:
  352. * (VARIANT_BOOL *) pv = var.boolVal;
  353. break;
  354. case VT_VARIANT:
  355. VariantCopy( (VARIANT *) pv, &var);
  356. break;
  357. default:
  358. _ASSERTE(FALSE && "Unsupported type");
  359. break;
  360. }
  361. Error:
  362. RETURN(hr);
  363. }
  364. HRESULT
  365. PutDispatchProperty(
  366. IDispatch * pDisp,
  367. DISPID dispidProperty,
  368. VARENUM vt,
  369. va_list val)
  370. {
  371. VARIANT var;
  372. DISPPARAMS dp;
  373. EXCEPINFO ei;
  374. UINT uArgErr;
  375. DISPID dispidPropertyPut = DISPID_PROPERTYPUT;
  376. var.vt = (VARTYPE)vt;
  377. switch (vt)
  378. {
  379. case VT_I2:
  380. var.iVal = va_arg(val, short);
  381. break;
  382. case VT_I4:
  383. var.lVal = va_arg(val, int);
  384. break;
  385. case VT_DISPATCH:
  386. var.pdispVal = va_arg(val, IDispatch *);
  387. break;
  388. case VT_UNKNOWN:
  389. var.punkVal = va_arg(val, IUnknown *);
  390. break;
  391. case VT_BSTR:
  392. var.bstrVal = va_arg(val, BSTR);
  393. break;
  394. case VT_BOOL:
  395. var.boolVal = va_arg(val, VARIANT_BOOL);
  396. break;
  397. case VT_VARIANT:
  398. VariantCopy(&var, &(va_arg(val, VARIANT)));
  399. break;
  400. default:
  401. _ASSERTE(FALSE && "Unsupported type");
  402. break;
  403. }
  404. dp.rgvarg = &var;
  405. dp.cArgs = 1;
  406. dp.cNamedArgs = 1;
  407. dp.rgdispidNamedArgs = &dispidPropertyPut;
  408. RETURN(pDisp->Invoke(
  409. dispidProperty,
  410. IID_NULL,
  411. LOCALE_SYSTEM_DEFAULT,
  412. DISPATCH_PROPERTYPUT,
  413. &dp,
  414. NULL,
  415. &ei,
  416. &uArgErr));
  417. }
  418. HRESULT
  419. __cdecl
  420. PutDispatchProperty(
  421. IDispatch * pDisp,
  422. DISPID dispidProperty,
  423. VARENUM vt,
  424. ...)
  425. {
  426. HRESULT hr;
  427. va_list val;
  428. va_start(val, vt);
  429. hr = PutDispatchProperty(pDisp, dispidProperty, vt, val);
  430. va_end(val);
  431. RETURN(hr);
  432. }
  433. HRESULT
  434. __cdecl
  435. PutDispatchProperty(
  436. IDispatch * pDisp,
  437. WCHAR * pstrProperty,
  438. VARENUM vt,
  439. ...)
  440. {
  441. HRESULT hr;
  442. DISPID dispid;
  443. va_list val;
  444. hr = pDisp->GetIDsOfNames(
  445. IID_NULL,
  446. &pstrProperty,
  447. 1,
  448. LOCALE_SYSTEM_DEFAULT,
  449. &dispid);
  450. if (hr)
  451. {
  452. #if DBG == 1
  453. switch (hr)
  454. {
  455. case DISP_E_MEMBERNOTFOUND:
  456. case DISP_E_UNKNOWNNAME:
  457. case TYPE_E_ELEMENTNOTFOUND:
  458. case E_NOTIMPL:
  459. break;
  460. default:
  461. _ASSERTE(FALSE && "Unexpected error code from GetIDsOfNames.");
  462. break;
  463. }
  464. #endif
  465. RETURN(DISP_E_MEMBERNOTFOUND);
  466. }
  467. va_start(val, vt);
  468. hr = PutDispatchProperty(pDisp, dispid, vt, val);
  469. va_end(val);
  470. RETURN(hr);
  471. }