xref: /reactos/sdk/lib/atl/atlbase.h (revision 9d3c3a75)
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             samDesired |= KEY_WOW64_64KEY;
1083             lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, 0, samDesired, &hKey);
1084         }
1085         if (lRes == ERROR_SUCCESS)
1086         {
1087             Close();
1088             m_hKey = hKey;
1089         }
1090         return lRes;
1091     }
1092 
1093     LONG Create(HKEY hKeyParent, LPCTSTR lpszKeyName,
1094                 LPTSTR lpszClass = REG_NONE,
1095                 DWORD dwOptions = REG_OPTION_NON_VOLATILE,
1096                 REGSAM samDesired = KEY_READ | KEY_WRITE,
1097                 LPSECURITY_ATTRIBUTES lpSecAttr = NULL,
1098                 LPDWORD lpdwDisposition = NULL) throw()
1099     {
1100         ATLASSERT(hKeyParent);
1101         ATLASSERT(lpszKeyName);
1102 
1103         HKEY hKey = NULL;
1104         LONG lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, 0, lpszClass,
1105                                      dwOptions, samDesired, lpSecAttr, &hKey,
1106                                      lpdwDisposition);
1107         if (lRes != ERROR_SUCCESS)
1108         {
1109             samDesired |= KEY_WOW64_64KEY;
1110             lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, 0, lpszClass,
1111                                     dwOptions, samDesired, lpSecAttr, &hKey,
1112                                     lpdwDisposition);
1113         }
1114         if (lRes == ERROR_SUCCESS)
1115         {
1116             Close();
1117             m_hKey = hKey;
1118         }
1119         return lRes;
1120     }
1121 
1122     LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw()
1123     {
1124         ATLASSERT(m_hKey);
1125         return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, (LPBYTE)pData, pnBytes);
1126     }
1127 
1128     LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) throw()
1129     {
1130         ULONG size = sizeof(DWORD);
1131         DWORD type = 0;
1132         LONG lRet = QueryValue(pszValueName, &type, &dwValue, &size);
1133 
1134         if (lRet == ERROR_SUCCESS && type != REG_DWORD)
1135             lRet = ERROR_INVALID_DATA;
1136 
1137         return lRet;
1138     }
1139 
1140     LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) throw()
1141     {
1142         DWORD type = 0;
1143         LONG lRet = QueryValue(pszValueName, &type, pValue, pnBytes);
1144 
1145         if (lRet == ERROR_SUCCESS && type != REG_BINARY)
1146             lRet = ERROR_INVALID_DATA;
1147 
1148         return lRet;
1149     }
1150 
1151     LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) throw()
1152     {
1153         ULONG size = (*pnChars) * sizeof(TCHAR);
1154         DWORD type = 0;
1155         LONG lRet = QueryValue(pszValueName, &type, pszValue, &size);
1156 
1157         if (lRet == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)
1158             lRet = ERROR_INVALID_DATA;
1159 
1160         *pnChars = size / sizeof(TCHAR);
1161         return lRet;
1162     }
1163 
1164     LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) throw()
1165     {
1166         OLECHAR buf[40] = {0};
1167         ULONG nChars = 39;
1168         LONG lRet;
1169 
1170 #ifdef UNICODE
1171         lRet = QueryStringValue(pszValueName, buf, &nChars);
1172 #else
1173         CHAR bufA[40] = {0};
1174         lRet = QueryStringValue(pszValueName, bufA, &nChars);
1175         if (lRet != ERROR_SUCCESS)
1176             return lRet;
1177         if (!::MultiByteToWideChar(CP_THREAD_ACP, 0, bufA, -1, buf, 39))
1178             lRet = ERROR_INVALID_DATA;
1179 #endif
1180         if (lRet != ERROR_SUCCESS)
1181             return lRet;
1182 
1183         if (!SUCCEEDED(::CLSIDFromString(buf, &guidValue)))
1184             return ERROR_INVALID_DATA;
1185 
1186         return lRet;
1187     }
1188 
1189     LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) throw()
1190     {
1191         ULONG size = sizeof(ULONGLONG);
1192         DWORD type = 0;
1193         LONG lRet = QueryValue(pszValueName, &type, &qwValue, &size);
1194 
1195         if (lRet == ERROR_SUCCESS && type != REG_QWORD)
1196             lRet = ERROR_INVALID_DATA;
1197 
1198         return lRet;
1199     }
1200 
1201     LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue,
1202                                ULONG* pnChars) throw()
1203     {
1204         ULONG size = (*pnChars) * sizeof(TCHAR);
1205         DWORD type;
1206         LONG lRet = QueryValue(pszValueName, &type, pszValue, &size);
1207 
1208         if (lRet == ERROR_SUCCESS && type != REG_MULTI_SZ)
1209             lRet = ERROR_INVALID_DATA;
1210 
1211         *pnChars = size / sizeof(TCHAR);
1212         return lRet;
1213     }
1214 
1215     LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw()
1216     {
1217         ATLASSERT(m_hKey);
1218         return ::RegSetValueEx(m_hKey, pszValueName, 0, dwType, (const BYTE*)pValue, nBytes);
1219     }
1220 
1221     LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) throw()
1222     {
1223         return SetValue(pszValueName, REG_DWORD, &dwValue, sizeof(DWORD));
1224     }
1225 
1226     LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) throw()
1227     {
1228         SIZE_T length;
1229         switch (dwType)
1230         {
1231         case REG_SZ:
1232         case REG_EXPAND_SZ:
1233             length = (_tcslen(pszValue) + 1) * sizeof(TCHAR);
1234             return SetValue(pszValueName, dwType, pszValue, length);
1235         case REG_MULTI_SZ:
1236             return SetMultiStringValue(pszValueName, pszValue);
1237         default:
1238             return ERROR_INVALID_DATA;
1239         }
1240     }
1241 
1242     LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) throw()
1243     {
1244         OLECHAR buf[40] = {0};
1245         ::StringFromGUID2(guidValue, buf, 39);
1246 #ifdef UNICODE
1247         return SetStringValue(pszValueName, buf);
1248 #else
1249         CHAR bufA[40] = {0};
1250         ::WideCharToMultiByte(CP_THREAD_ACP, 0, buf, -1, bufA, 40, NULL, NULL);
1251         return SetStringValue(pszValueName, bufA);
1252 #endif
1253     }
1254 
1255     LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) throw()
1256     {
1257         return SetValue(pszValueName, REG_BINARY, pValue, nBytes);
1258     }
1259 
1260     LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) throw()
1261     {
1262         ULONG dwSize = CRegKey::_GetMultiStringSize(pszValue);
1263         return SetValue(pszValueName, REG_MULTI_SZ, pszValue, dwSize);
1264     }
1265 
1266     LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) throw()
1267     {
1268         ULONG dwSize = sizeof(ULONGLONG);
1269         return SetValue(pszValueName, REG_QWORD, &qwValue, dwSize);
1270     }
1271 
1272     LONG NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter,
1273                               HANDLE hEvent, BOOL bAsync = TRUE) throw()
1274     {
1275         ATLASSERT(m_hKey);
1276         LONG ret = ::RegNotifyChangeKeyValue(m_hKey, bWatchSubtree,
1277                                              dwNotifyFilter, hEvent, bAsync);
1278         return ret;
1279     }
1280 
1281     LONG Flush() throw()
1282     {
1283         ATLASSERT(m_hKey);
1284         LONG ret = ::RegFlushKey(m_hKey);
1285         return ret;
1286     }
1287 
1288     static LONG WINAPI SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName,
1289                                 LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL)
1290     {
1291         CRegKey key;
1292         LONG lRet = key.Create(hKeyParent, lpszKeyName);
1293         if (lRet == ERROR_SUCCESS)
1294         {
1295             lRet = key.SetStringValue(lpszValueName, lpszValue);
1296         }
1297         return lRet;
1298     }
1299 
1300     LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue,
1301                      LPCTSTR lpszValueName = NULL) throw()
1302     {
1303         CRegKey key;
1304         LONG lRet = key.Create(m_hKey, lpszKeyName);
1305         if (lRet == ERROR_SUCCESS)
1306         {
1307             lRet = key.SetStringValue(lpszValueName, lpszValue);
1308         }
1309         return lRet;
1310     }
1311 
1312     LONG DeleteValue(LPCTSTR lpszValue) throw()
1313     {
1314         ATLASSERT(m_hKey);
1315         return ::RegDeleteValue(m_hKey, lpszValue);
1316     }
1317 
1318     LONG DeleteSubKey(LPCTSTR lpszSubKey) throw()
1319     {
1320         ATLASSERT(m_hKey);
1321         ATLASSERT(lpszSubKey);
1322         return ::RegDeleteKey(m_hKey, lpszSubKey);
1323     }
1324 
1325     LONG RecurseDeleteKey(LPCTSTR lpszKey) throw()
1326     {
1327         ATLASSERT(m_hKey);
1328         ATLASSERT(lpszKey);
1329         return CRegKey::_DoDeleteKeyTree(m_hKey, lpszKey);
1330     }
1331 
1332     LONG EnumKey(DWORD iIndex, LPTSTR pszName, LPDWORD pnNameLength,
1333                  FILETIME* pftLastWriteTime = NULL) throw()
1334     {
1335         ATLASSERT(m_hKey);
1336         LONG ret = ::RegEnumKeyEx(m_hKey, iIndex, pszName, pnNameLength, NULL,
1337                                   NULL, NULL, pftLastWriteTime);
1338         return ret;
1339     }
1340 
1341     LONG GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd,
1342                         LPDWORD pnBytes) throw()
1343     {
1344         ATLASSERT(m_hKey);
1345         LONG ret = ::RegGetKeySecurity(m_hKey, si, psd, pnBytes);
1346         return ret;
1347     }
1348 
1349     LONG SetKeySecurity(SECURITY_INFORMATION si,
1350                         PSECURITY_DESCRIPTOR psd) throw()
1351     {
1352         ATLASSERT(m_hKey);
1353         LONG ret = ::RegSetKeySecurity(m_hKey, si, psd);
1354         return ret;
1355     }
1356 
1357     operator HKEY() const throw()
1358     {
1359         return m_hKey;
1360     }
1361 
1362     CRegKey& operator=(CRegKey& key) throw()
1363     {
1364         if (m_hKey != key.m_hKey)
1365         {
1366             Close();
1367             Attach(key.Detach());
1368         }
1369         return *this;
1370     }
1371 
1372 protected:
1373     // get the total size of a multistring
1374     static ULONG _GetMultiStringSize(LPCTSTR pszz)
1375     {
1376         size_t count = 0;
1377         do
1378         {
1379             size_t len = _tcslen(pszz);
1380             count += len + 1;
1381             pszz += len + 1;
1382         } while (*pszz != TEXT('\0'));
1383         ++count;
1384         ATLASSERT(count * sizeof(TCHAR) <= ULONG_MAX);
1385         return (ULONG)count * sizeof(TCHAR);
1386     }
1387 
1388     // delete key recursively
1389     static LONG _DoDeleteKeyTree(HKEY hParentKey, LPCTSTR lpszKey)
1390     {
1391         ATLASSERT(hParentKey);
1392         ATLASSERT(lpszKey);
1393 
1394         // open the key
1395         CRegKey key;
1396         LONG ret = key.Open(hParentKey, lpszKey);
1397         if (ret != ERROR_SUCCESS)
1398         {
1399             return ret;     // failure
1400         }
1401 
1402         // get the longest length of subkey names
1403         DWORD NameMax;
1404         ret = ::RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &NameMax, NULL,
1405                                 NULL, NULL, NULL, NULL, NULL);
1406         if (ret != ERROR_SUCCESS)
1407         {
1408             return ret;     // failure
1409         }
1410         ++NameMax;  // for NUL
1411 
1412         // allocate the string buffer for names if necessary
1413         TCHAR szNameBuf[MAX_PATH], *pszName;
1414         if (NameMax > MAX_PATH)
1415         {
1416             pszName = (TCHAR *)malloc(NameMax * sizeof(TCHAR));
1417             ATLASSERT(pszName);
1418             if (pszName == NULL)
1419             {
1420                 return ERROR_OUTOFMEMORY;   // failure
1421             }
1422         }
1423         else
1424         {
1425             NameMax = MAX_PATH;
1426             pszName = szNameBuf;
1427         }
1428 
1429         // enumerate every subkey and delete
1430         for (;;)
1431         {
1432             DWORD Count = NameMax;
1433             ret = key.EnumKey(0, pszName, &Count);
1434             if (ret != ERROR_SUCCESS)
1435             {
1436                 if (ret == ERROR_NO_MORE_ITEMS)
1437                     ret = ERROR_SUCCESS;
1438                 break;
1439             }
1440 
1441             ret = CRegKey::_DoDeleteKeyTree(key, pszName);
1442             if (ret != ERROR_SUCCESS)
1443                 break;
1444         }
1445 
1446         // close key
1447         key.Close();
1448 
1449         // delete the subkey
1450         if (ret == ERROR_SUCCESS)
1451             ret = ::RegDeleteKey(hParentKey, lpszKey);
1452 
1453         // delete the buffer if any
1454         if (pszName != szNameBuf)
1455             free(pszName);
1456 
1457         return ret;
1458     }
1459 };
1460 
1461 template<class T>
1462 class CComHeapPtr : public CHeapPtr<T, CComAllocator>
1463 {
1464 public:
1465     CComHeapPtr()
1466     {
1467     }
1468 
1469     explicit CComHeapPtr(T *lp) :
1470         CHeapPtr<T, CComAllocator>(lp)
1471     {
1472     }
1473 };
1474 
1475 
1476 inline HRESULT __stdcall AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID &iid, LPDWORD pdw)
1477 {
1478     CComPtr<IConnectionPointContainer>        container;
1479     CComPtr<IConnectionPoint>                connectionPoint;
1480     HRESULT                                    hResult;
1481 
1482     if (pUnkCP == NULL)
1483         return E_INVALIDARG;
1484     hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
1485     if (FAILED(hResult))
1486         return hResult;
1487     hResult = container->FindConnectionPoint(iid, &connectionPoint);
1488     if (FAILED(hResult))
1489         return hResult;
1490     return connectionPoint->Advise(pUnk, pdw);
1491 }
1492 
1493 inline HRESULT __stdcall AtlUnadvise(IUnknown *pUnkCP, const IID &iid, DWORD dw)
1494 {
1495     CComPtr<IConnectionPointContainer>        container;
1496     CComPtr<IConnectionPoint>                connectionPoint;
1497     HRESULT                                    hResult;
1498 
1499     if (pUnkCP == NULL)
1500         return E_INVALIDARG;
1501     hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
1502     if (FAILED(hResult))
1503         return hResult;
1504     hResult = container->FindConnectionPoint(iid, &connectionPoint);
1505     if (FAILED(hResult))
1506         return hResult;
1507     return connectionPoint->Unadvise(dw);
1508 }
1509 
1510 inline HRESULT __stdcall AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject)
1511 {
1512     int i;
1513     IUnknown *resultInterface;
1514     HRESULT hResult;
1515 
1516     ATLASSERT(pThis != NULL && pEntries != NULL);
1517     if (pThis == NULL || pEntries == NULL)
1518         return E_INVALIDARG;
1519     ATLASSERT(ppvObject != NULL);
1520     if (ppvObject == NULL)
1521         return E_POINTER;
1522 
1523     if (InlineIsEqualUnknown(iid))
1524     {
1525         resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[0].dw);
1526         *ppvObject = resultInterface;
1527         resultInterface->AddRef();
1528         return S_OK;
1529     }
1530 
1531     i = 0;
1532     while (pEntries[i].pFunc != 0)
1533     {
1534         if (pEntries[i].piid == NULL || InlineIsEqualGUID(iid, *pEntries[i].piid))
1535         {
1536             if (pEntries[i].pFunc == reinterpret_cast<_ATL_CREATORARGFUNC *>(1))
1537             {
1538                 ATLASSERT(pEntries[i].piid != NULL);
1539                 resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[i].dw);
1540                 *ppvObject = resultInterface;
1541                 resultInterface->AddRef();
1542                 return S_OK;
1543             }
1544             else
1545             {
1546                 hResult = pEntries[i].pFunc(pThis, iid, ppvObject, 0);
1547                 if (hResult == S_OK)
1548                     return hResult;
1549                 if (FAILED(hResult) && pEntries[i].piid != NULL)
1550                     break;
1551             }
1552         }
1553         i++;
1554     }
1555     *ppvObject = NULL;
1556     return E_NOINTERFACE;
1557 }
1558 
1559 inline HRESULT __stdcall AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule)
1560 {
1561     if (pWinModule == NULL)
1562         return E_INVALIDARG;
1563     pWinModule->m_pCreateWndList = NULL;
1564     return pWinModule->m_csWindowCreate.Init();
1565 }
1566 
1567 inline HRESULT __stdcall AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst)
1568 {
1569     if (pWinModule == NULL)
1570         return E_INVALIDARG;
1571     pWinModule->m_csWindowCreate.Term();
1572     return S_OK;
1573 }
1574 
1575 inline void __stdcall AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject)
1576 {
1577     CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true);
1578 
1579     ATLASSERT(pWinModule != NULL);
1580     ATLASSERT(pObject != NULL);
1581 
1582     pData->m_pThis = pObject;
1583     pData->m_dwThreadID = ::GetCurrentThreadId();
1584     pData->m_pNext = pWinModule->m_pCreateWndList;
1585     pWinModule->m_pCreateWndList = pData;
1586 }
1587 
1588 inline void *__stdcall AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule)
1589 {
1590     CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true);
1591     void *result;
1592     _AtlCreateWndData *currentEntry;
1593     _AtlCreateWndData **previousLink;
1594     DWORD threadID;
1595 
1596     ATLASSERT(pWinModule != NULL);
1597 
1598     result = NULL;
1599     threadID = GetCurrentThreadId();
1600     currentEntry = pWinModule->m_pCreateWndList;
1601     previousLink = &pWinModule->m_pCreateWndList;
1602     while (currentEntry != NULL)
1603     {
1604         if (currentEntry->m_dwThreadID == threadID)
1605         {
1606             *previousLink = currentEntry->m_pNext;
1607             result = currentEntry->m_pThis;
1608             break;
1609         }
1610         previousLink = &currentEntry->m_pNext;
1611         currentEntry = currentEntry->m_pNext;
1612     }
1613     return result;
1614 }
1615 
1616 // Adapted from dll/win32/atl/atl.c
1617 inline HRESULT WINAPI AtlLoadTypeLib(HINSTANCE inst, LPCOLESTR lpszIndex,
1618         BSTR *pbstrPath, ITypeLib **ppTypeLib)
1619 {
1620     size_t index_len = lpszIndex ? wcslen(lpszIndex) : 0;
1621     CComHeapPtr<WCHAR> path;
1622     path.Allocate(MAX_PATH + index_len + wcslen(L".tlb"));
1623 
1624     if (!path)
1625         return E_OUTOFMEMORY;
1626 
1627     size_t path_len = GetModuleFileNameW(inst, path, MAX_PATH);
1628     if (!path_len)
1629         return HRESULT_FROM_WIN32(GetLastError());
1630 
1631     if (index_len)
1632         wcscat(path, lpszIndex);
1633 
1634     CComPtr<ITypeLib> typelib;
1635     HRESULT hResult = LoadTypeLib(path, &typelib);
1636     if (FAILED(hResult))
1637     {
1638         WCHAR *ptr;
1639         for (ptr = path+path_len-1; ptr > path && *ptr != '\\' && *ptr != '.'; ptr--)
1640             ;
1641         if (*ptr != '.')
1642             ptr = (WCHAR*)path + path_len;
1643         wcscpy(ptr, L".tlb");
1644 
1645         hResult = LoadTypeLib(path, &typelib);
1646     }
1647 
1648     if (SUCCEEDED(hResult))
1649     {
1650         *pbstrPath = SysAllocString(path);
1651         if (!*pbstrPath)
1652         {
1653             typelib.Release();
1654             hResult = E_OUTOFMEMORY;
1655         }
1656     }
1657 
1658     if (FAILED(hResult))
1659         return hResult;
1660 
1661     *ppTypeLib = typelib.Detach();
1662     return S_OK;
1663 }
1664 
1665 // Adapted from dll/win32/atl/atl.c
1666 inline HRESULT WINAPI AtlRegisterTypeLib(HINSTANCE inst, const WCHAR *index)
1667 {
1668     CComBSTR path;
1669     CComPtr<ITypeLib> typelib;
1670     HRESULT hResult = AtlLoadTypeLib(inst, index, &path, &typelib);
1671     if (FAILED(hResult))
1672         return hResult;
1673 
1674     return RegisterTypeLib(typelib, path, NULL); /* FIXME: pass help directory */
1675 }
1676 
1677 // Adapted from dll/win32/atl/atl.c
1678 inline HRESULT WINAPI AtlRegisterClassCategoriesHelper(REFCLSID clsid, const _ATL_CATMAP_ENTRY *catmap, BOOL reg)
1679 {
1680     if (!catmap)
1681         return S_OK;
1682 
1683     CComPtr<ICatRegister> catreg;
1684 
1685     HRESULT hResult = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&catreg);
1686     if (FAILED(hResult))
1687         return hResult;
1688 
1689     for (const _ATL_CATMAP_ENTRY *iter = catmap; iter->iType != _ATL_CATMAP_ENTRY_END; iter++)
1690     {
1691         CATID catid = *iter->pcatid;
1692 
1693         if (iter->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED)
1694         {
1695             if (reg)
1696                 hResult = catreg->RegisterClassImplCategories(clsid, 1, &catid);
1697             else
1698                 hResult = catreg->UnRegisterClassImplCategories(clsid, 1, &catid);
1699         }
1700         else
1701         {
1702             if (reg)
1703                 hResult = catreg->RegisterClassReqCategories(clsid, 1, &catid);
1704             else
1705                 hResult = catreg->UnRegisterClassReqCategories(clsid, 1, &catid);
1706         }
1707         if (FAILED(hResult))
1708             return hResult;
1709     }
1710 
1711     if (!reg)
1712     {
1713         WCHAR reg_path[256] = L"CLSID\\";
1714 
1715         StringFromGUID2(clsid, reg_path + wcslen(reg_path), 64);
1716         wcscat(reg_path, L"\\");
1717         WCHAR* ptr = reg_path + wcslen(reg_path);
1718 
1719         wcscpy(ptr, L"Implemented Categories");
1720         RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
1721 
1722         wcscpy(ptr, L"Required Categories");
1723         RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
1724     }
1725 
1726     return hResult;
1727 }
1728 
1729 
1730 // Adapted from dll/win32/atl80/atl80.c
1731 inline HRESULT __stdcall AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid)
1732 {
1733     HRESULT hResult = S_OK;
1734 
1735     for (_ATL_OBJMAP_ENTRY ** iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++)
1736     {
1737         if (!*iter)
1738             continue;
1739         _ATL_OBJMAP_ENTRY* entry = *iter;
1740         if (clsid && !IsEqualCLSID(*entry->pclsid, *clsid))
1741             continue;
1742 
1743         hResult = entry->pfnUpdateRegistry(TRUE);
1744         if (FAILED(hResult))
1745             return hResult;
1746 
1747         const _ATL_CATMAP_ENTRY *catmap = entry->pfnGetCategoryMap();
1748         if (catmap)
1749         {
1750             hResult = AtlRegisterClassCategoriesHelper(*entry->pclsid, catmap, TRUE);
1751             if (FAILED(hResult))
1752                 return hResult;
1753         }
1754     }
1755 
1756     if (bRegTypeLib)
1757     {
1758         hResult = AtlRegisterTypeLib(mod->m_hInstTypeLib, NULL);
1759     }
1760 
1761     return hResult;
1762 }
1763 
1764 // Adapted from dll/win32/atl/atl.c
1765 inline HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bUnRegTypeLib, const CLSID *clsid)
1766 {
1767     HRESULT hResult = S_OK;
1768 
1769     for (_ATL_OBJMAP_ENTRY **iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++)
1770     {
1771         if (!*iter)
1772             continue;
1773         _ATL_OBJMAP_ENTRY* entry = *iter;
1774         if (clsid && !IsEqualCLSID(*entry->pclsid, *clsid))
1775             continue;
1776 
1777         const _ATL_CATMAP_ENTRY *catmap = entry->pfnGetCategoryMap();
1778         if (catmap)
1779         {
1780             hResult = AtlRegisterClassCategoriesHelper(*entry->pclsid, catmap, FALSE);
1781             if (FAILED(hResult))
1782                 return hResult;
1783         }
1784 
1785         hResult = entry->pfnUpdateRegistry(FALSE);
1786         if (FAILED(hResult))
1787             return hResult;
1788     }
1789 
1790     if (bUnRegTypeLib)
1791     {
1792         CComPtr<ITypeLib> typelib;
1793         TLIBATTR *attr;
1794         CComBSTR path;
1795 
1796         hResult = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib);
1797         if (FAILED(hResult))
1798             return hResult;
1799 
1800         hResult = typelib->GetLibAttr(&attr);
1801         if (SUCCEEDED(hResult))
1802         {
1803             hResult = UnRegisterTypeLib(attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind);
1804             typelib->ReleaseTLibAttr(attr);
1805         }
1806     }
1807 
1808     return hResult;
1809 }
1810 
1811 
1812 // Adapted from dll/win32/atl/atl.c
1813 inline HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags)
1814 {
1815     _ATL_OBJMAP_ENTRY **iter;
1816     IUnknown* unk = NULL;
1817     HRESULT hr;
1818 
1819     if (!module)
1820         return E_INVALIDARG;
1821 
1822     for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++)
1823     {
1824         if (!(*iter)->pfnGetClassObject)
1825             continue;
1826 
1827         hr = (*iter)->pfnGetClassObject((void*)(*iter)->pfnCreateInstance, IID_IUnknown, (void**)&unk);
1828         if (FAILED(hr))
1829             return hr;
1830 
1831         hr = CoRegisterClassObject(*(*iter)->pclsid, unk, context, flags, &(*iter)->dwRegister);
1832         unk->Release();
1833         if (FAILED(hr))
1834             return hr;
1835     }
1836 
1837     return S_OK;
1838 }
1839 
1840 
1841 // Adapted from dll/win32/atl/atl.c
1842 inline HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module)
1843 {
1844     _ATL_OBJMAP_ENTRY **iter;
1845     HRESULT hr;
1846 
1847     if (!module)
1848         return E_INVALIDARG;
1849 
1850     for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++)
1851     {
1852         hr = CoRevokeClassObject((*iter)->dwRegister);
1853         if (FAILED(hr))
1854             return hr;
1855     }
1856 
1857     return S_OK;
1858 }
1859 
1860 }; // namespace ATL
1861 
1862 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE
1863 using namespace ATL;
1864 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE
1865