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.

704 lines
26 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: atlstl/automation/multiple_dispatch.hpp
  3. *
  4. * Purpose: A class template that makes the methods and properties exhibited
  5. * through multiple IDispatch interfaces visible to script clients.
  6. *
  7. * Created: 15th May 2006
  8. * Updated: 18th June 2012
  9. *
  10. * Home: http://stlsoft.org/
  11. *
  12. * Copyright (c) 2007-2012, Matthew Wilson and Synesis Software
  13. * All rights reserved.
  14. *
  15. * Redistribution and use in source and binary forms, with or without
  16. * modification, are permitted provided that the following conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright notice, this
  19. * list of conditions and the following disclaimer.
  20. * - Redistributions in binary form must reproduce the above copyright notice,
  21. * this list of conditions and the following disclaimer in the documentation
  22. * and/or other materials provided with the distribution.
  23. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  24. * any contributors may be used to endorse or promote products derived from
  25. * this software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * ////////////////////////////////////////////////////////////////////// */
  40. /** \file atlstl/automation/multiple_dispatch.hpp
  41. * \brief [C++ only; requires ATL library] Definition of the
  42. * atlstl::IDispatchImpl2 and atlstl::IDispatchImpl3
  43. * class templates, which make the methods and properties exhibited through
  44. * multiple IDispatch interfaces visible to scripting clients
  45. * (\ref group__library__com_automation "COM Automation" Library).
  46. */
  47. #ifndef ATLSTL_INCL_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH
  48. #define ATLSTL_INCL_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH_MAJOR 2
  51. # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH_MINOR 1
  52. # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH_REVISION 2
  53. # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH_EDIT 17
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Compatibility
  57. */
  58. /*
  59. [Incompatibilies-start]
  60. [Incompatibilies-end]
  61. */
  62. /* /////////////////////////////////////////////////////////////////////////
  63. * Includes
  64. */
  65. #ifndef ATLSTL_INCL_ATLSTL_HPP_ATLSTL
  66. # include <atlstl/atlstl.hpp>
  67. #endif /* !ATLSTL_INCL_ATLSTL_HPP_ATLSTL */
  68. /* /////////////////////////////////////////////////////////////////////////
  69. * Namespace
  70. */
  71. #ifndef _ATLSTL_NO_NAMESPACE
  72. # if defined(_STLSOFT_NO_NAMESPACE) || \
  73. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  74. /* There is no stlsoft namespace, so must define ::atlstl */
  75. namespace atlstl
  76. {
  77. # else
  78. /* Define stlsoft::atlstl_project */
  79. namespace stlsoft
  80. {
  81. namespace atlstl_project
  82. {
  83. # endif /* _STLSOFT_NO_NAMESPACE */
  84. #endif /* !_ATLSTL_NO_NAMESPACE */
  85. /* /////////////////////////////////////////////////////////////////////////
  86. * Classes
  87. */
  88. /** \brief Class template that enables the methods and properties exhibited
  89. * through two IDispatch interfaces to be visible to scripting clients.
  90. *
  91. * \ingroup group__library__com_automation
  92. *
  93. * The class template is used in place of ATL's IDispatchImpl class in the
  94. * parent class list of a class template that support two dispinterfaces.
  95. * Consider the <a href = "http://openrj.org/">Open-RJ</a> COM mapping's
  96. * Field class [IDL]:
  97. \code
  98. // openrj.com.idl
  99. [ . . . ]
  100. interface IField
  101. : IDispatch
  102. {
  103. [propget, id(1), . . .]
  104. HRESULT Name([out, retval] BSTR* pVal);
  105. [propget, id(2), . . .]
  106. HRESULT Value([out, retval] BSTR* pVal);
  107. };
  108. [ . . . ]
  109. interface IDocumenter
  110. : IDispatch
  111. {
  112. [propget, id(1), . . .]
  113. HRESULT DocString([out, retval] BSTR* pVal);
  114. };
  115. coclass Field
  116. {
  117. [default] interface IField;
  118. interface IDocumenter;
  119. };
  120. \endcode
  121. * As indicated, it supports two dispinterfaces: <b>IField</b> and
  122. * <b>IDocumenter</b>. Note that each interface has a property with dispid
  123. * <b>1</b>.
  124. *
  125. * By default, the ATL class template IDispatchImpl assumes that just a
  126. * single "active" dispinterface. We might envisage the following
  127. * (C++) class definition for <b>Field</b>:
  128. *
  129. \code
  130. class ATL_NO_VTABLE Field
  131. : public CComObjectRootEx<CComSingleThreadModel>
  132. , public CComCoClass<Field, &CLSID_Field>
  133. , public atlstl::SupportErrorInfoImpl<&IID_IField>
  134. , public IDispatchImpl<IField, &IID_IField, &LIBID_OPENRJ_COMLib>
  135. , public IDispatchImpl<IDocumenter, &IID_IDocumenter, &LIBID_OPENRJ_COMLib>
  136. {
  137. . . .
  138. };
  139. \endcode
  140. * Unfortunately, scripting clients, which elicit DISPIDs at runtime via an
  141. * automation server's <code>IDispatch::GetIDsOfNames()</code> method, will
  142. * see only those methods and properties from <b>IField</b> in such a case.
  143. * No parts of the <b>IDocumenter</b> interface will be visible or
  144. * accessible.
  145. *
  146. * This is where IDispatchImpl2 comes in. It implements GetIDsOfNames() and
  147. * Invoke(), operating over both its dispinterfaces to elicit the dispid(s)
  148. * for requested name(s) by querying each interface in turn. It is used with
  149. * the Field class as follows:
  150. *
  151. \code
  152. class ATL_NO_VTABLE Field
  153. : public CComObjectRootEx<CComSingleThreadModel>
  154. , public CComCoClass<Field, &CLSID_Field>
  155. , public atlstl::SupportErrorInfoImpl<&IID_IField>
  156. , public atlstl::IDispatchImpl2<IField, &IID_IField, IDocumenter, &IID_IDocumenter, &LIBID_OPENRJ_COMLib>
  157. {
  158. . . .
  159. };
  160. \endcode
  161. *
  162. * Now all members of all dispinterfaces are visible to scripting clients.
  163. * Note that the class also handles the case where the dispinterfaces have
  164. * members/properties with the same dispids. (See GetIDsOfNames() and
  165. * Invoke() for details of the mechanism.)
  166. */
  167. // [[synesis:class: atlstl::IDispatchImpl2<T<I0>, IID const*, T<I1>, IID const*, GUID const*>]]
  168. template< ss_typename_param_k I0
  169. , IID const* IID0
  170. , ss_typename_param_k I1
  171. , IID const* IID1
  172. , GUID const* LibID
  173. >
  174. class IDispatchImpl2
  175. : public IDispatchImpl<I0, IID0, LibID>
  176. , public IDispatchImpl<I1, IID1, LibID>
  177. {
  178. /// \name Member Types
  179. /// @{
  180. public:
  181. typedef IDispatchImpl<I0, IID0, LibID> dispatch_parent_0_type; //!< \brief The type of the first dispinterface
  182. typedef IDispatchImpl<I1, IID1, LibID> dispatch_parent_1_type; //!< \brief The type of the second dispinterface
  183. /// @}
  184. /// \name IDispatch methods
  185. /// @{
  186. protected:
  187. /** \brief Provides the required behaviour of
  188. * <code>IDispatch::GetIDsOfNames()</code>, by querying the two
  189. * dispinterfaces, in order, to match the name(s).
  190. *
  191. * This method operates by first determining which, if any, of the
  192. * two parent dispinterfaces can resolve the names. If successful, the
  193. * resultant dispatch Ids are then striped with a bit in their
  194. * most-significant byte(s) to record the index of the dispinterface
  195. * which has thus undertaken to interpret them. This stripe is then
  196. * detected
  197. *
  198. * \remarks Names are matched en bloc: they are either all matched by one
  199. * interface, or all by the other. It is <b>never</b> the case that
  200. * some part are matched by one and the remainder by the other.
  201. *
  202. * \note If a dispid returned from a successful call to one of the
  203. * underlying dispinterfaces' <code>GetIDsOfNames()</code> already
  204. * uses the striping bit, it is left alone. Such methods will be
  205. * successfully called in Invoke(), in its post-stripe processing.
  206. */
  207. STDMETHOD(GetIDsOfNames)( REFIID riid
  208. , LPOLESTR* rgszNames
  209. , UINT cNames
  210. , LCID lcid
  211. , DISPID* rgdispid)
  212. {
  213. unsigned index = 1;
  214. HRESULT hr = dispatch_parent_0_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  215. if( FAILED(hr) &&
  216. DISP_E_UNKNOWNNAME == hr)
  217. {
  218. ++index;
  219. hr = dispatch_parent_1_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  220. }
  221. // Encode interface info into the dispid
  222. if(SUCCEEDED(hr))
  223. {
  224. DISPID dispidFlag = DISPID(0x1) << (8 * sizeof(DISPID) - 2);
  225. dispidFlag >>= (index - 1);
  226. for(UINT i = 0; i < cNames; ++i)
  227. {
  228. if(rgdispid[i] < 0)
  229. {
  230. // Leave these alone. They'll be processed on a first-come-first-serve
  231. // basis, which assumes that the GetIDsOfNames() and Invoke() of I0 and
  232. // I1 are faithfully inter-related.
  233. }
  234. else
  235. {
  236. ATLSTL_MESSAGE_ASSERT("Dispatch Id is out of range!", 0 == (dispidFlag & rgdispid[i]));
  237. rgdispid[i] |= dispidFlag;
  238. }
  239. }
  240. }
  241. return hr;
  242. }
  243. /** \brief Provides the required behaviour of
  244. * <code>IDispatch::Invoke()</code>, by invoking this method on the
  245. * requisite dispinterface.
  246. *
  247. * This method operates by detecting the striping bit on the dispid,
  248. * from which the appropriate dispiniterface is determined. The
  249. * stripe is then removed, and the method invoked.
  250. *
  251. * \remarks Names are matched en bloc: they are either all matched by one
  252. * interface, or all by the other. It is <b>never</b> the case that
  253. * some part are matched by one and the remainder by the other.
  254. *
  255. * \note If no striping is apparent, the invocation is conducted on
  256. * each interface in turn.
  257. */
  258. STDMETHOD(Invoke)( DISPID dispidMember
  259. , REFIID riid
  260. , LCID lcid
  261. , WORD wFlags
  262. , DISPPARAMS* pdispparams
  263. , VARIANT* pvarResult
  264. , EXCEPINFO* pexcepinfo
  265. , UINT* puArgErr)
  266. {
  267. if(dispidMember >= 0)
  268. {
  269. DISPID dispidFlag = DISPID(0x1) << (8 * sizeof(DISPID) - 2);
  270. dispidFlag >>= 0;
  271. if(dispidMember & dispidFlag)
  272. {
  273. return dispatch_parent_0_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  274. }
  275. dispidFlag >>= 1;
  276. if(dispidMember & dispidFlag)
  277. {
  278. return dispatch_parent_1_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  279. }
  280. }
  281. HRESULT hr = dispatch_parent_0_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  282. if( FAILED(hr) &&
  283. DISP_E_MEMBERNOTFOUND == hr)
  284. {
  285. hr = dispatch_parent_1_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  286. }
  287. return hr;
  288. }
  289. /// @}
  290. };
  291. /** \brief Class template that enables the methods and properties exhibited
  292. * through three IDispatch interfaces to be visible to scripting clients.
  293. *
  294. * \ingroup group__library__com_automation
  295. *
  296. * IDispatchImpl3 is used (and operates) in exactly the same way as
  297. * IDispatchImpl2, except that it supports three dispinterfaces, rather than
  298. * two.
  299. */
  300. // [[synesis:class: atlstl::IDispatchImpl2<T<I0>, IID const*, T<I1>, IID const*, T<I2>, IID const*, GUID const*>]]
  301. template< ss_typename_param_k I0
  302. , IID const* IID0
  303. , ss_typename_param_k I1
  304. , IID const* IID1
  305. , ss_typename_param_k I2
  306. , IID const* IID2
  307. , GUID const* LibID
  308. >
  309. class IDispatchImpl3
  310. : public IDispatchImpl<I0, IID0, LibID>
  311. , public IDispatchImpl<I1, IID1, LibID>
  312. , public IDispatchImpl<I2, IID2, LibID>
  313. {
  314. /// \name Member Types
  315. /// @{
  316. public:
  317. typedef IDispatchImpl<I0, IID0, LibID> dispatch_parent_0_type; //!< \brief The type of the first dispinterface
  318. typedef IDispatchImpl<I1, IID1, LibID> dispatch_parent_1_type; //!< \brief The type of the second dispinterface
  319. typedef IDispatchImpl<I2, IID2, LibID> dispatch_parent_2_type; //!< \brief The type of the third dispinterface
  320. /// @}
  321. /// \name IDispatch methods
  322. /// @{
  323. protected:
  324. /** \brief Provides the required behaviour of
  325. * <code>IDispatch::GetIDsOfNames()</code>, by querying the three
  326. * dispinterfaces, in order, to match the name(s).
  327. *
  328. * This method operates by first determining which, if any, of the
  329. * three parent dispinterfaces can resolve the names. If successful, the
  330. * resultant dispatch Ids are then striped with a bit in their
  331. * most-significant byte(s) to record the index of the dispinterface
  332. * which has thus undertaken to interpret them. This stripe is then
  333. * detected
  334. *
  335. * \remarks Names are matched en bloc: they are either all matched by one
  336. * interface, or all by the other. It is <b>never</b> the case that
  337. * some part are matched by one and the remainder by the other.
  338. *
  339. * \note If a dispid returned from a successful call to one of the
  340. * underlying dispinterfaces' <code>GetIDsOfNames()</code> already
  341. * uses the striping bit, it is left alone. Such methods will be
  342. * successfully called in Invoke(), in its post-stripe processing.
  343. */
  344. STDMETHOD(GetIDsOfNames)( REFIID riid
  345. , LPOLESTR* rgszNames
  346. , UINT cNames
  347. , LCID lcid
  348. , DISPID* rgdispid)
  349. {
  350. unsigned index = 1;
  351. HRESULT hr = dispatch_parent_0_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  352. if( FAILED(hr) &&
  353. DISP_E_UNKNOWNNAME == hr)
  354. {
  355. ++index;
  356. hr = dispatch_parent_1_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  357. }
  358. if( FAILED(hr) &&
  359. DISP_E_UNKNOWNNAME == hr)
  360. {
  361. ++index;
  362. hr = dispatch_parent_2_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  363. }
  364. // Encode interface info into the dispid
  365. if(SUCCEEDED(hr))
  366. {
  367. DISPID dispidFlag = DISPID(0x1) << (8 * sizeof(DISPID) - 2);
  368. dispidFlag >>= (index - 1);
  369. for(UINT i = 0; i < cNames; ++i)
  370. {
  371. if(rgdispid[i] < 0)
  372. {
  373. // Leave these alone. They'll be processed on a first-come-first-serve
  374. // basis, which assumes that the GetIDsOfNames() and Invoke() of I0 and
  375. // I1 are faithfully inter-related.
  376. }
  377. else
  378. {
  379. ATLSTL_MESSAGE_ASSERT("Dispatch Id is out of range!", 0 == (dispidFlag & rgdispid[i]));
  380. rgdispid[i] |= dispidFlag;
  381. }
  382. }
  383. }
  384. return hr;
  385. }
  386. /** \brief Provides the required behaviour of
  387. * <code>IDispatch::Invoke()</code>, by invoking this method on the
  388. * requisite dispinterface.
  389. *
  390. * This method operates by detecting the striping bit on the dispid,
  391. * from which the appropriate dispiniterface is determined. The
  392. * stripe is then removed, and the method invoked.
  393. *
  394. * \remarks Names are matched en bloc: they are either all matched by one
  395. * interface, or all by the other. It is <b>never</b> the case that
  396. * some part are matched by one and the remainder by the other.
  397. *
  398. * \note If no striping is apparent, the invocation is conducted on
  399. * each interface in turn.
  400. */
  401. STDMETHOD(Invoke)( DISPID dispidMember
  402. , REFIID riid
  403. , LCID lcid
  404. , WORD wFlags
  405. , DISPPARAMS* pdispparams
  406. , VARIANT* pvarResult
  407. , EXCEPINFO* pexcepinfo
  408. , UINT* puArgErr)
  409. {
  410. if(dispidMember >= 0)
  411. {
  412. DISPID dispidFlag = DISPID(0x1) << (8 * sizeof(DISPID) - 2);
  413. dispidFlag >>= 0;
  414. if(dispidMember & dispidFlag)
  415. {
  416. return dispatch_parent_0_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  417. }
  418. dispidFlag >>= 1;
  419. if(dispidMember & dispidFlag)
  420. {
  421. return dispatch_parent_1_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  422. }
  423. dispidFlag >>= 1;
  424. if(dispidMember & dispidFlag)
  425. {
  426. return dispatch_parent_2_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  427. }
  428. }
  429. HRESULT hr = dispatch_parent_0_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  430. if( FAILED(hr) &&
  431. DISP_E_MEMBERNOTFOUND == hr)
  432. {
  433. hr = dispatch_parent_1_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  434. }
  435. if( FAILED(hr) &&
  436. DISP_E_MEMBERNOTFOUND == hr)
  437. {
  438. hr = dispatch_parent_2_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  439. }
  440. return hr;
  441. }
  442. /// @}
  443. };
  444. /** \brief Class template that enables the methods and properties exhibited
  445. * through four IDispatch interfaces to be visible to scripting clients.
  446. *
  447. * \ingroup group__library__com_automation
  448. *
  449. * IDispatchImpl4 is used (and operates) in exactly the same way as
  450. * IDispatchImpl3, except that it supports four dispinterfaces, rather than
  451. * three.
  452. */
  453. // [[synesis:class: atlstl::IDispatchImpl2<T<I0>, IID const*, T<I1>, IID const*, T<I2>, IID const*, T<I3>, IID const*, GUID const*>]]
  454. template< ss_typename_param_k I0
  455. , IID const* IID0
  456. , ss_typename_param_k I1
  457. , IID const* IID1
  458. , ss_typename_param_k I2
  459. , IID const* IID2
  460. , ss_typename_param_k I3
  461. , IID const* IID3
  462. , GUID const* LibID
  463. >
  464. class IDispatchImpl4
  465. : public IDispatchImpl<I0, IID0, LibID>
  466. , public IDispatchImpl<I1, IID1, LibID>
  467. , public IDispatchImpl<I2, IID2, LibID>
  468. , public IDispatchImpl<I3, IID3, LibID>
  469. {
  470. /// \name Member Types
  471. /// @{
  472. public:
  473. typedef IDispatchImpl<I0, IID0, LibID> dispatch_parent_0_type; //!< \brief The type of the first dispinterface
  474. typedef IDispatchImpl<I1, IID1, LibID> dispatch_parent_1_type; //!< \brief The type of the second dispinterface
  475. typedef IDispatchImpl<I2, IID2, LibID> dispatch_parent_2_type; //!< \brief The type of the third dispinterface
  476. typedef IDispatchImpl<I3, IID3, LibID> dispatch_parent_3_type; //!< \brief The type of the fourth dispinterface
  477. /// @}
  478. /// \name IDispatch methods
  479. /// @{
  480. protected:
  481. /** \brief Provides the required behaviour of
  482. * <code>IDispatch::GetIDsOfNames()</code>, by querying the four
  483. * dispinterfaces, in order, to match the name(s).
  484. *
  485. * This method operates by first determining which, if any, of the
  486. * four parent dispinterfaces can resolve the names. If successful, the
  487. * resultant dispatch Ids are then striped with a bit in their
  488. * most-significant byte(s) to record the index of the dispinterface
  489. * which has thus undertaken to interpret them. This stripe is then
  490. * detected
  491. *
  492. * \remarks Names are matched en bloc: they are either all matched by one
  493. * interface, or all by the other. It is <b>never</b> the case that
  494. * some part are matched by one and the remainder by the other.
  495. *
  496. * \note If a dispid returned from a successful call to one of the
  497. * underlying dispinterfaces' <code>GetIDsOfNames()</code> already
  498. * uses the striping bit, it is left alone. Such methods will be
  499. * successfully called in Invoke(), in its post-stripe processing.
  500. */
  501. STDMETHOD(GetIDsOfNames)( REFIID riid
  502. , LPOLESTR* rgszNames
  503. , UINT cNames
  504. , LCID lcid
  505. , DISPID* rgdispid)
  506. {
  507. unsigned index = 1;
  508. HRESULT hr = dispatch_parent_0_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  509. if( FAILED(hr) &&
  510. DISP_E_UNKNOWNNAME == hr)
  511. {
  512. ++index;
  513. hr = dispatch_parent_1_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  514. }
  515. if( FAILED(hr) &&
  516. DISP_E_UNKNOWNNAME == hr)
  517. {
  518. ++index;
  519. hr = dispatch_parent_2_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  520. }
  521. if( FAILED(hr) &&
  522. DISP_E_UNKNOWNNAME == hr)
  523. {
  524. ++index;
  525. hr = dispatch_parent_3_type::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  526. }
  527. // Encode interface info into the dispid
  528. if(SUCCEEDED(hr))
  529. {
  530. DISPID dispidFlag = DISPID(0x1) << (8 * sizeof(DISPID) - 2);
  531. dispidFlag >>= (index - 1);
  532. for(UINT i = 0; i < cNames; ++i)
  533. {
  534. if(rgdispid[i] < 0)
  535. {
  536. // Leave these alone. They'll be processed on a first-come-first-serve
  537. // basis, which assumes that the GetIDsOfNames() and Invoke() of I0 and
  538. // I1 are faithfully inter-related.
  539. }
  540. else
  541. {
  542. ATLSTL_MESSAGE_ASSERT("Dispatch Id is out of range!", 0 == (dispidFlag & rgdispid[i]));
  543. rgdispid[i] |= dispidFlag;
  544. }
  545. }
  546. }
  547. return hr;
  548. }
  549. /** \brief Provides the required behaviour of
  550. * <code>IDispatch::Invoke()</code>, by invoking this method on the
  551. * requisite dispinterface.
  552. *
  553. * This method operates by detecting the striping bit on the dispid,
  554. * from which the appropriate dispiniterface is determined. The
  555. * stripe is then removed, and the method invoked.
  556. *
  557. * \remarks Names are matched en bloc: they are either all matched by one
  558. * interface, or all by the other. It is <b>never</b> the case that
  559. * some part are matched by one and the remainder by the other.
  560. *
  561. * \note If no striping is apparent, the invocation is conducted on
  562. * each interface in turn.
  563. */
  564. STDMETHOD(Invoke)( DISPID dispidMember
  565. , REFIID riid
  566. , LCID lcid
  567. , WORD wFlags
  568. , DISPPARAMS* pdispparams
  569. , VARIANT* pvarResult
  570. , EXCEPINFO* pexcepinfo
  571. , UINT* puArgErr)
  572. {
  573. if(dispidMember >= 0)
  574. {
  575. DISPID dispidFlag = DISPID(0x1) << (8 * sizeof(DISPID) - 2);
  576. dispidFlag >>= 0;
  577. if(dispidMember & dispidFlag)
  578. {
  579. return dispatch_parent_0_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  580. }
  581. dispidFlag >>= 1;
  582. if(dispidMember & dispidFlag)
  583. {
  584. return dispatch_parent_1_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  585. }
  586. dispidFlag >>= 1;
  587. if(dispidMember & dispidFlag)
  588. {
  589. return dispatch_parent_2_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  590. }
  591. dispidFlag >>= 1;
  592. if(dispidMember & dispidFlag)
  593. {
  594. return dispatch_parent_3_type::Invoke(dispidMember & ~dispidFlag, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  595. }
  596. }
  597. HRESULT hr = dispatch_parent_0_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  598. if( FAILED(hr) &&
  599. DISP_E_MEMBERNOTFOUND == hr)
  600. {
  601. hr = dispatch_parent_1_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  602. }
  603. if( FAILED(hr) &&
  604. DISP_E_MEMBERNOTFOUND == hr)
  605. {
  606. hr = dispatch_parent_2_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  607. }
  608. if( FAILED(hr) &&
  609. DISP_E_MEMBERNOTFOUND == hr)
  610. {
  611. hr = dispatch_parent_3_type::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  612. }
  613. return hr;
  614. }
  615. /// @}
  616. };
  617. /* ////////////////////////////////////////////////////////////////////// */
  618. #ifndef _ATLSTL_NO_NAMESPACE
  619. # if defined(_STLSOFT_NO_NAMESPACE) || \
  620. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  621. } // namespace atlstl
  622. # else
  623. } // namespace atlstl_project
  624. } // namespace stlsoft
  625. # endif /* _STLSOFT_NO_NAMESPACE */
  626. #endif /* !_ATLSTL_NO_NAMESPACE */
  627. /* ////////////////////////////////////////////////////////////////////// */
  628. #endif /* !ATLSTL_INCL_ATLSTL_AUTOMATION_HPP_MULTIPLE_DISPATCH */
  629. /* ///////////////////////////// end of file //////////////////////////// */