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