1 /* 2 * ReactOS ATL 3 * 4 * Copyright 2009 Andrew Hill <ash77@reactos.org> 5 * Copyright 2013 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 #pragma once 23 24 #include <cguid.h> // for GUID_NULL 25 26 namespace ATL 27 { 28 29 template <class Base, const IID *piid, class T, class Copy, class ThreadModel = CComObjectThreadModel> 30 class CComEnum; 31 32 #define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator<ATL::CComObjectCached<cf> > _ClassFactoryCreatorClass; 33 #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory) 34 #define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton<obj>) 35 36 class CComObjectRootBase 37 { 38 public: 39 LONG m_dwRef; 40 public: 41 CComObjectRootBase() 42 { 43 m_dwRef = 0; 44 } 45 46 ~CComObjectRootBase() 47 { 48 } 49 50 void SetVoid(void *) 51 { 52 } 53 54 HRESULT _AtlFinalConstruct() 55 { 56 return S_OK; 57 } 58 59 HRESULT FinalConstruct() 60 { 61 return S_OK; 62 } 63 64 void InternalFinalConstructAddRef() 65 { 66 } 67 68 void InternalFinalConstructRelease() 69 { 70 } 71 72 void FinalRelease() 73 { 74 } 75 76 static void WINAPI ObjectMain(bool) 77 { 78 } 79 80 static const struct _ATL_CATMAP_ENTRY *GetCategoryMap() 81 { 82 return NULL; 83 } 84 85 static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject) 86 { 87 return AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject); 88 } 89 90 }; 91 92 template <class ThreadModel> 93 class CComObjectRootEx : public CComObjectRootBase 94 { 95 private: 96 typename ThreadModel::AutoDeleteCriticalSection m_critsec; 97 public: 98 ~CComObjectRootEx() 99 { 100 } 101 102 ULONG InternalAddRef() 103 { 104 ATLASSERT(m_dwRef >= 0); 105 return ThreadModel::Increment(&m_dwRef); 106 } 107 108 ULONG InternalRelease() 109 { 110 ATLASSERT(m_dwRef > 0); 111 return ThreadModel::Decrement(&m_dwRef); 112 } 113 114 void Lock() 115 { 116 m_critsec.Lock(); 117 } 118 119 void Unlock() 120 { 121 m_critsec.Unlock(); 122 } 123 124 HRESULT _AtlInitialConstruct() 125 { 126 return m_critsec.Init(); 127 } 128 }; 129 130 template <class Base> 131 class CComObject : public Base 132 { 133 public: 134 CComObject(void * = NULL) 135 { 136 _pAtlModule->Lock(); 137 } 138 139 virtual ~CComObject() 140 { 141 this->FinalRelease(); 142 _pAtlModule->Unlock(); 143 } 144 145 STDMETHOD_(ULONG, AddRef)() 146 { 147 return this->InternalAddRef(); 148 } 149 150 STDMETHOD_(ULONG, Release)() 151 { 152 ULONG newRefCount; 153 154 newRefCount = this->InternalRelease(); 155 if (newRefCount == 0) 156 delete this; 157 return newRefCount; 158 } 159 160 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject) 161 { 162 return this->_InternalQueryInterface(iid, ppvObject); 163 } 164 165 static HRESULT WINAPI CreateInstance(CComObject<Base> **pp) 166 { 167 CComObject<Base> *newInstance; 168 HRESULT hResult; 169 170 ATLASSERT(pp != NULL); 171 if (pp == NULL) 172 return E_POINTER; 173 174 hResult = E_OUTOFMEMORY; 175 newInstance = NULL; 176 ATLTRY(newInstance = new CComObject<Base>()) 177 if (newInstance != NULL) 178 { 179 newInstance->SetVoid(NULL); 180 newInstance->InternalFinalConstructAddRef(); 181 hResult = newInstance->_AtlInitialConstruct(); 182 if (SUCCEEDED(hResult)) 183 hResult = newInstance->FinalConstruct(); 184 if (SUCCEEDED(hResult)) 185 hResult = newInstance->_AtlFinalConstruct(); 186 newInstance->InternalFinalConstructRelease(); 187 if (hResult != S_OK) 188 { 189 delete newInstance; 190 newInstance = NULL; 191 } 192 } 193 *pp = newInstance; 194 return hResult; 195 } 196 197 198 }; 199 200 template <class Base> 201 class CComContainedObject : public Base 202 { 203 public: 204 IUnknown* m_pUnkOuter; 205 CComContainedObject(void * pv = NULL) : m_pUnkOuter(static_cast<IUnknown*>(pv)) 206 { 207 } 208 209 STDMETHOD_(ULONG, AddRef)() 210 { 211 return m_pUnkOuter->AddRef(); 212 } 213 214 STDMETHOD_(ULONG, Release)() 215 { 216 return m_pUnkOuter->Release(); 217 } 218 219 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject) 220 { 221 return m_pUnkOuter->QueryInterface(iid, ppvObject); 222 } 223 224 IUnknown* GetControllingUnknown() 225 { 226 return m_pUnkOuter; 227 } 228 }; 229 230 template <class contained> 231 class CComAggObject : public contained 232 { 233 public: 234 CComContainedObject<contained> m_contained; 235 236 CComAggObject(void * pv = NULL) : m_contained(static_cast<contained*>(pv)) 237 { 238 _pAtlModule->Lock(); 239 } 240 241 virtual ~CComAggObject() 242 { 243 this->FinalRelease(); 244 _pAtlModule->Unlock(); 245 } 246 247 HRESULT FinalConstruct() 248 { 249 return m_contained.FinalConstruct(); 250 } 251 void FinalRelease() 252 { 253 m_contained.FinalRelease(); 254 } 255 256 STDMETHOD_(ULONG, AddRef)() 257 { 258 return this->InternalAddRef(); 259 } 260 261 STDMETHOD_(ULONG, Release)() 262 { 263 ULONG newRefCount; 264 newRefCount = this->InternalRelease(); 265 if (newRefCount == 0) 266 delete this; 267 return newRefCount; 268 } 269 270 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject) 271 { 272 if (ppvObject == NULL) 273 return E_POINTER; 274 if (iid == IID_IUnknown) 275 *ppvObject = reinterpret_cast<void*>(this); 276 else 277 return m_contained._InternalQueryInterface(iid, ppvObject); 278 return S_OK; 279 } 280 281 static HRESULT WINAPI CreateInstance(IUnknown * punkOuter, CComAggObject<contained> **pp) 282 { 283 CComAggObject<contained> *newInstance; 284 HRESULT hResult; 285 286 ATLASSERT(pp != NULL); 287 if (pp == NULL) 288 return E_POINTER; 289 290 hResult = E_OUTOFMEMORY; 291 newInstance = NULL; 292 ATLTRY(newInstance = new CComAggObject<contained>(punkOuter)) 293 if (newInstance != NULL) 294 { 295 newInstance->SetVoid(NULL); 296 newInstance->InternalFinalConstructAddRef(); 297 hResult = newInstance->_AtlInitialConstruct(); 298 if (SUCCEEDED(hResult)) 299 hResult = newInstance->FinalConstruct(); 300 if (SUCCEEDED(hResult)) 301 hResult = newInstance->_AtlFinalConstruct(); 302 newInstance->InternalFinalConstructRelease(); 303 if (hResult != S_OK) 304 { 305 delete newInstance; 306 newInstance = NULL; 307 } 308 } 309 *pp = newInstance; 310 return hResult; 311 } 312 }; 313 314 template <class contained> 315 class CComPolyObject : public contained 316 { 317 public: 318 CComContainedObject<contained> m_contained; 319 320 CComPolyObject(void * pv = NULL) 321 : m_contained(pv ? static_cast<contained*>(pv) : this) 322 { 323 _pAtlModule->Lock(); 324 } 325 326 virtual ~CComPolyObject() 327 { 328 this->FinalRelease(); 329 _pAtlModule->Unlock(); 330 } 331 332 HRESULT FinalConstruct() 333 { 334 return m_contained.FinalConstruct(); 335 } 336 void FinalRelease() 337 { 338 m_contained.FinalRelease(); 339 } 340 341 STDMETHOD_(ULONG, AddRef)() 342 { 343 return this->InternalAddRef(); 344 } 345 346 STDMETHOD_(ULONG, Release)() 347 { 348 ULONG newRefCount; 349 newRefCount = this->InternalRelease(); 350 if (newRefCount == 0) 351 delete this; 352 return newRefCount; 353 } 354 355 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject) 356 { 357 if (ppvObject == NULL) 358 return E_POINTER; 359 if (iid == IID_IUnknown) 360 *ppvObject = reinterpret_cast<void*>(this); 361 else 362 return m_contained._InternalQueryInterface(iid, ppvObject); 363 return S_OK; 364 } 365 366 static HRESULT WINAPI CreateInstance(IUnknown * punkOuter, CComPolyObject<contained> **pp) 367 { 368 CComPolyObject<contained> *newInstance; 369 HRESULT hResult; 370 371 ATLASSERT(pp != NULL); 372 if (pp == NULL) 373 return E_POINTER; 374 375 hResult = E_OUTOFMEMORY; 376 newInstance = NULL; 377 ATLTRY(newInstance = new CComPolyObject<contained>(punkOuter)) 378 if (newInstance != NULL) 379 { 380 newInstance->SetVoid(NULL); 381 newInstance->InternalFinalConstructAddRef(); 382 hResult = newInstance->_AtlInitialConstruct(); 383 if (SUCCEEDED(hResult)) 384 hResult = newInstance->FinalConstruct(); 385 if (SUCCEEDED(hResult)) 386 hResult = newInstance->_AtlFinalConstruct(); 387 newInstance->InternalFinalConstructRelease(); 388 if (hResult != S_OK) 389 { 390 delete newInstance; 391 newInstance = NULL; 392 } 393 } 394 *pp = newInstance; 395 return hResult; 396 } 397 }; 398 399 template <HRESULT hResult> 400 class CComFailCreator 401 { 402 public: 403 static HRESULT WINAPI CreateInstance(void *, REFIID, LPVOID *ppv) 404 { 405 ATLASSERT(ppv != NULL); 406 if (ppv == NULL) 407 return E_POINTER; 408 *ppv = NULL; 409 410 return hResult; 411 } 412 }; 413 414 template <class T1> 415 class CComCreator 416 { 417 public: 418 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv) 419 { 420 T1 *newInstance; 421 HRESULT hResult; 422 423 ATLASSERT(ppv != NULL); 424 if (ppv == NULL) 425 return E_POINTER; 426 *ppv = NULL; 427 428 hResult = E_OUTOFMEMORY; 429 newInstance = NULL; 430 ATLTRY(newInstance = new T1(pv)) 431 if (newInstance != NULL) 432 { 433 newInstance->SetVoid(pv); 434 newInstance->InternalFinalConstructAddRef(); 435 hResult = newInstance->_AtlInitialConstruct(); 436 if (SUCCEEDED(hResult)) 437 hResult = newInstance->FinalConstruct(); 438 if (SUCCEEDED(hResult)) 439 hResult = newInstance->_AtlFinalConstruct(); 440 newInstance->InternalFinalConstructRelease(); 441 if (SUCCEEDED(hResult)) 442 hResult = newInstance->QueryInterface(riid, ppv); 443 if (FAILED(hResult)) 444 { 445 delete newInstance; 446 newInstance = NULL; 447 } 448 } 449 return hResult; 450 } 451 }; 452 453 template <class T1, class T2> 454 class CComCreator2 455 { 456 public: 457 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv) 458 { 459 ATLASSERT(ppv != NULL && riid != NULL); 460 461 if (pv == NULL) 462 return T1::CreateInstance(NULL, riid, ppv); 463 else 464 return T2::CreateInstance(pv, riid, ppv); 465 } 466 }; 467 468 template <class Base> 469 class CComObjectCached : public Base 470 { 471 public: 472 CComObjectCached(void * = NULL) 473 { 474 } 475 476 virtual ~CComObjectCached() 477 { 478 this->FinalRelease(); 479 } 480 481 STDMETHOD_(ULONG, AddRef)() 482 { 483 ULONG newRefCount; 484 485 newRefCount = this->InternalAddRef(); 486 if (newRefCount == 2) 487 _pAtlModule->Lock(); 488 return newRefCount; 489 } 490 491 STDMETHOD_(ULONG, Release)() 492 { 493 ULONG newRefCount; 494 495 newRefCount = this->InternalRelease(); 496 if (newRefCount == 0) 497 delete this; 498 else if (newRefCount == 1) 499 _pAtlModule->Unlock(); 500 return newRefCount; 501 } 502 503 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject) 504 { 505 return this->_InternalQueryInterface(iid, ppvObject); 506 } 507 508 static HRESULT WINAPI CreateInstance(CComObjectCached<Base> **pp) 509 { 510 CComObjectCached<Base> *newInstance; 511 HRESULT hResult; 512 513 ATLASSERT(pp != NULL); 514 if (pp == NULL) 515 return E_POINTER; 516 517 hResult = E_OUTOFMEMORY; 518 newInstance = NULL; 519 ATLTRY(newInstance = new CComObjectCached<Base>()) 520 if (newInstance != NULL) 521 { 522 newInstance->SetVoid(NULL); 523 newInstance->InternalFinalConstructAddRef(); 524 hResult = newInstance->_AtlInitialConstruct(); 525 if (SUCCEEDED(hResult)) 526 hResult = newInstance->FinalConstruct(); 527 if (SUCCEEDED(hResult)) 528 hResult = newInstance->_AtlFinalConstruct(); 529 newInstance->InternalFinalConstructRelease(); 530 if (hResult != S_OK) 531 { 532 delete newInstance; 533 newInstance = NULL; 534 } 535 } 536 *pp = newInstance; 537 return hResult; 538 } 539 }; 540 541 #define BEGIN_COM_MAP(x) \ 542 public: \ 543 typedef x _ComMapClass; \ 544 HRESULT _InternalQueryInterface(REFIID iid, void **ppvObject) \ 545 { \ 546 return this->InternalQueryInterface(this, _GetEntries(), iid, ppvObject); \ 547 } \ 548 const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() \ 549 { \ 550 static const ATL::_ATL_INTMAP_ENTRY _entries[] = { 551 552 #define END_COM_MAP() \ 553 {NULL, 0, 0} \ 554 }; \ 555 return _entries; \ 556 } \ 557 virtual ULONG STDMETHODCALLTYPE AddRef() = 0; \ 558 virtual ULONG STDMETHODCALLTYPE Release() = 0; \ 559 STDMETHOD(QueryInterface)(REFIID, void **) = 0; 560 561 #define COM_INTERFACE_ENTRY_IID(iid, x) \ 562 {&iid, offsetofclass(x, _ComMapClass), _ATL_SIMPLEMAPENTRY}, 563 564 #define COM_INTERFACE_ENTRY(x) \ 565 {&_ATL_IIDOF(x), \ 566 offsetofclass(x, _ComMapClass), \ 567 _ATL_SIMPLEMAPENTRY}, 568 569 #define COM_INTERFACE_ENTRY2_IID(iid, x, x2) \ 570 {&iid, \ 571 reinterpret_cast<DWORD_PTR>(static_cast<x *>(static_cast<x2 *>(reinterpret_cast<_ComMapClass *>(_ATL_PACKING)))) - _ATL_PACKING, \ 572 _ATL_SIMPLEMAPENTRY}, 573 574 #define COM_INTERFACE_ENTRY_BREAK(x) \ 575 {&_ATL_IIDOF(x), \ 576 NULL, \ 577 _Break}, // Break is a function that issues int 3. 578 579 #define COM_INTERFACE_ENTRY_NOINTERFACE(x) \ 580 {&_ATL_IIDOF(x), \ 581 NULL, \ 582 _NoInterface}, // NoInterface returns E_NOINTERFACE. 583 584 #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func) \ 585 {&iid, \ 586 dw, \ 587 func}, 588 589 #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func) \ 590 {NULL, \ 591 dw, \ 592 func}, 593 594 #define COM_INTERFACE_ENTRY_CHAIN(classname) \ 595 {NULL, \ 596 reinterpret_cast<DWORD>(&_CComChainData<classname, _ComMapClass>::data), \ 597 _Chain}, 598 599 #define DECLARE_NO_REGISTRY()\ 600 static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/) \ 601 { \ 602 return S_OK; \ 603 } 604 605 #define DECLARE_REGISTRY_RESOURCEID(x) \ 606 static HRESULT WINAPI UpdateRegistry(BOOL bRegister) \ 607 { \ 608 return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \ 609 } 610 611 #define DECLARE_NOT_AGGREGATABLE(x) \ 612 public: \ 613 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass; 614 615 #define DECLARE_AGGREGATABLE(x) \ 616 public: \ 617 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComCreator<ATL::CComAggObject<x> > > _CreatorClass; 618 619 #define DECLARE_ONLY_AGGREGATABLE(x) \ 620 public: \ 621 typedef ATL::CComCreator2<ATL::CComFailCreator<E_FAIL>, ATL::CComCreator<ATL::CComAggObject<x> > > _CreatorClass; 622 623 #define DECLARE_POLY_AGGREGATABLE(x) \ 624 public: \ 625 typedef ATL::CComCreator<ATL::CComPolyObject<x> > _CreatorClass; 626 627 #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk) \ 628 {&iid, \ 629 (DWORD_PTR)offsetof(_ComMapClass, punk), \ 630 _Delegate}, 631 632 #define DECLARE_GET_CONTROLLING_UNKNOWN() \ 633 public: \ 634 virtual IUnknown *GetControllingUnknown() \ 635 { \ 636 return GetUnknown(); \ 637 } 638 639 #define DECLARE_PROTECT_FINAL_CONSTRUCT() \ 640 void InternalFinalConstructAddRef() \ 641 { \ 642 InternalAddRef(); \ 643 } \ 644 void InternalFinalConstructRelease() \ 645 { \ 646 InternalRelease(); \ 647 } 648 649 #define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = { 650 651 #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL}}; 652 653 #define OBJECT_ENTRY(clsid, class) \ 654 { \ 655 &clsid, \ 656 class::UpdateRegistry, \ 657 class::_ClassFactoryCreatorClass::CreateInstance, \ 658 class::_CreatorClass::CreateInstance, \ 659 NULL, \ 660 0, \ 661 class::GetObjectDescription, \ 662 class::GetCategoryMap, \ 663 class::ObjectMain }, 664 665 class CComClassFactory : 666 public IClassFactory, 667 public CComObjectRootEx<CComGlobalsThreadModel> 668 { 669 public: 670 _ATL_CREATORFUNC *m_pfnCreateInstance; 671 672 virtual ~CComClassFactory() 673 { 674 } 675 676 public: 677 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj) 678 { 679 HRESULT hResult; 680 681 ATLASSERT(m_pfnCreateInstance != NULL); 682 683 if (ppvObj == NULL) 684 return E_POINTER; 685 *ppvObj = NULL; 686 687 if (pUnkOuter != NULL && InlineIsEqualUnknown(riid) == FALSE) 688 hResult = CLASS_E_NOAGGREGATION; 689 else 690 hResult = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); 691 return hResult; 692 } 693 694 STDMETHOD(LockServer)(BOOL fLock) 695 { 696 if (fLock) 697 _pAtlModule->Lock(); 698 else 699 _pAtlModule->Unlock(); 700 return S_OK; 701 } 702 703 void SetVoid(void *pv) 704 { 705 m_pfnCreateInstance = (_ATL_CREATORFUNC *)pv; 706 } 707 708 BEGIN_COM_MAP(CComClassFactory) 709 COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory) 710 END_COM_MAP() 711 }; 712 713 template <class T> 714 class CComClassFactorySingleton : 715 public CComClassFactory 716 { 717 public: 718 HRESULT m_hrCreate; 719 IUnknown *m_spObj; 720 721 public: 722 CComClassFactorySingleton() : 723 m_hrCreate(S_OK), 724 m_spObj(NULL) 725 { 726 } 727 728 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj) 729 { 730 HRESULT hResult; 731 732 if (ppvObj == NULL) 733 return E_POINTER; 734 *ppvObj = NULL; 735 736 if (pUnkOuter != NULL) 737 hResult = CLASS_E_NOAGGREGATION; 738 else if (m_hrCreate == S_OK && m_spObj == NULL) 739 { 740 _SEH2_TRY 741 { 742 Lock(); 743 if (m_hrCreate == S_OK && m_spObj == NULL) 744 { 745 CComObjectCached<T> *pObj; 746 m_hrCreate = CComObjectCached<T>::CreateInstance(&pObj); 747 if (SUCCEEDED(m_hrCreate)) 748 { 749 m_hrCreate = pObj->QueryInterface(IID_IUnknown, reinterpret_cast<PVOID *>(&m_spObj)); 750 if (FAILED(m_hrCreate)) 751 delete pObj; 752 } 753 } 754 } 755 _SEH2_FINALLY 756 { 757 Unlock(); 758 } 759 _SEH2_END; 760 } 761 if (m_hrCreate == S_OK) 762 hResult = m_spObj->QueryInterface(riid, ppvObj); 763 else 764 hResult = m_hrCreate; 765 return hResult; 766 } 767 }; 768 769 template <class T, const CLSID *pclsid = &CLSID_NULL> 770 class CComCoClass 771 { 772 public: 773 DECLARE_CLASSFACTORY() 774 775 static LPCTSTR WINAPI GetObjectDescription() 776 { 777 return NULL; 778 } 779 }; 780 781 template <class T> 782 class _Copy 783 { 784 public: 785 static HRESULT copy(T *pTo, const T *pFrom) 786 { 787 memcpy(pTo, pFrom, sizeof(T)); 788 return S_OK; 789 } 790 791 static void init(T *) 792 { 793 } 794 795 static void destroy(T *) 796 { 797 } 798 }; 799 800 template<> 801 class _Copy<CONNECTDATA> 802 { 803 public: 804 static HRESULT copy(CONNECTDATA *pTo, const CONNECTDATA *pFrom) 805 { 806 *pTo = *pFrom; 807 if (pTo->pUnk) 808 pTo->pUnk->AddRef(); 809 return S_OK; 810 } 811 812 static void init(CONNECTDATA *) 813 { 814 } 815 816 static void destroy(CONNECTDATA *p) 817 { 818 if (p->pUnk) 819 p->pUnk->Release(); 820 } 821 }; 822 823 template <class T> 824 class _CopyInterface 825 { 826 public: 827 static HRESULT copy(T **pTo, T **pFrom) 828 { 829 *pTo = *pFrom; 830 if (*pTo) 831 (*pTo)->AddRef(); 832 return S_OK; 833 } 834 835 static void init(T **) 836 { 837 } 838 839 static void destroy(T **p) 840 { 841 if (*p) 842 (*p)->Release(); 843 } 844 }; 845 846 enum CComEnumFlags 847 { 848 AtlFlagNoCopy = 0, 849 AtlFlagTakeOwnership = 2, // BitOwn 850 AtlFlagCopy = 3 // BitOwn | BitCopy 851 }; 852 853 template <class Base, const IID *piid, class T, class Copy> 854 class CComEnumImpl : public Base 855 { 856 private: 857 typedef CComObject<CComEnum<Base, piid, T, Copy> > enumeratorClass; 858 public: 859 CComPtr<IUnknown> m_spUnk; 860 DWORD m_dwFlags; 861 T *m_begin; 862 T *m_end; 863 T *m_iter; 864 public: 865 CComEnumImpl() 866 { 867 m_dwFlags = 0; 868 m_begin = NULL; 869 m_end = NULL; 870 m_iter = NULL; 871 } 872 873 virtual ~CComEnumImpl() 874 { 875 T *x; 876 877 if ((m_dwFlags & BitOwn) != 0) 878 { 879 for (x = m_begin; x != m_end; x++) 880 Copy::destroy(x); 881 delete [] m_begin; 882 } 883 } 884 885 HRESULT Init(T *begin, T *end, IUnknown *pUnk, CComEnumFlags flags = AtlFlagNoCopy) 886 { 887 T *newBuffer; 888 T *sourcePtr; 889 T *destPtr; 890 T *cleanupPtr; 891 HRESULT hResult; 892 893 if (flags == AtlFlagCopy) 894 { 895 ATLTRY(newBuffer = new T[end - begin]) 896 if (newBuffer == NULL) 897 return E_OUTOFMEMORY; 898 destPtr = newBuffer; 899 for (sourcePtr = begin; sourcePtr != end; sourcePtr++) 900 { 901 Copy::init(destPtr); 902 hResult = Copy::copy(destPtr, sourcePtr); 903 if (FAILED(hResult)) 904 { 905 cleanupPtr = m_begin; 906 while (cleanupPtr < destPtr) 907 Copy::destroy(cleanupPtr++); 908 delete [] newBuffer; 909 return hResult; 910 } 911 destPtr++; 912 } 913 m_begin = newBuffer; 914 m_end = m_begin + (end - begin); 915 } 916 else 917 { 918 m_begin = begin; 919 m_end = end; 920 } 921 m_spUnk = pUnk; 922 m_dwFlags = flags; 923 m_iter = m_begin; 924 return S_OK; 925 } 926 927 STDMETHOD(Next)(ULONG celt, T *rgelt, ULONG *pceltFetched) 928 { 929 ULONG numAvailable; 930 ULONG numToFetch; 931 T *rgeltTemp; 932 HRESULT hResult; 933 934 if (pceltFetched != NULL) 935 *pceltFetched = 0; 936 if (celt == 0) 937 return E_INVALIDARG; 938 if (rgelt == NULL || (celt != 1 && pceltFetched == NULL)) 939 return E_POINTER; 940 if (m_begin == NULL || m_end == NULL || m_iter == NULL) 941 return E_FAIL; 942 943 numAvailable = static_cast<ULONG>(m_end - m_iter); 944 if (celt < numAvailable) 945 numToFetch = celt; 946 else 947 numToFetch = numAvailable; 948 if (pceltFetched != NULL) 949 *pceltFetched = numToFetch; 950 rgeltTemp = rgelt; 951 while (numToFetch != 0) 952 { 953 hResult = Copy::copy(rgeltTemp, m_iter); 954 if (FAILED(hResult)) 955 { 956 while (rgelt < rgeltTemp) 957 Copy::destroy(rgelt++); 958 if (pceltFetched != NULL) 959 *pceltFetched = 0; 960 return hResult; 961 } 962 rgeltTemp++; 963 m_iter++; 964 numToFetch--; 965 } 966 if (numAvailable < celt) 967 return S_FALSE; 968 return S_OK; 969 } 970 971 STDMETHOD(Skip)(ULONG celt) 972 { 973 ULONG numAvailable; 974 ULONG numToSkip; 975 976 if (celt == 0) 977 return E_INVALIDARG; 978 979 numAvailable = static_cast<ULONG>(m_end - m_iter); 980 if (celt < numAvailable) 981 numToSkip = celt; 982 else 983 numToSkip = numAvailable; 984 m_iter += numToSkip; 985 if (numAvailable < celt) 986 return S_FALSE; 987 return S_OK; 988 } 989 990 STDMETHOD(Reset)() 991 { 992 m_iter = m_begin; 993 return S_OK; 994 } 995 996 STDMETHOD(Clone)(Base **ppEnum) 997 { 998 enumeratorClass *newInstance; 999 HRESULT hResult; 1000 1001 hResult = E_POINTER; 1002 if (ppEnum != NULL) 1003 { 1004 *ppEnum = NULL; 1005 hResult = enumeratorClass::CreateInstance(&newInstance); 1006 if (SUCCEEDED(hResult)) 1007 { 1008 hResult = newInstance->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk); 1009 if (SUCCEEDED(hResult)) 1010 { 1011 newInstance->m_iter = m_iter; 1012 hResult = newInstance->_InternalQueryInterface(*piid, (void **)ppEnum); 1013 } 1014 if (FAILED(hResult)) 1015 delete newInstance; 1016 } 1017 } 1018 return hResult; 1019 } 1020 1021 protected: 1022 enum FlagBits 1023 { 1024 BitCopy = 1, 1025 BitOwn = 2 1026 }; 1027 }; 1028 1029 template <class Base, const IID *piid, class T, class Copy, class ThreadModel> 1030 class CComEnum : 1031 public CComEnumImpl<Base, piid, T, Copy>, 1032 public CComObjectRootEx<ThreadModel> 1033 { 1034 public: 1035 typedef CComEnum<Base, piid, T, Copy > _CComEnum; 1036 typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase; 1037 1038 BEGIN_COM_MAP(_CComEnum) 1039 COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase) 1040 END_COM_MAP() 1041 }; 1042 1043 #ifndef _DEFAULT_VECTORLENGTH 1044 #define _DEFAULT_VECTORLENGTH 4 1045 #endif 1046 1047 class CComDynamicUnkArray 1048 { 1049 public: 1050 int m_nSize; 1051 IUnknown **m_ppUnk; 1052 public: 1053 CComDynamicUnkArray() 1054 { 1055 m_nSize = 0; 1056 m_ppUnk = NULL; 1057 } 1058 1059 ~CComDynamicUnkArray() 1060 { 1061 free(m_ppUnk); 1062 } 1063 1064 IUnknown **begin() 1065 { 1066 return m_ppUnk; 1067 } 1068 1069 IUnknown **end() 1070 { 1071 return &m_ppUnk[m_nSize]; 1072 } 1073 1074 IUnknown *GetAt(int nIndex) 1075 { 1076 ATLASSERT(nIndex >= 0 && nIndex < m_nSize); 1077 if (nIndex >= 0 && nIndex < m_nSize) 1078 return m_ppUnk[nIndex]; 1079 else 1080 return NULL; 1081 } 1082 1083 IUnknown *WINAPI GetUnknown(DWORD dwCookie) 1084 { 1085 ATLASSERT(dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize)); 1086 if (dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize)) 1087 return GetAt(dwCookie - 1); 1088 else 1089 return NULL; 1090 } 1091 1092 DWORD WINAPI GetCookie(IUnknown **ppFind) 1093 { 1094 IUnknown **x; 1095 DWORD curCookie; 1096 1097 ATLASSERT(ppFind != NULL && *ppFind != NULL); 1098 if (ppFind != NULL && *ppFind != NULL) 1099 { 1100 curCookie = 1; 1101 for (x = begin(); x < end(); x++) 1102 { 1103 if (*x == *ppFind) 1104 return curCookie; 1105 curCookie++; 1106 } 1107 } 1108 return 0; 1109 } 1110 1111 DWORD Add(IUnknown *pUnk) 1112 { 1113 IUnknown **x; 1114 IUnknown **newArray; 1115 int newSize; 1116 DWORD curCookie; 1117 1118 ATLASSERT(pUnk != NULL); 1119 if (m_nSize == 0) 1120 { 1121 newSize = _DEFAULT_VECTORLENGTH * sizeof(IUnknown *); 1122 ATLTRY(newArray = reinterpret_cast<IUnknown **>(malloc(newSize))); 1123 if (newArray == NULL) 1124 return 0; 1125 memset(newArray, 0, newSize); 1126 m_ppUnk = newArray; 1127 m_nSize = _DEFAULT_VECTORLENGTH; 1128 } 1129 curCookie = 1; 1130 for (x = begin(); x < end(); x++) 1131 { 1132 if (*x == NULL) 1133 { 1134 *x = pUnk; 1135 return curCookie; 1136 } 1137 curCookie++; 1138 } 1139 newSize = m_nSize * 2; 1140 newArray = reinterpret_cast<IUnknown **>(realloc(m_ppUnk, newSize * sizeof(IUnknown *))); 1141 if (newArray == NULL) 1142 return 0; 1143 m_ppUnk = newArray; 1144 memset(&m_ppUnk[m_nSize], 0, (newSize - m_nSize) * sizeof(IUnknown *)); 1145 curCookie = m_nSize + 1; 1146 m_nSize = newSize; 1147 m_ppUnk[curCookie - 1] = pUnk; 1148 return curCookie; 1149 } 1150 1151 BOOL Remove(DWORD dwCookie) 1152 { 1153 DWORD index; 1154 1155 index = dwCookie - 1; 1156 ATLASSERT(index < dwCookie && index < static_cast<DWORD>(m_nSize)); 1157 if (index < dwCookie && index < static_cast<DWORD>(m_nSize) && m_ppUnk[index] != NULL) 1158 { 1159 m_ppUnk[index] = NULL; 1160 return TRUE; 1161 } 1162 return FALSE; 1163 } 1164 1165 private: 1166 CComDynamicUnkArray &operator = (const CComDynamicUnkArray &) 1167 { 1168 return *this; 1169 } 1170 1171 CComDynamicUnkArray(const CComDynamicUnkArray &) 1172 { 1173 } 1174 }; 1175 1176 struct _ATL_CONNMAP_ENTRY 1177 { 1178 DWORD_PTR dwOffset; 1179 }; 1180 1181 template <const IID *piid> 1182 class _ICPLocator 1183 { 1184 public: 1185 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject) = 0; 1186 virtual ULONG STDMETHODCALLTYPE AddRef() = 0; 1187 virtual ULONG STDMETHODCALLTYPE Release() = 0; 1188 }; 1189 1190 template<class T, const IID *piid, class CDV = CComDynamicUnkArray> 1191 class IConnectionPointImpl : public _ICPLocator<piid> 1192 { 1193 typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA, _Copy<CONNECTDATA> > CComEnumConnections; 1194 public: 1195 CDV m_vec; 1196 public: 1197 ~IConnectionPointImpl() 1198 { 1199 IUnknown **x; 1200 1201 for (x = m_vec.begin(); x < m_vec.end(); x++) 1202 if (*x != NULL) 1203 (*x)->Release(); 1204 } 1205 1206 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject) 1207 { 1208 IConnectionPointImpl<T, piid, CDV> *pThis; 1209 1210 pThis = reinterpret_cast<IConnectionPointImpl<T, piid, CDV>*>(this); 1211 1212 ATLASSERT(ppvObject != NULL); 1213 if (ppvObject == NULL) 1214 return E_POINTER; 1215 1216 if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid)) 1217 { 1218 *ppvObject = this; 1219 pThis->AddRef(); 1220 return S_OK; 1221 } 1222 else 1223 { 1224 *ppvObject = NULL; 1225 return E_NOINTERFACE; 1226 } 1227 } 1228 1229 STDMETHOD(GetConnectionInterface)(IID *piid2) 1230 { 1231 if (piid2 == NULL) 1232 return E_POINTER; 1233 *piid2 = *piid; 1234 return S_OK; 1235 } 1236 1237 STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC) 1238 { 1239 T *pThis; 1240 1241 pThis = static_cast<T *>(this); 1242 return pThis->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(ppCPC)); 1243 } 1244 1245 STDMETHOD(Advise)(IUnknown *pUnkSink, DWORD *pdwCookie) 1246 { 1247 IUnknown *adviseTarget; 1248 IID interfaceID; 1249 HRESULT hResult; 1250 1251 if (pdwCookie != NULL) 1252 *pdwCookie = 0; 1253 if (pUnkSink == NULL || pdwCookie == NULL) 1254 return E_POINTER; 1255 GetConnectionInterface(&interfaceID); // can't fail 1256 hResult = pUnkSink->QueryInterface(interfaceID, reinterpret_cast<void **>(&adviseTarget)); 1257 if (SUCCEEDED(hResult)) 1258 { 1259 *pdwCookie = m_vec.Add(adviseTarget); 1260 if (*pdwCookie != 0) 1261 hResult = S_OK; 1262 else 1263 { 1264 adviseTarget->Release(); 1265 hResult = CONNECT_E_ADVISELIMIT; 1266 } 1267 } 1268 else if (hResult == E_NOINTERFACE) 1269 hResult = CONNECT_E_CANNOTCONNECT; 1270 return hResult; 1271 } 1272 1273 STDMETHOD(Unadvise)(DWORD dwCookie) 1274 { 1275 IUnknown *adviseTarget; 1276 HRESULT hResult; 1277 1278 adviseTarget = m_vec.GetUnknown(dwCookie); 1279 if (m_vec.Remove(dwCookie)) 1280 { 1281 if (adviseTarget != NULL) 1282 adviseTarget->Release(); 1283 hResult = S_OK; 1284 } 1285 else 1286 hResult = CONNECT_E_NOCONNECTION; 1287 return hResult; 1288 } 1289 1290 STDMETHOD(EnumConnections)(IEnumConnections **ppEnum) 1291 { 1292 CComObject<CComEnumConnections> *newEnumerator; 1293 CONNECTDATA *itemBuffer; 1294 CONNECTDATA *itemBufferEnd; 1295 IUnknown **x; 1296 HRESULT hResult; 1297 1298 ATLASSERT(ppEnum != NULL); 1299 if (ppEnum == NULL) 1300 return E_POINTER; 1301 *ppEnum = NULL; 1302 1303 ATLTRY(itemBuffer = new CONNECTDATA[m_vec.end() - m_vec.begin()]) 1304 if (itemBuffer == NULL) 1305 return E_OUTOFMEMORY; 1306 itemBufferEnd = itemBuffer; 1307 for (x = m_vec.begin(); x < m_vec.end(); x++) 1308 { 1309 if (*x != NULL) 1310 { 1311 (*x)->AddRef(); 1312 itemBufferEnd->pUnk = *x; 1313 itemBufferEnd->dwCookie = m_vec.GetCookie(x); 1314 itemBufferEnd++; 1315 } 1316 } 1317 ATLTRY(newEnumerator = new CComObject<CComEnumConnections>) 1318 if (newEnumerator == NULL) 1319 return E_OUTOFMEMORY; 1320 newEnumerator->Init(itemBuffer, itemBufferEnd, NULL, AtlFlagTakeOwnership); // can't fail 1321 hResult = newEnumerator->_InternalQueryInterface(IID_IEnumConnections, (void **)ppEnum); 1322 if (FAILED(hResult)) 1323 delete newEnumerator; 1324 return hResult; 1325 } 1326 }; 1327 1328 template <class T> 1329 class IConnectionPointContainerImpl : public IConnectionPointContainer 1330 { 1331 typedef const _ATL_CONNMAP_ENTRY * (*handlerFunctionType)(int *); 1332 typedef CComEnum<IEnumConnectionPoints, &IID_IEnumConnectionPoints, IConnectionPoint *, _CopyInterface<IConnectionPoint> > 1333 CComEnumConnectionPoints; 1334 1335 public: 1336 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints **ppEnum) 1337 { 1338 const _ATL_CONNMAP_ENTRY *entryPtr; 1339 int connectionPointCount; 1340 IConnectionPoint **itemBuffer; 1341 int destIndex; 1342 handlerFunctionType handlerFunction; 1343 CComEnumConnectionPoints *newEnumerator; 1344 HRESULT hResult; 1345 1346 ATLASSERT(ppEnum != NULL); 1347 if (ppEnum == NULL) 1348 return E_POINTER; 1349 *ppEnum = NULL; 1350 1351 entryPtr = T::GetConnMap(&connectionPointCount); 1352 ATLTRY(itemBuffer = new IConnectionPoint * [connectionPointCount]) 1353 if (itemBuffer == NULL) 1354 return E_OUTOFMEMORY; 1355 1356 destIndex = 0; 1357 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1)) 1358 { 1359 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2)) 1360 { 1361 entryPtr++; 1362 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset); 1363 entryPtr = handlerFunction(NULL); 1364 } 1365 else 1366 { 1367 itemBuffer[destIndex++] = reinterpret_cast<IConnectionPoint *>((char *)this + entryPtr->dwOffset); 1368 entryPtr++; 1369 } 1370 } 1371 1372 ATLTRY(newEnumerator = new CComObject<CComEnumConnectionPoints>) 1373 if (newEnumerator == NULL) 1374 { 1375 delete [] itemBuffer; 1376 return E_OUTOFMEMORY; 1377 } 1378 1379 newEnumerator->Init(&itemBuffer[0], &itemBuffer[destIndex], NULL, AtlFlagTakeOwnership); // can't fail 1380 hResult = newEnumerator->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum); 1381 if (FAILED(hResult)) 1382 delete newEnumerator; 1383 return hResult; 1384 } 1385 1386 STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint **ppCP) 1387 { 1388 IID interfaceID; 1389 const _ATL_CONNMAP_ENTRY *entryPtr; 1390 handlerFunctionType handlerFunction; 1391 IConnectionPoint *connectionPoint; 1392 HRESULT hResult; 1393 1394 if (ppCP == NULL) 1395 return E_POINTER; 1396 *ppCP = NULL; 1397 hResult = CONNECT_E_NOCONNECTION; 1398 entryPtr = T::GetConnMap(NULL); 1399 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1)) 1400 { 1401 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2)) 1402 { 1403 entryPtr++; 1404 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset); 1405 entryPtr = handlerFunction(NULL); 1406 } 1407 else 1408 { 1409 connectionPoint = reinterpret_cast<IConnectionPoint *>(reinterpret_cast<char *>(this) + entryPtr->dwOffset); 1410 if (SUCCEEDED(connectionPoint->GetConnectionInterface(&interfaceID)) && InlineIsEqualGUID(riid, interfaceID)) 1411 { 1412 *ppCP = connectionPoint; 1413 connectionPoint->AddRef(); 1414 hResult = S_OK; 1415 break; 1416 } 1417 entryPtr++; 1418 } 1419 } 1420 return hResult; 1421 } 1422 }; 1423 1424 #define BEGIN_CONNECTION_POINT_MAP(x) \ 1425 typedef x _atl_conn_classtype; \ 1426 static const ATL::_ATL_CONNMAP_ENTRY *GetConnMap(int *pnEntries) { \ 1427 static const ATL::_ATL_CONNMAP_ENTRY _entries[] = { 1428 1429 #define END_CONNECTION_POINT_MAP() \ 1430 {(DWORD_PTR)-1} }; \ 1431 if (pnEntries) \ 1432 *pnEntries = sizeof(_entries) / sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \ 1433 return _entries;} 1434 1435 #define CONNECTION_POINT_ENTRY(iid) \ 1436 {offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype) - \ 1437 offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)}, 1438 1439 1440 1441 /* TODO: 1442 - IDispatchImpl contains a static member of type CComTypeInfoHolder that manages the type information for the dual interface. 1443 If you have multiple objects that implement the same dual interface, only one instance of CComTypeInfoHolder is used. 1444 - By default, the IDispatchImpl class looks up the type information for T in the registry. 1445 To implement an unregistered interface, you can use the IDispatchImpl class without accessing the registry by using a predefined version number. 1446 If you create an IDispatchImpl object that has 0xFFFF as the value for wMajor and 0xFFFF as the value for wMinor, 1447 the IDispatchImpl class retrieves the type library from the .dll file instead of the registry. 1448 */ 1449 template<class T, const IID* piid /*= &__uuidof(T)*/, const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1, WORD wMinor = 0> 1450 class IDispatchImpl : 1451 public T 1452 { 1453 private: 1454 CComPtr<ITypeInfo> m_pTypeInfo; 1455 1456 STDMETHOD(EnsureTILoaded)(LCID lcid) 1457 { 1458 HRESULT hr = S_OK; 1459 if (m_pTypeInfo != NULL) 1460 return hr; 1461 1462 if (IsEqualCLSID(CLSID_NULL, *plibid)) 1463 OutputDebugStringA("IDispatchImpl: plibid is CLSID_NULL!\r\n"); 1464 1465 // Should we assert here? 1466 if (wMajor == 0xffff && wMinor == 0xffff) 1467 OutputDebugStringA("IDispatchImpl: not fully implemented, missing functionality to load TLB from file!\r\n"); 1468 1469 CComPtr<ITypeLib> spTypeLib; 1470 hr = LoadRegTypeLib(*plibid, wMajor, wMinor, lcid, &spTypeLib); 1471 if (SUCCEEDED(hr)) 1472 { 1473 hr = spTypeLib->GetTypeInfoOfGuid(*piid, &m_pTypeInfo); 1474 } 1475 return hr; 1476 } 1477 1478 public: 1479 IDispatchImpl() 1480 { 1481 } 1482 1483 1484 // *** IDispatch methods *** 1485 STDMETHOD(GetTypeInfoCount)(UINT *pctinfo) 1486 { 1487 if (pctinfo == NULL) 1488 return E_POINTER; 1489 1490 *pctinfo = 1; 1491 return S_OK; 1492 } 1493 1494 STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 1495 { 1496 if (iTInfo != 0) 1497 return DISP_E_BADINDEX; 1498 if (ppTInfo == NULL) 1499 return E_POINTER; 1500 1501 HRESULT hr = EnsureTILoaded(lcid); 1502 *ppTInfo = m_pTypeInfo; 1503 if (*ppTInfo) 1504 (*ppTInfo)->AddRef(); 1505 1506 return hr; 1507 } 1508 1509 STDMETHOD(GetIDsOfNames)(REFIID /*riid*/, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) 1510 { 1511 HRESULT hr = EnsureTILoaded(lcid); 1512 if (SUCCEEDED(hr)) 1513 hr = m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId); 1514 return hr; 1515 } 1516 1517 STDMETHOD(Invoke)(DISPID dispIdMember, REFIID /*riid*/, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 1518 { 1519 HRESULT hr = EnsureTILoaded(lcid); 1520 if (SUCCEEDED(hr)) 1521 hr = m_pTypeInfo->Invoke(this, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 1522 return hr; 1523 } 1524 }; 1525 1526 }; // namespace ATL 1527