DualEventCall.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #ifndef __DualEventCall_h__
  2. #define __DualEventCall_h__
  3. /////////////////////////////////////////////////////////////////////////////
  4. // DualEventsCall.h | Declaration of the classes used in the for_each
  5. // statements of the connection point sinks.
  6. #ifndef _INC_STDARG
  7. #include <stdarg.h>
  8. #endif // !_INC_STDARG
  9. #ifndef __EventCall_h__
  10. #include "EventCall.h"
  11. #endif // !__EventCall_h__
  12. /////////////////////////////////////////////////////////////////////////////
  13. // TCComDualEventCall is used internally by the TCComDualEventCP_Fn macros as
  14. // a base class for a function object that maintains the set of arguments
  15. // passed to an IDispatch-based connection point sink.
  16. //
  17. // The function call operator() of this class will be called for each
  18. // *IDispatch* connection point sink maintained by a connection point
  19. // derived from TCComDualEventCP.
  20. //
  21. // Since this class is used internally by the TCComDualEventCP_Fn macros, it
  22. // is unlikely that you will ever need to use it directly.
  23. //
  24. // Parameters:
  25. // If_vtbl - Specifies the interface name of the v-table connection point
  26. // sink which is also implemented by the IDispatch-based connection point
  27. // sink.
  28. //
  29. // See Also: TCComDualEventCP_Fn macros, TCComDualEventsCP, TCComEventCall,
  30. // TCComEventsCP
  31. template <class If_vtbl>
  32. class ATL_NO_VTABLE TCComDualEventCall : public TCComEventCall<If_vtbl>
  33. {
  34. // Construction / Destruction
  35. public:
  36. TCComDualEventCall();
  37. virtual ~TCComDualEventCall();
  38. // Disallow copy constructor
  39. private:
  40. TCComDualEventCall(const TCComDualEventCall&);
  41. // Operators
  42. public:
  43. HRESULT operator()(IDispatch* pdisp);
  44. // Overrides
  45. protected:
  46. virtual void OnCreateDispParams() = 0;
  47. // Implementation
  48. protected:
  49. void SetDispParams(DISPID dispid, UINT cArgs, ...);
  50. void SetDispParamsV(DISPID dispid, UINT cArgs, va_list argptr);
  51. // Group=Data Members
  52. protected:
  53. // A *DISPPARAMS* structure used in subsequent calls to
  54. // *IDispatch::Invoke*.
  55. //
  56. // See Also: TCComDualEventCall::operator()
  57. DISPPARAMS m_DispParams;
  58. // A dispatch ID used in subsequent calls to *IDispatch::Invoke*.
  59. //
  60. // See Also: TCComDualEventCall::operator()
  61. DISPID m_dispid;
  62. };
  63. /////////////////////////////////////////////////////////////////////////////
  64. // Group=Construction / Destruction
  65. /////////////////////////////////////////////////////////////////////////////
  66. // Initializes the instance by setting m_dispid to *DISPID_UNKNOWN* and
  67. // clearing m_DispParams to zeroes.
  68. template <class If_vtbl>
  69. inline TCComDualEventCall<If_vtbl>::TCComDualEventCall() :
  70. m_dispid(DISPID_UNKNOWN)
  71. {
  72. // Initialize the DISPPARAMS structure
  73. ZeroMemory(&m_DispParams, sizeof(m_DispParams));
  74. }
  75. /////////////////////////////////////////////////////////////////////////////
  76. // Deletes the dispatch arguments structure, if one was created.
  77. //
  78. // See Also: TCComDualEventCall::SetDispParams
  79. template <class If_vtbl>
  80. TCComDualEventCall<If_vtbl>::~TCComDualEventCall()
  81. {
  82. if (NULL != m_DispParams.rgvarg)
  83. delete [] m_DispParams.rgvarg;
  84. }
  85. /////////////////////////////////////////////////////////////////////////////
  86. // Group=Operators
  87. /////////////////////////////////////////////////////////////////////////////
  88. // Description: Function call operator.
  89. //
  90. // This function call operator calls *Invoke* on the specified
  91. // *IDispatch* pointer, specifying m_dispid as the dispatch ID, and passing
  92. // the arguments specified in a prior call to SetDispParams. If the arguments
  93. // have not been specified yet, the virtual OnCreateDispParams override is
  94. // called to specify the arguments.
  95. //
  96. // The current *IErrorInfo* for the thread is saved/restored before/after the
  97. // *Invoke* method call so that it stays intact.
  98. //
  99. // Parameters:
  100. // pdisp - The *IDispatch* pointer on which to call *Invoke*.
  101. //
  102. // Return Value: The HRESULT of the *IDispatch::Invoke* call is returned.
  103. //
  104. // See Also: TCComDualEventCall::SetDispParams,
  105. // TCComDualEventCall::OnCreateDispParams
  106. template <class If_vtbl>
  107. HRESULT TCComDualEventCall<If_vtbl>::operator()(IDispatch* pdisp)
  108. {
  109. HRESULT hr = S_OK;
  110. if (NULL != pdisp)
  111. {
  112. // Format the class::function name
  113. char szFn[_MAX_PATH] = "";
  114. #ifdef _DEBUG
  115. sprintf(szFn, "TCComDualEventCall<%hs>::operator()",
  116. TCTypeName(If_vtbl));
  117. #endif
  118. __try
  119. {
  120. // Create the arguments array the first time only
  121. if (NULL == m_DispParams.rgvarg)
  122. OnCreateDispParams();
  123. // Reset the IErrorInfo* for this thread and invoke the event method
  124. _VERIFYE(SUCCEEDED(::SetErrorInfo(0, m_pei)));
  125. hr = pdisp->Invoke(m_dispid, IID_NULL, LOCALE_USER_DEFAULT,
  126. DISPATCH_METHOD, &m_DispParams, NULL, NULL, NULL);
  127. #ifdef _DEBUG
  128. char szMsg[_MAX_PATH];
  129. sprintf(szMsg, "Invoke for event call %hs", GetEventName());
  130. if (SUCCEEDED(hr))
  131. {
  132. //_TRACE2("%hs: %hs succeeded\n", szFn, szMsg);
  133. }
  134. else
  135. {
  136. strcat(szMsg, " returned");
  137. TCReportHR(szFn, szMsg, hr);
  138. }
  139. #endif _DEBUG
  140. }
  141. __except(1)
  142. {
  143. _TRACE1("%hs: Caught an unknown exception\n", szFn);
  144. return E_UNEXPECTED;
  145. }
  146. }
  147. // Return the last HRESULT
  148. return hr;
  149. }
  150. /////////////////////////////////////////////////////////////////////////////
  151. // Group=Overrides
  152. #ifdef _DOCJET_ONLY
  153. ///////////////////////////////////////////////////////////////////////////
  154. // Description: Pure-virtual override that creates the dispatch parameters.
  155. //
  156. // Overridden in derived classes to call SetDispParams. This is called only
  157. // once by the function call operator(), just prior to the first time that
  158. // the operator calls *IDispatch::Invoke*.
  159. //
  160. // See Also: TCComDualEventCall::SetDispParams,
  161. // TCComDualEventCall::SetDispParamsV, TCComDualEventCall::operator()
  162. template <class If_vtbl>
  163. virtual void TCComDualEventCall<If_vtbl>::OnCreateDispParams() = 0;
  164. #endif // _DOCJET_ONLY
  165. /////////////////////////////////////////////////////////////////////////////
  166. // Group=Implementation
  167. /////////////////////////////////////////////////////////////////////////////
  168. // Description: Sets the dispatch ID and dispatch parameters for subsequent
  169. // *Invoke* calls.
  170. //
  171. // Sets the dispatch ID and dispatch parameters for subsequent
  172. // *Invoke* calls. This method simply accesses the variable argument list and
  173. // passes it to SetDispParamsV. Please see that method for more information.
  174. //
  175. // Parameters:
  176. // dispid - The dispatch ID used in subsequent *Invoke* calls.
  177. // cArgs - The number of dispatch arguments specified in the variable
  178. // argument list.
  179. //
  180. // See Also: TCComDualEventCall::SetDispParamsV,
  181. // TCComDualEventCall::operator(), TCComDualEventCall::OnCreateDispParams
  182. template <class If_vtbl>
  183. void TCComDualEventCall<If_vtbl>::SetDispParams(DISPID dispid, UINT cArgs,
  184. ...)
  185. {
  186. va_list argptr;
  187. va_start(argptr, cArgs);
  188. SetDispParamsV(dispid, cArgs, argptr);
  189. va_end(argptr);
  190. }
  191. /////////////////////////////////////////////////////////////////////////////
  192. // Description: Sets the dispatch ID and dispatch parameters for subsequent
  193. // *Invoke* calls.
  194. //
  195. // This method saves the specified /dispid/ and creates an array of
  196. // *VARIANTARG* structures suitable for use with the
  197. // *IDispatch::Invoke* method. This method is to be called by the
  198. // derived-class implementation of the virtual OnCreateDispParams override.
  199. //
  200. // For each pair of arguments in the specified variable argument list,
  201. // /argptr/, a *VARIANTARG* is created and initialized. The *VARIANTARG* is
  202. // then assigned the variant type and variant value specified in the argument
  203. // pair. So, for example, the following would set three dispatch parameters,
  204. // of types *VT_BOOL*, *VT_I4*, and *VT_BSTR* to *VARIANT_TRUE*, 137, and
  205. // "Hello", respectively:
  206. //
  207. // CComBSTR bstrText("Hello");
  208. // pCall->SetDispParams(DISPID_HELLO, 3, VT_BOOL, VARIANT_TRUE,
  209. // VT_I4, 137, VT_BSTR, bstrText);
  210. //
  211. // Note: Notice that although 3 is specified as the /cArgs/ parameter, the
  212. // variable argument list contains six actual parameters. This is because for
  213. // each argument specified in /cArgs/, an argument /pair/ is implied, since
  214. // each dispatch argument has a variant type and value.
  215. //
  216. // Parameters:
  217. // dispid - The dispatch ID used in subsequent *Invoke* calls.
  218. // cArgs - The number of dispatch arguments specified in the variable
  219. // argument list.
  220. // argptr - The standardized representation of a variable argument list.
  221. //
  222. // See Also: TCComDualEventCall::SetDispParams,
  223. // TCComDualEventCall::operator(), TCComDualEventCall::OnCreateDispParams
  224. template <class If_vtbl>
  225. void TCComDualEventCall<If_vtbl>::SetDispParamsV(DISPID dispid, UINT cArgs,
  226. va_list argptr)
  227. {
  228. // This function should only be called, at most, once per instance
  229. assert(NULL == m_DispParams.rgvarg);
  230. // Save the specified dispatch id
  231. m_dispid = dispid;
  232. // Return immediately if 0 arguments specified
  233. if (!cArgs)
  234. return;
  235. // Create the VARIANTARG array with the specified number of arguments
  236. m_DispParams.rgvarg = new VARIANTARG[m_DispParams.cArgs = cArgs];
  237. // Loop thru each argument and initialize the VARIANTARG array element
  238. while (cArgs--)
  239. {
  240. VariantInit(&m_DispParams.rgvarg[cArgs]);
  241. VARTYPE vt = va_arg(argptr, VARTYPE);
  242. switch (V_VT(&m_DispParams.rgvarg[cArgs]) = vt)
  243. {
  244. case VT_BOOL:
  245. V_BOOL(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, VARIANT_BOOL);
  246. break;
  247. case VT_I1:
  248. V_I1(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, CHAR);
  249. break;
  250. case VT_I2:
  251. V_I2(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, SHORT);
  252. break;
  253. case VT_I4:
  254. V_I4(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, LONG);
  255. break;
  256. case VT_UI1:
  257. V_UI1(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, BYTE);
  258. break;
  259. case VT_UI2:
  260. V_UI2(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, USHORT);
  261. break;
  262. case VT_ERROR:
  263. V_ERROR(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, SCODE);
  264. break;
  265. case VT_R4:
  266. V_R4(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, FLOAT);
  267. break;
  268. case VT_R8:
  269. V_R8(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, DOUBLE);
  270. break;
  271. case VT_DECIMAL:
  272. V_DECIMAL(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, DECIMAL);
  273. break;
  274. case VT_CY:
  275. V_CY(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, CY);
  276. break;
  277. case VT_DATE:
  278. V_DATE(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, DATE);
  279. break;
  280. case VT_BSTR:
  281. V_BSTR(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, BSTR);
  282. break;
  283. case VT_UNKNOWN:
  284. V_UNKNOWN(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, IUnknown*);
  285. break;
  286. case VT_DISPATCH:
  287. V_DISPATCH(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, IDispatch*);
  288. break;
  289. case VT_VARIANT:
  290. V_VARIANTREF(&m_DispParams.rgvarg[cArgs]) = va_arg(argptr, VARIANT*);
  291. break;
  292. default:
  293. _TRACE_BEGIN
  294. _TRACE_PART0("TCComDualEventCall<If_vtbl>::SetDispParamsV(): ");
  295. _TRACE_PART2("Specified VARTYPE %hu (0x%04X) is unsupported\n", vt, vt);
  296. _TRACE_END
  297. _ASSERT(false);
  298. }
  299. }
  300. }
  301. /////////////////////////////////////////////////////////////////////////////
  302. #endif // !__DualEventCall_h__