[ATL][ATL_APITEST] Add CAtlList::InsertBefore/After + test
[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 "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