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