[ATL]
[reactos.git] / reactos / 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
26 #ifdef _MSC_VER
27 // It is common to use this in ATL constructors. They only store this for later use, so the usage is safe.
28 #pragma warning(disable:4355)
29 #endif
30
31 #ifndef _ATL_PACKING
32 #define _ATL_PACKING 8
33 #endif
34
35 #ifndef _ATL_FREE_THREADED
36 #ifndef _ATL_APARTMENT_THREADED
37 #ifndef _ATL_SINGLE_THREADED
38 #define _ATL_FREE_THREADED
39 #endif
40 #endif
41 #endif
42
43 #ifndef ATLTRY
44 #define ATLTRY(x) x;
45 #endif
46
47 #ifdef _ATL_DISABLE_NO_VTABLE
48 #define ATL_NO_VTABLE
49 #else
50 #define ATL_NO_VTABLE __declspec(novtable)
51 #endif
52
53 #define offsetofclass(base, derived) (reinterpret_cast<DWORD_PTR>(static_cast<base *>(reinterpret_cast<derived *>(_ATL_PACKING))) - _ATL_PACKING)
54
55 namespace ATL
56 {
57
58 class CAtlModule;
59 class CComModule;
60 class CAtlComModule;
61 __declspec(selectany) CAtlModule *_pAtlModule = NULL;
62 __declspec(selectany) CComModule *_pModule = NULL;
63 extern CAtlComModule _AtlComModule;
64
65 typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void *pv, REFIID riid, LPVOID *ppv);
66 typedef LPCTSTR (WINAPI _ATL_DESCRIPTIONFUNC)();
67 typedef const struct _ATL_CATMAP_ENTRY * (_ATL_CATMAPFUNC)();
68
69 struct _ATL_OBJMAP_ENTRY30
70 {
71 const CLSID *pclsid;
72 HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);
73 _ATL_CREATORFUNC *pfnGetClassObject;
74 _ATL_CREATORFUNC *pfnCreateInstance;
75 IUnknown *pCF;
76 DWORD dwRegister;
77 _ATL_DESCRIPTIONFUNC *pfnGetObjectDescription;
78 _ATL_CATMAPFUNC *pfnGetCategoryMap;
79 void (WINAPI *pfnObjectMain)(bool bStarting);
80
81 HRESULT WINAPI RevokeClassObject()
82 {
83 if (dwRegister == 0)
84 return S_OK;
85 return CoRevokeClassObject(dwRegister);
86 }
87
88 HRESULT WINAPI RegisterClassObject(DWORD dwClsContext, DWORD dwFlags)
89 {
90 IUnknown *p;
91 HRESULT hResult;
92
93 p = NULL;
94 if (pfnGetClassObject == NULL)
95 return S_OK;
96
97 hResult = pfnGetClassObject(reinterpret_cast<LPVOID *>(pfnCreateInstance), IID_IUnknown, reinterpret_cast<LPVOID *>(&p));
98 if (SUCCEEDED(hResult))
99 hResult = CoRegisterClassObject(*pclsid, p, dwClsContext, dwFlags, &dwRegister);
100
101 if (p != NULL)
102 p->Release();
103
104 return hResult;
105 }
106 };
107
108 typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY;
109
110 typedef void (__stdcall _ATL_TERMFUNC)(DWORD_PTR dw);
111
112 struct _ATL_TERMFUNC_ELEM
113 {
114 _ATL_TERMFUNC *pFunc;
115 DWORD_PTR dw;
116 _ATL_TERMFUNC_ELEM *pNext;
117 };
118
119 struct _ATL_MODULE70
120 {
121 UINT cbSize;
122 LONG m_nLockCnt;
123 _ATL_TERMFUNC_ELEM *m_pTermFuncs;
124 CComCriticalSection m_csStaticDataInitAndTypeInfo;
125 };
126 typedef _ATL_MODULE70 _ATL_MODULE;
127
128 typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void *pv, REFIID riid, LPVOID *ppv, DWORD_PTR dw);
129
130 #define _ATL_SIMPLEMAPENTRY ((ATL::_ATL_CREATORARGFUNC *)1)
131
132 struct _ATL_INTMAP_ENTRY
133 {
134 const IID *piid;
135 DWORD_PTR dw;
136 _ATL_CREATORARGFUNC *pFunc;
137 };
138
139 struct _AtlCreateWndData
140 {
141 void *m_pThis;
142 DWORD m_dwThreadID;
143 _AtlCreateWndData *m_pNext;
144 };
145
146 struct _ATL_COM_MODULE70
147 {
148 UINT cbSize;
149 HINSTANCE m_hInstTypeLib;
150 _ATL_OBJMAP_ENTRY **m_ppAutoObjMapFirst;
151 _ATL_OBJMAP_ENTRY **m_ppAutoObjMapLast;
152 CComCriticalSection m_csObjMap;
153 };
154 typedef _ATL_COM_MODULE70 _ATL_COM_MODULE;
155
156 struct _ATL_WIN_MODULE70
157 {
158 UINT cbSize;
159 CComCriticalSection m_csWindowCreate;
160 _AtlCreateWndData *m_pCreateWndList;
161 #ifdef NOTYET
162 CSimpleArray<ATOM> m_rgWindowClassAtoms;
163 #endif
164 };
165 typedef _ATL_WIN_MODULE70 _ATL_WIN_MODULE;
166
167 struct _ATL_REGMAP_ENTRY
168 {
169 LPCOLESTR szKey;
170 LPCOLESTR szData;
171 };
172
173 HRESULT __stdcall AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule);
174 HRESULT __stdcall AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst);
175 HRESULT __stdcall AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject);
176 void __stdcall AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject);
177 void *__stdcall AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule);
178 HRESULT __stdcall AtlComModuleGetClassObject(_ATL_COM_MODULE *pComModule, REFCLSID rclsid, REFIID riid, LPVOID *ppv);
179
180 template<class TLock>
181 class CComCritSecLock
182 {
183 private:
184 bool m_bLocked;
185 TLock &m_cs;
186 public:
187 CComCritSecLock(TLock &cs, bool bInitialLock = true) : m_cs(cs)
188 {
189 HRESULT hResult;
190
191 m_bLocked = false;
192 if (bInitialLock)
193 {
194 hResult = Lock();
195 if (FAILED(hResult))
196 {
197 ATLASSERT(false);
198 }
199 }
200 }
201
202 ~CComCritSecLock()
203 {
204 if (m_bLocked)
205 Unlock();
206 }
207
208 HRESULT Lock()
209 {
210 HRESULT hResult;
211
212 ATLASSERT(!m_bLocked);
213 hResult = m_cs.Lock();
214 if (FAILED(hResult))
215 return hResult;
216 m_bLocked = true;
217
218 return S_OK;
219 }
220
221 void Unlock()
222 {
223 HRESULT hResult;
224
225 ATLASSERT(m_bLocked);
226 hResult = m_cs.Unlock();
227 if (FAILED(hResult))
228 {
229 ATLASSERT(false);
230 }
231 m_bLocked = false;
232 }
233 };
234
235 inline BOOL WINAPI InlineIsEqualUnknown(REFGUID rguid1)
236 {
237 return (
238 ((unsigned long *)&rguid1)[0] == 0 &&
239 ((unsigned long *)&rguid1)[1] == 0 &&
240 ((unsigned long *)&rguid1)[2] == 0x000000C0 &&
241 ((unsigned long *)&rguid1)[3] == 0x46000000);
242 }
243
244 class CComMultiThreadModelNoCS
245 {
246 public:
247 typedef CComFakeCriticalSection AutoCriticalSection;
248 typedef CComFakeCriticalSection CriticalSection;
249 typedef CComMultiThreadModelNoCS ThreadModelNoCS;
250 typedef CComFakeCriticalSection AutoDeleteCriticalSection;
251
252 static ULONG WINAPI Increment(LPLONG p)
253 {
254 return InterlockedIncrement(p);
255 }
256
257 static ULONG WINAPI Decrement(LPLONG p)
258 {
259 return InterlockedDecrement(p);
260 }
261 };
262
263 class CComMultiThreadModel
264 {
265 public:
266 typedef CComAutoCriticalSection AutoCriticalSection;
267 typedef CComCriticalSection CriticalSection;
268 typedef CComMultiThreadModelNoCS ThreadModelNoCS;
269 typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection;
270
271 static ULONG WINAPI Increment(LPLONG p)
272 {
273 return InterlockedIncrement(p);
274 }
275
276 static ULONG WINAPI Decrement(LPLONG p)
277 {
278 return InterlockedDecrement(p);
279 }
280 };
281
282 class CComSingleThreadModel
283 {
284 public:
285 typedef CComFakeCriticalSection AutoCriticalSection;
286 typedef CComFakeCriticalSection CriticalSection;
287 typedef CComSingleThreadModel ThreadModelNoCS;
288 typedef CComFakeCriticalSection AutoDeleteCriticalSection;
289
290 static ULONG WINAPI Increment(LPLONG p)
291 {
292 return ++*p;
293 }
294
295 static ULONG WINAPI Decrement(LPLONG p)
296 {
297 return --*p;
298 }
299 };
300
301 #if defined(_ATL_FREE_THREADED)
302
303 typedef CComMultiThreadModel CComObjectThreadModel;
304 typedef CComMultiThreadModel CComGlobalsThreadModel;
305
306 #elif defined(_ATL_APARTMENT_THREADED)
307
308 typedef CComSingleThreadModel CComObjectThreadModel;
309 typedef CComMultiThreadModel CComGlobalsThreadModel;
310
311 #elif defined(_ATL_SINGLE_THREADED)
312
313 typedef CComSingleThreadModel CComObjectThreadModel;
314 typedef CComSingleThreadModel CComGlobalsThreadModel;
315
316 #else
317 #error No threading model
318 #endif
319
320 class CAtlModule : public _ATL_MODULE
321 {
322 protected:
323 static GUID m_libid;
324 public:
325 CAtlModule()
326 {
327 ATLASSERT(_pAtlModule == NULL);
328 _pAtlModule = this;
329 cbSize = sizeof(_ATL_MODULE);
330 m_nLockCnt = 0;
331 }
332
333 virtual LONG GetLockCount()
334 {
335 return m_nLockCnt;
336 }
337
338 virtual LONG Lock()
339 {
340 return CComGlobalsThreadModel::Increment(&m_nLockCnt);
341 }
342
343 virtual LONG Unlock()
344 {
345 return CComGlobalsThreadModel::Decrement(&m_nLockCnt);
346 }
347
348 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* /*pRegistrar*/) = 0;
349
350 HRESULT WINAPI UpdateRegistryFromResource(LPCTSTR lpszRes, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries = NULL)
351 {
352 CRegObject registrar;
353 WCHAR modulePath[MAX_PATH];
354 HRESULT hResult;
355 PCWSTR lpwszRes;
356
357 hResult = CommonInitRegistrar(registrar, modulePath, sizeof(modulePath) / sizeof(modulePath[0]), pMapEntries);
358 if (FAILED(hResult))
359 return hResult;
360 #ifdef UNICODE
361 lpwszRes = lpszRes;
362 #else
363 /* FIXME: this is a bit of a hack, need to re-evaluate */
364 WCHAR resid[MAX_PATH];
365 MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, resid, MAX_PATH);
366 lpwszRes = resid;
367 #endif
368 if (bRegister != FALSE)
369 hResult = registrar.ResourceRegisterSz(modulePath, lpwszRes, L"REGISTRY");
370 else
371 hResult = registrar.ResourceUnregisterSz(modulePath, lpwszRes, L"REGISTRY");
372
373 return hResult;
374 }
375
376 HRESULT WINAPI UpdateRegistryFromResource(UINT nResID, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries = NULL)
377 {
378 CRegObject registrar;
379 WCHAR modulePath[MAX_PATH];
380 HRESULT hResult;
381
382 hResult = CommonInitRegistrar(registrar, modulePath, sizeof(modulePath) / sizeof(modulePath[0]), pMapEntries);
383 if (FAILED(hResult))
384 return hResult;
385
386 if (bRegister != FALSE)
387 hResult = registrar.ResourceRegister(modulePath, nResID, L"REGISTRY");
388 else
389 hResult = registrar.ResourceUnregister(modulePath, nResID, L"REGISTRY");
390
391 return hResult;
392 }
393
394 private:
395 HRESULT CommonInitRegistrar(CRegObject &registrar, WCHAR *modulePath, DWORD modulePathCount, struct _ATL_REGMAP_ENTRY *pMapEntries)
396 {
397 HINSTANCE hInstance;
398 DWORD dwFLen;
399 HRESULT hResult;
400
401 hInstance = _AtlBaseModule.GetModuleInstance();
402 dwFLen = GetModuleFileNameW(hInstance, modulePath, modulePathCount);
403 if (dwFLen == modulePathCount)
404 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
405 else if (dwFLen == 0)
406 return HRESULT_FROM_WIN32(GetLastError());
407
408 if (pMapEntries != NULL)
409 {
410 while (pMapEntries->szKey != NULL)
411 {
412 ATLASSERT(pMapEntries->szData != NULL);
413 hResult = registrar.AddReplacement(pMapEntries->szKey, pMapEntries->szData);
414 if (FAILED(hResult))
415 return hResult;
416 pMapEntries++;
417 }
418 }
419
420 hResult = AddCommonRGSReplacements(&registrar);
421 if (FAILED(hResult))
422 return hResult;
423
424 hResult = registrar.AddReplacement(L"Module", modulePath);
425 if (FAILED(hResult))
426 return hResult;
427
428 hResult = registrar.AddReplacement(L"Module_Raw", modulePath);
429 if (FAILED(hResult))
430 return hResult;
431
432 return S_OK;
433 }
434 };
435
436 __declspec(selectany) GUID CAtlModule::m_libid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} };
437
438 template <class T>
439 class CAtlModuleT : public CAtlModule
440 {
441 public:
442
443 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase *pRegistrar)
444 {
445 return pRegistrar->AddReplacement(L"APPID", T::GetAppId());
446 }
447
448 static LPCOLESTR GetAppId()
449 {
450 return L"";
451 }
452 };
453
454 class CAtlComModule : public _ATL_COM_MODULE
455 {
456 public:
457 CAtlComModule()
458 {
459 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)this, &m_hInstTypeLib);
460 m_ppAutoObjMapFirst = NULL;
461 m_ppAutoObjMapLast = NULL;
462 if (FAILED(m_csObjMap.Init()))
463 {
464 ATLASSERT(0);
465 CAtlBaseModule::m_bInitFailed = true;
466 return;
467 }
468 cbSize = sizeof(_ATL_COM_MODULE);
469 }
470
471 ~CAtlComModule()
472 {
473 Term();
474 }
475
476 void Term()
477 {
478 if (cbSize != 0)
479 {
480 ATLASSERT(m_ppAutoObjMapFirst == NULL);
481 ATLASSERT(m_ppAutoObjMapLast == NULL);
482 m_csObjMap.Term();
483 cbSize = 0;
484 }
485 }
486 };
487
488 template <class T>
489 class CAtlDllModuleT : public CAtlModuleT<T>
490 {
491 public:
492 CAtlDllModuleT()
493 {
494 }
495
496 HRESULT DllCanUnloadNow()
497 {
498 T *pThis;
499
500 pThis = static_cast<T *>(this);
501 if (pThis->GetLockCount() == 0)
502 return S_OK;
503 return S_FALSE;
504 }
505
506 HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
507 {
508 T *pThis;
509
510 pThis = static_cast<T *>(this);
511 return pThis->GetClassObject(rclsid, riid, ppv);
512 }
513
514 HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE)
515 {
516 T *pThis;
517 HRESULT hResult;
518
519 pThis = static_cast<T *>(this);
520 hResult = pThis->RegisterServer(bRegTypeLib);
521 return hResult;
522 }
523
524 HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE)
525 {
526 T *pThis;
527 HRESULT hResult;
528
529 pThis = static_cast<T *>(this);
530 hResult = pThis->UnregisterServer(bUnRegTypeLib);
531 return hResult;
532 }
533
534 HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
535 {
536 return AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv);
537 }
538 };
539
540 class CComModule : public CAtlModuleT<CComModule>
541 {
542 public:
543 _ATL_OBJMAP_ENTRY *m_pObjMap;
544 public:
545 CComModule()
546 {
547 ATLASSERT(_pModule == NULL);
548 _pModule = this;
549 _pModule->m_pObjMap = NULL;
550 }
551
552 ~CComModule()
553 {
554 _pModule = NULL;
555 }
556
557 HRESULT Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE /* h */, const GUID *plibid)
558 {
559 _ATL_OBJMAP_ENTRY *objectMapEntry;
560
561 if (plibid != NULL)
562 m_libid = *plibid;
563
564 if (p != reinterpret_cast<_ATL_OBJMAP_ENTRY *>(-1))
565 {
566 m_pObjMap = p;
567 if (p != NULL)
568 {
569 objectMapEntry = p;
570 while (objectMapEntry->pclsid != NULL)
571 {
572 objectMapEntry->pfnObjectMain(true);
573 objectMapEntry++;
574 }
575 }
576 }
577 return S_OK;
578 }
579
580 void Term()
581 {
582 _ATL_OBJMAP_ENTRY *objectMapEntry;
583
584 if (m_pObjMap != NULL)
585 {
586 objectMapEntry = m_pObjMap;
587 while (objectMapEntry->pclsid != NULL)
588 {
589 if (objectMapEntry->pCF != NULL)
590 objectMapEntry->pCF->Release();
591 objectMapEntry->pCF = NULL;
592 objectMapEntry->pfnObjectMain(false);
593 objectMapEntry++;
594 }
595 }
596 }
597
598 HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
599 {
600 _ATL_OBJMAP_ENTRY *objectMapEntry;
601 HRESULT hResult;
602
603 ATLASSERT(ppv != NULL);
604 if (ppv == NULL)
605 return E_POINTER;
606 *ppv = NULL;
607 hResult = S_OK;
608 if (m_pObjMap != NULL)
609 {
610 objectMapEntry = m_pObjMap;
611 while (objectMapEntry->pclsid != NULL)
612 {
613 if (objectMapEntry->pfnGetClassObject != NULL && InlineIsEqualGUID(rclsid, *objectMapEntry->pclsid) != FALSE)
614 {
615 if (objectMapEntry->pCF == NULL)
616 {
617 CComCritSecLock<CComCriticalSection> lock(_AtlComModule.m_csObjMap, true);
618
619 if (objectMapEntry->pCF == NULL)
620 hResult = objectMapEntry->pfnGetClassObject(reinterpret_cast<void *>(objectMapEntry->pfnCreateInstance), IID_IUnknown, reinterpret_cast<LPVOID *>(&objectMapEntry->pCF));
621 }
622 if (objectMapEntry->pCF != NULL)
623 hResult = objectMapEntry->pCF->QueryInterface(riid, ppv);
624 break;
625 }
626 objectMapEntry++;
627 }
628 }
629 if (hResult == S_OK && *ppv == NULL)
630 {
631 // FIXME: call AtlComModuleGetClassObject
632 hResult = CLASS_E_CLASSNOTAVAILABLE;
633 }
634 return hResult;
635 }
636
637 HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL)
638 {
639 _ATL_OBJMAP_ENTRY *objectMapEntry;
640 HRESULT hResult;
641
642 hResult = S_OK;
643 objectMapEntry = m_pObjMap;
644 if (objectMapEntry != NULL)
645 {
646 while (objectMapEntry->pclsid != NULL)
647 {
648 if (pCLSID == NULL || IsEqualGUID(*pCLSID, *objectMapEntry->pclsid) != FALSE)
649 {
650 hResult = objectMapEntry->pfnUpdateRegistry(TRUE);
651 if (FAILED(hResult))
652 break;
653 }
654 objectMapEntry++;
655 }
656 }
657 return hResult;
658 }
659
660 HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL)
661 {
662 _ATL_OBJMAP_ENTRY *objectMapEntry;
663 HRESULT hResult;
664
665 hResult = S_OK;
666 objectMapEntry = m_pObjMap;
667 if (objectMapEntry != NULL)
668 {
669 while (objectMapEntry->pclsid != NULL)
670 {
671 if (pCLSID == NULL || IsEqualGUID(*pCLSID, *objectMapEntry->pclsid) != FALSE)
672 {
673 hResult = objectMapEntry->pfnUpdateRegistry(FALSE); //unregister
674 if (FAILED(hResult))
675 break;
676 }
677 objectMapEntry++;
678 }
679 }
680 return hResult;
681 }
682
683 HRESULT DllCanUnloadNow()
684 {
685 if (GetLockCount() == 0)
686 return S_OK;
687 return S_FALSE;
688 }
689
690 HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
691 {
692 return GetClassObject(rclsid, riid, ppv);
693 }
694
695 HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE)
696 {
697 return RegisterServer(bRegTypeLib);
698 }
699
700 HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE)
701 {
702 return UnregisterServer(bUnRegTypeLib);
703 }
704
705 };
706
707 class CAtlWinModule : public _ATL_WIN_MODULE
708 {
709 public:
710 CAtlWinModule()
711 {
712 HRESULT hResult;
713
714 hResult = AtlWinModuleInit(this);
715 if (FAILED(hResult))
716 {
717 CAtlBaseModule::m_bInitFailed = true;
718 ATLASSERT(0);
719 }
720 }
721
722 ~CAtlWinModule()
723 {
724 Term();
725 }
726
727 void Term()
728 {
729 AtlWinModuleTerm(this, _AtlBaseModule.GetModuleInstance());
730 }
731
732 void AddCreateWndData(_AtlCreateWndData *pData, void *pObject)
733 {
734 AtlWinModuleAddCreateWndData(this, pData, pObject);
735 }
736
737 void *ExtractCreateWndData()
738 {
739 return AtlWinModuleExtractCreateWndData(this);
740 }
741 };
742
743 extern CAtlWinModule _AtlWinModule;
744
745 template<class T>
746 class CComPtr
747 {
748 public:
749 T *p;
750 public:
751 CComPtr()
752 {
753 p = NULL;
754 }
755
756 CComPtr(T *lp)
757 {
758 p = lp;
759 if (p != NULL)
760 p->AddRef();
761 }
762
763 CComPtr(const CComPtr<T> &lp)
764 {
765 p = lp.p;
766 if (p != NULL)
767 p->AddRef();
768 }
769
770 ~CComPtr()
771 {
772 if (p != NULL)
773 p->Release();
774 }
775
776 T *operator = (T *lp)
777 {
778 if (p != NULL)
779 p->Release();
780 p = lp;
781 if (p != NULL)
782 p->AddRef();
783 return *this;
784 }
785
786 T *operator = (const CComPtr<T> &lp)
787 {
788 if (p != NULL)
789 p->Release();
790 p = lp.p;
791 if (p != NULL)
792 p->AddRef();
793 return *this;
794 }
795
796 void Release()
797 {
798 if (p != NULL)
799 {
800 p->Release();
801 p = NULL;
802 }
803 }
804
805 void Attach(T *lp)
806 {
807 if (p != NULL)
808 p->Release();
809 p = lp;
810 }
811
812 T *Detach()
813 {
814 T *saveP;
815
816 saveP = p;
817 p = NULL;
818 return saveP;
819 }
820
821 T **operator & ()
822 {
823 ATLASSERT(p == NULL);
824 return &p;
825 }
826
827 operator T * ()
828 {
829 return p;
830 }
831
832 T *operator -> ()
833 {
834 ATLASSERT(p != NULL);
835 return p;
836 }
837 };
838
839
840 // TODO: When someone needs it, make the allocator a template, so you can use it for both
841 // CoTask* allocations, and CRT-like allocations (malloc, realloc, free)
842 template<class T>
843 class CComHeapPtr
844 {
845 public:
846 CComHeapPtr() :
847 m_Data(NULL)
848 {
849 }
850
851 explicit CComHeapPtr(T *lp) :
852 m_Data(lp)
853 {
854 }
855
856 explicit CComHeapPtr(CComHeapPtr<T> &lp)
857 {
858 m_Data = lp.Detach();
859 }
860
861 ~CComHeapPtr()
862 {
863 Release();
864 }
865
866 T *operator = (CComHeapPtr<T> &lp)
867 {
868 if (lp.m_Data != m_Data)
869 Attach(lp.Detach());
870 return *this;
871 }
872
873 bool Allocate(size_t nElements = 1)
874 {
875 ATLASSERT(m_Data == NULL);
876 m_Data = static_cast<T*>(::CoTaskMemAlloc(nElements * sizeof(T)));
877 return m_Data != NULL;
878 }
879
880 bool Reallocate(_In_ size_t nElements)
881 {
882 T* newData = static_cast<T*>(::CoTaskMemRealloc(m_Data, nElements * sizeof(T)));
883 if (newData == NULL)
884 return false;
885 m_Data = newData;
886 return true;
887 }
888
889 void Release()
890 {
891 if (m_Data)
892 {
893 ::CoTaskMemFree(m_Data);
894 m_Data = NULL;
895 }
896 }
897
898 void Attach(T *lp)
899 {
900 Release();
901 m_Data = lp;
902 }
903
904 T *Detach()
905 {
906 T *saveP = m_Data;
907 m_Data = NULL;
908 return saveP;
909 }
910
911 T **operator &()
912 {
913 ATLASSERT(m_Data == NULL);
914 return &m_Data;
915 }
916
917 operator T* () const
918 {
919 return m_Data;
920 }
921
922 protected:
923 T *m_Data;
924 };
925
926
927 class CComBSTR
928 {
929 public:
930 BSTR m_str;
931 public:
932 CComBSTR() :
933 m_str(NULL)
934 {
935 }
936
937 CComBSTR(LPCOLESTR pSrc)
938 {
939 if (pSrc == NULL)
940 m_str = NULL;
941 else
942 m_str = ::SysAllocString(pSrc);
943 }
944
945 CComBSTR(int length)
946 {
947 if (length == 0)
948 m_str = NULL;
949 else
950 m_str = ::SysAllocStringLen(NULL, length);
951 }
952
953 CComBSTR(int length, LPCOLESTR pSrc)
954 {
955 if (length == 0)
956 m_str = NULL;
957 else
958 m_str = ::SysAllocStringLen(pSrc, length);
959 }
960
961 CComBSTR(PCSTR pSrc)
962 {
963 if (pSrc)
964 {
965 int len = MultiByteToWideChar(CP_THREAD_ACP, 0, pSrc, -1, NULL, 0);
966 m_str = ::SysAllocStringLen(NULL, len - 1);
967 if (m_str)
968 {
969 int res = MultiByteToWideChar(CP_THREAD_ACP, 0, pSrc, -1, m_str, len);
970 ATLASSERT(res == len);
971 if (res != len)
972 {
973 ::SysFreeString(m_str);
974 m_str = NULL;
975 }
976 }
977 }
978 else
979 {
980 m_str = NULL;
981 }
982 }
983
984 CComBSTR(const CComBSTR &other)
985 {
986 m_str = other.Copy();
987 }
988
989 CComBSTR(REFGUID guid)
990 {
991 OLECHAR szGuid[40];
992 ::StringFromGUID2(guid, szGuid, 40);
993 m_str = ::SysAllocString(szGuid);
994 }
995
996 ~CComBSTR()
997 {
998 ::SysFreeString(m_str);
999 m_str = NULL;
1000 }
1001
1002 operator BSTR () const
1003 {
1004 return m_str;
1005 }
1006
1007 BSTR *operator & ()
1008 {
1009 return &m_str;
1010 }
1011
1012 CComBSTR &operator = (const CComBSTR &other)
1013 {
1014 ::SysFreeString(m_str);
1015 m_str = other.Copy();
1016 return *this;
1017 }
1018
1019 BSTR Copy() const
1020 {
1021 if (!m_str)
1022 return NULL;
1023 return ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
1024 }
1025
1026 HRESULT CopyTo(BSTR *other) const
1027 {
1028 if (!other)
1029 return E_POINTER;
1030 *other = Copy();
1031 return S_OK;
1032 }
1033
1034 bool LoadString(HMODULE module, DWORD uID)
1035 {
1036 ::SysFreeString(m_str);
1037 m_str = NULL;
1038 const wchar_t *ptr = NULL;
1039 int len = ::LoadStringW(module, uID, (PWSTR)&ptr, 0);
1040 if (len)
1041 m_str = ::SysAllocStringLen(ptr, len);
1042 return m_str != NULL;
1043 }
1044
1045 unsigned int Length() const
1046 {
1047 return ::SysStringLen(m_str);
1048 }
1049
1050 unsigned int ByteLength() const
1051 {
1052 return ::SysStringByteLen(m_str);
1053 }
1054 };
1055
1056 class CComVariant : public tagVARIANT
1057 {
1058 public:
1059 CComVariant()
1060 {
1061 ::VariantInit(this);
1062 }
1063
1064 ~CComVariant()
1065 {
1066 Clear();
1067 }
1068
1069 HRESULT Clear()
1070 {
1071 return ::VariantClear(this);
1072 }
1073 };
1074
1075 inline HRESULT __stdcall AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID &iid, LPDWORD pdw)
1076 {
1077 CComPtr<IConnectionPointContainer> container;
1078 CComPtr<IConnectionPoint> connectionPoint;
1079 HRESULT hResult;
1080
1081 if (pUnkCP == NULL)
1082 return E_INVALIDARG;
1083 hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
1084 if (FAILED(hResult))
1085 return hResult;
1086 hResult = container->FindConnectionPoint(iid, &connectionPoint);
1087 if (FAILED(hResult))
1088 return hResult;
1089 return connectionPoint->Advise(pUnk, pdw);
1090 }
1091
1092 inline HRESULT __stdcall AtlUnadvise(IUnknown *pUnkCP, const IID &iid, DWORD dw)
1093 {
1094 CComPtr<IConnectionPointContainer> container;
1095 CComPtr<IConnectionPoint> connectionPoint;
1096 HRESULT hResult;
1097
1098 if (pUnkCP == NULL)
1099 return E_INVALIDARG;
1100 hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
1101 if (FAILED(hResult))
1102 return hResult;
1103 hResult = container->FindConnectionPoint(iid, &connectionPoint);
1104 if (FAILED(hResult))
1105 return hResult;
1106 return connectionPoint->Unadvise(dw);
1107 }
1108
1109 inline HRESULT __stdcall AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject)
1110 {
1111 int i;
1112 IUnknown *resultInterface;
1113 HRESULT hResult;
1114
1115 ATLASSERT(pThis != NULL && pEntries != NULL);
1116 if (pThis == NULL || pEntries == NULL)
1117 return E_INVALIDARG;
1118 ATLASSERT(ppvObject != NULL);
1119 if (ppvObject == NULL)
1120 return E_POINTER;
1121
1122 if (InlineIsEqualUnknown(iid))
1123 {
1124 resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[0].dw);
1125 *ppvObject = resultInterface;
1126 resultInterface->AddRef();
1127 return S_OK;
1128 }
1129
1130 i = 0;
1131 while (pEntries[i].pFunc != 0)
1132 {
1133 if (pEntries[i].piid == NULL || InlineIsEqualGUID(iid, *pEntries[i].piid))
1134 {
1135 if (pEntries[i].pFunc == reinterpret_cast<_ATL_CREATORARGFUNC *>(1))
1136 {
1137 ATLASSERT(pEntries[i].piid != NULL);
1138 resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[i].dw);
1139 *ppvObject = resultInterface;
1140 resultInterface->AddRef();
1141 return S_OK;
1142 }
1143 else
1144 {
1145 hResult = pEntries[i].pFunc(pThis, iid, ppvObject, 0);
1146 if (hResult == S_OK || (FAILED(hResult) && pEntries[i].piid != NULL))
1147 return hResult;
1148 }
1149 break;
1150 }
1151 i++;
1152 }
1153 *ppvObject = NULL;
1154 return E_NOINTERFACE;
1155 }
1156
1157 inline HRESULT __stdcall AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule)
1158 {
1159 if (pWinModule == NULL)
1160 return E_INVALIDARG;
1161 pWinModule->m_pCreateWndList = NULL;
1162 return pWinModule->m_csWindowCreate.Init();
1163 }
1164
1165 inline HRESULT __stdcall AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst)
1166 {
1167 if (pWinModule == NULL)
1168 return E_INVALIDARG;
1169 pWinModule->m_csWindowCreate.Term();
1170 return S_OK;
1171 }
1172
1173 inline void __stdcall AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject)
1174 {
1175 CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true);
1176
1177 ATLASSERT(pWinModule != NULL);
1178 ATLASSERT(pObject != NULL);
1179
1180 pData->m_pThis = pObject;
1181 pData->m_dwThreadID = ::GetCurrentThreadId();
1182 pData->m_pNext = pWinModule->m_pCreateWndList;
1183 pWinModule->m_pCreateWndList = pData;
1184 }
1185
1186 inline void *__stdcall AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule)
1187 {
1188 CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true);
1189 void *result;
1190 _AtlCreateWndData *currentEntry;
1191 _AtlCreateWndData **previousLink;
1192 DWORD threadID;
1193
1194 ATLASSERT(pWinModule != NULL);
1195
1196 result = NULL;
1197 threadID = GetCurrentThreadId();
1198 currentEntry = pWinModule->m_pCreateWndList;
1199 previousLink = &pWinModule->m_pCreateWndList;
1200 while (currentEntry != NULL)
1201 {
1202 if (currentEntry->m_dwThreadID == threadID)
1203 {
1204 *previousLink = currentEntry->m_pNext;
1205 result = currentEntry->m_pThis;
1206 break;
1207 }
1208 previousLink = &currentEntry->m_pNext;
1209 currentEntry = currentEntry->m_pNext;
1210 }
1211 return result;
1212 }
1213
1214 }; // namespace ATL
1215
1216 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE
1217 using namespace ATL;
1218 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE