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