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