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.

555 lines
13 KiB

  1. #include <comdef.h>
  2. #pragma hdrstop
  3. #include <stdarg.h>
  4. #include <malloc.h>
  5. #pragma intrinsic(memset)
  6. #pragma warning(disable:4290)
  7. /////////////////////////////////////////////////////////////////////////////
  8. void __stdcall
  9. _com_issue_error(HRESULT hr) throw(_com_error)
  10. {
  11. _com_raise_error(hr, NULL);
  12. }
  13. void __stdcall
  14. _com_issue_errorex(HRESULT hr, IUnknown* punk, REFIID riid) throw(_com_error)
  15. {
  16. IErrorInfo* perrinfo = NULL;
  17. if (punk == NULL) {
  18. goto exeunt;
  19. }
  20. ISupportErrorInfo* psei;
  21. if (FAILED(punk->QueryInterface(__uuidof(ISupportErrorInfo),
  22. (void**)&psei))) {
  23. goto exeunt;
  24. }
  25. HRESULT hrSupportsErrorInfo;
  26. hrSupportsErrorInfo = psei->InterfaceSupportsErrorInfo(riid);
  27. psei->Release();
  28. if (hrSupportsErrorInfo != S_OK) {
  29. goto exeunt;
  30. }
  31. if (GetErrorInfo(0, &perrinfo) != S_OK) {
  32. perrinfo = NULL;
  33. }
  34. exeunt:
  35. _com_raise_error(hr, perrinfo);
  36. }
  37. /////////////////////////////////////////////////////////////////////////////
  38. #define VT_OPTIONAL 0x0800
  39. struct FLOAT_ARG { BYTE floatBits[sizeof(float)]; };
  40. struct DOUBLE_ARG { BYTE doubleBits[sizeof(double)]; };
  41. /////////////////////////////////////////////////////////////////////////////
  42. static HRESULT
  43. _com_invoke_helper(IDispatch* pDispatch,
  44. DISPID dwDispID,
  45. WORD wFlags,
  46. VARTYPE vtRet,
  47. void* pvRet,
  48. const wchar_t* pwParamInfo,
  49. va_list argList,
  50. IErrorInfo** pperrinfo) throw()
  51. {
  52. *pperrinfo = NULL;
  53. if (pDispatch == NULL) {
  54. return E_POINTER;
  55. }
  56. DISPPARAMS dispparams;
  57. VARIANT* rgvarg;
  58. rgvarg = NULL;
  59. memset(&dispparams, 0, sizeof dispparams);
  60. // determine number of arguments
  61. if (pwParamInfo != NULL) {
  62. dispparams.cArgs = lstrlenW(pwParamInfo);
  63. }
  64. DISPID dispidNamed;
  65. dispidNamed = DISPID_PROPERTYPUT;
  66. if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) {
  67. if (dispparams.cArgs <= 0) {
  68. return E_INVALIDARG;
  69. }
  70. dispparams.cNamedArgs = 1;
  71. dispparams.rgdispidNamedArgs = &dispidNamed;
  72. }
  73. if (dispparams.cArgs != 0) {
  74. // allocate memory for all VARIANT parameters
  75. rgvarg = (VARIANT*)_alloca(dispparams.cArgs * sizeof(VARIANT));
  76. memset(rgvarg, 0, sizeof(VARIANT) * dispparams.cArgs);
  77. dispparams.rgvarg = rgvarg;
  78. // get ready to walk vararg list
  79. const wchar_t* pw = pwParamInfo;
  80. VARIANT* pArg;
  81. pArg = rgvarg + dispparams.cArgs - 1; // params go in opposite order
  82. while (*pw != 0) {
  83. pArg->vt = *pw & ~VT_OPTIONAL; // set the variant type
  84. switch (pArg->vt) {
  85. case VT_I2:
  86. #ifdef _MAC
  87. pArg->iVal = (short)va_arg(argList, int);
  88. #else
  89. pArg->iVal = va_arg(argList, short);
  90. #endif
  91. break;
  92. case VT_I4:
  93. pArg->lVal = va_arg(argList, long);
  94. break;
  95. case VT_R4:
  96. // Note: All float arguments to vararg functions are passed
  97. // as doubles instead. That's why they are passed as VT_R8
  98. // instead of VT_R4.
  99. pArg->vt = VT_R8;
  100. *(DOUBLE_ARG*)&pArg->dblVal = va_arg(argList, DOUBLE_ARG);
  101. break;
  102. case VT_R8:
  103. *(DOUBLE_ARG*)&pArg->dblVal = va_arg(argList, DOUBLE_ARG);
  104. break;
  105. case VT_DATE:
  106. *(DOUBLE_ARG*)&pArg->date = va_arg(argList, DOUBLE_ARG);
  107. break;
  108. case VT_CY:
  109. pArg->cyVal = *va_arg(argList, CY*);
  110. break;
  111. case VT_BSTR:
  112. pArg->bstrVal = va_arg(argList, BSTR);
  113. break;
  114. case VT_DISPATCH:
  115. pArg->pdispVal = va_arg(argList, LPDISPATCH);
  116. break;
  117. case VT_ERROR:
  118. pArg->scode = va_arg(argList, SCODE);
  119. break;
  120. case VT_BOOL:
  121. #ifdef _MAC
  122. V_BOOL(pArg) = (VARIANT_BOOL)va_arg(argList, int)
  123. ? VARIANT_TRUE : VARIANT_FALSE;
  124. #else
  125. V_BOOL(pArg) = va_arg(argList, VARIANT_BOOL)
  126. ? VARIANT_TRUE : VARIANT_FALSE;
  127. #endif
  128. break;
  129. case VT_VARIANT:
  130. *pArg = *va_arg(argList, VARIANT*);
  131. break;
  132. case VT_UNKNOWN:
  133. pArg->punkVal = va_arg(argList, LPUNKNOWN);
  134. break;
  135. case VT_DECIMAL:
  136. pArg->decVal = *va_arg(argList, DECIMAL*);
  137. pArg->vt = VT_DECIMAL;
  138. break;
  139. case VT_UI1:
  140. #ifdef _MAC
  141. pArg->bVal = (BYTE)va_arg(argList, int);
  142. #else
  143. pArg->bVal = va_arg(argList, BYTE);
  144. #endif
  145. break;
  146. case VT_I2|VT_BYREF:
  147. pArg->piVal = va_arg(argList, short*);
  148. break;
  149. case VT_I4|VT_BYREF:
  150. pArg->plVal = va_arg(argList, long*);
  151. break;
  152. case VT_R4|VT_BYREF:
  153. pArg->pfltVal = va_arg(argList, float*);
  154. break;
  155. case VT_R8|VT_BYREF:
  156. pArg->pdblVal = va_arg(argList, double*);
  157. break;
  158. case VT_DATE|VT_BYREF:
  159. pArg->pdate = va_arg(argList, DATE*);
  160. break;
  161. case VT_CY|VT_BYREF:
  162. pArg->pcyVal = va_arg(argList, CY*);
  163. break;
  164. case VT_BSTR|VT_BYREF:
  165. pArg->pbstrVal = va_arg(argList, BSTR*);
  166. break;
  167. case VT_DISPATCH|VT_BYREF:
  168. pArg->ppdispVal = va_arg(argList, LPDISPATCH*);
  169. break;
  170. case VT_ERROR|VT_BYREF:
  171. pArg->pscode = va_arg(argList, SCODE*);
  172. break;
  173. case VT_BOOL|VT_BYREF:
  174. pArg->pboolVal = va_arg(argList, VARIANT_BOOL*);
  175. break;
  176. case VT_VARIANT|VT_BYREF:
  177. pArg->pvarVal = va_arg(argList, VARIANT*);
  178. break;
  179. case VT_UNKNOWN|VT_BYREF:
  180. pArg->ppunkVal = va_arg(argList, LPUNKNOWN*);
  181. break;
  182. case VT_DECIMAL|VT_BYREF:
  183. pArg->pdecVal = va_arg(argList, DECIMAL*);
  184. break;
  185. case VT_UI1|VT_BYREF:
  186. pArg->pbVal = va_arg(argList, BYTE*);
  187. break;
  188. default:
  189. // M00REVIEW - For safearrays, should be able to type-check
  190. // against the base VT_* type.(?)
  191. if (pArg->vt & VT_ARRAY) {
  192. if (pArg->vt & VT_BYREF) {
  193. pArg->pparray = va_arg(argList, LPSAFEARRAY*);
  194. } else {
  195. pArg->parray = va_arg(argList, LPSAFEARRAY);
  196. }
  197. break;
  198. }
  199. // unknown type!
  200. return E_INVALIDARG;
  201. }
  202. --pArg; // get ready to fill next argument
  203. ++pw;
  204. }
  205. // Check for missing optional unnamed args at the end of the arglist,
  206. // and remove them from the DISPPARAMS. This permits calling servers
  207. // which modify their action depending on the actual number of args.
  208. // E.g. Excel95 Application.Workbooks returns a Workbooks* if called
  209. // with no args, a Workbook* if called with one arg - this shouldn't
  210. // be necessary, but Excel95 doesn't appear to check for missing
  211. // args indicated by VT_ERROR/DISP_E_PARAMNOTFOUND.
  212. pArg = rgvarg + dispparams.cNamedArgs;
  213. pw = pwParamInfo + dispparams.cArgs - dispparams.cNamedArgs - 1;
  214. unsigned int cMissingArgs = 0;
  215. // Count the number of missing arguments
  216. while (pw >= pwParamInfo) {
  217. // Optional args must be VARIANT or VARIANT*
  218. if ((*pw & ~VT_BYREF) != (VT_VARIANT|VT_OPTIONAL)) {
  219. break;
  220. }
  221. VARIANT* pVar;
  222. pVar = (*pw & VT_BYREF) ? pArg->pvarVal : pArg;
  223. if (V_VT(pVar) != VT_ERROR ||
  224. V_ERROR(pVar) != DISP_E_PARAMNOTFOUND)
  225. {
  226. break;
  227. }
  228. ++cMissingArgs;
  229. ++pArg;
  230. --pw;
  231. }
  232. // Move the named args up next to the remaining unnamed args and
  233. // adjust the DISPPARAMS struct.
  234. if (cMissingArgs > 0) {
  235. for (unsigned int c = 0; c < dispparams.cNamedArgs; ++c) {
  236. rgvarg[c + cMissingArgs] = rgvarg[c];
  237. }
  238. dispparams.cArgs -= cMissingArgs;
  239. dispparams.rgvarg += cMissingArgs;
  240. }
  241. }
  242. // initialize return value
  243. VARIANT* pvarResult;
  244. VARIANT vaResult;
  245. VariantInit(&vaResult);
  246. pvarResult = (vtRet != VT_EMPTY) ? &vaResult : NULL;
  247. // initialize EXCEPINFO struct
  248. EXCEPINFO excepInfo;
  249. memset(&excepInfo, 0, sizeof excepInfo);
  250. UINT nArgErr;
  251. nArgErr = (UINT)-1; // initialize to invalid arg
  252. // make the call
  253. HRESULT hr = pDispatch->Invoke(dwDispID, __uuidof(NULL), 0, wFlags,
  254. &dispparams, pvarResult, &excepInfo,
  255. &nArgErr);
  256. // throw exception on failure
  257. if (FAILED(hr)) {
  258. VariantClear(&vaResult);
  259. if (hr != DISP_E_EXCEPTION) {
  260. // non-exception error code
  261. // M00REVIEW - Is this all? What about looking for IErrorInfo?
  262. // - Only if IID is passed in, I'd think
  263. return hr;
  264. }
  265. // make sure excepInfo is filled in
  266. if (excepInfo.pfnDeferredFillIn != NULL) {
  267. excepInfo.pfnDeferredFillIn(&excepInfo);
  268. }
  269. // allocate new error info, and fill it
  270. ICreateErrorInfo *pcerrinfo = NULL;
  271. if (SUCCEEDED(CreateErrorInfo(&pcerrinfo))) {
  272. // Set up ErrInfo object
  273. // M00REVIEW - Use IID if decide to pass that in
  274. pcerrinfo->SetGUID(__uuidof(IDispatch));
  275. pcerrinfo->SetDescription(excepInfo.bstrDescription);
  276. pcerrinfo->SetHelpContext(excepInfo.dwHelpContext);
  277. pcerrinfo->SetHelpFile(excepInfo.bstrHelpFile);
  278. pcerrinfo->SetSource(excepInfo.bstrSource);
  279. if (FAILED(pcerrinfo->QueryInterface(__uuidof(IErrorInfo),
  280. (void**)pperrinfo))) {
  281. *pperrinfo = NULL;
  282. }
  283. }
  284. if (excepInfo.wCode != 0) {
  285. hr = _com_error::WCodeToHRESULT(excepInfo.wCode);
  286. } else {
  287. hr = excepInfo.scode;
  288. }
  289. return hr;
  290. }
  291. if (vtRet != VT_EMPTY) {
  292. // convert return value unless already correct
  293. if (vtRet != VT_VARIANT && vtRet != vaResult.vt) {
  294. hr = VariantChangeType(&vaResult, &vaResult, 0, vtRet);
  295. if (FAILED(hr)) {
  296. VariantClear(&vaResult);
  297. return hr;
  298. }
  299. }
  300. // copy return value into return spot!
  301. switch (vtRet) {
  302. case VT_I2:
  303. *(short*)pvRet = vaResult.iVal;
  304. break;
  305. case VT_I4:
  306. *(long*)pvRet = vaResult.lVal;
  307. break;
  308. case VT_R4:
  309. *(FLOAT_ARG*)pvRet = *(FLOAT_ARG*)&vaResult.fltVal;
  310. break;
  311. case VT_R8:
  312. *(DOUBLE_ARG*)pvRet = *(DOUBLE_ARG*)&vaResult.dblVal;
  313. break;
  314. case VT_DATE:
  315. *(DOUBLE_ARG*)pvRet = *(DOUBLE_ARG*)&vaResult.date;
  316. break;
  317. case VT_CY:
  318. *(CY*)pvRet = vaResult.cyVal;
  319. break;
  320. case VT_BSTR:
  321. *(BSTR*)pvRet = vaResult.bstrVal;
  322. break;
  323. case VT_DISPATCH:
  324. *(LPDISPATCH*)pvRet = vaResult.pdispVal;
  325. break;
  326. case VT_ERROR:
  327. *(SCODE*)pvRet = vaResult.scode;
  328. break;
  329. case VT_BOOL:
  330. *(VARIANT_BOOL*)pvRet = V_BOOL(&vaResult);
  331. break;
  332. case VT_VARIANT:
  333. *(VARIANT*)pvRet = vaResult;
  334. break;
  335. case VT_UNKNOWN:
  336. *(LPUNKNOWN*)pvRet = vaResult.punkVal;
  337. break;
  338. case VT_DECIMAL:
  339. *(DECIMAL*)pvRet = vaResult.decVal;
  340. break;
  341. case VT_UI1:
  342. *(BYTE*)pvRet = vaResult.bVal;
  343. break;
  344. default:
  345. if ((vtRet & (VT_ARRAY|VT_BYREF)) == VT_ARRAY) {
  346. // M00REVIEW - type-check against the base VT_* type?
  347. *(LPSAFEARRAY*)pvRet = vaResult.parray;
  348. break;
  349. }
  350. // invalid return type!
  351. VariantClear(&vaResult);
  352. return E_INVALIDARG;
  353. }
  354. }
  355. return hr;
  356. }
  357. /////////////////////////////////////////////////////////////////////////////
  358. HRESULT __cdecl
  359. _com_dispatch_raw_method(IDispatch* pDispatch,
  360. DISPID dwDispID,
  361. WORD wFlags,
  362. VARTYPE vtRet,
  363. void* pvRet,
  364. const wchar_t* pwParamInfo,
  365. ...) throw()
  366. {
  367. va_list argList;
  368. va_start(argList, pwParamInfo);
  369. IErrorInfo* perrinfo;
  370. HRESULT hr = _com_invoke_helper(pDispatch,
  371. dwDispID,
  372. wFlags,
  373. vtRet,
  374. pvRet,
  375. pwParamInfo,
  376. argList,
  377. &perrinfo);
  378. if (FAILED(hr)) {
  379. SetErrorInfo(0, perrinfo);
  380. }
  381. va_end(argList);
  382. return hr;
  383. }
  384. HRESULT __cdecl
  385. _com_dispatch_method(IDispatch* pDispatch,
  386. DISPID dwDispID,
  387. WORD wFlags,
  388. VARTYPE vtRet,
  389. void* pvRet,
  390. const wchar_t* pwParamInfo,
  391. ...) throw(_com_error)
  392. {
  393. va_list argList;
  394. va_start(argList, pwParamInfo);
  395. IErrorInfo* perrinfo;
  396. HRESULT hr = _com_invoke_helper(pDispatch,
  397. dwDispID,
  398. wFlags,
  399. vtRet,
  400. pvRet,
  401. pwParamInfo,
  402. argList,
  403. &perrinfo);
  404. if (FAILED(hr)) {
  405. _com_raise_error(hr, perrinfo);
  406. }
  407. va_end(argList);
  408. return hr;
  409. }
  410. HRESULT __stdcall
  411. _com_dispatch_raw_propget(IDispatch* pDispatch,
  412. DISPID dwDispID,
  413. VARTYPE vtProp,
  414. void* pvProp) throw()
  415. {
  416. return _com_dispatch_raw_method(pDispatch,
  417. dwDispID,
  418. DISPATCH_PROPERTYGET,
  419. vtProp,
  420. pvProp,
  421. NULL);
  422. }
  423. HRESULT __stdcall
  424. _com_dispatch_propget(IDispatch* pDispatch,
  425. DISPID dwDispID,
  426. VARTYPE vtProp,
  427. void* pvProp) throw(_com_error)
  428. {
  429. return _com_dispatch_method(pDispatch,
  430. dwDispID,
  431. DISPATCH_PROPERTYGET,
  432. vtProp,
  433. pvProp,
  434. NULL);
  435. }
  436. HRESULT __cdecl
  437. _com_dispatch_raw_propput(IDispatch* pDispatch,
  438. DISPID dwDispID,
  439. VARTYPE vtProp,
  440. ...) throw()
  441. {
  442. va_list argList;
  443. va_start(argList, vtProp);
  444. #ifdef _MAC
  445. argList -= 2;
  446. #endif
  447. wchar_t rgwParams[2];
  448. rgwParams[0] = vtProp;
  449. rgwParams[1] = 0;
  450. WORD wFlags = (vtProp == VT_DISPATCH || vtProp == VT_UNKNOWN)
  451. ? DISPATCH_PROPERTYPUTREF : DISPATCH_PROPERTYPUT;
  452. IErrorInfo* perrinfo;
  453. HRESULT hr = _com_invoke_helper(pDispatch,
  454. dwDispID,
  455. wFlags,
  456. VT_EMPTY,
  457. NULL,
  458. rgwParams,
  459. argList,
  460. &perrinfo);
  461. if (FAILED(hr)) {
  462. SetErrorInfo(0, perrinfo);
  463. }
  464. va_end(argList);
  465. return hr;
  466. }
  467. HRESULT __cdecl
  468. _com_dispatch_propput(IDispatch* pDispatch,
  469. DISPID dwDispID,
  470. VARTYPE vtProp,
  471. ...) throw(_com_error)
  472. {
  473. va_list argList;
  474. va_start(argList, vtProp);
  475. #ifdef _MAC
  476. argList -= 2;
  477. #endif
  478. wchar_t rgwParams[2];
  479. rgwParams[0] = vtProp;
  480. rgwParams[1] = 0;
  481. WORD wFlags = (vtProp == VT_DISPATCH || vtProp == VT_UNKNOWN)
  482. ? DISPATCH_PROPERTYPUTREF : DISPATCH_PROPERTYPUT;
  483. IErrorInfo* perrinfo;
  484. HRESULT hr = _com_invoke_helper(pDispatch,
  485. dwDispID,
  486. wFlags,
  487. VT_EMPTY,
  488. NULL,
  489. rgwParams,
  490. argList,
  491. &perrinfo);
  492. if (FAILED(hr)) {
  493. _com_raise_error(hr, perrinfo);
  494. }
  495. va_end(argList);
  496. return hr;
  497. }