1 /* 2 * ReactOS ATL 3 * 4 * Copyright 2009 Andrew Hill <ash77@reactos.org> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 #pragma once 22 23 #include "atldef.h" 24 #include "atlcore.h" 25 #include "statreg.h" 26 #include "atlcomcli.h" 27 #include "atlalloc.h" 28 #include "atlexcept.h" 29 #include "atltrace.h" 30 #include "comcat.h" 31 #include "tchar.h" 32 33 #ifdef _MSC_VER 34 // It is common to use this in ATL constructors. They only store this for later use, so the usage is safe. 35 #pragma warning(disable:4355) 36 #endif 37 38 #ifndef ATLTRY 39 #define ATLTRY(x) x; 40 #endif 41 42 #ifdef _ATL_DISABLE_NO_VTABLE 43 #define ATL_NO_VTABLE 44 #else 45 #define ATL_NO_VTABLE __declspec(novtable) 46 #endif 47 48 #ifndef ATL_DEPRECATED 49 #define ATL_DEPRECATED __declspec(deprecated) 50 #endif 51 52 53 namespace ATL 54 { 55 56 class CAtlModule; 57 class CComModule; 58 class CAtlComModule; 59 __declspec(selectany) CAtlModule *_pAtlModule = NULL; 60 __declspec(selectany) CComModule *_pModule = NULL; 61 62 template <bool isDll, typename T> struct CAtlValidateModuleConfiguration 63 { 64 #if !defined(_WINDLL) && !defined(_USRDLL) 65 static_assert(!isDll, "_WINDLL or _USRDLL must be defined when 'CAtlDllModuleT<T>' is used"); 66 #else 67 static_assert(isDll, "_WINDLL or _USRDLL must be defined when 'CAtlExeModuleT<T>' is used"); 68 #endif 69 }; 70 71 72 struct _ATL_CATMAP_ENTRY 73 { 74 int iType; 75 const GUID* pcatid; 76 }; 77 78 #define _ATL_CATMAP_ENTRY_END 0 79 #define _ATL_CATMAP_ENTRY_IMPLEMENTED 1 80 #define _ATL_CATMAP_ENTRY_REQUIRED 2 81 82 83 typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void *pv, REFIID riid, LPVOID *ppv); 84 typedef LPCTSTR (WINAPI _ATL_DESCRIPTIONFUNC)(); 85 typedef const struct _ATL_CATMAP_ENTRY * (_ATL_CATMAPFUNC)(); 86 87 struct _ATL_OBJMAP_ENTRY30 88 { 89 const CLSID *pclsid; 90 HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister); 91 _ATL_CREATORFUNC *pfnGetClassObject; 92 _ATL_CREATORFUNC *pfnCreateInstance; 93 IUnknown *pCF; 94 DWORD dwRegister; 95 _ATL_DESCRIPTIONFUNC *pfnGetObjectDescription; 96 _ATL_CATMAPFUNC *pfnGetCategoryMap; 97 void (WINAPI *pfnObjectMain)(bool bStarting); 98 99 HRESULT WINAPI RevokeClassObject() 100 { 101 if (dwRegister == 0) 102 return S_OK; 103 return CoRevokeClassObject(dwRegister); 104 } 105 106 HRESULT WINAPI RegisterClassObject(DWORD dwClsContext, DWORD dwFlags) 107 { 108 IUnknown *p; 109 HRESULT hResult; 110 111 p = NULL; 112 if (pfnGetClassObject == NULL) 113 return S_OK; 114 115 hResult = pfnGetClassObject(reinterpret_cast<LPVOID *>(pfnCreateInstance), IID_IUnknown, reinterpret_cast<LPVOID *>(&p)); 116 if (SUCCEEDED(hResult)) 117 hResult = CoRegisterClassObject(*pclsid, p, dwClsContext, dwFlags, &dwRegister); 118 119 if (p != NULL) 120 p->Release(); 121 122 return hResult; 123 } 124 }; 125 126 typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY; 127 128 typedef void (__stdcall _ATL_TERMFUNC)(DWORD_PTR dw); 129 130 struct _ATL_TERMFUNC_ELEM 131 { 132 _ATL_TERMFUNC *pFunc; 133 DWORD_PTR dw; 134 _ATL_TERMFUNC_ELEM *pNext; 135 }; 136 137 struct _ATL_MODULE70 138 { 139 UINT cbSize; 140 LONG m_nLockCnt; 141 _ATL_TERMFUNC_ELEM *m_pTermFuncs; 142 CComCriticalSection m_csStaticDataInitAndTypeInfo; 143 }; 144 typedef _ATL_MODULE70 _ATL_MODULE; 145 146 typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void *pv, REFIID riid, LPVOID *ppv, DWORD_PTR dw); 147 148 #define _ATL_SIMPLEMAPENTRY ((ATL::_ATL_CREATORARGFUNC *)1) 149 150 struct _ATL_INTMAP_ENTRY 151 { 152 const IID *piid; 153 DWORD_PTR dw; 154 _ATL_CREATORARGFUNC *pFunc; 155 }; 156 157 struct _AtlCreateWndData 158 { 159 void *m_pThis; 160 DWORD m_dwThreadID; 161 _AtlCreateWndData *m_pNext; 162 }; 163 164 struct _ATL_COM_MODULE70 165 { 166 UINT cbSize; 167 HINSTANCE m_hInstTypeLib; 168 _ATL_OBJMAP_ENTRY **m_ppAutoObjMapFirst; 169 _ATL_OBJMAP_ENTRY **m_ppAutoObjMapLast; 170 CComCriticalSection m_csObjMap; 171 }; 172 typedef _ATL_COM_MODULE70 _ATL_COM_MODULE; 173 174 struct _ATL_WIN_MODULE70 175 { 176 UINT cbSize; 177 CComCriticalSection m_csWindowCreate; 178 _AtlCreateWndData *m_pCreateWndList; 179 #ifdef NOTYET 180 CSimpleArray<ATOM> m_rgWindowClassAtoms; 181 #endif 182 }; 183 typedef _ATL_WIN_MODULE70 _ATL_WIN_MODULE; 184 185 186 // Auto object map 187 188 #if defined(_MSC_VER) 189 #pragma section("ATL$__a", read, write) 190 #pragma section("ATL$__z", read, write) 191 #pragma section("ATL$__m", read, write) 192 #define _ATLALLOC(x) __declspec(allocate(x)) 193 194 #if defined(_M_IX86) 195 #define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:___pobjMap_" #class)); 196 #elif defined(_M_IA64) || defined(_M_AMD64) || (_M_ARM) || defined(_M_ARM64) 197 #define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pobjMap_" #class)); 198 #else 199 #error Your platform is not supported. 200 #endif 201 202 #elif defined(__GNUC__) 203 204 // GCC completely ignores __attribute__((unused)) on the __pobjMap_ pointer, so we pass it to a function that is not allowed to be optimized.... 205 static int __attribute__((optimize("O0"), unused)) hack_for_gcc(const _ATL_OBJMAP_ENTRY * const *) 206 { 207 return 1; 208 } 209 210 #define _ATLALLOC(x) __attribute__((section(x))) 211 #define OBJECT_ENTRY_PRAGMA(class) static int __pobjMap_hack_##class = hack_for_gcc(&__pobjMap_##class); 212 213 #else 214 #error Your compiler is not supported. 215 #endif 216 217 218 extern "C" 219 { 220 __declspec(selectany) _ATLALLOC("ATL$__a") _ATL_OBJMAP_ENTRY *__pobjMapEntryFirst = NULL; 221 __declspec(selectany) _ATLALLOC("ATL$__z") _ATL_OBJMAP_ENTRY *__pobjMapEntryLast = NULL; 222 } 223 224 225 struct _ATL_REGMAP_ENTRY 226 { 227 LPCOLESTR szKey; 228 LPCOLESTR szData; 229 }; 230 231 HRESULT WINAPI AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule); 232 HRESULT WINAPI AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst); 233 HRESULT WINAPI AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject); 234 void WINAPI AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject); 235 void *WINAPI AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule); 236 HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pComModule, REFCLSID rclsid, REFIID riid, LPVOID *ppv); 237 238 HRESULT WINAPI AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid); 239 HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid); 240 241 HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags); 242 HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module); 243 244 245 template<class TLock> 246 class CComCritSecLock 247 { 248 private: 249 bool m_bLocked; 250 TLock &m_cs; 251 public: 252 CComCritSecLock(TLock &cs, bool bInitialLock = true) : m_cs(cs) 253 { 254 HRESULT hResult; 255 256 m_bLocked = false; 257 if (bInitialLock) 258 { 259 hResult = Lock(); 260 if (FAILED(hResult)) 261 { 262 ATLASSERT(false); 263 } 264 } 265 } 266 267 ~CComCritSecLock() 268 { 269 if (m_bLocked) 270 Unlock(); 271 } 272 273 HRESULT Lock() 274 { 275 HRESULT hResult; 276 277 ATLASSERT(!m_bLocked); 278 hResult = m_cs.Lock(); 279 if (FAILED(hResult)) 280 return hResult; 281 m_bLocked = true; 282 283 return S_OK; 284 } 285 286 void Unlock() 287 { 288 HRESULT hResult; 289 290 ATLASSERT(m_bLocked); 291 hResult = m_cs.Unlock(); 292 if (FAILED(hResult)) 293 { 294 ATLASSERT(false); 295 } 296 m_bLocked = false; 297 } 298 }; 299 300 301 class CHandle 302 { 303 public: 304 HANDLE m_handle; 305 306 public: 307 CHandle() : 308 m_handle(NULL) 309 { 310 } 311 312 CHandle(_Inout_ CHandle& handle) : 313 m_handle(NULL) 314 { 315 Attach(handle.Detach()); 316 } 317 318 explicit CHandle(_In_ HANDLE handle) : 319 m_handle(handle) 320 { 321 } 322 323 ~CHandle() 324 { 325 if (m_handle) 326 { 327 Close(); 328 } 329 } 330 331 CHandle& operator=(_Inout_ CHandle& handle) 332 { 333 if (this != &handle) 334 { 335 if (m_handle) 336 { 337 Close(); 338 } 339 Attach(handle.Detach()); 340 } 341 342 return *this; 343 } 344 345 operator HANDLE() const 346 { 347 return m_handle; 348 } 349 350 void Attach(_In_ HANDLE handle) 351 { 352 ATLASSERT(m_handle == NULL); 353 m_handle = handle; 354 } 355 356 HANDLE Detach() 357 { 358 HANDLE handle = m_handle; 359 m_handle = NULL; 360 return handle; 361 } 362 363 void Close() 364 { 365 if (m_handle) 366 { 367 ::CloseHandle(m_handle); 368 m_handle = NULL; 369 } 370 } 371 }; 372 373 374 inline BOOL WINAPI InlineIsEqualUnknown(REFGUID rguid1) 375 { 376 return ( 377 ((unsigned long *)&rguid1)[0] == 0 && 378 ((unsigned long *)&rguid1)[1] == 0 && 379 ((unsigned long *)&rguid1)[2] == 0x000000C0 && 380 ((unsigned long *)&rguid1)[3] == 0x46000000); 381 } 382 383 class CComMultiThreadModelNoCS 384 { 385 public: 386 typedef CComFakeCriticalSection AutoCriticalSection; 387 typedef CComFakeCriticalSection CriticalSection; 388 typedef CComMultiThreadModelNoCS ThreadModelNoCS; 389 typedef CComFakeCriticalSection AutoDeleteCriticalSection; 390 391 static ULONG WINAPI Increment(LPLONG p) 392 { 393 return InterlockedIncrement(p); 394 } 395 396 static ULONG WINAPI Decrement(LPLONG p) 397 { 398 return InterlockedDecrement(p); 399 } 400 }; 401 402 class CComMultiThreadModel 403 { 404 public: 405 typedef CComAutoCriticalSection AutoCriticalSection; 406 typedef CComCriticalSection CriticalSection; 407 typedef CComMultiThreadModelNoCS ThreadModelNoCS; 408 typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection; 409 410 static ULONG WINAPI Increment(LPLONG p) 411 { 412 return InterlockedIncrement(p); 413 } 414 415 static ULONG WINAPI Decrement(LPLONG p) 416 { 417 return InterlockedDecrement(p); 418 } 419 }; 420 421 class CComSingleThreadModel 422 { 423 public: 424 typedef CComFakeCriticalSection AutoCriticalSection; 425 typedef CComFakeCriticalSection CriticalSection; 426 typedef CComSingleThreadModel ThreadModelNoCS; 427 typedef CComFakeCriticalSection AutoDeleteCriticalSection; 428 429 static ULONG WINAPI Increment(LPLONG p) 430 { 431 return ++*p; 432 } 433 434 static ULONG WINAPI Decrement(LPLONG p) 435 { 436 return --*p; 437 } 438 }; 439 440 #if defined(_ATL_FREE_THREADED) 441 442 typedef CComMultiThreadModel CComObjectThreadModel; 443 typedef CComMultiThreadModel CComGlobalsThreadModel; 444 445 #elif defined(_ATL_APARTMENT_THREADED) 446 447 typedef CComSingleThreadModel CComObjectThreadModel; 448 typedef CComMultiThreadModel CComGlobalsThreadModel; 449 450 #elif defined(_ATL_SINGLE_THREADED) 451 452 typedef CComSingleThreadModel CComObjectThreadModel; 453 typedef CComSingleThreadModel CComGlobalsThreadModel; 454 455 #else 456 #error No threading model 457 #endif 458 459 class CAtlModule : public _ATL_MODULE 460 { 461 public: 462 static GUID m_libid; 463 464 CAtlModule() 465 { 466 ATLASSERT(_pAtlModule == NULL); 467 _pAtlModule = this; 468 cbSize = sizeof(_ATL_MODULE); 469 m_nLockCnt = 0; 470 } 471 472 virtual LONG GetLockCount() 473 { 474 return m_nLockCnt; 475 } 476 477 virtual LONG Lock() 478 { 479 return CComGlobalsThreadModel::Increment(&m_nLockCnt); 480 } 481 482 virtual LONG Unlock() 483 { 484 return CComGlobalsThreadModel::Decrement(&m_nLockCnt); 485 } 486 487 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* /*pRegistrar*/) = 0; 488 489 HRESULT WINAPI UpdateRegistryFromResource(LPCTSTR lpszRes, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries = NULL) 490 { 491 CRegObject registrar; 492 WCHAR modulePath[MAX_PATH]; 493 HRESULT hResult; 494 PCWSTR lpwszRes; 495 496 hResult = CommonInitRegistrar(registrar, modulePath, sizeof(modulePath) / sizeof(modulePath[0]), pMapEntries); 497 if (FAILED(hResult)) 498 return hResult; 499 #ifdef UNICODE 500 lpwszRes = lpszRes; 501 #else 502 /* FIXME: this is a bit of a hack, need to re-evaluate */ 503 WCHAR resid[MAX_PATH]; 504 MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, resid, MAX_PATH); 505 lpwszRes = resid; 506 #endif 507 if (bRegister != FALSE) 508 hResult = registrar.ResourceRegisterSz(modulePath, lpwszRes, L"REGISTRY"); 509 else 510 hResult = registrar.ResourceUnregisterSz(modulePath, lpwszRes, L"REGISTRY"); 511 512 return hResult; 513 } 514 515 HRESULT WINAPI UpdateRegistryFromResource(UINT nResID, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries = NULL) 516 { 517 CRegObject registrar; 518 WCHAR modulePath[MAX_PATH]; 519 HRESULT hResult; 520 521 hResult = CommonInitRegistrar(registrar, modulePath, sizeof(modulePath) / sizeof(modulePath[0]), pMapEntries); 522 if (FAILED(hResult)) 523 return hResult; 524 525 if (bRegister != FALSE) 526 hResult = registrar.ResourceRegister(modulePath, nResID, L"REGISTRY"); 527 else 528 hResult = registrar.ResourceUnregister(modulePath, nResID, L"REGISTRY"); 529 530 return hResult; 531 } 532 533 private: 534 HRESULT CommonInitRegistrar(CRegObject ®istrar, WCHAR *modulePath, DWORD modulePathCount, struct _ATL_REGMAP_ENTRY *pMapEntries) 535 { 536 HINSTANCE hInstance; 537 DWORD dwFLen; 538 HRESULT hResult; 539 540 hInstance = _AtlBaseModule.GetModuleInstance(); 541 dwFLen = GetModuleFileNameW(hInstance, modulePath, modulePathCount); 542 if (dwFLen == modulePathCount) 543 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 544 else if (dwFLen == 0) 545 return HRESULT_FROM_WIN32(GetLastError()); 546 547 if (pMapEntries != NULL) 548 { 549 while (pMapEntries->szKey != NULL) 550 { 551 ATLASSERT(pMapEntries->szData != NULL); 552 hResult = registrar.AddReplacement(pMapEntries->szKey, pMapEntries->szData); 553 if (FAILED(hResult)) 554 return hResult; 555 pMapEntries++; 556 } 557 } 558 559 hResult = AddCommonRGSReplacements(®istrar); 560 if (FAILED(hResult)) 561 return hResult; 562 563 hResult = registrar.AddReplacement(L"Module", modulePath); 564 if (FAILED(hResult)) 565 return hResult; 566 567 hResult = registrar.AddReplacement(L"Module_Raw", modulePath); 568 if (FAILED(hResult)) 569 return hResult; 570 571 return S_OK; 572 } 573 }; 574 575 __declspec(selectany) GUID CAtlModule::m_libid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }; 576 577 template <class T> 578 class CAtlModuleT : public CAtlModule 579 { 580 public: 581 582 HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL); 583 HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL); 584 585 586 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase *pRegistrar) 587 { 588 return pRegistrar->AddReplacement(L"APPID", T::GetAppId()); 589 } 590 591 static LPCOLESTR GetAppId() 592 { 593 return L""; 594 } 595 }; 596 597 class CAtlComModule : public _ATL_COM_MODULE 598 { 599 public: 600 CAtlComModule() 601 { 602 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)this, &m_hInstTypeLib); 603 604 m_ppAutoObjMapFirst = &__pobjMapEntryFirst + 1; 605 m_ppAutoObjMapLast = &__pobjMapEntryLast; 606 if (FAILED(m_csObjMap.Init())) 607 { 608 ATLASSERT(0); 609 CAtlBaseModule::m_bInitFailed = true; 610 return; 611 } 612 cbSize = sizeof(_ATL_COM_MODULE); 613 } 614 615 ~CAtlComModule() 616 { 617 Term(); 618 } 619 620 HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL) 621 { 622 return AtlComModuleRegisterServer(this, bRegTypeLib, pCLSID); 623 } 624 625 HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL) 626 { 627 return AtlComModuleUnregisterServer(this, bUnRegTypeLib, pCLSID); 628 } 629 630 void Term() 631 { 632 if (cbSize != 0) 633 { 634 for (_ATL_OBJMAP_ENTRY **iter = m_ppAutoObjMapFirst; iter < m_ppAutoObjMapLast; iter++) 635 { 636 _ATL_OBJMAP_ENTRY *ptr = *iter; 637 if (!ptr) 638 continue; 639 640 if (!ptr->pCF) 641 continue; 642 643 ptr->pCF->Release(); 644 ptr->pCF = NULL; 645 } 646 m_csObjMap.Term(); 647 cbSize = 0; 648 } 649 } 650 651 void ExecuteObjectMain(bool bStarting) 652 { 653 for (_ATL_OBJMAP_ENTRY **iter = m_ppAutoObjMapFirst; iter < m_ppAutoObjMapLast; iter++) 654 { 655 if (!*iter) 656 continue; 657 658 (*iter)->pfnObjectMain(bStarting); 659 } 660 } 661 }; 662 663 __declspec(selectany) CAtlComModule _AtlComModule; 664 665 666 template <class T> 667 HRESULT CAtlModuleT<T>::RegisterServer(BOOL bRegTypeLib, const CLSID *pCLSID) 668 { 669 return _AtlComModule.RegisterServer(bRegTypeLib, pCLSID); 670 } 671 672 template <class T> 673 HRESULT CAtlModuleT<T>::UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID) 674 { 675 return _AtlComModule.UnregisterServer(bUnRegTypeLib, pCLSID); 676 } 677 678 template <class T> 679 class CAtlDllModuleT 680 : public CAtlModuleT<T> 681 , private CAtlValidateModuleConfiguration<true, T> 682 683 { 684 public: 685 CAtlDllModuleT() 686 { 687 _AtlComModule.ExecuteObjectMain(true); 688 } 689 690 ~CAtlDllModuleT() 691 { 692 _AtlComModule.ExecuteObjectMain(false); 693 } 694 695 HRESULT DllCanUnloadNow() 696 { 697 T *pThis; 698 699 pThis = static_cast<T *>(this); 700 if (pThis->GetLockCount() == 0) 701 return S_OK; 702 return S_FALSE; 703 } 704 705 HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 706 { 707 T *pThis; 708 709 pThis = static_cast<T *>(this); 710 return pThis->GetClassObject(rclsid, riid, ppv); 711 } 712 713 HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE) 714 { 715 T *pThis; 716 HRESULT hResult; 717 718 pThis = static_cast<T *>(this); 719 hResult = pThis->RegisterServer(bRegTypeLib); 720 return hResult; 721 } 722 723 HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE) 724 { 725 T *pThis; 726 HRESULT hResult; 727 728 pThis = static_cast<T *>(this); 729 hResult = pThis->UnregisterServer(bUnRegTypeLib); 730 return hResult; 731 } 732 733 HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 734 { 735 return AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv); 736 } 737 }; 738 739 740 template <class T> 741 class CAtlExeModuleT 742 : public CAtlModuleT<T> 743 , private CAtlValidateModuleConfiguration<false, T> 744 { 745 public: 746 DWORD m_dwMainThreadID; 747 //DWORD m_dwTimeOut; 748 //DWORD m_dwPause; 749 //bool m_bDelayShutdown; 750 751 CAtlExeModuleT() 752 :m_dwMainThreadID(::GetCurrentThreadId()) 753 { 754 _AtlComModule.ExecuteObjectMain(true); 755 } 756 757 ~CAtlExeModuleT() 758 { 759 _AtlComModule.ExecuteObjectMain(false); 760 } 761 762 int WinMain(int nShowCmd) 763 { 764 HRESULT hr = T::InitializeCom(); 765 if (FAILED(hr)) 766 return hr; 767 768 T* pThis = static_cast<T*>(this); 769 770 LPCTSTR lpCommandLine = GetCommandLine(); 771 if (pThis->ParseCommandLine(lpCommandLine, &hr)) 772 { 773 hr = pThis->Run(nShowCmd); 774 } 775 776 T::UninitializeCom(); 777 return hr; 778 } 779 780 781 HRESULT Run(int nShowCmd = SW_HIDE) 782 { 783 HRESULT hr = S_OK; 784 785 T* pThis = static_cast<T*>(this); 786 hr = pThis->PreMessageLoop(nShowCmd); 787 788 if (hr == S_OK) 789 { 790 pThis->RunMessageLoop(); 791 hr = pThis->PostMessageLoop(); 792 } 793 794 return hr; 795 } 796 797 LONG Lock() 798 { 799 return CoAddRefServerProcess(); 800 } 801 802 LONG Unlock() 803 { 804 LONG lRet = CoReleaseServerProcess(); 805 if (lRet == 0) 806 { 807 ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); 808 } 809 return lRet; 810 } 811 812 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) 813 { 814 // unimplemented! 815 return true; 816 } 817 818 HRESULT PreMessageLoop(int nShowCmd) 819 { 820 T* pThis = static_cast<T*>(this); 821 return pThis->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE); 822 } 823 824 void RunMessageLoop() 825 { 826 MSG msg; 827 while (GetMessage(&msg, 0, 0, 0) > 0) 828 { 829 TranslateMessage(&msg); 830 DispatchMessage(&msg); 831 } 832 } 833 834 HRESULT PostMessageLoop() 835 { 836 T* pThis = static_cast<T*>(this); 837 return pThis->RevokeClassObjects(); 838 } 839 840 HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) 841 { 842 return AtlComModuleRegisterClassObjects(&_AtlComModule, dwClsContext, dwFlags); 843 } 844 845 HRESULT RevokeClassObjects() 846 { 847 return AtlComModuleRevokeClassObjects(&_AtlComModule); 848 } 849 850 static HRESULT InitializeCom() 851 { 852 #if defined(_ATL_FREE_THREADED) 853 constexpr COINIT coInit = COINIT_MULTITHREADED; 854 #else 855 constexpr COINIT coInit = COINIT_APARTMENTTHREADED; 856 #endif 857 return ::CoInitializeEx(NULL, coInit); 858 } 859 860 static void UninitializeCom() 861 { 862 ::CoUninitialize(); 863 } 864 865 }; 866 867 868 869 class CComModule : public CAtlModuleT<CComModule> 870 { 871 public: 872 _ATL_OBJMAP_ENTRY *m_pObjMap; 873 public: 874 CComModule() 875 { 876 ATLASSERT(_pModule == NULL); 877 _pModule = this; 878 _pModule->m_pObjMap = NULL; 879 } 880 881 ~CComModule() 882 { 883 _pModule = NULL; 884 } 885 886 HRESULT Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE /* h */, const GUID *plibid) 887 { 888 _ATL_OBJMAP_ENTRY *objectMapEntry; 889 890 if (plibid != NULL) 891 m_libid = *plibid; 892 893 if (p != reinterpret_cast<_ATL_OBJMAP_ENTRY *>(-1)) 894 { 895 m_pObjMap = p; 896 if (p != NULL) 897 { 898 objectMapEntry = p; 899 while (objectMapEntry->pclsid != NULL) 900 { 901 objectMapEntry->pfnObjectMain(true); 902 objectMapEntry++; 903 } 904 } 905 } 906 907 for (_ATL_OBJMAP_ENTRY **iter = _AtlComModule.m_ppAutoObjMapFirst; iter < _AtlComModule.m_ppAutoObjMapLast; iter++) 908 { 909 if (*iter != NULL) 910 (*iter)->pfnObjectMain(true); 911 } 912 913 return S_OK; 914 } 915 916 void Term() 917 { 918 _ATL_OBJMAP_ENTRY *objectMapEntry; 919 920 if (m_pObjMap != NULL) 921 { 922 objectMapEntry = m_pObjMap; 923 while (objectMapEntry->pclsid != NULL) 924 { 925 if (objectMapEntry->pCF != NULL) 926 objectMapEntry->pCF->Release(); 927 objectMapEntry->pCF = NULL; 928 objectMapEntry->pfnObjectMain(false); 929 objectMapEntry++; 930 } 931 } 932 933 for (_ATL_OBJMAP_ENTRY **iter = _AtlComModule.m_ppAutoObjMapFirst; iter < _AtlComModule.m_ppAutoObjMapLast; iter++) 934 { 935 if (*iter != NULL) 936 (*iter)->pfnObjectMain(false); 937 } 938 939 } 940 941 HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 942 { 943 _ATL_OBJMAP_ENTRY *objectMapEntry; 944 HRESULT hResult; 945 946 ATLASSERT(ppv != NULL); 947 if (ppv == NULL) 948 return E_POINTER; 949 *ppv = NULL; 950 hResult = S_OK; 951 if (m_pObjMap != NULL) 952 { 953 objectMapEntry = m_pObjMap; 954 while (objectMapEntry->pclsid != NULL) 955 { 956 if (objectMapEntry->pfnGetClassObject != NULL && InlineIsEqualGUID(rclsid, *objectMapEntry->pclsid) != FALSE) 957 { 958 if (objectMapEntry->pCF == NULL) 959 { 960 CComCritSecLock<CComCriticalSection> lock(_AtlComModule.m_csObjMap, true); 961 962 if (objectMapEntry->pCF == NULL) 963 hResult = objectMapEntry->pfnGetClassObject(reinterpret_cast<void *>(objectMapEntry->pfnCreateInstance), IID_IUnknown, reinterpret_cast<LPVOID *>(&objectMapEntry->pCF)); 964 } 965 if (objectMapEntry->pCF != NULL) 966 hResult = objectMapEntry->pCF->QueryInterface(riid, ppv); 967 break; 968 } 969 objectMapEntry++; 970 } 971 } 972 if (hResult == S_OK && *ppv == NULL) 973 { 974 hResult = AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv); 975 } 976 return hResult; 977 } 978 979 HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL) 980 { 981 _ATL_OBJMAP_ENTRY *objectMapEntry; 982 HRESULT hResult; 983 984 hResult = S_OK; 985 objectMapEntry = m_pObjMap; 986 if (objectMapEntry != NULL) 987 { 988 while (objectMapEntry->pclsid != NULL) 989 { 990 if (pCLSID == NULL || IsEqualGUID(*pCLSID, *objectMapEntry->pclsid) != FALSE) 991 { 992 hResult = objectMapEntry->pfnUpdateRegistry(TRUE); 993 if (FAILED(hResult)) 994 break; 995 } 996 objectMapEntry++; 997 } 998 } 999 if (SUCCEEDED(hResult)) 1000 hResult = CAtlModuleT<CComModule>::RegisterServer(bRegTypeLib, pCLSID); 1001 return hResult; 1002 } 1003 1004 HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL) 1005 { 1006 _ATL_OBJMAP_ENTRY *objectMapEntry; 1007 HRESULT hResult; 1008 1009 hResult = S_OK; 1010 objectMapEntry = m_pObjMap; 1011 if (objectMapEntry != NULL) 1012 { 1013 while (objectMapEntry->pclsid != NULL) 1014 { 1015 if (pCLSID == NULL || IsEqualGUID(*pCLSID, *objectMapEntry->pclsid) != FALSE) 1016 { 1017 hResult = objectMapEntry->pfnUpdateRegistry(FALSE); //unregister 1018 if (FAILED(hResult)) 1019 break; 1020 } 1021 objectMapEntry++; 1022 } 1023 } 1024 if (SUCCEEDED(hResult)) 1025 hResult = CAtlModuleT<CComModule>::UnregisterServer(bUnRegTypeLib, pCLSID); 1026 1027 return hResult; 1028 } 1029 1030 HRESULT DllCanUnloadNow() 1031 { 1032 if (GetLockCount() == 0) 1033 return S_OK; 1034 return S_FALSE; 1035 } 1036 1037 HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 1038 { 1039 return GetClassObject(rclsid, riid, ppv); 1040 } 1041 1042 HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE) 1043 { 1044 return RegisterServer(bRegTypeLib); 1045 } 1046 1047 HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE) 1048 { 1049 return UnregisterServer(bUnRegTypeLib); 1050 } 1051 1052 }; 1053 1054 class CAtlWinModule : public _ATL_WIN_MODULE 1055 { 1056 public: 1057 CAtlWinModule() 1058 { 1059 HRESULT hResult; 1060 1061 hResult = AtlWinModuleInit(this); 1062 if (FAILED(hResult)) 1063 { 1064 CAtlBaseModule::m_bInitFailed = true; 1065 ATLASSERT(0); 1066 } 1067 } 1068 1069 ~CAtlWinModule() 1070 { 1071 Term(); 1072 } 1073 1074 void Term() 1075 { 1076 AtlWinModuleTerm(this, _AtlBaseModule.GetModuleInstance()); 1077 } 1078 1079 void AddCreateWndData(_AtlCreateWndData *pData, void *pObject) 1080 { 1081 AtlWinModuleAddCreateWndData(this, pData, pObject); 1082 } 1083 1084 void *ExtractCreateWndData() 1085 { 1086 return AtlWinModuleExtractCreateWndData(this); 1087 } 1088 }; 1089 1090 __declspec(selectany) CAtlWinModule _AtlWinModule; 1091 1092 1093 class CComAllocator 1094 { 1095 public: 1096 static void* Allocate(_In_ size_t size) 1097 { 1098 return ::CoTaskMemAlloc(size); 1099 } 1100 1101 static void* Reallocate(_In_opt_ void* ptr, _In_ size_t size) 1102 { 1103 return ::CoTaskMemRealloc(ptr, size); 1104 } 1105 1106 static void Free(_In_opt_ void* ptr) 1107 { 1108 ::CoTaskMemFree(ptr); 1109 } 1110 }; 1111 1112 class CRegKey 1113 { 1114 public: 1115 HKEY m_hKey; 1116 #if 0 1117 // FIXME & TODO: 1118 CAtlTransactionManager* m_pTM; 1119 #endif 1120 1121 public: 1122 1123 CRegKey() noexcept 1124 : m_hKey(NULL) 1125 { 1126 } 1127 1128 CRegKey(CRegKey& key) noexcept 1129 : m_hKey(key.Detach()) 1130 { 1131 } 1132 1133 explicit CRegKey(HKEY hKey) noexcept 1134 : m_hKey(hKey) 1135 { 1136 } 1137 1138 #if 0 1139 // FIXME & TODO: 1140 CRegKey(CAtlTransactionManager* pTM) noexcept 1141 { 1142 ... 1143 } 1144 #endif 1145 1146 ~CRegKey() noexcept 1147 { 1148 Close(); 1149 } 1150 1151 void Attach(HKEY hKey) noexcept 1152 { 1153 m_hKey = hKey; 1154 } 1155 1156 LONG Close() noexcept 1157 { 1158 if (m_hKey) 1159 { 1160 HKEY hKey = Detach(); 1161 return ::RegCloseKey(hKey); 1162 } 1163 return ERROR_SUCCESS; 1164 } 1165 1166 HKEY Detach() noexcept 1167 { 1168 HKEY hKey = m_hKey; 1169 m_hKey = NULL; 1170 return hKey; 1171 } 1172 1173 LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName, 1174 REGSAM samDesired = KEY_READ | KEY_WRITE) noexcept 1175 { 1176 ATLASSERT(hKeyParent); 1177 ATLASSERT(lpszKeyName); 1178 1179 HKEY hKey = NULL; 1180 LONG lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, 0, samDesired, &hKey); 1181 if (lRes == ERROR_SUCCESS) 1182 { 1183 Close(); 1184 m_hKey = hKey; 1185 } 1186 return lRes; 1187 } 1188 1189 LONG Create(HKEY hKeyParent, LPCTSTR lpszKeyName, 1190 LPTSTR lpszClass = REG_NONE, 1191 DWORD dwOptions = REG_OPTION_NON_VOLATILE, 1192 REGSAM samDesired = KEY_READ | KEY_WRITE, 1193 LPSECURITY_ATTRIBUTES lpSecAttr = NULL, 1194 LPDWORD lpdwDisposition = NULL) noexcept 1195 { 1196 ATLASSERT(hKeyParent); 1197 ATLASSERT(lpszKeyName); 1198 1199 HKEY hKey = NULL; 1200 LONG lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, 0, lpszClass, 1201 dwOptions, samDesired, lpSecAttr, &hKey, 1202 lpdwDisposition); 1203 if (lRes == ERROR_SUCCESS) 1204 { 1205 Close(); 1206 m_hKey = hKey; 1207 } 1208 return lRes; 1209 } 1210 1211 LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) noexcept 1212 { 1213 ATLASSERT(m_hKey); 1214 return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, (LPBYTE)pData, pnBytes); 1215 } 1216 1217 LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) noexcept 1218 { 1219 ULONG size = sizeof(DWORD); 1220 DWORD type = 0; 1221 LONG lRet = QueryValue(pszValueName, &type, &dwValue, &size); 1222 1223 if (lRet == ERROR_SUCCESS && type != REG_DWORD) 1224 lRet = ERROR_INVALID_DATA; 1225 1226 return lRet; 1227 } 1228 1229 LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) noexcept 1230 { 1231 DWORD type = 0; 1232 LONG lRet = QueryValue(pszValueName, &type, pValue, pnBytes); 1233 1234 if (lRet == ERROR_SUCCESS && type != REG_BINARY) 1235 lRet = ERROR_INVALID_DATA; 1236 1237 return lRet; 1238 } 1239 1240 LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) noexcept 1241 { 1242 ULONG size = (*pnChars) * sizeof(TCHAR); 1243 DWORD type = 0; 1244 LONG lRet = QueryValue(pszValueName, &type, pszValue, &size); 1245 1246 if (lRet == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ) 1247 lRet = ERROR_INVALID_DATA; 1248 1249 *pnChars = size / sizeof(TCHAR); 1250 return lRet; 1251 } 1252 1253 LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) noexcept 1254 { 1255 OLECHAR buf[40] = {0}; 1256 ULONG nChars = 39; 1257 LONG lRet; 1258 1259 #ifdef UNICODE 1260 lRet = QueryStringValue(pszValueName, buf, &nChars); 1261 #else 1262 CHAR bufA[40] = {0}; 1263 lRet = QueryStringValue(pszValueName, bufA, &nChars); 1264 if (lRet != ERROR_SUCCESS) 1265 return lRet; 1266 if (!::MultiByteToWideChar(CP_THREAD_ACP, 0, bufA, -1, buf, 39)) 1267 lRet = ERROR_INVALID_DATA; 1268 #endif 1269 if (lRet != ERROR_SUCCESS) 1270 return lRet; 1271 1272 if (!SUCCEEDED(::CLSIDFromString(buf, &guidValue))) 1273 return ERROR_INVALID_DATA; 1274 1275 return lRet; 1276 } 1277 1278 LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) noexcept 1279 { 1280 ULONG size = sizeof(ULONGLONG); 1281 DWORD type = 0; 1282 LONG lRet = QueryValue(pszValueName, &type, &qwValue, &size); 1283 1284 if (lRet == ERROR_SUCCESS && type != REG_QWORD) 1285 lRet = ERROR_INVALID_DATA; 1286 1287 return lRet; 1288 } 1289 1290 LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, 1291 ULONG* pnChars) noexcept 1292 { 1293 ULONG size = (*pnChars) * sizeof(TCHAR); 1294 DWORD type; 1295 LONG lRet = QueryValue(pszValueName, &type, pszValue, &size); 1296 1297 if (lRet == ERROR_SUCCESS && type != REG_MULTI_SZ) 1298 lRet = ERROR_INVALID_DATA; 1299 1300 *pnChars = size / sizeof(TCHAR); 1301 return lRet; 1302 } 1303 1304 LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) noexcept 1305 { 1306 ATLASSERT(m_hKey); 1307 return ::RegSetValueEx(m_hKey, pszValueName, 0, dwType, (const BYTE*)pValue, nBytes); 1308 } 1309 1310 LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) noexcept 1311 { 1312 return SetValue(pszValueName, REG_DWORD, &dwValue, sizeof(DWORD)); 1313 } 1314 1315 LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) noexcept 1316 { 1317 SIZE_T length; 1318 switch (dwType) 1319 { 1320 case REG_SZ: 1321 case REG_EXPAND_SZ: 1322 length = (_tcslen(pszValue) + 1) * sizeof(TCHAR); 1323 return SetValue(pszValueName, dwType, pszValue, length); 1324 case REG_MULTI_SZ: 1325 return SetMultiStringValue(pszValueName, pszValue); 1326 default: 1327 return ERROR_INVALID_DATA; 1328 } 1329 } 1330 1331 LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) noexcept 1332 { 1333 OLECHAR buf[40] = {0}; 1334 ::StringFromGUID2(guidValue, buf, 39); 1335 #ifdef UNICODE 1336 return SetStringValue(pszValueName, buf); 1337 #else 1338 CHAR bufA[40] = {0}; 1339 ::WideCharToMultiByte(CP_THREAD_ACP, 0, buf, -1, bufA, 40, NULL, NULL); 1340 return SetStringValue(pszValueName, bufA); 1341 #endif 1342 } 1343 1344 LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) noexcept 1345 { 1346 return SetValue(pszValueName, REG_BINARY, pValue, nBytes); 1347 } 1348 1349 LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) noexcept 1350 { 1351 ULONG dwSize = CRegKey::_GetMultiStringSize(pszValue); 1352 return SetValue(pszValueName, REG_MULTI_SZ, pszValue, dwSize); 1353 } 1354 1355 LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) noexcept 1356 { 1357 ULONG dwSize = sizeof(ULONGLONG); 1358 return SetValue(pszValueName, REG_QWORD, &qwValue, dwSize); 1359 } 1360 1361 LONG NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter, 1362 HANDLE hEvent, BOOL bAsync = TRUE) noexcept 1363 { 1364 ATLASSERT(m_hKey); 1365 LONG ret = ::RegNotifyChangeKeyValue(m_hKey, bWatchSubtree, 1366 dwNotifyFilter, hEvent, bAsync); 1367 return ret; 1368 } 1369 1370 LONG Flush() noexcept 1371 { 1372 ATLASSERT(m_hKey); 1373 LONG ret = ::RegFlushKey(m_hKey); 1374 return ret; 1375 } 1376 1377 static LONG WINAPI SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName, 1378 LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL) 1379 { 1380 CRegKey key; 1381 LONG lRet = key.Create(hKeyParent, lpszKeyName); 1382 if (lRet == ERROR_SUCCESS) 1383 { 1384 lRet = key.SetStringValue(lpszValueName, lpszValue); 1385 } 1386 return lRet; 1387 } 1388 1389 LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, 1390 LPCTSTR lpszValueName = NULL) noexcept 1391 { 1392 CRegKey key; 1393 LONG lRet = key.Create(m_hKey, lpszKeyName); 1394 if (lRet == ERROR_SUCCESS) 1395 { 1396 lRet = key.SetStringValue(lpszValueName, lpszValue); 1397 } 1398 return lRet; 1399 } 1400 1401 LONG DeleteValue(LPCTSTR lpszValue) noexcept 1402 { 1403 ATLASSERT(m_hKey); 1404 return ::RegDeleteValue(m_hKey, lpszValue); 1405 } 1406 1407 LONG DeleteSubKey(LPCTSTR lpszSubKey) noexcept 1408 { 1409 ATLASSERT(m_hKey); 1410 ATLASSERT(lpszSubKey); 1411 return ::RegDeleteKey(m_hKey, lpszSubKey); 1412 } 1413 1414 LONG RecurseDeleteKey(LPCTSTR lpszKey) noexcept 1415 { 1416 ATLASSERT(m_hKey); 1417 ATLASSERT(lpszKey); 1418 return CRegKey::_DoDeleteKeyTree(m_hKey, lpszKey); 1419 } 1420 1421 LONG EnumKey(DWORD iIndex, LPTSTR pszName, LPDWORD pnNameLength, 1422 FILETIME* pftLastWriteTime = NULL) noexcept 1423 { 1424 ATLASSERT(m_hKey); 1425 LONG ret = ::RegEnumKeyEx(m_hKey, iIndex, pszName, pnNameLength, NULL, 1426 NULL, NULL, pftLastWriteTime); 1427 return ret; 1428 } 1429 1430 LONG GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd, 1431 LPDWORD pnBytes) noexcept 1432 { 1433 ATLASSERT(m_hKey); 1434 LONG ret = ::RegGetKeySecurity(m_hKey, si, psd, pnBytes); 1435 return ret; 1436 } 1437 1438 LONG SetKeySecurity(SECURITY_INFORMATION si, 1439 PSECURITY_DESCRIPTOR psd) noexcept 1440 { 1441 ATLASSERT(m_hKey); 1442 LONG ret = ::RegSetKeySecurity(m_hKey, si, psd); 1443 return ret; 1444 } 1445 1446 operator HKEY() const noexcept 1447 { 1448 return m_hKey; 1449 } 1450 1451 CRegKey& operator=(CRegKey& key) noexcept 1452 { 1453 if (m_hKey != key.m_hKey) 1454 { 1455 Close(); 1456 Attach(key.Detach()); 1457 } 1458 return *this; 1459 } 1460 1461 protected: 1462 // get the total size of a multistring 1463 static ULONG _GetMultiStringSize(LPCTSTR pszz) 1464 { 1465 size_t count = 0; 1466 do 1467 { 1468 size_t len = _tcslen(pszz); 1469 count += len + 1; 1470 pszz += len + 1; 1471 } while (*pszz != TEXT('\0')); 1472 ++count; 1473 ATLASSERT(count * sizeof(TCHAR) <= ULONG_MAX); 1474 return (ULONG)count * sizeof(TCHAR); 1475 } 1476 1477 // delete key recursively 1478 static LONG _DoDeleteKeyTree(HKEY hParentKey, LPCTSTR lpszKey) 1479 { 1480 ATLASSERT(hParentKey); 1481 ATLASSERT(lpszKey); 1482 1483 // open the key 1484 CRegKey key; 1485 LONG ret = key.Open(hParentKey, lpszKey); 1486 if (ret != ERROR_SUCCESS) 1487 { 1488 return ret; // failure 1489 } 1490 1491 // get the longest length of subkey names 1492 DWORD NameMax; 1493 ret = ::RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &NameMax, NULL, 1494 NULL, NULL, NULL, NULL, NULL); 1495 if (ret != ERROR_SUCCESS) 1496 { 1497 return ret; // failure 1498 } 1499 ++NameMax; // for NUL 1500 1501 // allocate the string buffer for names if necessary 1502 TCHAR szNameBuf[MAX_PATH], *pszName; 1503 if (NameMax > MAX_PATH) 1504 { 1505 pszName = (TCHAR *)malloc(NameMax * sizeof(TCHAR)); 1506 ATLASSERT(pszName); 1507 if (pszName == NULL) 1508 { 1509 return ERROR_OUTOFMEMORY; // failure 1510 } 1511 } 1512 else 1513 { 1514 NameMax = MAX_PATH; 1515 pszName = szNameBuf; 1516 } 1517 1518 // enumerate every subkey and delete 1519 for (;;) 1520 { 1521 DWORD Count = NameMax; 1522 ret = key.EnumKey(0, pszName, &Count); 1523 if (ret != ERROR_SUCCESS) 1524 { 1525 if (ret == ERROR_NO_MORE_ITEMS) 1526 ret = ERROR_SUCCESS; 1527 break; 1528 } 1529 1530 ret = CRegKey::_DoDeleteKeyTree(key, pszName); 1531 if (ret != ERROR_SUCCESS) 1532 break; 1533 } 1534 1535 // close key 1536 key.Close(); 1537 1538 // delete the subkey 1539 if (ret == ERROR_SUCCESS) 1540 ret = ::RegDeleteKey(hParentKey, lpszKey); 1541 1542 // delete the buffer if any 1543 if (pszName != szNameBuf) 1544 free(pszName); 1545 1546 return ret; 1547 } 1548 }; 1549 1550 template<class T> 1551 class CComHeapPtr : public CHeapPtr<T, CComAllocator> 1552 { 1553 public: 1554 CComHeapPtr() 1555 { 1556 } 1557 1558 explicit CComHeapPtr(T *lp) : 1559 CHeapPtr<T, CComAllocator>(lp) 1560 { 1561 } 1562 }; 1563 1564 1565 inline HRESULT __stdcall AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID &iid, LPDWORD pdw) 1566 { 1567 CComPtr<IConnectionPointContainer> container; 1568 CComPtr<IConnectionPoint> connectionPoint; 1569 HRESULT hResult; 1570 1571 if (pUnkCP == NULL) 1572 return E_INVALIDARG; 1573 hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container); 1574 if (FAILED(hResult)) 1575 return hResult; 1576 hResult = container->FindConnectionPoint(iid, &connectionPoint); 1577 if (FAILED(hResult)) 1578 return hResult; 1579 return connectionPoint->Advise(pUnk, pdw); 1580 } 1581 1582 inline HRESULT __stdcall AtlUnadvise(IUnknown *pUnkCP, const IID &iid, DWORD dw) 1583 { 1584 CComPtr<IConnectionPointContainer> container; 1585 CComPtr<IConnectionPoint> connectionPoint; 1586 HRESULT hResult; 1587 1588 if (pUnkCP == NULL) 1589 return E_INVALIDARG; 1590 hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container); 1591 if (FAILED(hResult)) 1592 return hResult; 1593 hResult = container->FindConnectionPoint(iid, &connectionPoint); 1594 if (FAILED(hResult)) 1595 return hResult; 1596 return connectionPoint->Unadvise(dw); 1597 } 1598 1599 inline HRESULT __stdcall AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject) 1600 { 1601 int i; 1602 IUnknown *resultInterface; 1603 HRESULT hResult; 1604 1605 ATLASSERT(pThis != NULL && pEntries != NULL); 1606 if (pThis == NULL || pEntries == NULL) 1607 return E_INVALIDARG; 1608 1609 if (ppvObject == NULL) 1610 return E_POINTER; 1611 1612 if (InlineIsEqualUnknown(iid)) 1613 { 1614 resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[0].dw); 1615 *ppvObject = resultInterface; 1616 resultInterface->AddRef(); 1617 return S_OK; 1618 } 1619 1620 i = 0; 1621 while (pEntries[i].pFunc != 0) 1622 { 1623 if (pEntries[i].piid == NULL || InlineIsEqualGUID(iid, *pEntries[i].piid)) 1624 { 1625 if (pEntries[i].pFunc == reinterpret_cast<_ATL_CREATORARGFUNC *>(1)) 1626 { 1627 ATLASSERT(pEntries[i].piid != NULL); 1628 resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[i].dw); 1629 *ppvObject = resultInterface; 1630 resultInterface->AddRef(); 1631 return S_OK; 1632 } 1633 else 1634 { 1635 hResult = pEntries[i].pFunc(pThis, iid, ppvObject, 0); 1636 if (hResult == S_OK) 1637 return hResult; 1638 if (FAILED(hResult) && pEntries[i].piid != NULL) 1639 break; 1640 } 1641 } 1642 i++; 1643 } 1644 *ppvObject = NULL; 1645 return E_NOINTERFACE; 1646 } 1647 1648 inline HRESULT __stdcall AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule) 1649 { 1650 if (pWinModule == NULL) 1651 return E_INVALIDARG; 1652 pWinModule->m_pCreateWndList = NULL; 1653 return pWinModule->m_csWindowCreate.Init(); 1654 } 1655 1656 inline HRESULT __stdcall AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst) 1657 { 1658 if (pWinModule == NULL) 1659 return E_INVALIDARG; 1660 pWinModule->m_csWindowCreate.Term(); 1661 return S_OK; 1662 } 1663 1664 inline void __stdcall AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject) 1665 { 1666 CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true); 1667 1668 ATLASSERT(pWinModule != NULL); 1669 ATLASSERT(pObject != NULL); 1670 1671 pData->m_pThis = pObject; 1672 pData->m_dwThreadID = ::GetCurrentThreadId(); 1673 pData->m_pNext = pWinModule->m_pCreateWndList; 1674 pWinModule->m_pCreateWndList = pData; 1675 } 1676 1677 inline void *__stdcall AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule) 1678 { 1679 CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true); 1680 void *result; 1681 _AtlCreateWndData *currentEntry; 1682 _AtlCreateWndData **previousLink; 1683 DWORD threadID; 1684 1685 ATLASSERT(pWinModule != NULL); 1686 1687 result = NULL; 1688 threadID = GetCurrentThreadId(); 1689 currentEntry = pWinModule->m_pCreateWndList; 1690 previousLink = &pWinModule->m_pCreateWndList; 1691 while (currentEntry != NULL) 1692 { 1693 if (currentEntry->m_dwThreadID == threadID) 1694 { 1695 *previousLink = currentEntry->m_pNext; 1696 result = currentEntry->m_pThis; 1697 break; 1698 } 1699 previousLink = ¤tEntry->m_pNext; 1700 currentEntry = currentEntry->m_pNext; 1701 } 1702 return result; 1703 } 1704 1705 // Adapted from dll/win32/atl/atl.c 1706 inline HRESULT WINAPI AtlLoadTypeLib(HINSTANCE inst, LPCOLESTR lpszIndex, 1707 BSTR *pbstrPath, ITypeLib **ppTypeLib) 1708 { 1709 size_t index_len = lpszIndex ? wcslen(lpszIndex) : 0; 1710 CComHeapPtr<WCHAR> path; 1711 path.Allocate(MAX_PATH + index_len + wcslen(L".tlb")); 1712 1713 if (!path) 1714 return E_OUTOFMEMORY; 1715 1716 size_t path_len = GetModuleFileNameW(inst, path, MAX_PATH); 1717 if (!path_len) 1718 return HRESULT_FROM_WIN32(GetLastError()); 1719 1720 if (index_len) 1721 wcscat(path, lpszIndex); 1722 1723 CComPtr<ITypeLib> typelib; 1724 HRESULT hResult = LoadTypeLib(path, &typelib); 1725 if (FAILED(hResult)) 1726 { 1727 WCHAR *ptr; 1728 for (ptr = path+path_len-1; ptr > path && *ptr != '\\' && *ptr != '.'; ptr--) 1729 ; 1730 if (*ptr != '.') 1731 ptr = (WCHAR*)path + path_len; 1732 wcscpy(ptr, L".tlb"); 1733 1734 hResult = LoadTypeLib(path, &typelib); 1735 } 1736 1737 if (SUCCEEDED(hResult)) 1738 { 1739 *pbstrPath = SysAllocString(path); 1740 if (!*pbstrPath) 1741 { 1742 typelib.Release(); 1743 hResult = E_OUTOFMEMORY; 1744 } 1745 } 1746 1747 if (FAILED(hResult)) 1748 return hResult; 1749 1750 *ppTypeLib = typelib.Detach(); 1751 return S_OK; 1752 } 1753 1754 // Adapted from dll/win32/atl/atl.c 1755 inline HRESULT WINAPI AtlRegisterTypeLib(HINSTANCE inst, const WCHAR *index) 1756 { 1757 CComBSTR path; 1758 CComPtr<ITypeLib> typelib; 1759 HRESULT hResult = AtlLoadTypeLib(inst, index, &path, &typelib); 1760 if (FAILED(hResult)) 1761 return hResult; 1762 1763 return RegisterTypeLib(typelib, path, NULL); /* FIXME: pass help directory */ 1764 } 1765 1766 // Adapted from dll/win32/atl/atl.c 1767 inline HRESULT WINAPI AtlRegisterClassCategoriesHelper(REFCLSID clsid, const _ATL_CATMAP_ENTRY *catmap, BOOL reg) 1768 { 1769 if (!catmap) 1770 return S_OK; 1771 1772 CComPtr<ICatRegister> catreg; 1773 1774 HRESULT hResult = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&catreg); 1775 if (FAILED(hResult)) 1776 return hResult; 1777 1778 for (const _ATL_CATMAP_ENTRY *iter = catmap; iter->iType != _ATL_CATMAP_ENTRY_END; iter++) 1779 { 1780 CATID catid = *iter->pcatid; 1781 1782 if (iter->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED) 1783 { 1784 if (reg) 1785 hResult = catreg->RegisterClassImplCategories(clsid, 1, &catid); 1786 else 1787 hResult = catreg->UnRegisterClassImplCategories(clsid, 1, &catid); 1788 } 1789 else 1790 { 1791 if (reg) 1792 hResult = catreg->RegisterClassReqCategories(clsid, 1, &catid); 1793 else 1794 hResult = catreg->UnRegisterClassReqCategories(clsid, 1, &catid); 1795 } 1796 if (FAILED(hResult)) 1797 return hResult; 1798 } 1799 1800 if (!reg) 1801 { 1802 WCHAR reg_path[256] = L"CLSID\\"; 1803 1804 StringFromGUID2(clsid, reg_path + wcslen(reg_path), 64); 1805 wcscat(reg_path, L"\\"); 1806 WCHAR* ptr = reg_path + wcslen(reg_path); 1807 1808 wcscpy(ptr, L"Implemented Categories"); 1809 RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path); 1810 1811 wcscpy(ptr, L"Required Categories"); 1812 RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path); 1813 } 1814 1815 return hResult; 1816 } 1817 1818 1819 // Adapted from dll/win32/atl80/atl80.c 1820 inline HRESULT __stdcall AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid) 1821 { 1822 HRESULT hResult = S_OK; 1823 1824 for (_ATL_OBJMAP_ENTRY ** iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++) 1825 { 1826 if (!*iter) 1827 continue; 1828 _ATL_OBJMAP_ENTRY* entry = *iter; 1829 if (clsid && !IsEqualCLSID(*entry->pclsid, *clsid)) 1830 continue; 1831 1832 hResult = entry->pfnUpdateRegistry(TRUE); 1833 if (FAILED(hResult)) 1834 return hResult; 1835 1836 const _ATL_CATMAP_ENTRY *catmap = entry->pfnGetCategoryMap(); 1837 if (catmap) 1838 { 1839 hResult = AtlRegisterClassCategoriesHelper(*entry->pclsid, catmap, TRUE); 1840 if (FAILED(hResult)) 1841 return hResult; 1842 } 1843 } 1844 1845 if (bRegTypeLib) 1846 { 1847 hResult = AtlRegisterTypeLib(mod->m_hInstTypeLib, NULL); 1848 } 1849 1850 return hResult; 1851 } 1852 1853 // Adapted from dll/win32/atl/atl.c 1854 inline HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bUnRegTypeLib, const CLSID *clsid) 1855 { 1856 HRESULT hResult = S_OK; 1857 1858 for (_ATL_OBJMAP_ENTRY **iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++) 1859 { 1860 if (!*iter) 1861 continue; 1862 _ATL_OBJMAP_ENTRY* entry = *iter; 1863 if (clsid && !IsEqualCLSID(*entry->pclsid, *clsid)) 1864 continue; 1865 1866 const _ATL_CATMAP_ENTRY *catmap = entry->pfnGetCategoryMap(); 1867 if (catmap) 1868 { 1869 hResult = AtlRegisterClassCategoriesHelper(*entry->pclsid, catmap, FALSE); 1870 if (FAILED(hResult)) 1871 return hResult; 1872 } 1873 1874 hResult = entry->pfnUpdateRegistry(FALSE); 1875 if (FAILED(hResult)) 1876 return hResult; 1877 } 1878 1879 if (bUnRegTypeLib) 1880 { 1881 CComPtr<ITypeLib> typelib; 1882 TLIBATTR *attr; 1883 CComBSTR path; 1884 1885 hResult = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib); 1886 if (FAILED(hResult)) 1887 return hResult; 1888 1889 hResult = typelib->GetLibAttr(&attr); 1890 if (SUCCEEDED(hResult)) 1891 { 1892 hResult = UnRegisterTypeLib(attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind); 1893 typelib->ReleaseTLibAttr(attr); 1894 } 1895 } 1896 1897 return hResult; 1898 } 1899 1900 1901 // Adapted from dll/win32/atl/atl.c 1902 inline HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags) 1903 { 1904 _ATL_OBJMAP_ENTRY **iter; 1905 IUnknown* unk = NULL; 1906 HRESULT hr; 1907 1908 if (!module) 1909 return E_INVALIDARG; 1910 1911 for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) 1912 { 1913 _ATL_OBJMAP_ENTRY *ptr = *iter; 1914 if (!ptr) 1915 continue; 1916 1917 if (!ptr->pfnGetClassObject) 1918 continue; 1919 1920 hr = ptr->pfnGetClassObject((void*)ptr->pfnCreateInstance, IID_IUnknown, (void**)&unk); 1921 if (FAILED(hr)) 1922 return hr; 1923 1924 hr = CoRegisterClassObject(*ptr->pclsid, unk, context, flags, &ptr->dwRegister); 1925 unk->Release(); 1926 if (FAILED(hr)) 1927 return hr; 1928 } 1929 1930 return S_OK; 1931 } 1932 1933 1934 // Adapted from dll/win32/atl/atl.c 1935 inline HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module) 1936 { 1937 _ATL_OBJMAP_ENTRY **iter; 1938 HRESULT hr; 1939 1940 if (!module) 1941 return E_INVALIDARG; 1942 1943 for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++) 1944 { 1945 _ATL_OBJMAP_ENTRY *ptr = *iter; 1946 if (!ptr) 1947 continue; 1948 1949 hr = CoRevokeClassObject(ptr->dwRegister); 1950 if (FAILED(hr)) 1951 return hr; 1952 } 1953 1954 return S_OK; 1955 } 1956 1957 // Adapted from dll/win32/atl/atl.c 1958 inline HRESULT WINAPI 1959 AtlComModuleGetClassObject(_ATL_COM_MODULE *pm, REFCLSID rclsid, REFIID riid, void **ppv) 1960 { 1961 if (!pm) 1962 return E_INVALIDARG; 1963 1964 for (_ATL_OBJMAP_ENTRY **iter = pm->m_ppAutoObjMapFirst; iter < pm->m_ppAutoObjMapLast; iter++) 1965 { 1966 _ATL_OBJMAP_ENTRY *ptr = *iter; 1967 if (!ptr) 1968 continue; 1969 1970 if (IsEqualCLSID(*ptr->pclsid, rclsid) && ptr->pfnGetClassObject) 1971 { 1972 HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; 1973 1974 if (!ptr->pCF) 1975 { 1976 CComCritSecLock<CComCriticalSection> lock(_AtlComModule.m_csObjMap, true); 1977 if (!ptr->pCF) 1978 { 1979 hr = ptr->pfnGetClassObject((void *)ptr->pfnCreateInstance, IID_IUnknown, (void **)&ptr->pCF); 1980 } 1981 } 1982 if (ptr->pCF) 1983 hr = ptr->pCF->QueryInterface(riid, ppv); 1984 return hr; 1985 } 1986 } 1987 1988 return CLASS_E_CLASSNOTAVAILABLE; 1989 } 1990 1991 1992 }; // namespace ATL 1993 1994 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE 1995 using namespace ATL; 1996 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE 1997