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