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.

708 lines
22 KiB

  1. //
  2. // IConnectionPoint/IDispatch helper functions
  3. //
  4. #include "priv.h"
  5. #include <shlobj.h>
  6. //
  7. // IDispatch helper functions
  8. //
  9. // Takes a variable number of parameters for IDispatch, packages
  10. // them up.
  11. //
  12. // pdispparams - The DISPPARAMS structure that receives the result
  13. // of the packaging.
  14. //
  15. // rgvarg - Array of length cArgs.
  16. // It will be used to hold the parameters.
  17. //
  18. // cArgs - Number of pairs of generic arguments.
  19. //
  20. // ap - va_list of parameters to package. We package up the
  21. // first (2 * cArgs) of them. See SHPackDispParams
  22. // for details.
  23. typedef struct FAKEBSTR {
  24. ULONG cb;
  25. WCHAR wsz[1];
  26. } FAKEBSTR;
  27. const FAKEBSTR c_bstrNULL = { 0, L"" };
  28. LWSTDAPI SHPackDispParamsV(DISPPARAMS *pdispparams, VARIANTARG *rgvarg, UINT cArgs, va_list ap)
  29. {
  30. HRESULT hr = S_OK;
  31. ZeroMemory(rgvarg, cArgs * SIZEOF(VARIANTARG));
  32. // fill out DISPPARAMS structure
  33. pdispparams->rgvarg = rgvarg;
  34. pdispparams->rgdispidNamedArgs = NULL;
  35. pdispparams->cArgs = cArgs;
  36. pdispparams->cNamedArgs = 0;
  37. // parameters are ordered in ap with the right-most parameter
  38. // at index zero and the left-most parameter at the highest index; essentially,
  39. // the parameters are pushed from right to left. Put the first argument we
  40. // encounter at the highest index.
  41. // pVarArg points to the argument structure in the array we are currently
  42. // filling in. Initialize this to point at highest argument (zero-based,
  43. // hence the -1). For each passed-in argument we process, *decrement*
  44. // the pVarArg pointer to achieve the "push from right-to-left" effect.
  45. VARIANTARG * pVarArg = &rgvarg[cArgs - 1];
  46. int nCount = cArgs;
  47. while (nCount)
  48. {
  49. VARENUM vaType = va_arg(ap,VARENUM);
  50. // We don't have to call VariantInit because we zerod out
  51. // the entire array before entering this loop
  52. V_VT(pVarArg) = vaType;
  53. // the next field is a union, so we can be smart about filling it in
  54. //
  55. if (vaType & VT_BYREF)
  56. {
  57. // All byrefs can be packed the same way
  58. V_BYREF(pVarArg) = va_arg(ap, LPVOID);
  59. }
  60. else
  61. {
  62. switch (vaType)
  63. {
  64. case VT_BSTR:
  65. {
  66. // parameter is a BSTR
  67. // MFC doesn't like it when you pass NULL for a VT_BSTR type
  68. V_BSTR(pVarArg) = va_arg(ap, BSTR);
  69. if (V_BSTR(pVarArg) == NULL)
  70. V_BSTR(pVarArg) =(BSTR)c_bstrNULL.wsz;
  71. #ifdef DEBUG
  72. // Check if this BSTR is a valid BSTR
  73. FAKEBSTR *bstr = CONTAINING_RECORD(V_BSTR(pVarArg), FAKEBSTR, wsz);
  74. ASSERT(bstr->cb == lstrlenW(bstr->wsz) * SIZEOF(WCHAR));
  75. #endif
  76. break;
  77. }
  78. case VT_BOOL:
  79. V_BOOL(pVarArg) = va_arg(ap, VARIANT_BOOL);
  80. break;
  81. case VT_DISPATCH:
  82. V_DISPATCH(pVarArg) = va_arg(ap, LPDISPATCH);
  83. break;
  84. case VT_UNKNOWN:
  85. V_UNKNOWN(pVarArg) = va_arg(ap, LPUNKNOWN);
  86. break;
  87. default:
  88. AssertMsg(0, TEXT("Packing unknown variant type 0x%x as VT_I4"), vaType);
  89. // if we don't know what it is treat it as VT_I4.
  90. // Hopefully it's not a pointer or a VT_R8 or that sort of
  91. // thing, or we're in trouble.
  92. V_VT(pVarArg) = VT_I4;
  93. case VT_I4:
  94. V_I4(pVarArg) = va_arg(ap, LONG);
  95. break;
  96. }
  97. }
  98. nCount--;
  99. pVarArg--;
  100. }
  101. return hr;
  102. }
  103. //
  104. // Takes a variable number of generic parameters, packages
  105. // them up.
  106. //
  107. // pdispparams - The DISPPARAMS structure that receives the result
  108. // of the packaging.
  109. //
  110. // rgvarg - Array of length cArgs.
  111. // It will be used to hold the parameters.
  112. //
  113. // cArgs - Number of pairs of generic arguments (below).
  114. //
  115. // ... - A collection of (VARNUM, LPVOID) pairs of arguments.
  116. // The first is the type of the argument, and the
  117. // second is the corresponding value.
  118. //
  119. // As a special case, a null VT_BSTR can be passed
  120. // as a NULL pointer and we will turn it into a
  121. // genuine null BSTR.
  122. //
  123. // The following VARENUMs are supported:
  124. //
  125. // VT_BYREF - Anything that is VT_BYREF is okay
  126. // VT_BSTR
  127. // VT_BOOL
  128. // VT_DISPATCH
  129. // VT_UNKNOWN
  130. // VT_I4
  131. //
  132. // Any other type will be packaged randomly, so don't do that.
  133. //
  134. // Example:
  135. //
  136. // DISPPARAMS dispparams;
  137. // VARIANTARG args[4]; // room for 4 parameters
  138. // SHPackDispParams(&dispparams, args, 4, // and here they are
  139. // VT_BSTR, bstrURL,
  140. // VT_I4, dwFlags,
  141. // VT_BSTR, NULL, // no post data
  142. // VT_BSTR, bstrHeaders);
  143. //
  144. LWSTDAPI SHPackDispParams(DISPPARAMS *pdispparams, VARIANTARG *rgvarg, UINT cArgs, ...)
  145. {
  146. va_list ap;
  147. va_start(ap, cArgs);
  148. HRESULT hr = SHPackDispParamsV(pdispparams, rgvarg, cArgs, ap);
  149. va_end(ap);
  150. return hr;
  151. }
  152. //=============================================================================
  153. //
  154. // IConnectionPoint helper functions
  155. //-----------------------------------------------------------------------------
  156. //
  157. // INVOKECALLBACK
  158. //
  159. // Allows clients to customize the the invoke process. The callback
  160. // receives the following parameters:
  161. //
  162. // pdisp - The IDispatch that is about to receive an invoke.
  163. //
  164. // pinv - SHINVOKEPARAMS structure that describes the invoke
  165. // that is about to occur.
  166. //
  167. // The callback function is called before each sink is dispatched.
  168. // The callback can return any of the following values:
  169. //
  170. // S_OK Proceed with the invoke
  171. // S_FALSE Skip this invoke but keep invoking others
  172. // E_FAIL Stop invoking
  173. //
  174. // A client can do lazy-evaluation of dispatch arguments by installing
  175. // a callback that sets up the dispatch arguments on the first callback.
  176. //
  177. // A client can support a "Cancel" flag by returning E_FAIL once the
  178. // cancel has occurred.
  179. //
  180. // A client can pre-validate an IDispatch for compatibility reasons
  181. // and either touch up the arguments and return S_OK, or decide that
  182. // the IDispatch should be skipped and return S_FALSE.
  183. //
  184. // A client can append custom information to the end of the SHINVOKEPARAMS
  185. // structure to allow it to determine additional context.
  186. //
  187. // A client can do post-invoke goo by doing work on the pre-invoke
  188. // of the subsequent callback (plus one final bout of work when the
  189. // entire enumeration completes).
  190. //
  191. //
  192. // Obtaining a connection point sink is supposed to be easy. You just
  193. // QI for the interface. Unfortunately, too many components are buggy.
  194. //
  195. // mmc.exe faults if you QI for IDispatch
  196. // and punkCB is non-NULL. And if you do pass in NULL,
  197. // it returns S_OK but fills punkCB with NULL anyway.
  198. // Somebody must've had a rough day.
  199. //
  200. // Java responds only to its dispatch ID and not IID_IDispatch, even
  201. // though the dispatch ID is derived from IID_IDispatch.
  202. //
  203. // The Explorer Band responds only to IID_IDispatch and not to
  204. // the dispatch ID.
  205. //
  206. HRESULT GetConnectionPointSink(IUnknown *pUnk, const IID *piidCB, IUnknown **ppunkCB)
  207. {
  208. HRESULT hr = E_NOINTERFACE;
  209. *ppunkCB = NULL; // Pre-zero it to work around MMC
  210. if (piidCB) // Optional interface (Java/ExplBand)
  211. {
  212. hr = pUnk->QueryInterface(*piidCB, (void **) ppunkCB);
  213. if (*ppunkCB == NULL) // Clean up behind MMC
  214. hr = E_NOINTERFACE;
  215. }
  216. return hr;
  217. }
  218. //
  219. // Enumerate the connection point sinks, calling the callback for each one
  220. // found.
  221. //
  222. // The callback function is called once for each sink. The IUnknown is
  223. // whatever interface we could get from the sink (either piidCB or piidCB2).
  224. //
  225. typedef HRESULT (CALLBACK *ENUMCONNECTIONPOINTSPROC)(
  226. /* [in, iid_is(*piidCB)] */ IUnknown *psink, LPARAM lParam);
  227. HRESULT EnumConnectionPointSinks(
  228. IConnectionPoint *pcp, // IConnectionPoint victim
  229. const IID *piidCB, // Interface for callback
  230. const IID *piidCB2, // Alternate interface for callback
  231. ENUMCONNECTIONPOINTSPROC EnumProc, // Callback procedure
  232. LPARAM lParam) // Refdata for callback
  233. {
  234. HRESULT hr;
  235. IEnumConnections * pec;
  236. if (pcp)
  237. hr = pcp->EnumConnections(&pec);
  238. else
  239. hr = E_NOINTERFACE;
  240. if (SUCCEEDED(hr))
  241. {
  242. CONNECTDATA cd;
  243. ULONG cFetched;
  244. while (S_OK == (hr = pec->Next(1, &cd, &cFetched)))
  245. {
  246. IUnknown *punkCB;
  247. ASSERT(1 == cFetched);
  248. hr = GetConnectionPointSink(cd.pUnk, piidCB, &punkCB);
  249. if (FAILED(hr))
  250. hr = GetConnectionPointSink(cd.pUnk, piidCB2, &punkCB);
  251. if (EVAL(SUCCEEDED(hr)))
  252. {
  253. hr = EnumProc(punkCB, lParam);
  254. punkCB->Release();
  255. }
  256. else
  257. {
  258. hr = S_OK; // Pretend callback succeeded
  259. }
  260. cd.pUnk->Release();
  261. if (FAILED(hr)) break; // Callback asked to stop
  262. }
  263. pec->Release();
  264. hr = S_OK;
  265. }
  266. return hr;
  267. }
  268. //
  269. // Send out the callback (if applicable) and then do the invoke if the
  270. // callback said that was a good idea.
  271. //
  272. // Parameters:
  273. //
  274. // pcp - IConnectionPoint whose sinks are to be Invoke()d.
  275. // If this parameter is NULL, the function does nothing.
  276. // pinv - Structure containing parameters to INVOKE.
  277. HRESULT CALLBACK EnumInvokeCallback(IUnknown *psink, LPARAM lParam)
  278. {
  279. IDispatch *pdisp = (IDispatch *)psink;
  280. LPSHINVOKEPARAMS pinv = (LPSHINVOKEPARAMS)lParam;
  281. HRESULT hr;
  282. if (pinv->Callback)
  283. {
  284. // Now see if the callback wants to do pre-vet the pdisp.
  285. // It can return S_FALSE to skip this callback or E_FAIL to
  286. // stop the invoke altogether
  287. hr = pinv->Callback(pdisp, pinv);
  288. if (hr != S_OK) return hr;
  289. }
  290. pdisp->Invoke(pinv->dispidMember, *pinv->piid, pinv->lcid,
  291. pinv->wFlags, pinv->pdispparams, pinv->pvarResult,
  292. pinv->pexcepinfo, pinv->puArgErr);
  293. return S_OK;
  294. }
  295. //
  296. // IConnectionPoint_InvokeIndirect
  297. //
  298. // Given a connection point, call the IDispatch::Invoke for each
  299. // connected sink.
  300. //
  301. // The return value merely indicates whether the command was dispatched.
  302. // If any particular sink fails the IDispatch::Invoke, we will still
  303. // return S_OK, since the command was indeed dispatched.
  304. //
  305. // Parameters:
  306. //
  307. // pcp - IConnectionPoint whose sinks are to be Invoke()d.
  308. // If this parameter is NULL, the function does nothing.
  309. // pinv - Structure containing parameters to INVOKE.
  310. // The pdispparams field can be NULL; we will turn it
  311. // into a real DISPPARAMS for you.
  312. //
  313. // The SHINVOKEPARAMS.flags field can contain the following flags.
  314. //
  315. // IPFL_USECALLBACK - The callback field contains a callback function
  316. // Otherwise, it will be set to NULL.
  317. // IPFL_USEDEFAULT - Many fields in the SHINVOKEPARAMS will be set to
  318. // default values to save the caller effort:
  319. //
  320. // riid = IID_NULL
  321. // lcid = 0
  322. // wFlags = DISPATCH_METHOD
  323. // pvarResult = NULL
  324. // pexcepinfo = NULL
  325. // puArgErr = NULL
  326. //
  327. LWSTDAPI IConnectionPoint_InvokeIndirect(
  328. IConnectionPoint *pcp,
  329. SHINVOKEPARAMS *pinv)
  330. {
  331. HRESULT hr;
  332. DISPPARAMS dp = { 0 };
  333. IID iidCP;
  334. if (pinv->pdispparams == NULL)
  335. pinv->pdispparams = &dp;
  336. if (!(pinv->flags & IPFL_USECALLBACK))
  337. {
  338. pinv->Callback = NULL;
  339. }
  340. if (pinv->flags & IPFL_USEDEFAULTS)
  341. {
  342. pinv->piid = &IID_NULL;
  343. pinv->lcid = 0;
  344. pinv->wFlags = DISPATCH_METHOD;
  345. pinv->pvarResult = NULL;
  346. pinv->pexcepinfo = NULL;
  347. pinv->puArgErr = NULL;
  348. }
  349. // Try both the interface they actually connected on,
  350. // as well as IDispatch. Apparently Java responds only to
  351. // the connecting interface, and ExplBand responds only to
  352. // IDispatch, so we have to try both. (Sigh. Too many buggy
  353. // components in the system.)
  354. hr = EnumConnectionPointSinks(pcp,
  355. (pcp->GetConnectionInterface(&iidCP) == S_OK) ? &iidCP : NULL,
  356. &IID_IDispatch,
  357. EnumInvokeCallback,
  358. (LPARAM)pinv);
  359. // Put the original NULL back so the caller can re-use the SHINVOKEPARAMS.
  360. if (pinv->pdispparams == &dp)
  361. pinv->pdispparams = NULL;
  362. return hr;
  363. }
  364. //
  365. // Wrapper around IConnectionPoint_InvokeIndirect with special Cancel
  366. // semantics.
  367. //
  368. // Parameters:
  369. //
  370. // pcp - IConnectionPoint whose sinks are to be Invoke()d.
  371. // If this parameter is NULL, the function does nothing.
  372. // dispid - The DISPID to invoke
  373. // pdispparams - The DISPPARAMS for the invoke
  374. // pfCancel - Optional BOOL to cancel the invoke
  375. // ppvCancel - Optional LPVOID to cancel the invoke
  376. //
  377. // If either *pfCancel or *ppvCancel is nonzero/non-NULL, we stop the invoke
  378. // process. This allows a sink to "handle" the event and prevent other
  379. // sinks from receiving it. The ppvCancel parameter is for dispid's which
  380. // are queries that are asking for somebody to create an object and return it.
  381. //
  382. // It is the caller's responsibility to check the values of *pfCancel
  383. // and/or *ppvCancel to determine if the operation was cancelled.
  384. //
  385. typedef struct INVOKEWITHCANCEL {
  386. SHINVOKEPARAMS inv;
  387. LPBOOL pfCancel;
  388. void **ppvCancel;
  389. } INVOKEWITHCANCEL;
  390. HRESULT CALLBACK InvokeWithCancelProc(IDispatch *psink, SHINVOKEPARAMS *pinv)
  391. {
  392. INVOKEWITHCANCEL *piwc = CONTAINING_RECORD(pinv, INVOKEWITHCANCEL, inv);
  393. if ((piwc->pfCancel && *piwc->pfCancel) ||
  394. (piwc->ppvCancel && *piwc->ppvCancel))
  395. return E_FAIL;
  396. return S_OK;
  397. }
  398. LWSTDAPI IConnectionPoint_InvokeWithCancel(
  399. IConnectionPoint *pcp,
  400. DISPID dispidMember,
  401. DISPPARAMS * pdispparams,
  402. LPBOOL pfCancel,
  403. void **ppvCancel)
  404. {
  405. INVOKEWITHCANCEL iwc;
  406. iwc.inv.flags = IPFL_USECALLBACK | IPFL_USEDEFAULTS;
  407. iwc.inv.dispidMember = dispidMember;
  408. iwc.inv.pdispparams = pdispparams;
  409. iwc.inv.Callback = InvokeWithCancelProc;
  410. iwc.pfCancel = pfCancel;
  411. iwc.ppvCancel = ppvCancel;
  412. return IConnectionPoint_InvokeIndirect(pcp, &iwc.inv);
  413. }
  414. //
  415. // Wrapper around IConnectionPoint_InvokeIndirect with IPFL_USEDEFAULTS.
  416. //
  417. LWSTDAPI IConnectionPoint_SimpleInvoke(IConnectionPoint *pcp, DISPID dispidMember, DISPPARAMS *pdispparams)
  418. {
  419. SHINVOKEPARAMS inv;
  420. inv.flags = IPFL_USEDEFAULTS;
  421. inv.dispidMember = dispidMember;
  422. inv.pdispparams = pdispparams;
  423. return IConnectionPoint_InvokeIndirect(pcp, &inv);
  424. }
  425. //
  426. // Takes a variable number of parameters for IDispatch, packages
  427. // them up, and invokes them.
  428. //
  429. // The parameters to the IDispatch::Invoke will be
  430. //
  431. // dispidMember - dispidMember
  432. // riid - IID_NULL
  433. // lcid - 0
  434. // wFlags - DISPATCH_METHOD
  435. // pdispparams - <parameters to this function>
  436. // pvarResult - NULL
  437. // pexcepinfo - NULL
  438. // puArgErr - NULL
  439. //
  440. // The parameters to this function are
  441. //
  442. // pcp - IConnectionPoint whose sinks should be Invoke()d.
  443. // If this parameter is NULL, the function does nothing.
  444. // dispidMember - The DISPID to invoke.
  445. // rgvarg - Array of length cArgs.
  446. // It will be used to hold the parameters.
  447. // cArgs - Number of pairs of generic arguments (below).
  448. //
  449. // ap - va_list of parameters to package. We package up the
  450. // first (2 * cArgs) of them. See SHPackDispParams
  451. // for details.
  452. //
  453. LWSTDAPI IConnectionPoint_InvokeParamV(IConnectionPoint *pcp, DISPID dispidMember,
  454. VARIANTARG *rgvarg, UINT cArgs, va_list ap)
  455. {
  456. HRESULT hr;
  457. if (pcp)
  458. {
  459. DISPPARAMS dp;
  460. hr = SHPackDispParamsV(&dp, rgvarg, cArgs, ap);
  461. if (EVAL(SUCCEEDED(hr)))
  462. {
  463. hr = IConnectionPoint_SimpleInvoke(pcp, dispidMember, &dp);
  464. }
  465. }
  466. else
  467. hr = E_NOINTERFACE;
  468. return hr;
  469. }
  470. //
  471. // Given a connection point that represents IPropertyNotifySink,
  472. // call the IPropertyNotifySink::OnChanged for each connected sink.
  473. //
  474. // Parameters:
  475. //
  476. // pcp - IConnectionPoint whose sinks are to be notified.
  477. // If this parameter is NULL, the function does nothing.
  478. // dispid - To pass to IPropertyNotifySink::OnChanged.
  479. HRESULT CALLBACK OnChangedCallback(IUnknown *psink, LPARAM lParam)
  480. {
  481. IPropertyNotifySink *pns = (IPropertyNotifySink *)psink;
  482. DISPID dispid = (DISPID)lParam;
  483. pns->OnChanged(dispid);
  484. return S_OK;
  485. }
  486. LWSTDAPI IConnectionPoint_OnChanged(IConnectionPoint *pcp, DISPID dispid)
  487. {
  488. #ifdef DEBUG
  489. // Make sure it really is an IPropertyNotifySink connection point.
  490. if (pcp)
  491. {
  492. IID iid;
  493. HRESULT hr = pcp->GetConnectionInterface(&iid);
  494. ASSERT(SUCCEEDED(hr) && iid == IID_IPropertyNotifySink);
  495. }
  496. #endif
  497. return EnumConnectionPointSinks(pcp, &IID_IPropertyNotifySink, NULL,
  498. OnChangedCallback, (LPARAM)dispid);
  499. }
  500. //=============================================================================
  501. //
  502. // IConnectionPointContainer helper functions
  503. //
  504. // QI's for IConnectionPointContainer and then does the FindConnectionPoint.
  505. //
  506. // Parameters:
  507. //
  508. // punk - The object who might be an IConnectionPointContainer.
  509. // This parameter may be NULL, in which case the
  510. // operation fails.
  511. // riidCP - The connection point interface to locate.
  512. // pcpOut - Receives the IConnectionPoint, if any.
  513. LWSTDAPI IUnknown_FindConnectionPoint(IUnknown *punk, REFIID riidCP,
  514. IConnectionPoint **pcpOut)
  515. {
  516. HRESULT hr;
  517. *pcpOut = NULL;
  518. if (punk)
  519. {
  520. IConnectionPointContainer *pcpc;
  521. hr = punk->QueryInterface(IID_IConnectionPointContainer, (void **)&pcpc);
  522. if (SUCCEEDED(hr))
  523. {
  524. hr = pcpc->FindConnectionPoint(riidCP, pcpOut);
  525. pcpc->Release();
  526. }
  527. }
  528. else
  529. hr = E_NOINTERFACE;
  530. return hr;
  531. }
  532. //
  533. // Given an IUnknown, query for its connection point container,
  534. // find the corresponding connection point, package up the
  535. // invoke parameters, and call the IDispatch::Invoke for each
  536. // connected sink.
  537. //
  538. // See IConnectionPoint_InvokeParam for additional semantics.
  539. //
  540. // Parameters:
  541. //
  542. // punk - Object that might be an IConnectionPointContainer
  543. // riidCP - ConnectionPoint interface to request
  544. // pinv - Arguments for the Invoke.
  545. //
  546. LWSTDAPI IUnknown_CPContainerInvokeIndirect(IUnknown *punk, REFIID riidCP,
  547. SHINVOKEPARAMS *pinv)
  548. {
  549. IConnectionPoint *pcp;
  550. HRESULT hr = IUnknown_FindConnectionPoint(punk, riidCP, &pcp);
  551. if (SUCCEEDED(hr))
  552. {
  553. hr = IConnectionPoint_InvokeIndirect(pcp, pinv);
  554. pcp->Release();
  555. }
  556. return hr;
  557. }
  558. //
  559. // This is the ultimate in one-stop shopping.
  560. //
  561. // Given an IUnknown, query for its connection point container,
  562. // find the corresponding connection point, package up the
  563. // invoke parameters, and call the IDispatch::Invoke for each
  564. // connected sink.
  565. //
  566. // See IConnectionPoint_InvokeParam for additional semantics.
  567. //
  568. // Parameters:
  569. //
  570. // punk - Object that might be an IConnectionPointContainer
  571. // riidCP - ConnectionPoint interface to request
  572. // dispidMember - The DISPID to invoke.
  573. // rgvarg - Array of length cArgs.
  574. // It will be used to hold the parameters.
  575. // cArgs - Number of pairs of generic arguments (below).
  576. // ... - A collection of (VARNUM, LPVOID) pairs of arguments.
  577. // See SHPackDispParams for details.
  578. //
  579. // Example:
  580. //
  581. // IUnknown_CPContainerInvokeParam(punk, DIID_DShellFolderViewEvents,
  582. // DISPID_SELECTIONCHANGED, NULL, 0);
  583. LWSTDAPIV IUnknown_CPContainerInvokeParam(
  584. IUnknown *punk, REFIID riidCP,
  585. DISPID dispidMember, VARIANTARG *rgvarg, UINT cArgs, ...)
  586. {
  587. IConnectionPoint *pcp;
  588. HRESULT hr = IUnknown_FindConnectionPoint(punk, riidCP, &pcp);
  589. if (SUCCEEDED(hr))
  590. {
  591. va_list ap;
  592. va_start(ap, cArgs);
  593. hr = IConnectionPoint_InvokeParamV(pcp, dispidMember, rgvarg, cArgs, ap);
  594. va_end(ap);
  595. pcp->Release();
  596. }
  597. return hr;
  598. }
  599. //
  600. // Given an IUnknown, query for its connection point container,
  601. // find the corresponding connection point, and call the
  602. // IPropertyNotifySink::OnChanged for each connected sink.
  603. //
  604. // Parameters:
  605. //
  606. // punk - Object that might be an IConnectionPointContainer
  607. // dispid - To pass to IPropertyNotifySink::OnChanged.
  608. LWSTDAPI IUnknown_CPContainerOnChanged(IUnknown *punk, DISPID dispid)
  609. {
  610. IConnectionPoint *pcp;
  611. HRESULT hr = IUnknown_FindConnectionPoint(punk, IID_IPropertyNotifySink, &pcp);
  612. if (SUCCEEDED(hr))
  613. {
  614. hr = IConnectionPoint_OnChanged(pcp, dispid);
  615. pcp->Release();
  616. }
  617. return hr;
  618. }