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