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