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