reactos/sdk/lib/atl/atlbase.h
Katayama Hirofumi MZ d955b9321b
[ATL] s/throw()/noexcept/ (#5799)
Mechanically replace throw() with noexcept.
2023-10-16 15:40:17 +09:00

1996 lines
51 KiB
C++

/*
* ReactOS ATL
*
* Copyright 2009 Andrew Hill <ash77@reactos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "atldef.h"
#include "atlcore.h"
#include "statreg.h"
#include "atlcomcli.h"
#include "atlalloc.h"
#include "atlexcept.h"
#include "atltrace.h"
#include "comcat.h"
#include "tchar.h"
#ifdef _MSC_VER
// It is common to use this in ATL constructors. They only store this for later use, so the usage is safe.
#pragma warning(disable:4355)
#endif
#ifndef ATLTRY
#define ATLTRY(x) x;
#endif
#ifdef _ATL_DISABLE_NO_VTABLE
#define ATL_NO_VTABLE
#else
#define ATL_NO_VTABLE __declspec(novtable)
#endif
#ifndef ATL_DEPRECATED
#define ATL_DEPRECATED __declspec(deprecated)
#endif
namespace ATL
{
class CAtlModule;
class CComModule;
class CAtlComModule;
__declspec(selectany) CAtlModule *_pAtlModule = NULL;
__declspec(selectany) CComModule *_pModule = NULL;
template <bool isDll, typename T> struct CAtlValidateModuleConfiguration
{
#if !defined(_WINDLL) && !defined(_USRDLL)
static_assert(!isDll, "_WINDLL or _USRDLL must be defined when 'CAtlDllModuleT<T>' is used");
#else
static_assert(isDll, "_WINDLL or _USRDLL must be defined when 'CAtlExeModuleT<T>' is used");
#endif
};
struct _ATL_CATMAP_ENTRY
{
int iType;
const GUID* pcatid;
};
#define _ATL_CATMAP_ENTRY_END 0
#define _ATL_CATMAP_ENTRY_IMPLEMENTED 1
#define _ATL_CATMAP_ENTRY_REQUIRED 2
typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void *pv, REFIID riid, LPVOID *ppv);
typedef LPCTSTR (WINAPI _ATL_DESCRIPTIONFUNC)();
typedef const struct _ATL_CATMAP_ENTRY * (_ATL_CATMAPFUNC)();
struct _ATL_OBJMAP_ENTRY30
{
const CLSID *pclsid;
HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);
_ATL_CREATORFUNC *pfnGetClassObject;
_ATL_CREATORFUNC *pfnCreateInstance;
IUnknown *pCF;
DWORD dwRegister;
_ATL_DESCRIPTIONFUNC *pfnGetObjectDescription;
_ATL_CATMAPFUNC *pfnGetCategoryMap;
void (WINAPI *pfnObjectMain)(bool bStarting);
HRESULT WINAPI RevokeClassObject()
{
if (dwRegister == 0)
return S_OK;
return CoRevokeClassObject(dwRegister);
}
HRESULT WINAPI RegisterClassObject(DWORD dwClsContext, DWORD dwFlags)
{
IUnknown *p;
HRESULT hResult;
p = NULL;
if (pfnGetClassObject == NULL)
return S_OK;
hResult = pfnGetClassObject(reinterpret_cast<LPVOID *>(pfnCreateInstance), IID_IUnknown, reinterpret_cast<LPVOID *>(&p));
if (SUCCEEDED(hResult))
hResult = CoRegisterClassObject(*pclsid, p, dwClsContext, dwFlags, &dwRegister);
if (p != NULL)
p->Release();
return hResult;
}
};
typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY;
typedef void (__stdcall _ATL_TERMFUNC)(DWORD_PTR dw);
struct _ATL_TERMFUNC_ELEM
{
_ATL_TERMFUNC *pFunc;
DWORD_PTR dw;
_ATL_TERMFUNC_ELEM *pNext;
};
struct _ATL_MODULE70
{
UINT cbSize;
LONG m_nLockCnt;
_ATL_TERMFUNC_ELEM *m_pTermFuncs;
CComCriticalSection m_csStaticDataInitAndTypeInfo;
};
typedef _ATL_MODULE70 _ATL_MODULE;
typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void *pv, REFIID riid, LPVOID *ppv, DWORD_PTR dw);
#define _ATL_SIMPLEMAPENTRY ((ATL::_ATL_CREATORARGFUNC *)1)
struct _ATL_INTMAP_ENTRY
{
const IID *piid;
DWORD_PTR dw;
_ATL_CREATORARGFUNC *pFunc;
};
struct _AtlCreateWndData
{
void *m_pThis;
DWORD m_dwThreadID;
_AtlCreateWndData *m_pNext;
};
struct _ATL_COM_MODULE70
{
UINT cbSize;
HINSTANCE m_hInstTypeLib;
_ATL_OBJMAP_ENTRY **m_ppAutoObjMapFirst;
_ATL_OBJMAP_ENTRY **m_ppAutoObjMapLast;
CComCriticalSection m_csObjMap;
};
typedef _ATL_COM_MODULE70 _ATL_COM_MODULE;
struct _ATL_WIN_MODULE70
{
UINT cbSize;
CComCriticalSection m_csWindowCreate;
_AtlCreateWndData *m_pCreateWndList;
#ifdef NOTYET
CSimpleArray<ATOM> m_rgWindowClassAtoms;
#endif
};
typedef _ATL_WIN_MODULE70 _ATL_WIN_MODULE;
// Auto object map
#if defined(_MSC_VER)
#pragma section("ATL$__a", read, write)
#pragma section("ATL$__z", read, write)
#pragma section("ATL$__m", read, write)
#define _ATLALLOC(x) __declspec(allocate(x))
#if defined(_M_IX86)
#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:___pobjMap_" #class));
#elif defined(_M_IA64) || defined(_M_AMD64) || (_M_ARM) || defined(_M_ARM64)
#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pobjMap_" #class));
#else
#error Your platform is not supported.
#endif
#elif defined(__GNUC__)
// GCC completely ignores __attribute__((unused)) on the __pobjMap_ pointer, so we pass it to a function that is not allowed to be optimized....
static int __attribute__((optimize("O0"), unused)) hack_for_gcc(const _ATL_OBJMAP_ENTRY * const *)
{
return 1;
}
#define _ATLALLOC(x) __attribute__((section(x)))
#define OBJECT_ENTRY_PRAGMA(class) static int __pobjMap_hack_##class = hack_for_gcc(&__pobjMap_##class);
#else
#error Your compiler is not supported.
#endif
extern "C"
{
__declspec(selectany) _ATLALLOC("ATL$__a") _ATL_OBJMAP_ENTRY *__pobjMapEntryFirst = NULL;
__declspec(selectany) _ATLALLOC("ATL$__z") _ATL_OBJMAP_ENTRY *__pobjMapEntryLast = NULL;
}
struct _ATL_REGMAP_ENTRY
{
LPCOLESTR szKey;
LPCOLESTR szData;
};
HRESULT WINAPI AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule);
HRESULT WINAPI AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst);
HRESULT WINAPI AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject);
void WINAPI AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject);
void *WINAPI AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule);
HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pComModule, REFCLSID rclsid, REFIID riid, LPVOID *ppv);
HRESULT WINAPI AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid);
HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid);
HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags);
HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module);
template<class TLock>
class CComCritSecLock
{
private:
bool m_bLocked;
TLock &m_cs;
public:
CComCritSecLock(TLock &cs, bool bInitialLock = true) : m_cs(cs)
{
HRESULT hResult;
m_bLocked = false;
if (bInitialLock)
{
hResult = Lock();
if (FAILED(hResult))
{
ATLASSERT(false);
}
}
}
~CComCritSecLock()
{
if (m_bLocked)
Unlock();
}
HRESULT Lock()
{
HRESULT hResult;
ATLASSERT(!m_bLocked);
hResult = m_cs.Lock();
if (FAILED(hResult))
return hResult;
m_bLocked = true;
return S_OK;
}
void Unlock()
{
HRESULT hResult;
ATLASSERT(m_bLocked);
hResult = m_cs.Unlock();
if (FAILED(hResult))
{
ATLASSERT(false);
}
m_bLocked = false;
}
};
class CHandle
{
public:
HANDLE m_handle;
public:
CHandle() :
m_handle(NULL)
{
}
CHandle(_Inout_ CHandle& handle) :
m_handle(NULL)
{
Attach(handle.Detach());
}
explicit CHandle(_In_ HANDLE handle) :
m_handle(handle)
{
}
~CHandle()
{
if (m_handle)
{
Close();
}
}
CHandle& operator=(_Inout_ CHandle& handle)
{
if (this != &handle)
{
if (m_handle)
{
Close();
}
Attach(handle.Detach());
}
return *this;
}
operator HANDLE() const
{
return m_handle;
}
void Attach(_In_ HANDLE handle)
{
ATLASSERT(m_handle == NULL);
m_handle = handle;
}
HANDLE Detach()
{
HANDLE handle = m_handle;
m_handle = NULL;
return handle;
}
void Close()
{
if (m_handle)
{
::CloseHandle(m_handle);
m_handle = NULL;
}
}
};
inline BOOL WINAPI InlineIsEqualUnknown(REFGUID rguid1)
{
return (
((unsigned long *)&rguid1)[0] == 0 &&
((unsigned long *)&rguid1)[1] == 0 &&
((unsigned long *)&rguid1)[2] == 0x000000C0 &&
((unsigned long *)&rguid1)[3] == 0x46000000);
}
class CComMultiThreadModelNoCS
{
public:
typedef CComFakeCriticalSection AutoCriticalSection;
typedef CComFakeCriticalSection CriticalSection;
typedef CComMultiThreadModelNoCS ThreadModelNoCS;
typedef CComFakeCriticalSection AutoDeleteCriticalSection;
static ULONG WINAPI Increment(LPLONG p)
{
return InterlockedIncrement(p);
}
static ULONG WINAPI Decrement(LPLONG p)
{
return InterlockedDecrement(p);
}
};
class CComMultiThreadModel
{
public:
typedef CComAutoCriticalSection AutoCriticalSection;
typedef CComCriticalSection CriticalSection;
typedef CComMultiThreadModelNoCS ThreadModelNoCS;
typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection;
static ULONG WINAPI Increment(LPLONG p)
{
return InterlockedIncrement(p);
}
static ULONG WINAPI Decrement(LPLONG p)
{
return InterlockedDecrement(p);
}
};
class CComSingleThreadModel
{
public:
typedef CComFakeCriticalSection AutoCriticalSection;
typedef CComFakeCriticalSection CriticalSection;
typedef CComSingleThreadModel ThreadModelNoCS;
typedef CComFakeCriticalSection AutoDeleteCriticalSection;
static ULONG WINAPI Increment(LPLONG p)
{
return ++*p;
}
static ULONG WINAPI Decrement(LPLONG p)
{
return --*p;
}
};
#if defined(_ATL_FREE_THREADED)
typedef CComMultiThreadModel CComObjectThreadModel;
typedef CComMultiThreadModel CComGlobalsThreadModel;
#elif defined(_ATL_APARTMENT_THREADED)
typedef CComSingleThreadModel CComObjectThreadModel;
typedef CComMultiThreadModel CComGlobalsThreadModel;
#elif defined(_ATL_SINGLE_THREADED)
typedef CComSingleThreadModel CComObjectThreadModel;
typedef CComSingleThreadModel CComGlobalsThreadModel;
#else
#error No threading model
#endif
class CAtlModule : public _ATL_MODULE
{
public:
static GUID m_libid;
CAtlModule()
{
ATLASSERT(_pAtlModule == NULL);
_pAtlModule = this;
cbSize = sizeof(_ATL_MODULE);
m_nLockCnt = 0;
}
virtual LONG GetLockCount()
{
return m_nLockCnt;
}
virtual LONG Lock()
{
return CComGlobalsThreadModel::Increment(&m_nLockCnt);
}
virtual LONG Unlock()
{
return CComGlobalsThreadModel::Decrement(&m_nLockCnt);
}
virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* /*pRegistrar*/) = 0;
HRESULT WINAPI UpdateRegistryFromResource(LPCTSTR lpszRes, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries = NULL)
{
CRegObject registrar;
WCHAR modulePath[MAX_PATH];
HRESULT hResult;
PCWSTR lpwszRes;
hResult = CommonInitRegistrar(registrar, modulePath, sizeof(modulePath) / sizeof(modulePath[0]), pMapEntries);
if (FAILED(hResult))
return hResult;
#ifdef UNICODE
lpwszRes = lpszRes;
#else
/* FIXME: this is a bit of a hack, need to re-evaluate */
WCHAR resid[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, resid, MAX_PATH);
lpwszRes = resid;
#endif
if (bRegister != FALSE)
hResult = registrar.ResourceRegisterSz(modulePath, lpwszRes, L"REGISTRY");
else
hResult = registrar.ResourceUnregisterSz(modulePath, lpwszRes, L"REGISTRY");
return hResult;
}
HRESULT WINAPI UpdateRegistryFromResource(UINT nResID, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries = NULL)
{
CRegObject registrar;
WCHAR modulePath[MAX_PATH];
HRESULT hResult;
hResult = CommonInitRegistrar(registrar, modulePath, sizeof(modulePath) / sizeof(modulePath[0]), pMapEntries);
if (FAILED(hResult))
return hResult;
if (bRegister != FALSE)
hResult = registrar.ResourceRegister(modulePath, nResID, L"REGISTRY");
else
hResult = registrar.ResourceUnregister(modulePath, nResID, L"REGISTRY");
return hResult;
}
private:
HRESULT CommonInitRegistrar(CRegObject &registrar, WCHAR *modulePath, DWORD modulePathCount, struct _ATL_REGMAP_ENTRY *pMapEntries)
{
HINSTANCE hInstance;
DWORD dwFLen;
HRESULT hResult;
hInstance = _AtlBaseModule.GetModuleInstance();
dwFLen = GetModuleFileNameW(hInstance, modulePath, modulePathCount);
if (dwFLen == modulePathCount)
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
else if (dwFLen == 0)
return HRESULT_FROM_WIN32(GetLastError());
if (pMapEntries != NULL)
{
while (pMapEntries->szKey != NULL)
{
ATLASSERT(pMapEntries->szData != NULL);
hResult = registrar.AddReplacement(pMapEntries->szKey, pMapEntries->szData);
if (FAILED(hResult))
return hResult;
pMapEntries++;
}
}
hResult = AddCommonRGSReplacements(&registrar);
if (FAILED(hResult))
return hResult;
hResult = registrar.AddReplacement(L"Module", modulePath);
if (FAILED(hResult))
return hResult;
hResult = registrar.AddReplacement(L"Module_Raw", modulePath);
if (FAILED(hResult))
return hResult;
return S_OK;
}
};
__declspec(selectany) GUID CAtlModule::m_libid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} };
template <class T>
class CAtlModuleT : public CAtlModule
{
public:
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL);
HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL);
virtual HRESULT AddCommonRGSReplacements(IRegistrarBase *pRegistrar)
{
return pRegistrar->AddReplacement(L"APPID", T::GetAppId());
}
static LPCOLESTR GetAppId()
{
return L"";
}
};
class CAtlComModule : public _ATL_COM_MODULE
{
public:
CAtlComModule()
{
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)this, &m_hInstTypeLib);
m_ppAutoObjMapFirst = &__pobjMapEntryFirst + 1;
m_ppAutoObjMapLast = &__pobjMapEntryLast;
if (FAILED(m_csObjMap.Init()))
{
ATLASSERT(0);
CAtlBaseModule::m_bInitFailed = true;
return;
}
cbSize = sizeof(_ATL_COM_MODULE);
}
~CAtlComModule()
{
Term();
}
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL)
{
return AtlComModuleRegisterServer(this, bRegTypeLib, pCLSID);
}
HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL)
{
return AtlComModuleUnregisterServer(this, bUnRegTypeLib, pCLSID);
}
void Term()
{
if (cbSize != 0)
{
for (_ATL_OBJMAP_ENTRY **iter = m_ppAutoObjMapFirst; iter < m_ppAutoObjMapLast; iter++)
{
_ATL_OBJMAP_ENTRY *ptr = *iter;
if (!ptr)
continue;
if (!ptr->pCF)
continue;
ptr->pCF->Release();
ptr->pCF = NULL;
}
m_csObjMap.Term();
cbSize = 0;
}
}
void ExecuteObjectMain(bool bStarting)
{
for (_ATL_OBJMAP_ENTRY **iter = m_ppAutoObjMapFirst; iter < m_ppAutoObjMapLast; iter++)
{
if (!*iter)
continue;
(*iter)->pfnObjectMain(bStarting);
}
}
};
__declspec(selectany) CAtlComModule _AtlComModule;
template <class T>
HRESULT CAtlModuleT<T>::RegisterServer(BOOL bRegTypeLib, const CLSID *pCLSID)
{
return _AtlComModule.RegisterServer(bRegTypeLib, pCLSID);
}
template <class T>
HRESULT CAtlModuleT<T>::UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID)
{
return _AtlComModule.UnregisterServer(bUnRegTypeLib, pCLSID);
}
template <class T>
class CAtlDllModuleT
: public CAtlModuleT<T>
, private CAtlValidateModuleConfiguration<true, T>
{
public:
CAtlDllModuleT()
{
_AtlComModule.ExecuteObjectMain(true);
}
~CAtlDllModuleT()
{
_AtlComModule.ExecuteObjectMain(false);
}
HRESULT DllCanUnloadNow()
{
T *pThis;
pThis = static_cast<T *>(this);
if (pThis->GetLockCount() == 0)
return S_OK;
return S_FALSE;
}
HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
T *pThis;
pThis = static_cast<T *>(this);
return pThis->GetClassObject(rclsid, riid, ppv);
}
HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE)
{
T *pThis;
HRESULT hResult;
pThis = static_cast<T *>(this);
hResult = pThis->RegisterServer(bRegTypeLib);
return hResult;
}
HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE)
{
T *pThis;
HRESULT hResult;
pThis = static_cast<T *>(this);
hResult = pThis->UnregisterServer(bUnRegTypeLib);
return hResult;
}
HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
return AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv);
}
};
template <class T>
class CAtlExeModuleT
: public CAtlModuleT<T>
, private CAtlValidateModuleConfiguration<false, T>
{
public:
DWORD m_dwMainThreadID;
//DWORD m_dwTimeOut;
//DWORD m_dwPause;
//bool m_bDelayShutdown;
CAtlExeModuleT()
:m_dwMainThreadID(::GetCurrentThreadId())
{
_AtlComModule.ExecuteObjectMain(true);
}
~CAtlExeModuleT()
{
_AtlComModule.ExecuteObjectMain(false);
}
int WinMain(int nShowCmd)
{
HRESULT hr = T::InitializeCom();
if (FAILED(hr))
return hr;
T* pThis = static_cast<T*>(this);
LPCTSTR lpCommandLine = GetCommandLine();
if (pThis->ParseCommandLine(lpCommandLine, &hr))
{
hr = pThis->Run(nShowCmd);
}
T::UninitializeCom();
return hr;
}
HRESULT Run(int nShowCmd = SW_HIDE)
{
HRESULT hr = S_OK;
T* pThis = static_cast<T*>(this);
hr = pThis->PreMessageLoop(nShowCmd);
if (hr == S_OK)
{
pThis->RunMessageLoop();
hr = pThis->PostMessageLoop();
}
return hr;
}
LONG Lock()
{
return CoAddRefServerProcess();
}
LONG Unlock()
{
LONG lRet = CoReleaseServerProcess();
if (lRet == 0)
{
::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0);
}
return lRet;
}
bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode)
{
// unimplemented!
return true;
}
HRESULT PreMessageLoop(int nShowCmd)
{
T* pThis = static_cast<T*>(this);
return pThis->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
}
void RunMessageLoop()
{
MSG msg;
while (GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
HRESULT PostMessageLoop()
{
T* pThis = static_cast<T*>(this);
return pThis->RevokeClassObjects();
}
HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags)
{
return AtlComModuleRegisterClassObjects(&_AtlComModule, dwClsContext, dwFlags);
}
HRESULT RevokeClassObjects()
{
return AtlComModuleRevokeClassObjects(&_AtlComModule);
}
static HRESULT InitializeCom()
{
#if defined(_ATL_FREE_THREADED)
constexpr COINIT coInit = COINIT_MULTITHREADED;
#else
constexpr COINIT coInit = COINIT_APARTMENTTHREADED;
#endif
return ::CoInitializeEx(NULL, coInit);
}
static void UninitializeCom()
{
::CoUninitialize();
}
};
class CComModule : public CAtlModuleT<CComModule>
{
public:
_ATL_OBJMAP_ENTRY *m_pObjMap;
public:
CComModule()
{
ATLASSERT(_pModule == NULL);
_pModule = this;
_pModule->m_pObjMap = NULL;
}
~CComModule()
{
_pModule = NULL;
}
HRESULT Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE /* h */, const GUID *plibid)
{
_ATL_OBJMAP_ENTRY *objectMapEntry;
if (plibid != NULL)
m_libid = *plibid;
if (p != reinterpret_cast<_ATL_OBJMAP_ENTRY *>(-1))
{
m_pObjMap = p;
if (p != NULL)
{
objectMapEntry = p;
while (objectMapEntry->pclsid != NULL)
{
objectMapEntry->pfnObjectMain(true);
objectMapEntry++;
}
}
}
for (_ATL_OBJMAP_ENTRY **iter = _AtlComModule.m_ppAutoObjMapFirst; iter < _AtlComModule.m_ppAutoObjMapLast; iter++)
{
if (*iter != NULL)
(*iter)->pfnObjectMain(true);
}
return S_OK;
}
void Term()
{
_ATL_OBJMAP_ENTRY *objectMapEntry;
if (m_pObjMap != NULL)
{
objectMapEntry = m_pObjMap;
while (objectMapEntry->pclsid != NULL)
{
if (objectMapEntry->pCF != NULL)
objectMapEntry->pCF->Release();
objectMapEntry->pCF = NULL;
objectMapEntry->pfnObjectMain(false);
objectMapEntry++;
}
}
for (_ATL_OBJMAP_ENTRY **iter = _AtlComModule.m_ppAutoObjMapFirst; iter < _AtlComModule.m_ppAutoObjMapLast; iter++)
{
if (*iter != NULL)
(*iter)->pfnObjectMain(false);
}
}
HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
_ATL_OBJMAP_ENTRY *objectMapEntry;
HRESULT hResult;
ATLASSERT(ppv != NULL);
if (ppv == NULL)
return E_POINTER;
*ppv = NULL;
hResult = S_OK;
if (m_pObjMap != NULL)
{
objectMapEntry = m_pObjMap;
while (objectMapEntry->pclsid != NULL)
{
if (objectMapEntry->pfnGetClassObject != NULL && InlineIsEqualGUID(rclsid, *objectMapEntry->pclsid) != FALSE)
{
if (objectMapEntry->pCF == NULL)
{
CComCritSecLock<CComCriticalSection> lock(_AtlComModule.m_csObjMap, true);
if (objectMapEntry->pCF == NULL)
hResult = objectMapEntry->pfnGetClassObject(reinterpret_cast<void *>(objectMapEntry->pfnCreateInstance), IID_IUnknown, reinterpret_cast<LPVOID *>(&objectMapEntry->pCF));
}
if (objectMapEntry->pCF != NULL)
hResult = objectMapEntry->pCF->QueryInterface(riid, ppv);
break;
}
objectMapEntry++;
}
}
if (hResult == S_OK && *ppv == NULL)
{
hResult = AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv);
}
return hResult;
}
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID *pCLSID = NULL)
{
_ATL_OBJMAP_ENTRY *objectMapEntry;
HRESULT hResult;
hResult = S_OK;
objectMapEntry = m_pObjMap;
if (objectMapEntry != NULL)
{
while (objectMapEntry->pclsid != NULL)
{
if (pCLSID == NULL || IsEqualGUID(*pCLSID, *objectMapEntry->pclsid) != FALSE)
{
hResult = objectMapEntry->pfnUpdateRegistry(TRUE);
if (FAILED(hResult))
break;
}
objectMapEntry++;
}
}
if (SUCCEEDED(hResult))
hResult = CAtlModuleT<CComModule>::RegisterServer(bRegTypeLib, pCLSID);
return hResult;
}
HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID *pCLSID = NULL)
{
_ATL_OBJMAP_ENTRY *objectMapEntry;
HRESULT hResult;
hResult = S_OK;
objectMapEntry = m_pObjMap;
if (objectMapEntry != NULL)
{
while (objectMapEntry->pclsid != NULL)
{
if (pCLSID == NULL || IsEqualGUID(*pCLSID, *objectMapEntry->pclsid) != FALSE)
{
hResult = objectMapEntry->pfnUpdateRegistry(FALSE); //unregister
if (FAILED(hResult))
break;
}
objectMapEntry++;
}
}
if (SUCCEEDED(hResult))
hResult = CAtlModuleT<CComModule>::UnregisterServer(bUnRegTypeLib, pCLSID);
return hResult;
}
HRESULT DllCanUnloadNow()
{
if (GetLockCount() == 0)
return S_OK;
return S_FALSE;
}
HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
return GetClassObject(rclsid, riid, ppv);
}
HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE)
{
return RegisterServer(bRegTypeLib);
}
HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE)
{
return UnregisterServer(bUnRegTypeLib);
}
};
class CAtlWinModule : public _ATL_WIN_MODULE
{
public:
CAtlWinModule()
{
HRESULT hResult;
hResult = AtlWinModuleInit(this);
if (FAILED(hResult))
{
CAtlBaseModule::m_bInitFailed = true;
ATLASSERT(0);
}
}
~CAtlWinModule()
{
Term();
}
void Term()
{
AtlWinModuleTerm(this, _AtlBaseModule.GetModuleInstance());
}
void AddCreateWndData(_AtlCreateWndData *pData, void *pObject)
{
AtlWinModuleAddCreateWndData(this, pData, pObject);
}
void *ExtractCreateWndData()
{
return AtlWinModuleExtractCreateWndData(this);
}
};
__declspec(selectany) CAtlWinModule _AtlWinModule;
class CComAllocator
{
public:
static void* Allocate(_In_ size_t size)
{
return ::CoTaskMemAlloc(size);
}
static void* Reallocate(_In_opt_ void* ptr, _In_ size_t size)
{
return ::CoTaskMemRealloc(ptr, size);
}
static void Free(_In_opt_ void* ptr)
{
::CoTaskMemFree(ptr);
}
};
class CRegKey
{
public:
HKEY m_hKey;
#if 0
// FIXME & TODO:
CAtlTransactionManager* m_pTM;
#endif
public:
CRegKey() noexcept
: m_hKey(NULL)
{
}
CRegKey(CRegKey& key) noexcept
: m_hKey(key.Detach())
{
}
explicit CRegKey(HKEY hKey) noexcept
: m_hKey(hKey)
{
}
#if 0
// FIXME & TODO:
CRegKey(CAtlTransactionManager* pTM) noexcept
{
...
}
#endif
~CRegKey() noexcept
{
Close();
}
void Attach(HKEY hKey) noexcept
{
m_hKey = hKey;
}
LONG Close() noexcept
{
if (m_hKey)
{
HKEY hKey = Detach();
return ::RegCloseKey(hKey);
}
return ERROR_SUCCESS;
}
HKEY Detach() noexcept
{
HKEY hKey = m_hKey;
m_hKey = NULL;
return hKey;
}
LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName,
REGSAM samDesired = KEY_READ | KEY_WRITE) noexcept
{
ATLASSERT(hKeyParent);
ATLASSERT(lpszKeyName);
HKEY hKey = NULL;
LONG lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, 0, samDesired, &hKey);
if (lRes == ERROR_SUCCESS)
{
Close();
m_hKey = hKey;
}
return lRes;
}
LONG Create(HKEY hKeyParent, LPCTSTR lpszKeyName,
LPTSTR lpszClass = REG_NONE,
DWORD dwOptions = REG_OPTION_NON_VOLATILE,
REGSAM samDesired = KEY_READ | KEY_WRITE,
LPSECURITY_ATTRIBUTES lpSecAttr = NULL,
LPDWORD lpdwDisposition = NULL) noexcept
{
ATLASSERT(hKeyParent);
ATLASSERT(lpszKeyName);
HKEY hKey = NULL;
LONG lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, 0, lpszClass,
dwOptions, samDesired, lpSecAttr, &hKey,
lpdwDisposition);
if (lRes == ERROR_SUCCESS)
{
Close();
m_hKey = hKey;
}
return lRes;
}
LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) noexcept
{
ATLASSERT(m_hKey);
return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, (LPBYTE)pData, pnBytes);
}
LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) noexcept
{
ULONG size = sizeof(DWORD);
DWORD type = 0;
LONG lRet = QueryValue(pszValueName, &type, &dwValue, &size);
if (lRet == ERROR_SUCCESS && type != REG_DWORD)
lRet = ERROR_INVALID_DATA;
return lRet;
}
LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) noexcept
{
DWORD type = 0;
LONG lRet = QueryValue(pszValueName, &type, pValue, pnBytes);
if (lRet == ERROR_SUCCESS && type != REG_BINARY)
lRet = ERROR_INVALID_DATA;
return lRet;
}
LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) noexcept
{
ULONG size = (*pnChars) * sizeof(TCHAR);
DWORD type = 0;
LONG lRet = QueryValue(pszValueName, &type, pszValue, &size);
if (lRet == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)
lRet = ERROR_INVALID_DATA;
*pnChars = size / sizeof(TCHAR);
return lRet;
}
LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) noexcept
{
OLECHAR buf[40] = {0};
ULONG nChars = 39;
LONG lRet;
#ifdef UNICODE
lRet = QueryStringValue(pszValueName, buf, &nChars);
#else
CHAR bufA[40] = {0};
lRet = QueryStringValue(pszValueName, bufA, &nChars);
if (lRet != ERROR_SUCCESS)
return lRet;
if (!::MultiByteToWideChar(CP_THREAD_ACP, 0, bufA, -1, buf, 39))
lRet = ERROR_INVALID_DATA;
#endif
if (lRet != ERROR_SUCCESS)
return lRet;
if (!SUCCEEDED(::CLSIDFromString(buf, &guidValue)))
return ERROR_INVALID_DATA;
return lRet;
}
LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) noexcept
{
ULONG size = sizeof(ULONGLONG);
DWORD type = 0;
LONG lRet = QueryValue(pszValueName, &type, &qwValue, &size);
if (lRet == ERROR_SUCCESS && type != REG_QWORD)
lRet = ERROR_INVALID_DATA;
return lRet;
}
LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue,
ULONG* pnChars) noexcept
{
ULONG size = (*pnChars) * sizeof(TCHAR);
DWORD type;
LONG lRet = QueryValue(pszValueName, &type, pszValue, &size);
if (lRet == ERROR_SUCCESS && type != REG_MULTI_SZ)
lRet = ERROR_INVALID_DATA;
*pnChars = size / sizeof(TCHAR);
return lRet;
}
LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) noexcept
{
ATLASSERT(m_hKey);
return ::RegSetValueEx(m_hKey, pszValueName, 0, dwType, (const BYTE*)pValue, nBytes);
}
LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) noexcept
{
return SetValue(pszValueName, REG_DWORD, &dwValue, sizeof(DWORD));
}
LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) noexcept
{
SIZE_T length;
switch (dwType)
{
case REG_SZ:
case REG_EXPAND_SZ:
length = (_tcslen(pszValue) + 1) * sizeof(TCHAR);
return SetValue(pszValueName, dwType, pszValue, length);
case REG_MULTI_SZ:
return SetMultiStringValue(pszValueName, pszValue);
default:
return ERROR_INVALID_DATA;
}
}
LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) noexcept
{
OLECHAR buf[40] = {0};
::StringFromGUID2(guidValue, buf, 39);
#ifdef UNICODE
return SetStringValue(pszValueName, buf);
#else
CHAR bufA[40] = {0};
::WideCharToMultiByte(CP_THREAD_ACP, 0, buf, -1, bufA, 40, NULL, NULL);
return SetStringValue(pszValueName, bufA);
#endif
}
LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) noexcept
{
return SetValue(pszValueName, REG_BINARY, pValue, nBytes);
}
LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) noexcept
{
ULONG dwSize = CRegKey::_GetMultiStringSize(pszValue);
return SetValue(pszValueName, REG_MULTI_SZ, pszValue, dwSize);
}
LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) noexcept
{
ULONG dwSize = sizeof(ULONGLONG);
return SetValue(pszValueName, REG_QWORD, &qwValue, dwSize);
}
LONG NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter,
HANDLE hEvent, BOOL bAsync = TRUE) noexcept
{
ATLASSERT(m_hKey);
LONG ret = ::RegNotifyChangeKeyValue(m_hKey, bWatchSubtree,
dwNotifyFilter, hEvent, bAsync);
return ret;
}
LONG Flush() noexcept
{
ATLASSERT(m_hKey);
LONG ret = ::RegFlushKey(m_hKey);
return ret;
}
static LONG WINAPI SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName,
LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL)
{
CRegKey key;
LONG lRet = key.Create(hKeyParent, lpszKeyName);
if (lRet == ERROR_SUCCESS)
{
lRet = key.SetStringValue(lpszValueName, lpszValue);
}
return lRet;
}
LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue,
LPCTSTR lpszValueName = NULL) noexcept
{
CRegKey key;
LONG lRet = key.Create(m_hKey, lpszKeyName);
if (lRet == ERROR_SUCCESS)
{
lRet = key.SetStringValue(lpszValueName, lpszValue);
}
return lRet;
}
LONG DeleteValue(LPCTSTR lpszValue) noexcept
{
ATLASSERT(m_hKey);
return ::RegDeleteValue(m_hKey, lpszValue);
}
LONG DeleteSubKey(LPCTSTR lpszSubKey) noexcept
{
ATLASSERT(m_hKey);
ATLASSERT(lpszSubKey);
return ::RegDeleteKey(m_hKey, lpszSubKey);
}
LONG RecurseDeleteKey(LPCTSTR lpszKey) noexcept
{
ATLASSERT(m_hKey);
ATLASSERT(lpszKey);
return CRegKey::_DoDeleteKeyTree(m_hKey, lpszKey);
}
LONG EnumKey(DWORD iIndex, LPTSTR pszName, LPDWORD pnNameLength,
FILETIME* pftLastWriteTime = NULL) noexcept
{
ATLASSERT(m_hKey);
LONG ret = ::RegEnumKeyEx(m_hKey, iIndex, pszName, pnNameLength, NULL,
NULL, NULL, pftLastWriteTime);
return ret;
}
LONG GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd,
LPDWORD pnBytes) noexcept
{
ATLASSERT(m_hKey);
LONG ret = ::RegGetKeySecurity(m_hKey, si, psd, pnBytes);
return ret;
}
LONG SetKeySecurity(SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR psd) noexcept
{
ATLASSERT(m_hKey);
LONG ret = ::RegSetKeySecurity(m_hKey, si, psd);
return ret;
}
operator HKEY() const noexcept
{
return m_hKey;
}
CRegKey& operator=(CRegKey& key) noexcept
{
if (m_hKey != key.m_hKey)
{
Close();
Attach(key.Detach());
}
return *this;
}
protected:
// get the total size of a multistring
static ULONG _GetMultiStringSize(LPCTSTR pszz)
{
size_t count = 0;
do
{
size_t len = _tcslen(pszz);
count += len + 1;
pszz += len + 1;
} while (*pszz != TEXT('\0'));
++count;
ATLASSERT(count * sizeof(TCHAR) <= ULONG_MAX);
return (ULONG)count * sizeof(TCHAR);
}
// delete key recursively
static LONG _DoDeleteKeyTree(HKEY hParentKey, LPCTSTR lpszKey)
{
ATLASSERT(hParentKey);
ATLASSERT(lpszKey);
// open the key
CRegKey key;
LONG ret = key.Open(hParentKey, lpszKey);
if (ret != ERROR_SUCCESS)
{
return ret; // failure
}
// get the longest length of subkey names
DWORD NameMax;
ret = ::RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &NameMax, NULL,
NULL, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS)
{
return ret; // failure
}
++NameMax; // for NUL
// allocate the string buffer for names if necessary
TCHAR szNameBuf[MAX_PATH], *pszName;
if (NameMax > MAX_PATH)
{
pszName = (TCHAR *)malloc(NameMax * sizeof(TCHAR));
ATLASSERT(pszName);
if (pszName == NULL)
{
return ERROR_OUTOFMEMORY; // failure
}
}
else
{
NameMax = MAX_PATH;
pszName = szNameBuf;
}
// enumerate every subkey and delete
for (;;)
{
DWORD Count = NameMax;
ret = key.EnumKey(0, pszName, &Count);
if (ret != ERROR_SUCCESS)
{
if (ret == ERROR_NO_MORE_ITEMS)
ret = ERROR_SUCCESS;
break;
}
ret = CRegKey::_DoDeleteKeyTree(key, pszName);
if (ret != ERROR_SUCCESS)
break;
}
// close key
key.Close();
// delete the subkey
if (ret == ERROR_SUCCESS)
ret = ::RegDeleteKey(hParentKey, lpszKey);
// delete the buffer if any
if (pszName != szNameBuf)
free(pszName);
return ret;
}
};
template<class T>
class CComHeapPtr : public CHeapPtr<T, CComAllocator>
{
public:
CComHeapPtr()
{
}
explicit CComHeapPtr(T *lp) :
CHeapPtr<T, CComAllocator>(lp)
{
}
};
inline HRESULT __stdcall AtlAdvise(IUnknown *pUnkCP, IUnknown *pUnk, const IID &iid, LPDWORD pdw)
{
CComPtr<IConnectionPointContainer> container;
CComPtr<IConnectionPoint> connectionPoint;
HRESULT hResult;
if (pUnkCP == NULL)
return E_INVALIDARG;
hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
if (FAILED(hResult))
return hResult;
hResult = container->FindConnectionPoint(iid, &connectionPoint);
if (FAILED(hResult))
return hResult;
return connectionPoint->Advise(pUnk, pdw);
}
inline HRESULT __stdcall AtlUnadvise(IUnknown *pUnkCP, const IID &iid, DWORD dw)
{
CComPtr<IConnectionPointContainer> container;
CComPtr<IConnectionPoint> connectionPoint;
HRESULT hResult;
if (pUnkCP == NULL)
return E_INVALIDARG;
hResult = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
if (FAILED(hResult))
return hResult;
hResult = container->FindConnectionPoint(iid, &connectionPoint);
if (FAILED(hResult))
return hResult;
return connectionPoint->Unadvise(dw);
}
inline HRESULT __stdcall AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject)
{
int i;
IUnknown *resultInterface;
HRESULT hResult;
ATLASSERT(pThis != NULL && pEntries != NULL);
if (pThis == NULL || pEntries == NULL)
return E_INVALIDARG;
if (ppvObject == NULL)
return E_POINTER;
if (InlineIsEqualUnknown(iid))
{
resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[0].dw);
*ppvObject = resultInterface;
resultInterface->AddRef();
return S_OK;
}
i = 0;
while (pEntries[i].pFunc != 0)
{
if (pEntries[i].piid == NULL || InlineIsEqualGUID(iid, *pEntries[i].piid))
{
if (pEntries[i].pFunc == reinterpret_cast<_ATL_CREATORARGFUNC *>(1))
{
ATLASSERT(pEntries[i].piid != NULL);
resultInterface = reinterpret_cast<IUnknown *>(reinterpret_cast<char *>(pThis) + pEntries[i].dw);
*ppvObject = resultInterface;
resultInterface->AddRef();
return S_OK;
}
else
{
hResult = pEntries[i].pFunc(pThis, iid, ppvObject, 0);
if (hResult == S_OK)
return hResult;
if (FAILED(hResult) && pEntries[i].piid != NULL)
break;
}
}
i++;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
inline HRESULT __stdcall AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule)
{
if (pWinModule == NULL)
return E_INVALIDARG;
pWinModule->m_pCreateWndList = NULL;
return pWinModule->m_csWindowCreate.Init();
}
inline HRESULT __stdcall AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst)
{
if (pWinModule == NULL)
return E_INVALIDARG;
pWinModule->m_csWindowCreate.Term();
return S_OK;
}
inline void __stdcall AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject)
{
CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true);
ATLASSERT(pWinModule != NULL);
ATLASSERT(pObject != NULL);
pData->m_pThis = pObject;
pData->m_dwThreadID = ::GetCurrentThreadId();
pData->m_pNext = pWinModule->m_pCreateWndList;
pWinModule->m_pCreateWndList = pData;
}
inline void *__stdcall AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule)
{
CComCritSecLock<CComCriticalSection> lock(pWinModule->m_csWindowCreate, true);
void *result;
_AtlCreateWndData *currentEntry;
_AtlCreateWndData **previousLink;
DWORD threadID;
ATLASSERT(pWinModule != NULL);
result = NULL;
threadID = GetCurrentThreadId();
currentEntry = pWinModule->m_pCreateWndList;
previousLink = &pWinModule->m_pCreateWndList;
while (currentEntry != NULL)
{
if (currentEntry->m_dwThreadID == threadID)
{
*previousLink = currentEntry->m_pNext;
result = currentEntry->m_pThis;
break;
}
previousLink = &currentEntry->m_pNext;
currentEntry = currentEntry->m_pNext;
}
return result;
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI AtlLoadTypeLib(HINSTANCE inst, LPCOLESTR lpszIndex,
BSTR *pbstrPath, ITypeLib **ppTypeLib)
{
size_t index_len = lpszIndex ? wcslen(lpszIndex) : 0;
CComHeapPtr<WCHAR> path;
path.Allocate(MAX_PATH + index_len + wcslen(L".tlb"));
if (!path)
return E_OUTOFMEMORY;
size_t path_len = GetModuleFileNameW(inst, path, MAX_PATH);
if (!path_len)
return HRESULT_FROM_WIN32(GetLastError());
if (index_len)
wcscat(path, lpszIndex);
CComPtr<ITypeLib> typelib;
HRESULT hResult = LoadTypeLib(path, &typelib);
if (FAILED(hResult))
{
WCHAR *ptr;
for (ptr = path+path_len-1; ptr > path && *ptr != '\\' && *ptr != '.'; ptr--)
;
if (*ptr != '.')
ptr = (WCHAR*)path + path_len;
wcscpy(ptr, L".tlb");
hResult = LoadTypeLib(path, &typelib);
}
if (SUCCEEDED(hResult))
{
*pbstrPath = SysAllocString(path);
if (!*pbstrPath)
{
typelib.Release();
hResult = E_OUTOFMEMORY;
}
}
if (FAILED(hResult))
return hResult;
*ppTypeLib = typelib.Detach();
return S_OK;
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI AtlRegisterTypeLib(HINSTANCE inst, const WCHAR *index)
{
CComBSTR path;
CComPtr<ITypeLib> typelib;
HRESULT hResult = AtlLoadTypeLib(inst, index, &path, &typelib);
if (FAILED(hResult))
return hResult;
return RegisterTypeLib(typelib, path, NULL); /* FIXME: pass help directory */
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI AtlRegisterClassCategoriesHelper(REFCLSID clsid, const _ATL_CATMAP_ENTRY *catmap, BOOL reg)
{
if (!catmap)
return S_OK;
CComPtr<ICatRegister> catreg;
HRESULT hResult = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&catreg);
if (FAILED(hResult))
return hResult;
for (const _ATL_CATMAP_ENTRY *iter = catmap; iter->iType != _ATL_CATMAP_ENTRY_END; iter++)
{
CATID catid = *iter->pcatid;
if (iter->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED)
{
if (reg)
hResult = catreg->RegisterClassImplCategories(clsid, 1, &catid);
else
hResult = catreg->UnRegisterClassImplCategories(clsid, 1, &catid);
}
else
{
if (reg)
hResult = catreg->RegisterClassReqCategories(clsid, 1, &catid);
else
hResult = catreg->UnRegisterClassReqCategories(clsid, 1, &catid);
}
if (FAILED(hResult))
return hResult;
}
if (!reg)
{
WCHAR reg_path[256] = L"CLSID\\";
StringFromGUID2(clsid, reg_path + wcslen(reg_path), 64);
wcscat(reg_path, L"\\");
WCHAR* ptr = reg_path + wcslen(reg_path);
wcscpy(ptr, L"Implemented Categories");
RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
wcscpy(ptr, L"Required Categories");
RegDeleteKeyW(HKEY_CLASSES_ROOT, reg_path);
}
return hResult;
}
// Adapted from dll/win32/atl80/atl80.c
inline HRESULT __stdcall AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid)
{
HRESULT hResult = S_OK;
for (_ATL_OBJMAP_ENTRY ** iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++)
{
if (!*iter)
continue;
_ATL_OBJMAP_ENTRY* entry = *iter;
if (clsid && !IsEqualCLSID(*entry->pclsid, *clsid))
continue;
hResult = entry->pfnUpdateRegistry(TRUE);
if (FAILED(hResult))
return hResult;
const _ATL_CATMAP_ENTRY *catmap = entry->pfnGetCategoryMap();
if (catmap)
{
hResult = AtlRegisterClassCategoriesHelper(*entry->pclsid, catmap, TRUE);
if (FAILED(hResult))
return hResult;
}
}
if (bRegTypeLib)
{
hResult = AtlRegisterTypeLib(mod->m_hInstTypeLib, NULL);
}
return hResult;
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bUnRegTypeLib, const CLSID *clsid)
{
HRESULT hResult = S_OK;
for (_ATL_OBJMAP_ENTRY **iter = mod->m_ppAutoObjMapFirst; iter < mod->m_ppAutoObjMapLast; iter++)
{
if (!*iter)
continue;
_ATL_OBJMAP_ENTRY* entry = *iter;
if (clsid && !IsEqualCLSID(*entry->pclsid, *clsid))
continue;
const _ATL_CATMAP_ENTRY *catmap = entry->pfnGetCategoryMap();
if (catmap)
{
hResult = AtlRegisterClassCategoriesHelper(*entry->pclsid, catmap, FALSE);
if (FAILED(hResult))
return hResult;
}
hResult = entry->pfnUpdateRegistry(FALSE);
if (FAILED(hResult))
return hResult;
}
if (bUnRegTypeLib)
{
CComPtr<ITypeLib> typelib;
TLIBATTR *attr;
CComBSTR path;
hResult = AtlLoadTypeLib(mod->m_hInstTypeLib, NULL, &path, &typelib);
if (FAILED(hResult))
return hResult;
hResult = typelib->GetLibAttr(&attr);
if (SUCCEEDED(hResult))
{
hResult = UnRegisterTypeLib(attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, attr->lcid, attr->syskind);
typelib->ReleaseTLibAttr(attr);
}
}
return hResult;
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags)
{
_ATL_OBJMAP_ENTRY **iter;
IUnknown* unk = NULL;
HRESULT hr;
if (!module)
return E_INVALIDARG;
for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++)
{
_ATL_OBJMAP_ENTRY *ptr = *iter;
if (!ptr)
continue;
if (!ptr->pfnGetClassObject)
continue;
hr = ptr->pfnGetClassObject((void*)ptr->pfnCreateInstance, IID_IUnknown, (void**)&unk);
if (FAILED(hr))
return hr;
hr = CoRegisterClassObject(*ptr->pclsid, unk, context, flags, &ptr->dwRegister);
unk->Release();
if (FAILED(hr))
return hr;
}
return S_OK;
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module)
{
_ATL_OBJMAP_ENTRY **iter;
HRESULT hr;
if (!module)
return E_INVALIDARG;
for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++)
{
_ATL_OBJMAP_ENTRY *ptr = *iter;
if (!ptr)
continue;
hr = CoRevokeClassObject(ptr->dwRegister);
if (FAILED(hr))
return hr;
}
return S_OK;
}
// Adapted from dll/win32/atl/atl.c
inline HRESULT WINAPI
AtlComModuleGetClassObject(_ATL_COM_MODULE *pm, REFCLSID rclsid, REFIID riid, void **ppv)
{
if (!pm)
return E_INVALIDARG;
for (_ATL_OBJMAP_ENTRY **iter = pm->m_ppAutoObjMapFirst; iter < pm->m_ppAutoObjMapLast; iter++)
{
_ATL_OBJMAP_ENTRY *ptr = *iter;
if (!ptr)
continue;
if (IsEqualCLSID(*ptr->pclsid, rclsid) && ptr->pfnGetClassObject)
{
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
if (!ptr->pCF)
{
CComCritSecLock<CComCriticalSection> lock(_AtlComModule.m_csObjMap, true);
if (!ptr->pCF)
{
hr = ptr->pfnGetClassObject((void *)ptr->pfnCreateInstance, IID_IUnknown, (void **)&ptr->pCF);
}
}
if (ptr->pCF)
hr = ptr->pCF->QueryInterface(riid, ppv);
return hr;
}
}
return CLASS_E_CLASSNOTAVAILABLE;
}
}; // namespace ATL
#ifndef _ATL_NO_AUTOMATIC_NAMESPACE
using namespace ATL;
#endif //!_ATL_NO_AUTOMATIC_NAMESPACE