You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2278 lines
54 KiB
2278 lines
54 KiB
// This is a part of the Active Template Library.
|
|
// Copyright (C) 1996-2001 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Active Template Library Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Active Template Library product.
|
|
|
|
#ifndef __ATLBASE_H__
|
|
#define __ATLBASE_H__
|
|
|
|
#pragma once
|
|
|
|
#ifdef _ATL_ALL_WARNINGS
|
|
#pragma warning( push )
|
|
#endif
|
|
|
|
#pragma warning(disable: 4127) // constant expression
|
|
#pragma warning(disable: 4097) // typedef name used as synonym for class-name
|
|
#pragma warning(disable: 4786) // identifier was truncated in the debug information
|
|
#pragma warning(disable: 4291) // allow placement new
|
|
#pragma warning(disable: 4201) // nameless unions are part of C++
|
|
#pragma warning(disable: 4103) // pragma pack
|
|
#pragma warning(disable: 4268) // const static/global data initialized to zeros
|
|
|
|
#pragma warning (push)
|
|
|
|
#ifndef __cplusplus
|
|
#error ATL requires C++ compilation (use a .cpp suffix)
|
|
#endif
|
|
|
|
#include <atldef.h>
|
|
#ifndef _WINSOCKAPI_
|
|
#include <winsock2.h>
|
|
#endif
|
|
#include <windows.h>
|
|
#include <winnls.h>
|
|
#include <ole2.h>
|
|
#include <oleauto.h>
|
|
|
|
#include <comcat.h>
|
|
#include <stddef.h>
|
|
#include <winsvc.h>
|
|
|
|
#include <tchar.h>
|
|
#include <malloc.h>
|
|
#include <limits.h>
|
|
#include <errno.h>
|
|
|
|
//REVIEW: Lame definition of InterlockedExchangePointer in system headers
|
|
#ifdef _M_IX86
|
|
#undef InterlockedExchangePointer
|
|
inline void* InterlockedExchangePointer(void** pp, void* pNew) throw()
|
|
{
|
|
return( reinterpret_cast<void*>(static_cast<LONG_PTR>(::InterlockedExchange(reinterpret_cast<LONG*>(pp), static_cast<LONG>(reinterpret_cast<LONG_PTR>(pNew))))) );
|
|
}
|
|
#endif
|
|
|
|
#ifndef _ATL_NO_DEBUG_CRT
|
|
// Warning: if you define the above symbol, you will have
|
|
// to provide your own definition of the ATLASSERT(x) macro
|
|
// in order to compile ATL
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
#include <olectl.h>
|
|
#include <winreg.h>
|
|
#include <atliface.h>
|
|
|
|
#include <errno.h>
|
|
#include <process.h> // for _beginthreadex, _endthreadex
|
|
|
|
#ifdef _DEBUG
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#endif
|
|
|
|
#include <atlconv.h>
|
|
|
|
#include <shlwapi.h>
|
|
|
|
#include <atlsimpcoll.h>
|
|
|
|
#pragma pack(push, _ATL_PACKING)
|
|
|
|
#ifndef _ATL_NO_DEFAULT_LIBS
|
|
|
|
#ifdef _DEBUG
|
|
#pragma comment(lib, "atlsd.lib")
|
|
#else
|
|
#pragma comment(lib, "atls.lib")
|
|
#endif
|
|
#endif // !_ATL_NO_DEFAULT_LIBS
|
|
|
|
// {394C3DE0-3C6F-11d2-817B-00C04F797AB7}
|
|
_declspec(selectany) GUID GUID_ATLVer70 = { 0x394c3de0, 0x3c6f, 0x11d2, { 0x81, 0x7b, 0x0, 0xc0, 0x4f, 0x79, 0x7a, 0xb7 } };
|
|
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
struct _ATL_CATMAP_ENTRY
|
|
{
|
|
int iType;
|
|
const CATID* 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 HRESULT (WINAPI _ATL_CREATORARGFUNC)(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw);
|
|
typedef HRESULT (WINAPI _ATL_MODULEFUNC)(DWORD_PTR dw);
|
|
typedef LPCTSTR (WINAPI _ATL_DESCRIPTIONFUNC)();
|
|
typedef const struct _ATL_CATMAP_ENTRY* (_ATL_CATMAPFUNC)();
|
|
typedef void (__stdcall _ATL_TERMFUNC)(DWORD_PTR dw);
|
|
|
|
// perfmon registration/unregistration function definitions
|
|
typedef HRESULT (*_ATL_PERFREGFUNC)(HINSTANCE hDllInstance);
|
|
typedef HRESULT (*_ATL_PERFUNREGFUNC)();
|
|
__declspec(selectany) _ATL_PERFREGFUNC _pPerfRegFunc = NULL;
|
|
__declspec(selectany) _ATL_PERFUNREGFUNC _pPerfUnRegFunc = NULL;
|
|
|
|
struct _ATL_TERMFUNC_ELEM
|
|
{
|
|
_ATL_TERMFUNC* pFunc;
|
|
DWORD_PTR dw;
|
|
_ATL_TERMFUNC_ELEM* pNext;
|
|
};
|
|
|
|
|
|
// Can't inherit from _ATL_OBJMAP_ENTRY20
|
|
// because it messes up the OBJECT_MAP macros
|
|
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;
|
|
|
|
// Added in ATL 3.0
|
|
void (WINAPI *pfnObjectMain)(bool bStarting);
|
|
};
|
|
|
|
typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY;
|
|
|
|
#if defined(_M_IA64) || defined(_M_IX86)
|
|
|
|
#pragma data_seg(push)
|
|
#pragma data_seg("ATL$__a")
|
|
__declspec(selectany) _ATL_OBJMAP_ENTRY* __pobjMapEntryFirst = NULL;
|
|
#pragma data_seg("ATL$__z")
|
|
__declspec(selectany) _ATL_OBJMAP_ENTRY* __pobjMapEntryLast = NULL;
|
|
#pragma data_seg("ATL$__m")
|
|
#if !defined(_M_IA64)
|
|
#pragma comment(linker, "/merge:ATL=.data")
|
|
#endif
|
|
#pragma data_seg(pop)
|
|
|
|
#else
|
|
|
|
//REVIEW: data_seg(push/pop)?
|
|
__declspec(selectany) _ATL_OBJMAP_ENTRY* __pobjMapEntryFirst = NULL;
|
|
__declspec(selectany) _ATL_OBJMAP_ENTRY* __pobjMapEntryLast = NULL;
|
|
|
|
#endif // defined(_M_IA64) || defined(_M_IX86)
|
|
|
|
struct _ATL_REGMAP_ENTRY
|
|
{
|
|
LPCOLESTR szKey;
|
|
LPCOLESTR szData;
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Threading Model Support
|
|
|
|
class CComCriticalSection
|
|
{
|
|
public:
|
|
CComCriticalSection() throw()
|
|
{
|
|
memset(&m_sec, 0, sizeof(CRITICAL_SECTION));
|
|
}
|
|
HRESULT Lock() throw()
|
|
{
|
|
EnterCriticalSection(&m_sec);
|
|
return S_OK;
|
|
}
|
|
HRESULT Unlock() throw()
|
|
{
|
|
LeaveCriticalSection(&m_sec);
|
|
return S_OK;
|
|
}
|
|
HRESULT Init() throw()
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&m_sec);
|
|
}
|
|
// structured exception may be raised in low memory situations
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
if (STATUS_NO_MEMORY == GetExceptionCode())
|
|
hRes = E_OUTOFMEMORY;
|
|
else
|
|
hRes = E_FAIL;
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT Term() throw()
|
|
{
|
|
DeleteCriticalSection(&m_sec);
|
|
return S_OK;
|
|
}
|
|
CRITICAL_SECTION m_sec;
|
|
};
|
|
|
|
// Module
|
|
|
|
// Used by any project that uses ATL
|
|
struct _ATL_BASE_MODULE70
|
|
{
|
|
UINT cbSize;
|
|
HINSTANCE m_hInst;
|
|
HINSTANCE m_hInstResource;
|
|
DWORD dwAtlBuildVer;
|
|
GUID* pguidVer;
|
|
CComCriticalSection m_csResource;
|
|
};
|
|
typedef _ATL_BASE_MODULE70 _ATL_BASE_MODULE;
|
|
|
|
|
|
// Used by COM related code in ATL
|
|
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;
|
|
|
|
|
|
// Used by Windowing code in ATL
|
|
struct _ATL_WIN_MODULE70
|
|
{
|
|
UINT cbSize;
|
|
CComCriticalSection m_csWindowCreate;
|
|
ATOM m_rgWindowClassAtoms[128];
|
|
int m_nAtomIndex;
|
|
};
|
|
typedef _ATL_WIN_MODULE70 _ATL_WIN_MODULE;
|
|
|
|
struct _ATL_MODULE70
|
|
{
|
|
UINT cbSize;
|
|
LONG m_nLockCnt;
|
|
_ATL_TERMFUNC_ELEM* m_pTermFuncs;
|
|
CComCriticalSection m_csStaticDataInitAndTypeInfo;
|
|
};
|
|
|
|
typedef _ATL_MODULE70 _ATL_MODULE;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//This define makes debugging asserts easier.
|
|
#define _ATL_SIMPLEMAPENTRY ((ATL::_ATL_CREATORARGFUNC*)1)
|
|
|
|
struct _ATL_INTMAP_ENTRY
|
|
{
|
|
const IID* piid; // the interface id (IID)
|
|
DWORD_PTR dw;
|
|
_ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// QI Support
|
|
|
|
ATLAPI AtlInternalQueryInterface(void* pThis,
|
|
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Smart Pointer helpers
|
|
|
|
ATLAPI_(IUnknown*) AtlComPtrAssign(IUnknown** pp, IUnknown* lp);
|
|
ATLAPI_(IUnknown*) AtlComQIPtrAssign(IUnknown** pp, IUnknown* lp, REFIID riid);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IDispatch Error handling
|
|
|
|
ATLAPI AtlSetErrorInfo(const CLSID& clsid, LPCOLESTR lpszDesc,
|
|
DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes,
|
|
HINSTANCE hInst);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Module
|
|
|
|
|
|
ATLAPI AtlComModuleGetClassObject(_ATL_COM_MODULE* pComModule, REFCLSID rclsid, REFIID riid, LPVOID* ppv);
|
|
|
|
ATLAPI AtlComModuleRegisterServer(_ATL_COM_MODULE* pComModule, BOOL bRegTypeLib, const CLSID* pCLSID = NULL);
|
|
ATLAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE* pComModule, BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL);
|
|
|
|
ATLAPI AtlRegisterClassCategoriesHelper( REFCLSID clsid, const struct _ATL_CATMAP_ENTRY* pCatMap, BOOL bRegister );
|
|
|
|
ATLAPI AtlRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex);
|
|
ATLAPI AtlUnRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex);
|
|
ATLAPI AtlLoadTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex, BSTR* pbstrPath, ITypeLib** ppTypeLib);
|
|
|
|
ATLAPI AtlModuleAddTermFunc(_ATL_MODULE* pModule, _ATL_TERMFUNC* pFunc, DWORD_PTR dw);
|
|
ATLAPI_(void) AtlCallTermFunc(_ATL_MODULE* pModule);
|
|
|
|
}; //namespace ATL
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GUID comparison
|
|
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
inline BOOL InlineIsEqualUnknown(REFGUID rguid1)
|
|
{
|
|
return (
|
|
((PLONG) &rguid1)[0] == 0 &&
|
|
((PLONG) &rguid1)[1] == 0 &&
|
|
((PLONG) &rguid1)[2] == 0x000000C0 &&
|
|
((PLONG) &rguid1)[3] == 0x46000000);
|
|
}
|
|
|
|
|
|
}; // namespace ATL
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
ATL_NOINLINE inline HRESULT AtlHresultFromLastError() throw()
|
|
{
|
|
DWORD dwErr = ::GetLastError();
|
|
return HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
ATL_NOINLINE inline HRESULT AtlHresultFromWin32(DWORD nError) throw()
|
|
{
|
|
return( HRESULT_FROM_WIN32( nError ) );
|
|
}
|
|
|
|
}; // namespace ATL
|
|
|
|
#include <atlexcept.h>
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
template <class T>
|
|
class _NoAddRefReleaseOnCComPtr : public T
|
|
{
|
|
private:
|
|
STDMETHOD_(ULONG, AddRef)()=0;
|
|
STDMETHOD_(ULONG, Release)()=0;
|
|
};
|
|
|
|
template< typename T >
|
|
class CAutoVectorPtr
|
|
{
|
|
public:
|
|
CAutoVectorPtr() throw() :
|
|
m_p( NULL )
|
|
{
|
|
}
|
|
CAutoVectorPtr( CAutoVectorPtr< T >& p ) throw()
|
|
{
|
|
m_p = p.Detach(); // Transfer ownership
|
|
}
|
|
explicit CAutoVectorPtr( T* p ) throw() :
|
|
m_p( p )
|
|
{
|
|
}
|
|
~CAutoVectorPtr() throw()
|
|
{
|
|
Free();
|
|
}
|
|
|
|
operator T*() const throw()
|
|
{
|
|
return( m_p );
|
|
}
|
|
|
|
CAutoVectorPtr< T >& operator=( CAutoVectorPtr< T >& p ) throw()
|
|
{
|
|
Free();
|
|
Attach( p.Detach() ); // Transfer ownership
|
|
|
|
return( *this );
|
|
}
|
|
|
|
// Allocate the vector
|
|
bool Allocate( size_t nElements ) throw()
|
|
{
|
|
ATLASSERT( m_p == NULL );
|
|
ATLTRY( m_p = new T[nElements] );
|
|
if( m_p == NULL )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
// Attach to an existing pointer (takes ownership)
|
|
void Attach( T* p ) throw()
|
|
{
|
|
ATLASSERT( m_p == NULL );
|
|
m_p = p;
|
|
}
|
|
|
|
|
|
// Detach the pointer (releases ownership)
|
|
T* Detach() throw()
|
|
{
|
|
T* p;
|
|
|
|
p = m_p;
|
|
m_p = NULL;
|
|
|
|
return( p );
|
|
}
|
|
// Delete the vector pointed to, and set the pointer to NULL
|
|
void Free() throw()
|
|
{
|
|
delete[] m_p;
|
|
m_p = NULL;
|
|
}
|
|
|
|
public:
|
|
T* m_p;
|
|
};
|
|
|
|
|
|
//CComPtrBase provides the basis for all other smart pointers
|
|
//The other smartpointers add their own constructors and operators
|
|
template <class T>
|
|
class CComPtrBase
|
|
{
|
|
protected:
|
|
CComPtrBase() throw()
|
|
{
|
|
p = NULL;
|
|
}
|
|
CComPtrBase(int nNull) throw()
|
|
{
|
|
ATLASSERT(nNull == 0);
|
|
(void)nNull;
|
|
p = NULL;
|
|
}
|
|
CComPtrBase(T* lp) throw()
|
|
{
|
|
p = lp;
|
|
if (p != NULL)
|
|
p->AddRef();
|
|
}
|
|
public:
|
|
typedef T _PtrClass;
|
|
~CComPtrBase() throw()
|
|
{
|
|
if (p)
|
|
p->Release();
|
|
}
|
|
operator T*() const throw()
|
|
{
|
|
return p;
|
|
}
|
|
T& operator*() const throw()
|
|
{
|
|
ATLASSERT(p!=NULL);
|
|
return *p;
|
|
}
|
|
//The assert on operator& usually indicates a bug. If this is really
|
|
//what is needed, however, take the address of the p member explicitly.
|
|
T** operator&() throw()
|
|
{
|
|
ATLASSERT(p==NULL);
|
|
return &p;
|
|
}
|
|
|
|
_NoAddRefReleaseOnCComPtr<T>* operator->() const throw()
|
|
{
|
|
ATLASSERT(p!=NULL);
|
|
return (_NoAddRefReleaseOnCComPtr<T>*)p;
|
|
}
|
|
|
|
bool operator!() const throw()
|
|
{
|
|
return (p == NULL);
|
|
}
|
|
bool operator<(T* pT) const throw()
|
|
{
|
|
return p < pT;
|
|
}
|
|
bool operator==(T* pT) const throw()
|
|
{
|
|
return p == pT;
|
|
}
|
|
|
|
// Release the interface and set to NULL
|
|
void Release() throw()
|
|
{
|
|
T* pTemp = p;
|
|
if (pTemp)
|
|
{
|
|
p = NULL;
|
|
pTemp->Release();
|
|
}
|
|
}
|
|
// Compare two objects for equivalence
|
|
bool IsEqualObject(IUnknown* pOther) throw()
|
|
{
|
|
if (p == pOther)
|
|
return true;
|
|
|
|
if (p == NULL || pOther == NULL)
|
|
return false; // One is NULL the other is not
|
|
|
|
CComPtr<IUnknown> punk1;
|
|
CComPtr<IUnknown> punk2;
|
|
p->QueryInterface(__uuidof(IUnknown), (void**)&punk1);
|
|
pOther->QueryInterface(__uuidof(IUnknown), (void**)&punk2);
|
|
return punk1 == punk2;
|
|
}
|
|
// Attach to an existing interface (does not AddRef)
|
|
void Attach(T* p2) throw()
|
|
{
|
|
if (p)
|
|
p->Release();
|
|
p = p2;
|
|
}
|
|
// Detach the interface (does not Release)
|
|
T* Detach() throw()
|
|
{
|
|
T* pt = p;
|
|
p = NULL;
|
|
return pt;
|
|
}
|
|
HRESULT CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) throw()
|
|
{
|
|
ATLASSERT(p == NULL);
|
|
return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);
|
|
}
|
|
HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) throw()
|
|
{
|
|
CLSID clsid;
|
|
HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
|
|
ATLASSERT(p == NULL);
|
|
if (SUCCEEDED(hr))
|
|
hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);
|
|
return hr;
|
|
}
|
|
template <class Q>
|
|
HRESULT QueryInterface(Q** pp) const throw()
|
|
{
|
|
ATLASSERT(pp != NULL);
|
|
return p->QueryInterface(__uuidof(Q), (void**)pp);
|
|
}
|
|
T* p;
|
|
};
|
|
|
|
template <class T>
|
|
class CComPtr : public CComPtrBase<T>
|
|
{
|
|
public:
|
|
CComPtr() throw()
|
|
{
|
|
}
|
|
|
|
CComPtr(int nNull) throw() :
|
|
CComPtrBase<T>(nNull)
|
|
{
|
|
}
|
|
|
|
CComPtr(T* lp) throw() :
|
|
CComPtrBase<T>(lp)
|
|
{
|
|
}
|
|
|
|
CComPtr(const CComPtr<T>& lp) throw() :
|
|
CComPtrBase<T>(lp.p)
|
|
{
|
|
}
|
|
|
|
template <typename Q>
|
|
T* operator=(const CComPtr<Q>& lp) throw()
|
|
{
|
|
return static_cast<T*>(AtlComQIPtrAssign((IUnknown**)&p, lp, __uuidof(T)));
|
|
}
|
|
};
|
|
|
|
|
|
template <class T, const IID* piid = &__uuidof(T)>
|
|
class CComQIPtr : public CComPtr<T>
|
|
{
|
|
public:
|
|
CComQIPtr() throw()
|
|
{
|
|
}
|
|
CComQIPtr(T* lp) throw() :
|
|
CComPtr<T>(lp)
|
|
{
|
|
}
|
|
CComQIPtr(const CComQIPtr<T,piid>& lp) throw() :
|
|
CComPtr<T>(lp.p)
|
|
{
|
|
}
|
|
CComQIPtr(IUnknown* lp) throw()
|
|
{
|
|
if (lp != NULL)
|
|
lp->QueryInterface(*piid, (void **)&p);
|
|
}
|
|
T* operator=(T* lp) throw()
|
|
{
|
|
return static_cast<T*>(AtlComPtrAssign((IUnknown**)&p, lp));
|
|
}
|
|
T* operator=(const CComQIPtr<T,piid>& lp) throw()
|
|
{
|
|
return static_cast<T*>(AtlComPtrAssign((IUnknown**)&p, lp.p));
|
|
}
|
|
T* operator=(IUnknown* lp) throw()
|
|
{
|
|
return static_cast<T*>(AtlComQIPtrAssign((IUnknown**)&p, lp, *piid));
|
|
}
|
|
};
|
|
|
|
//Specialization to make it work
|
|
template<>
|
|
class CComQIPtr<IUnknown, &IID_IUnknown> : public CComPtr<IUnknown>
|
|
{
|
|
public:
|
|
CComQIPtr() throw()
|
|
{
|
|
}
|
|
CComQIPtr(IUnknown* lp) throw()
|
|
{
|
|
//Actually do a QI to get identity
|
|
if (lp != NULL)
|
|
lp->QueryInterface(__uuidof(IUnknown), (void **)&p);
|
|
}
|
|
CComQIPtr(const CComQIPtr<IUnknown,&IID_IUnknown>& lp) throw() :
|
|
CComPtr<IUnknown>(lp.p)
|
|
{
|
|
}
|
|
IUnknown* operator=(IUnknown* lp) throw()
|
|
{
|
|
//Actually do a QI to get identity
|
|
return AtlComQIPtrAssign((IUnknown**)&p, lp, __uuidof(IUnknown));
|
|
}
|
|
IUnknown* operator=(const CComQIPtr<IUnknown,&IID_IUnknown>& lp) throw()
|
|
{
|
|
return AtlComPtrAssign((IUnknown**)&p, lp.p);
|
|
}
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Threading Model Support
|
|
|
|
class CComAutoCriticalSection : public CComCriticalSection
|
|
{
|
|
public:
|
|
CComAutoCriticalSection()
|
|
{
|
|
HRESULT hr = CComCriticalSection::Init();
|
|
if (FAILED(hr))
|
|
AtlThrow(hr);
|
|
}
|
|
~CComAutoCriticalSection() throw()
|
|
{
|
|
CComCriticalSection::Term();
|
|
}
|
|
private :
|
|
HRESULT Init(); // Not implemented. CComAutoCriticalSection::Init should never be called
|
|
HRESULT Term(); // Not implemented. CComAutoCriticalSection::Term should never be called
|
|
};
|
|
|
|
class CComFakeCriticalSection
|
|
{
|
|
public:
|
|
HRESULT Lock() throw() { return S_OK; }
|
|
HRESULT Unlock() throw() { return S_OK; }
|
|
HRESULT Init() throw() { return S_OK; }
|
|
HRESULT Term() throw() { return S_OK; }
|
|
};
|
|
|
|
template< class TLock >
|
|
class CComCritSecLock
|
|
{
|
|
public:
|
|
CComCritSecLock( TLock& cs, bool bInitialLock = true );
|
|
~CComCritSecLock() throw();
|
|
|
|
HRESULT Lock() throw();
|
|
void Unlock() throw();
|
|
|
|
// Implementation
|
|
private:
|
|
TLock& m_cs;
|
|
bool m_bLocked;
|
|
|
|
// Private to avoid accidental use
|
|
CComCritSecLock( const CComCritSecLock& ) throw();
|
|
CComCritSecLock& operator=( const CComCritSecLock& ) throw();
|
|
};
|
|
|
|
template< class TLock >
|
|
inline CComCritSecLock< TLock >::CComCritSecLock( TLock& cs, bool bInitialLock ) :
|
|
m_cs( cs ),
|
|
m_bLocked( false )
|
|
{
|
|
if( bInitialLock )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = Lock();
|
|
if( FAILED( hr ) )
|
|
{
|
|
AtlThrow( hr );
|
|
}
|
|
}
|
|
}
|
|
|
|
template< class TLock >
|
|
inline CComCritSecLock< TLock >::~CComCritSecLock() throw()
|
|
{
|
|
if( m_bLocked )
|
|
{
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
template< class TLock >
|
|
inline HRESULT CComCritSecLock< TLock >::Lock() throw()
|
|
{
|
|
HRESULT hr;
|
|
|
|
ATLASSERT( !m_bLocked );
|
|
hr = m_cs.Lock();
|
|
if( FAILED( hr ) )
|
|
{
|
|
return( hr );
|
|
}
|
|
m_bLocked = true;
|
|
|
|
return( S_OK );
|
|
}
|
|
|
|
template< class TLock >
|
|
inline void CComCritSecLock< TLock >::Unlock() throw()
|
|
{
|
|
ATLASSERT( m_bLocked );
|
|
m_cs.Unlock();
|
|
m_bLocked = false;
|
|
}
|
|
|
|
class CComMultiThreadModelNoCS
|
|
{
|
|
public:
|
|
static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);}
|
|
static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);}
|
|
typedef CComFakeCriticalSection AutoCriticalSection;
|
|
typedef CComFakeCriticalSection CriticalSection;
|
|
typedef CComMultiThreadModelNoCS ThreadModelNoCS;
|
|
};
|
|
|
|
class CComMultiThreadModel
|
|
{
|
|
public:
|
|
static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);}
|
|
static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);}
|
|
typedef CComAutoCriticalSection AutoCriticalSection;
|
|
typedef CComCriticalSection CriticalSection;
|
|
typedef CComMultiThreadModelNoCS ThreadModelNoCS;
|
|
};
|
|
|
|
class CComSingleThreadModel
|
|
{
|
|
public:
|
|
static ULONG WINAPI Increment(LPLONG p) throw() {return ++(*p);}
|
|
static ULONG WINAPI Decrement(LPLONG p) throw() {return --(*p);}
|
|
typedef CComFakeCriticalSection AutoCriticalSection;
|
|
typedef CComFakeCriticalSection CriticalSection;
|
|
typedef CComSingleThreadModel ThreadModelNoCS;
|
|
};
|
|
|
|
#if defined(_ATL_APARTMENT_THREADED)
|
|
|
|
#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_FREE_THREADED)
|
|
#pragma message ("More than one global threading model defined.")
|
|
#endif
|
|
|
|
typedef CComSingleThreadModel CComObjectThreadModel;
|
|
typedef CComMultiThreadModel CComGlobalsThreadModel;
|
|
|
|
#elif defined(_ATL_FREE_THREADED)
|
|
|
|
#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_APARTMENT_THREADED)
|
|
#pragma message ("More than one global threading model defined.")
|
|
#endif
|
|
|
|
typedef CComMultiThreadModel CComObjectThreadModel;
|
|
typedef CComMultiThreadModel CComGlobalsThreadModel;
|
|
|
|
#else
|
|
#pragma message ("No global threading model defined")
|
|
#endif
|
|
|
|
}; // namespace ATL
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Dual argument helper classes
|
|
|
|
#define UpdateRegistryFromResource UpdateRegistryFromResourceS
|
|
|
|
#ifndef _delayimp_h
|
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
|
#endif
|
|
|
|
class CAtlBaseModule : public _ATL_BASE_MODULE
|
|
{
|
|
public :
|
|
static bool m_bInitFailed;
|
|
CAtlBaseModule() throw()
|
|
{
|
|
cbSize = sizeof(_ATL_BASE_MODULE);
|
|
|
|
m_hInst = m_hInstResource = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
|
|
|
dwAtlBuildVer = _ATL_VER;
|
|
pguidVer = &GUID_ATLVer70;
|
|
|
|
if (FAILED(m_csResource.Init()))
|
|
{
|
|
ATLASSERT(0);
|
|
CAtlBaseModule::m_bInitFailed = true;
|
|
}
|
|
}
|
|
|
|
~CAtlBaseModule() throw ()
|
|
{
|
|
}
|
|
|
|
HINSTANCE GetModuleInstance() throw()
|
|
{
|
|
return m_hInst;
|
|
}
|
|
HINSTANCE GetResourceInstance() throw()
|
|
{
|
|
return m_hInstResource;
|
|
}
|
|
};
|
|
|
|
__declspec(selectany) bool CAtlBaseModule::m_bInitFailed = false;
|
|
extern CAtlBaseModule _AtlBaseModule;
|
|
|
|
class CAtlComModule : public _ATL_COM_MODULE
|
|
{
|
|
public:
|
|
|
|
CAtlComModule() throw()
|
|
{
|
|
cbSize = sizeof(_ATL_COM_MODULE);
|
|
|
|
m_hInstTypeLib = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
|
|
|
m_ppAutoObjMapFirst = &__pobjMapEntryFirst + 1;
|
|
m_ppAutoObjMapLast = &__pobjMapEntryLast;
|
|
|
|
if (FAILED(m_csObjMap.Init()))
|
|
{
|
|
ATLASSERT(0);
|
|
CAtlBaseModule::m_bInitFailed = true;
|
|
}
|
|
}
|
|
|
|
~CAtlComModule()
|
|
{
|
|
Term();
|
|
}
|
|
|
|
// Called from ~CAtlComModule or from ~CAtlExeModule.
|
|
void Term()
|
|
{
|
|
if (cbSize == 0)
|
|
return;
|
|
|
|
for (_ATL_OBJMAP_ENTRY** ppEntry = m_ppAutoObjMapFirst; ppEntry < m_ppAutoObjMapLast; ppEntry++)
|
|
{
|
|
if (*ppEntry != NULL)
|
|
{
|
|
_ATL_OBJMAP_ENTRY* pEntry = *ppEntry;
|
|
if (pEntry->pCF != NULL)
|
|
pEntry->pCF->Release();
|
|
pEntry->pCF = NULL;
|
|
}
|
|
}
|
|
// Set to 0 to indicate that this function has been called
|
|
// At this point no one should be concerned about cbsize
|
|
// having the correct value
|
|
cbSize = 0;
|
|
}
|
|
|
|
// RegisterServer walks the ATL Autogenerated object map and registers each object in the map
|
|
// If pCLSID is not NULL then only the object referred to by pCLSID is registered (The default case)
|
|
// otherwise all the objects are registered
|
|
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL)
|
|
{
|
|
return AtlComModuleRegisterServer(this, bRegTypeLib, pCLSID);
|
|
}
|
|
|
|
// UnregisterServer walks the ATL Autogenerated object map and unregisters each object in the map
|
|
// If pCLSID is not NULL then only the object referred to by pCLSID is unregistered (The default case)
|
|
// otherwise all the objects are unregistered.
|
|
HRESULT UnregisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL)
|
|
{
|
|
return AtlComModuleUnregisterServer(this, bRegTypeLib, pCLSID);
|
|
}
|
|
};
|
|
|
|
class CAtlModule;
|
|
__declspec(selectany) CAtlModule* _pAtlModule = NULL;
|
|
|
|
class CRegObject;
|
|
|
|
class ATL_NO_VTABLE CAtlModule : public _ATL_MODULE
|
|
{
|
|
public :
|
|
static GUID m_libid;
|
|
IGlobalInterfaceTable* m_pGIT;
|
|
|
|
CAtlModule() throw()
|
|
{
|
|
// Should have only one instance of a class
|
|
// derived from CAtlModule in a project.
|
|
ATLASSERT(_pAtlModule == NULL);
|
|
cbSize = sizeof(_ATL_MODULE);
|
|
m_pTermFuncs = NULL;
|
|
|
|
m_nLockCnt = 0;
|
|
_pAtlModule = this;
|
|
if (FAILED(m_csStaticDataInitAndTypeInfo.Init()))
|
|
{
|
|
ATLASSERT(0);
|
|
CAtlBaseModule::m_bInitFailed = true;
|
|
}
|
|
|
|
m_pGIT = NULL;
|
|
}
|
|
|
|
void Term() throw()
|
|
{
|
|
// cbSize == 0 indicates that Term has already been called
|
|
if (cbSize == 0)
|
|
return;
|
|
|
|
// Call term functions
|
|
if (m_pTermFuncs != NULL)
|
|
{
|
|
AtlCallTermFunc(this);
|
|
m_pTermFuncs = NULL;
|
|
}
|
|
|
|
if (m_pGIT != NULL)
|
|
m_pGIT->Release();
|
|
|
|
cbSize = 0;
|
|
}
|
|
|
|
~CAtlModule() throw()
|
|
{
|
|
Term();
|
|
}
|
|
|
|
virtual LONG Lock() throw()
|
|
{
|
|
return CComGlobalsThreadModel::Increment(&m_nLockCnt);
|
|
}
|
|
|
|
virtual LONG Unlock() throw()
|
|
{
|
|
return CComGlobalsThreadModel::Decrement(&m_nLockCnt);
|
|
}
|
|
|
|
virtual LONG GetLockCount() throw()
|
|
{
|
|
return m_nLockCnt;
|
|
}
|
|
|
|
HRESULT AddTermFunc(_ATL_TERMFUNC* pFunc, DWORD_PTR dw) throw()
|
|
{
|
|
return AtlModuleAddTermFunc(this, pFunc, dw);
|
|
}
|
|
|
|
virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* /*pRegistrar*/) throw()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// Statically linking to Registry component
|
|
HRESULT WINAPI UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister,
|
|
struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw();
|
|
HRESULT WINAPI UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister,
|
|
struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw();
|
|
|
|
// Implementation
|
|
|
|
static void EscapeSingleQuote(LPOLESTR lpDest, LPCOLESTR lp) throw()
|
|
{
|
|
while (*lp)
|
|
{
|
|
*lpDest++ = *lp;
|
|
if (*lp == '\'')
|
|
*lpDest++ = *lp;
|
|
lp++;
|
|
}
|
|
*lpDest = NULL;
|
|
}
|
|
};
|
|
|
|
__declspec(selectany) GUID CAtlModule::m_libid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} };
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE CAtlModuleT : public CAtlModule
|
|
{
|
|
public :
|
|
CAtlModuleT() throw()
|
|
{
|
|
T::InitLibId();
|
|
}
|
|
|
|
static void InitLibId() throw()
|
|
{
|
|
}
|
|
|
|
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) throw();
|
|
HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL) throw();
|
|
};
|
|
|
|
|
|
class CComModule;
|
|
__declspec(selectany) CComModule* _pModule = NULL;
|
|
class CComModule : public CAtlModuleT<CComModule>
|
|
{
|
|
public :
|
|
|
|
CComModule()
|
|
{
|
|
// Should have only one instance of a class
|
|
// derived from CComModule in a project.
|
|
ATLASSERT(_pModule == NULL);
|
|
_pModule = this;
|
|
}
|
|
|
|
HINSTANCE m_hInst;
|
|
HINSTANCE m_hInstTypeLib;
|
|
|
|
// For Backward compatibility
|
|
_ATL_OBJMAP_ENTRY* m_pObjMap;
|
|
|
|
HRESULT Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid = NULL) throw();
|
|
void Term() throw();
|
|
|
|
HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw();
|
|
// Registry support (helpers)
|
|
HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) throw();
|
|
HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL) throw();
|
|
HRESULT UnregisterServer(const CLSID* pCLSID = NULL) throw();
|
|
|
|
// Statically linking to Registry Ponent
|
|
virtual HRESULT WINAPI UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister,
|
|
struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw()
|
|
{
|
|
return CAtlModuleT<CComModule>::UpdateRegistryFromResourceS(lpszRes, bRegister, pMapEntries);
|
|
}
|
|
virtual HRESULT WINAPI UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister,
|
|
struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw()
|
|
{
|
|
return CAtlModuleT<CComModule>::UpdateRegistryFromResourceS(nResID, bRegister, pMapEntries);
|
|
}
|
|
|
|
};
|
|
|
|
#define ATL_VARIANT_TRUE VARIANT_BOOL( -1 )
|
|
#define ATL_VARIANT_FALSE VARIANT_BOOL( 0 )
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CComBSTR
|
|
|
|
class CComBSTR
|
|
{
|
|
public:
|
|
BSTR m_str;
|
|
CComBSTR() throw()
|
|
{
|
|
m_str = NULL;
|
|
}
|
|
CComBSTR(int nSize)
|
|
{
|
|
if (nSize == 0)
|
|
m_str = NULL;
|
|
else
|
|
{
|
|
m_str = ::SysAllocStringLen(NULL, nSize);
|
|
if (m_str == NULL)
|
|
AtlThrow(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
CComBSTR(LPCOLESTR pSrc)
|
|
{
|
|
if (pSrc == NULL)
|
|
m_str = NULL;
|
|
else
|
|
{
|
|
m_str = ::SysAllocString(pSrc);
|
|
if (m_str == NULL)
|
|
AtlThrow(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
CComBSTR(const CComBSTR& src)
|
|
{
|
|
m_str = src.Copy();
|
|
if (!!src && m_str == NULL)
|
|
AtlThrow(E_OUTOFMEMORY);
|
|
|
|
}
|
|
CComBSTR& operator=(const CComBSTR& src)
|
|
{
|
|
if (m_str != src.m_str)
|
|
{
|
|
::SysFreeString(m_str);
|
|
m_str = src.Copy();
|
|
if (!!src && m_str == NULL)
|
|
AtlThrow(E_OUTOFMEMORY);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CComBSTR& operator=(LPCOLESTR pSrc)
|
|
{
|
|
::SysFreeString(m_str);
|
|
if (pSrc != NULL)
|
|
{
|
|
m_str = ::SysAllocString(pSrc);
|
|
if (m_str == NULL)
|
|
AtlThrow(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
m_str = NULL;
|
|
return *this;
|
|
}
|
|
|
|
~CComBSTR() throw()
|
|
{
|
|
::SysFreeString(m_str);
|
|
}
|
|
unsigned int Length() const throw()
|
|
{
|
|
return (m_str == NULL)? 0 : SysStringLen(m_str);
|
|
}
|
|
unsigned int ByteLength() const throw()
|
|
{
|
|
return (m_str == NULL)? 0 : SysStringByteLen(m_str);
|
|
}
|
|
operator BSTR() const throw()
|
|
{
|
|
return m_str;
|
|
}
|
|
BSTR* operator&() throw()
|
|
{
|
|
return &m_str;
|
|
}
|
|
BSTR Copy() const throw()
|
|
{
|
|
if (m_str == NULL)
|
|
return NULL;
|
|
return ::SysAllocStringByteLen((char*)m_str, ::SysStringByteLen(m_str));
|
|
}
|
|
void Attach(BSTR src) throw()
|
|
{
|
|
::SysFreeString(m_str);
|
|
m_str = src;
|
|
}
|
|
BSTR Detach() throw()
|
|
{
|
|
BSTR s = m_str;
|
|
m_str = NULL;
|
|
return s;
|
|
}
|
|
void Empty() throw()
|
|
{
|
|
::SysFreeString(m_str);
|
|
m_str = NULL;
|
|
}
|
|
bool operator!() const throw()
|
|
{
|
|
return (m_str == NULL);
|
|
}
|
|
|
|
HRESULT Append(LPCOLESTR lpsz) throw()
|
|
{
|
|
return Append(lpsz, UINT(lstrlenW(lpsz)));
|
|
}
|
|
|
|
// a BSTR is just a LPCOLESTR so we need a special version to signify
|
|
// that we are appending a BSTR
|
|
HRESULT AppendBSTR(BSTR p) throw()
|
|
{
|
|
if (p == NULL)
|
|
return S_OK;
|
|
BSTR bstrNew = NULL;
|
|
HRESULT hr;
|
|
hr = VarBstrCat(m_str, p, &bstrNew);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
::SysFreeString(m_str);
|
|
m_str = bstrNew;
|
|
}
|
|
return hr;
|
|
}
|
|
HRESULT Append(LPCOLESTR lpsz, int nLen) throw()
|
|
{
|
|
if (lpsz == NULL || (m_str != NULL && nLen == 0))
|
|
return S_OK;
|
|
int n1 = Length();
|
|
BSTR b;
|
|
b = ::SysAllocStringLen(NULL, n1+nLen);
|
|
if (b == NULL)
|
|
return E_OUTOFMEMORY;
|
|
memcpy(b, m_str, n1*sizeof(OLECHAR));
|
|
memcpy(b+n1, lpsz, nLen*sizeof(OLECHAR));
|
|
b[n1+nLen] = NULL;
|
|
SysFreeString(m_str);
|
|
m_str = b;
|
|
return S_OK;
|
|
}
|
|
|
|
CComBSTR& operator+=(LPCOLESTR pszSrc)
|
|
{
|
|
HRESULT hr;
|
|
hr = Append(pszSrc);
|
|
if (FAILED(hr))
|
|
AtlThrow(hr);
|
|
return *this;
|
|
}
|
|
|
|
bool operator<(const CComBSTR& bstrSrc) const throw()
|
|
{
|
|
return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == VARCMP_LT;
|
|
}
|
|
bool operator<(LPCOLESTR pszSrc) const
|
|
{
|
|
CComBSTR bstr2(pszSrc);
|
|
return operator<(bstr2);
|
|
}
|
|
bool operator>(const CComBSTR& bstrSrc) const throw()
|
|
{
|
|
return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == VARCMP_GT;
|
|
}
|
|
bool operator>(LPCOLESTR pszSrc) const
|
|
{
|
|
CComBSTR bstr2(pszSrc);
|
|
return operator>(bstr2);
|
|
}
|
|
bool operator==(const CComBSTR& bstrSrc) const throw()
|
|
{
|
|
return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == VARCMP_EQ;
|
|
}
|
|
bool operator==(LPCOLESTR pszSrc) const
|
|
{
|
|
CComBSTR bstr2(pszSrc);
|
|
return operator==(bstr2);
|
|
}
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CComVariant
|
|
|
|
class CComVariant : public tagVARIANT
|
|
{
|
|
// Constructors
|
|
public:
|
|
CComVariant() throw()
|
|
{
|
|
::VariantInit(this);
|
|
}
|
|
~CComVariant() throw()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
CComVariant(LPCOLESTR lpszSrc)
|
|
{
|
|
vt = VT_EMPTY;
|
|
*this = lpszSrc;
|
|
}
|
|
|
|
// Assignment Operators
|
|
public:
|
|
|
|
CComVariant& operator=(const VARIANT& varSrc)
|
|
{
|
|
InternalCopy(&varSrc);
|
|
return *this;
|
|
}
|
|
|
|
CComVariant& operator=(LPCOLESTR lpszSrc)
|
|
{
|
|
Clear();
|
|
vt = VT_BSTR;
|
|
bstrVal = ::SysAllocString(lpszSrc);
|
|
|
|
if (bstrVal == NULL && lpszSrc != NULL)
|
|
{
|
|
vt = VT_ERROR;
|
|
scode = E_OUTOFMEMORY;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CComVariant& operator=(long nSrc) throw()
|
|
{
|
|
if (vt != VT_I4)
|
|
{
|
|
Clear();
|
|
vt = VT_I4;
|
|
}
|
|
lVal = nSrc;
|
|
return *this;
|
|
}
|
|
|
|
CComVariant& operator=(unsigned long nSrc) throw()
|
|
{
|
|
if (vt != VT_UI4)
|
|
{
|
|
Clear();
|
|
vt = VT_UI4;
|
|
}
|
|
ulVal = nSrc;
|
|
return *this;
|
|
}
|
|
|
|
|
|
// Operations
|
|
public:
|
|
HRESULT Clear() { return ::VariantClear(this); }
|
|
HRESULT Copy(const VARIANT* pSrc) { return ::VariantCopy(this, const_cast<VARIANT*>(pSrc)); }
|
|
|
|
HRESULT Detach(VARIANT* pDest)
|
|
{
|
|
ATLASSERT(pDest != NULL);
|
|
// Clear out the variant
|
|
HRESULT hr = ::VariantClear(pDest);
|
|
if (!FAILED(hr))
|
|
{
|
|
// Copy the contents and remove control from CComVariant
|
|
memcpy(pDest, this, sizeof(VARIANT));
|
|
vt = VT_EMPTY;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// Implementation
|
|
private:
|
|
|
|
void InternalCopy(const VARIANT* pSrc)
|
|
{
|
|
HRESULT hr = Copy(pSrc);
|
|
if (FAILED(hr))
|
|
{
|
|
vt = VT_ERROR;
|
|
scode = hr;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRegKey
|
|
|
|
class CRegKey
|
|
{
|
|
public:
|
|
CRegKey() throw();
|
|
~CRegKey() throw();
|
|
|
|
// Attributes
|
|
public:
|
|
operator HKEY() const throw();
|
|
HKEY m_hKey;
|
|
|
|
// Operations
|
|
public:
|
|
LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw();
|
|
LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) throw();
|
|
LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) throw();
|
|
LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) throw();
|
|
|
|
LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw();
|
|
LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) throw();
|
|
LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) throw();
|
|
|
|
// Create a new registry key (or open an existing one).
|
|
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) throw();
|
|
|
|
// Open an existing registry key.
|
|
LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName,
|
|
REGSAM samDesired = KEY_READ | KEY_WRITE) throw();
|
|
// Close the registry key.
|
|
LONG Close() throw();
|
|
|
|
// Detach the CRegKey object from its HKEY. Releases ownership.
|
|
HKEY Detach() throw();
|
|
// Attach the CRegKey object to an existing HKEY. Takes ownership.
|
|
void Attach(HKEY hKey) throw();
|
|
|
|
LONG DeleteSubKey(LPCTSTR lpszSubKey) throw();
|
|
LONG RecurseDeleteKey(LPCTSTR lpszKey) throw();
|
|
LONG DeleteValue(LPCTSTR lpszValue) throw();
|
|
};
|
|
|
|
inline CRegKey::CRegKey() :
|
|
m_hKey( NULL )
|
|
{
|
|
}
|
|
inline CRegKey::~CRegKey()
|
|
{
|
|
Close();
|
|
}
|
|
inline CRegKey::operator HKEY() const
|
|
{
|
|
return m_hKey;
|
|
}
|
|
|
|
inline HKEY CRegKey::Detach()
|
|
{
|
|
HKEY hKey = m_hKey;
|
|
m_hKey = NULL;
|
|
return hKey;
|
|
}
|
|
|
|
inline void CRegKey::Attach(HKEY hKey)
|
|
{
|
|
ATLASSERT(m_hKey == NULL);
|
|
m_hKey = hKey;
|
|
}
|
|
|
|
inline LONG CRegKey::DeleteSubKey(LPCTSTR lpszSubKey)
|
|
{
|
|
ATLASSERT(m_hKey != NULL);
|
|
return RegDeleteKey(m_hKey, lpszSubKey);
|
|
}
|
|
|
|
inline LONG CRegKey::DeleteValue(LPCTSTR lpszValue)
|
|
{
|
|
ATLASSERT(m_hKey != NULL);
|
|
return RegDeleteValue(m_hKey, (LPTSTR)lpszValue);
|
|
}
|
|
|
|
inline LONG CRegKey::Close()
|
|
{
|
|
LONG lRes = ERROR_SUCCESS;
|
|
if (m_hKey != NULL)
|
|
{
|
|
lRes = RegCloseKey(m_hKey);
|
|
m_hKey = NULL;
|
|
}
|
|
return lRes;
|
|
}
|
|
|
|
inline LONG CRegKey::Create(HKEY hKeyParent, LPCTSTR lpszKeyName,
|
|
LPTSTR lpszClass, DWORD dwOptions, REGSAM samDesired,
|
|
LPSECURITY_ATTRIBUTES lpSecAttr, LPDWORD lpdwDisposition)
|
|
{
|
|
ATLASSERT(hKeyParent != NULL);
|
|
DWORD dw;
|
|
HKEY hKey = NULL;
|
|
LONG lRes = RegCreateKeyEx(hKeyParent, lpszKeyName, 0,
|
|
lpszClass, dwOptions, samDesired, lpSecAttr, &hKey, &dw);
|
|
if (lpdwDisposition != NULL)
|
|
*lpdwDisposition = dw;
|
|
if (lRes == ERROR_SUCCESS)
|
|
{
|
|
lRes = Close();
|
|
m_hKey = hKey;
|
|
}
|
|
return lRes;
|
|
}
|
|
|
|
inline LONG CRegKey::Open(HKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired)
|
|
{
|
|
ATLASSERT(hKeyParent != NULL);
|
|
HKEY hKey = NULL;
|
|
LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyName, 0, samDesired, &hKey);
|
|
if (lRes == ERROR_SUCCESS)
|
|
{
|
|
lRes = Close();
|
|
ATLASSERT(lRes == ERROR_SUCCESS);
|
|
m_hKey = hKey;
|
|
}
|
|
return lRes;
|
|
}
|
|
|
|
inline LONG CRegKey::QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw()
|
|
{
|
|
ATLASSERT(m_hKey != NULL);
|
|
|
|
return( ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast< LPBYTE >( pData ), pnBytes) );
|
|
}
|
|
|
|
inline LONG CRegKey::QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue)
|
|
{
|
|
LONG lRes;
|
|
ULONG nBytes;
|
|
DWORD dwType;
|
|
|
|
ATLASSERT(m_hKey != NULL);
|
|
|
|
nBytes = sizeof(DWORD);
|
|
lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(&dwValue),
|
|
&nBytes);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
if (dwType != REG_DWORD)
|
|
return ERROR_INVALID_DATA;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
inline LONG CRegKey::QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars)
|
|
{
|
|
LONG lRes;
|
|
DWORD dwType;
|
|
ULONG nBytes;
|
|
|
|
ATLASSERT(m_hKey != NULL);
|
|
ATLASSERT(pnChars != NULL);
|
|
|
|
nBytes = (*pnChars)*sizeof(TCHAR);
|
|
*pnChars = 0;
|
|
lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pszValue),
|
|
&nBytes);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
if (dwType != REG_SZ)
|
|
return ERROR_INVALID_DATA;
|
|
*pnChars = nBytes/sizeof(TCHAR);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
inline LONG CRegKey::SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw()
|
|
{
|
|
ATLASSERT(m_hKey != NULL);
|
|
return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast<const BYTE*>(pValue), nBytes);
|
|
}
|
|
|
|
inline LONG CRegKey::SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue)
|
|
{
|
|
ATLASSERT(m_hKey != NULL);
|
|
return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast<const BYTE*>(&dwValue), sizeof(DWORD));
|
|
}
|
|
|
|
inline LONG CRegKey::SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType)
|
|
{
|
|
ATLASSERT(m_hKey != NULL);
|
|
ATLASSERT(pszValue != NULL);
|
|
ATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ));
|
|
|
|
return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast<const BYTE*>(pszValue), (lstrlen(pszValue)+1)*sizeof(TCHAR));
|
|
}
|
|
|
|
inline LONG CRegKey::SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue)
|
|
{
|
|
LPCTSTR pszTemp;
|
|
ULONG nBytes;
|
|
ULONG nLength;
|
|
|
|
ATLASSERT(m_hKey != NULL);
|
|
ATLASSERT(pszValue != NULL);
|
|
|
|
// Find the total length (in bytes) of all of the strings, including the
|
|
// terminating '\0' of each string, and the second '\0' that terminates
|
|
// the list.
|
|
nBytes = 0;
|
|
pszTemp = pszValue;
|
|
do
|
|
{
|
|
nLength = lstrlen(pszTemp)+1;
|
|
pszTemp += nLength;
|
|
nBytes += nLength*sizeof(TCHAR);
|
|
} while (nLength != 1);
|
|
|
|
return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast<const BYTE*>(pszValue),
|
|
nBytes);
|
|
}
|
|
|
|
inline LONG CRegKey::RecurseDeleteKey(LPCTSTR lpszKey)
|
|
{
|
|
CRegKey key;
|
|
LONG lRes = key.Open(m_hKey, lpszKey, KEY_READ | KEY_WRITE);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
FILETIME time;
|
|
DWORD dwSize = 256;
|
|
TCHAR szBuffer[256];
|
|
while (RegEnumKeyEx(key.m_hKey, 0, szBuffer, &dwSize, NULL, NULL, NULL,
|
|
&time)==ERROR_SUCCESS)
|
|
{
|
|
lRes = key.RecurseDeleteKey(szBuffer);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
dwSize = 256;
|
|
}
|
|
key.Close();
|
|
return DeleteSubKey(lpszKey);
|
|
}
|
|
|
|
#ifdef _ATL_STATIC_REGISTRY
|
|
}; //namespace ATL
|
|
|
|
#include <statreg.h>
|
|
|
|
namespace ATL
|
|
{
|
|
// Statically linking to Registry Ponent
|
|
inline HRESULT WINAPI CAtlModule::UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister,
|
|
struct _ATL_REGMAP_ENTRY* pMapEntries /*= NULL*/) throw()
|
|
{
|
|
CRegObject ro;
|
|
|
|
if (pMapEntries != NULL)
|
|
{
|
|
while (pMapEntries->szKey != NULL)
|
|
{
|
|
ATLASSERT(NULL != pMapEntries->szData);
|
|
ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData);
|
|
pMapEntries++;
|
|
}
|
|
}
|
|
|
|
HRESULT hr = AddCommonRGSReplacements(&ro);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
USES_CONVERSION;
|
|
TCHAR szModule[_MAX_PATH];
|
|
GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szModule, _MAX_PATH);
|
|
szModule[_MAX_PATH - 1] = TEXT('\0');
|
|
|
|
LPOLESTR pszModule;
|
|
pszModule = szModule;
|
|
|
|
OLECHAR pszModuleQuote[_MAX_PATH * 2];
|
|
EscapeSingleQuote(pszModuleQuote, pszModule);
|
|
ro.AddReplacement(OLESTR("Module"), pszModuleQuote);
|
|
|
|
LPCOLESTR szType = OLESTR("REGISTRY");
|
|
hr = (bRegister) ? ro.ResourceRegisterSz(pszModule, lpszRes, szType) :
|
|
ro.ResourceUnregisterSz(pszModule, lpszRes, szType);
|
|
return hr;
|
|
}
|
|
inline HRESULT WINAPI CAtlModule::UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister,
|
|
struct _ATL_REGMAP_ENTRY* pMapEntries /*= NULL*/) throw()
|
|
{
|
|
CRegObject ro;
|
|
|
|
if (pMapEntries != NULL)
|
|
{
|
|
while (pMapEntries->szKey != NULL)
|
|
{
|
|
ATLASSERT(NULL != pMapEntries->szData);
|
|
ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData);
|
|
pMapEntries++;
|
|
}
|
|
}
|
|
|
|
HRESULT hr = AddCommonRGSReplacements(&ro);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
USES_CONVERSION;
|
|
TCHAR szModule[_MAX_PATH];
|
|
GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szModule, _MAX_PATH);
|
|
szModule[_MAX_PATH - 1] = TEXT('\0');
|
|
|
|
LPOLESTR pszModule;
|
|
pszModule = szModule;
|
|
|
|
OLECHAR pszModuleQuote[_MAX_PATH * 2];
|
|
EscapeSingleQuote(pszModuleQuote, pszModule);
|
|
ro.AddReplacement(OLESTR("Module"), pszModuleQuote);
|
|
|
|
LPCOLESTR szType = OLESTR("REGISTRY");
|
|
hr = (bRegister) ? ro.ResourceRegister(pszModule, nResID, szType) :
|
|
ro.ResourceUnregister(pszModule, nResID, szType);
|
|
return hr;
|
|
}
|
|
#endif //_ATL_STATIC_REGISTRY
|
|
|
|
#pragma pack(pop)
|
|
|
|
}; //namespace ATL
|
|
|
|
#include <atlbase.inl>
|
|
|
|
#ifndef _ATL_NO_AUTOMATIC_NAMESPACE
|
|
using namespace ATL;
|
|
#endif //!_ATL_NO_AUTOMATIC_NAMESPACE
|
|
|
|
//only suck in definition if static linking
|
|
#ifndef _ATL_DLL_IMPL
|
|
#ifndef _ATL_DLL
|
|
#define _ATLBASE_IMPL
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _ATL_ATTRIBUTES
|
|
#include <atlplus.h>
|
|
#endif
|
|
|
|
//All exports go here
|
|
#ifdef _ATLBASE_IMPL
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// statics
|
|
|
|
static UINT WINAPI AtlGetDirLen(LPCOLESTR lpszPathName)
|
|
{
|
|
ATLASSERT(lpszPathName != NULL);
|
|
|
|
// always capture the complete file name including extension (if present)
|
|
LPCOLESTR lpszTemp = lpszPathName;
|
|
for (LPCOLESTR lpsz = lpszPathName; *lpsz != NULL; )
|
|
{
|
|
LPCOLESTR lp = CharNextW(lpsz);
|
|
// remember last directory/drive separator
|
|
if (*lpsz == OLESTR('\\') || *lpsz == OLESTR('/') || *lpsz == OLESTR(':'))
|
|
lpszTemp = lp;
|
|
lpsz = lp;
|
|
}
|
|
|
|
return UINT( lpszTemp-lpszPathName );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// QI support
|
|
|
|
ATLINLINE ATLAPI AtlInternalQueryInterface(void* pThis,
|
|
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
|
|
{
|
|
ATLASSERT(pThis != NULL);
|
|
// First entry in the com map should be a simple map entry
|
|
ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
|
|
if (ppvObject == NULL)
|
|
return E_POINTER;
|
|
*ppvObject = NULL;
|
|
if (InlineIsEqualUnknown(iid)) // use first interface
|
|
{
|
|
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
|
|
pUnk->AddRef();
|
|
*ppvObject = pUnk;
|
|
return S_OK;
|
|
}
|
|
while (pEntries->pFunc != NULL)
|
|
{
|
|
BOOL bBlind = (pEntries->piid == NULL);
|
|
if (bBlind || InlineIsEqualGUID(*(pEntries->piid), iid))
|
|
{
|
|
if (pEntries->pFunc == _ATL_SIMPLEMAPENTRY) //offset
|
|
{
|
|
ATLASSERT(!bBlind);
|
|
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
|
|
pUnk->AddRef();
|
|
*ppvObject = pUnk;
|
|
return S_OK;
|
|
}
|
|
else //actual function call
|
|
{
|
|
HRESULT hRes = pEntries->pFunc(pThis,
|
|
iid, ppvObject, pEntries->dw);
|
|
if (hRes == S_OK || (!bBlind && FAILED(hRes)))
|
|
return hRes;
|
|
}
|
|
}
|
|
pEntries++;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
ATLINLINE ATLAPI_(IUnknown*) AtlComQIPtrAssign(IUnknown** pp, IUnknown* lp, REFIID riid)
|
|
{
|
|
IUnknown* pTemp = *pp;
|
|
*pp = NULL;
|
|
if (lp != NULL)
|
|
lp->QueryInterface(riid, (void**)pp);
|
|
if (pTemp)
|
|
pTemp->Release();
|
|
return *pp;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IDispatch Error handling
|
|
|
|
ATLINLINE ATLAPI AtlSetErrorInfo(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID,
|
|
LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes, HINSTANCE hInst)
|
|
{
|
|
USES_CONVERSION;
|
|
TCHAR szDesc[1024];
|
|
szDesc[0] = NULL;
|
|
// For a valid HRESULT the id should be in the range [0x0200, 0xffff]
|
|
if (IS_INTRESOURCE(lpszDesc)) //id
|
|
{
|
|
UINT nID = LOWORD((DWORD_PTR)lpszDesc);
|
|
ATLASSERT((nID >= 0x0200 && nID <= 0xffff) || hRes != 0);
|
|
if (LoadString(hInst, nID, szDesc, 1024) == 0)
|
|
{
|
|
ATLASSERT(FALSE);
|
|
lstrcpy(szDesc, _T("Unknown Error"));
|
|
}
|
|
lpszDesc = szDesc;
|
|
if (hRes == 0)
|
|
hRes = MAKE_HRESULT(3, FACILITY_ITF, nID);
|
|
}
|
|
|
|
CComPtr<ICreateErrorInfo> pICEI;
|
|
if (SUCCEEDED(CreateErrorInfo(&pICEI)))
|
|
{
|
|
CComPtr<IErrorInfo> pErrorInfo;
|
|
pICEI->SetGUID(iid);
|
|
LPOLESTR lpsz;
|
|
ProgIDFromCLSID(clsid, &lpsz);
|
|
if (lpsz != NULL)
|
|
pICEI->SetSource(lpsz);
|
|
if (dwHelpID != 0 && lpszHelpFile != NULL)
|
|
{
|
|
pICEI->SetHelpContext(dwHelpID);
|
|
pICEI->SetHelpFile(const_cast<LPOLESTR>(lpszHelpFile));
|
|
}
|
|
CoTaskMemFree(lpsz);
|
|
pICEI->SetDescription((LPOLESTR)lpszDesc);
|
|
if (SUCCEEDED(pICEI->QueryInterface(__uuidof(IErrorInfo), (void**)&pErrorInfo)))
|
|
SetErrorInfo(0, pErrorInfo);
|
|
}
|
|
return (hRes == 0) ? DISP_E_EXCEPTION : hRes;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Module
|
|
|
|
//Although these functions are big, they are only used once in a module
|
|
//so we should make them inline.
|
|
|
|
|
|
ATLINLINE ATLAPI AtlComModuleGetClassObject(_ATL_COM_MODULE* pComModule, REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
|
{
|
|
ATLASSERT(pComModule != NULL);
|
|
if (pComModule == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
#ifndef _ATL_OLEDB_CONFORMANCE_TESTS
|
|
|
|
ATLASSERT(ppv != NULL);
|
|
|
|
#endif
|
|
|
|
if (ppv == NULL)
|
|
return E_POINTER;
|
|
*ppv = NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++)
|
|
{
|
|
if (*ppEntry != NULL)
|
|
{
|
|
_ATL_OBJMAP_ENTRY* pEntry = *ppEntry;
|
|
if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid))
|
|
{
|
|
if (pEntry->pCF == NULL)
|
|
{
|
|
CComCritSecLock<CComCriticalSection> lock(pComModule->m_csObjMap, false);
|
|
hr = lock.Lock();
|
|
if (FAILED(hr))
|
|
{
|
|
ATLASSERT(0);
|
|
break;
|
|
}
|
|
if (pEntry->pCF == NULL)
|
|
hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF);
|
|
}
|
|
if (pEntry->pCF != NULL)
|
|
hr = pEntry->pCF->QueryInterface(riid, ppv);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*ppv == NULL && hr == S_OK)
|
|
hr = CLASS_E_CLASSNOTAVAILABLE;
|
|
return hr;
|
|
}
|
|
|
|
ATLINLINE ATLAPI AtlModuleAddTermFunc(_ATL_MODULE* pModule, _ATL_TERMFUNC* pFunc, DWORD_PTR dw)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
_ATL_TERMFUNC_ELEM* pNew = NULL;
|
|
ATLTRY(pNew = new _ATL_TERMFUNC_ELEM);
|
|
if (pNew == NULL)
|
|
hr = E_OUTOFMEMORY;
|
|
else
|
|
{
|
|
pNew->pFunc = pFunc;
|
|
pNew->dw = dw;
|
|
CComCritSecLock<CComCriticalSection> lock(pModule->m_csStaticDataInitAndTypeInfo, false);
|
|
hr = lock.Lock();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pNew->pNext = pModule->m_pTermFuncs;
|
|
pModule->m_pTermFuncs = pNew;
|
|
}
|
|
else
|
|
{
|
|
delete pNew;
|
|
ATLASSERT(0);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
ATLINLINE ATLAPI_(void) AtlCallTermFunc(_ATL_MODULE* pModule)
|
|
{
|
|
_ATL_TERMFUNC_ELEM* pElem = pModule->m_pTermFuncs;
|
|
_ATL_TERMFUNC_ELEM* pNext = NULL;
|
|
while (pElem != NULL)
|
|
{
|
|
pElem->pFunc(pElem->dw);
|
|
pNext = pElem->pNext;
|
|
delete pElem;
|
|
pElem = pNext;
|
|
}
|
|
pModule->m_pTermFuncs = NULL;
|
|
}
|
|
|
|
ATLINLINE ATLAPI AtlRegisterClassCategoriesHelper( REFCLSID clsid,
|
|
const struct _ATL_CATMAP_ENTRY* pCatMap, BOOL bRegister )
|
|
{
|
|
CComPtr< ICatRegister > pCatRegister;
|
|
HRESULT hResult;
|
|
const struct _ATL_CATMAP_ENTRY* pEntry;
|
|
CATID catid;
|
|
|
|
if( pCatMap == NULL )
|
|
{
|
|
return( S_OK );
|
|
}
|
|
|
|
if (InlineIsEqualGUID(clsid, GUID_NULL))
|
|
{
|
|
ATLASSERT(0 && _T("Use OBJECT_ENTRY_NON_CREATEABLE_EX macro if you want to register class categories for non creatable objects."));
|
|
return S_OK;
|
|
}
|
|
|
|
hResult = CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL,
|
|
CLSCTX_INPROC_SERVER, __uuidof(ICatRegister), (void**)&pCatRegister );
|
|
if( FAILED( hResult ) )
|
|
{
|
|
// Since not all systems have the category manager installed, we'll allow
|
|
// the registration to succeed even though we didn't register our
|
|
// categories. If you really want to register categories on a system
|
|
// without the category manager, you can either manually add the
|
|
// appropriate entries to your registry script (.rgs), or you can
|
|
// redistribute comcat.dll.
|
|
return( S_OK );
|
|
}
|
|
|
|
hResult = S_OK;
|
|
pEntry = pCatMap;
|
|
while( pEntry->iType != _ATL_CATMAP_ENTRY_END )
|
|
{
|
|
catid = *pEntry->pcatid;
|
|
if( bRegister )
|
|
{
|
|
if( pEntry->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED )
|
|
{
|
|
hResult = pCatRegister->RegisterClassImplCategories( clsid, 1,
|
|
&catid );
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntry->iType == _ATL_CATMAP_ENTRY_REQUIRED );
|
|
hResult = pCatRegister->RegisterClassReqCategories( clsid, 1,
|
|
&catid );
|
|
}
|
|
if( FAILED( hResult ) )
|
|
{
|
|
return( hResult );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pEntry->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED )
|
|
{
|
|
pCatRegister->UnRegisterClassImplCategories( clsid, 1, &catid );
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( pEntry->iType == _ATL_CATMAP_ENTRY_REQUIRED );
|
|
pCatRegister->UnRegisterClassReqCategories( clsid, 1, &catid );
|
|
}
|
|
}
|
|
pEntry++;
|
|
}
|
|
|
|
// When unregistering remove "Implemented Categories" and "Required Categories" subkeys if they are empty.
|
|
if (!bRegister)
|
|
{
|
|
OLECHAR szGUID[64];
|
|
::StringFromGUID2(clsid, szGUID, 64);
|
|
USES_CONVERSION;
|
|
TCHAR* pszGUID = szGUID;
|
|
|
|
if (pszGUID != NULL)
|
|
{
|
|
TCHAR szKey[128];
|
|
lstrcpy(szKey, _T("CLSID\\"));
|
|
lstrcat(szKey, pszGUID);
|
|
lstrcat(szKey, _T("\\Required Categories"));
|
|
|
|
HKEY key;
|
|
DWORD cbSubKeys = 0;
|
|
|
|
LRESULT lRes = RegOpenKeyEx(HKEY_CLASSES_ROOT,
|
|
szKey,
|
|
0,
|
|
KEY_READ,
|
|
&key);
|
|
|
|
if (lRes == ERROR_SUCCESS)
|
|
{
|
|
lRes = RegQueryInfoKey(key, NULL, NULL, NULL, &cbSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
RegCloseKey(key);
|
|
|
|
if (lRes == ERROR_SUCCESS && cbSubKeys == 0)
|
|
{
|
|
RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
|
|
}
|
|
}
|
|
|
|
lstrcpy(szKey, _T("CLSID\\"));
|
|
lstrcat(szKey, pszGUID);
|
|
lstrcat(szKey, _T("\\Implemented Categories"));
|
|
|
|
lRes = RegOpenKeyEx(HKEY_CLASSES_ROOT,
|
|
szKey,
|
|
0,
|
|
KEY_READ,
|
|
&key);
|
|
|
|
if (lRes == ERROR_SUCCESS)
|
|
{
|
|
lRes = RegQueryInfoKey(key, NULL, NULL, NULL, &cbSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
RegCloseKey(key);
|
|
if (lRes == ERROR_SUCCESS && cbSubKeys == 0)
|
|
{
|
|
RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( S_OK );
|
|
}
|
|
|
|
// AtlComModuleRegisterServer walks the ATL Autogenerated Object Map and registers each object in the map
|
|
// If pCLSID is not NULL then only the object referred to by pCLSID is registered (The default case)
|
|
// otherwise all the objects are registered
|
|
ATLINLINE ATLAPI AtlComModuleRegisterServer(_ATL_COM_MODULE* pComModule, BOOL bRegTypeLib, const CLSID* pCLSID)
|
|
{
|
|
ATLASSERT(pComModule != NULL);
|
|
if (pComModule == NULL)
|
|
return E_INVALIDARG;
|
|
ATLASSERT(pComModule->m_hInstTypeLib != NULL);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++)
|
|
{
|
|
if (*ppEntry != NULL)
|
|
{
|
|
_ATL_OBJMAP_ENTRY* pEntry = *ppEntry;
|
|
if (pCLSID != NULL)
|
|
{
|
|
if (!IsEqualGUID(*pCLSID, *pEntry->pclsid))
|
|
continue;
|
|
}
|
|
hr = pEntry->pfnUpdateRegistry(TRUE);
|
|
if (FAILED(hr))
|
|
break;
|
|
hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid,
|
|
pEntry->pfnGetCategoryMap(), TRUE );
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && bRegTypeLib)
|
|
hr = AtlRegisterTypeLib(pComModule->m_hInstTypeLib, 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// AtlComUnregisterServer walks the ATL Object Map and unregisters each object in the map
|
|
// If pCLSID is not NULL then only the object referred to by pCLSID is unregistered (The default case)
|
|
// otherwise all the objects are unregistered.
|
|
ATLINLINE ATLAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE* pComModule, BOOL bUnRegTypeLib, const CLSID* pCLSID)
|
|
{
|
|
ATLASSERT(pComModule != NULL);
|
|
if (pComModule == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++)
|
|
{
|
|
if (*ppEntry != NULL)
|
|
{
|
|
_ATL_OBJMAP_ENTRY* pEntry = *ppEntry;
|
|
if (pCLSID != NULL)
|
|
{
|
|
if (!IsEqualGUID(*pCLSID, *pEntry->pclsid))
|
|
continue;
|
|
}
|
|
hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, pEntry->pfnGetCategoryMap(), FALSE );
|
|
if (FAILED(hr))
|
|
break;
|
|
hr = pEntry->pfnUpdateRegistry(FALSE); //unregister
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr) && bUnRegTypeLib)
|
|
hr = AtlUnRegisterTypeLib(pComModule->m_hInstTypeLib, 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// TypeLib Support
|
|
|
|
ATLINLINE ATLAPI AtlLoadTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex, BSTR* pbstrPath, ITypeLib** ppTypeLib)
|
|
{
|
|
ATLASSERT(pbstrPath != NULL && ppTypeLib != NULL);
|
|
if (pbstrPath == NULL || ppTypeLib == NULL)
|
|
return E_POINTER;
|
|
|
|
*pbstrPath = NULL;
|
|
*ppTypeLib = NULL;
|
|
|
|
USES_CONVERSION;
|
|
ATLASSERT(hInstTypeLib != NULL);
|
|
TCHAR szModule[_MAX_PATH+10];
|
|
|
|
ATLVERIFY( GetModuleFileName(hInstTypeLib, szModule, _MAX_PATH) != 0 );
|
|
|
|
// get the extension pointer in case of fail
|
|
LPTSTR lpszExt = NULL;
|
|
|
|
lpszExt = PathFindExtension(szModule);
|
|
|
|
if (lpszIndex != NULL)
|
|
lstrcat(szModule, lpszIndex);
|
|
LPOLESTR lpszModule = szModule;
|
|
HRESULT hr = LoadTypeLib(lpszModule, ppTypeLib);
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
// typelib not in module, try <module>.tlb instead
|
|
lstrcpy(lpszExt, _T(".tlb"));
|
|
lpszModule = szModule;
|
|
hr = LoadTypeLib(lpszModule, ppTypeLib);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pbstrPath = ::SysAllocString(lpszModule);
|
|
if (*pbstrPath == NULL)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
ATLINLINE ATLAPI AtlUnRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex)
|
|
{
|
|
CComBSTR bstrPath;
|
|
CComPtr<ITypeLib> pTypeLib;
|
|
HRESULT hr = AtlLoadTypeLib(hInstTypeLib, lpszIndex, &bstrPath, &pTypeLib);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TLIBATTR* ptla;
|
|
hr = pTypeLib->GetLibAttr(&ptla);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = UnRegisterTypeLib(ptla->guid, ptla->wMajorVerNum, ptla->wMinorVerNum, ptla->lcid, ptla->syskind);
|
|
pTypeLib->ReleaseTLibAttr(ptla);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
ATLINLINE ATLAPI AtlRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex)
|
|
{
|
|
CComBSTR bstrPath;
|
|
CComPtr<ITypeLib> pTypeLib;
|
|
HRESULT hr = AtlLoadTypeLib(hInstTypeLib, lpszIndex, &bstrPath, &pTypeLib);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
OLECHAR szDir[_MAX_PATH];
|
|
lstrcpyW(szDir, bstrPath);
|
|
// If index is specified remove it from the path
|
|
if (lpszIndex != NULL)
|
|
{
|
|
size_t nLenPath = lstrlenW(szDir);
|
|
size_t nLenIndex = lstrlenW(lpszIndex);
|
|
if (memcmp(szDir + nLenPath - nLenIndex, lpszIndex, nLenIndex) == 0)
|
|
szDir[nLenPath - nLenIndex] = 0;
|
|
}
|
|
szDir[AtlGetDirLen(szDir)] = 0;
|
|
hr = ::RegisterTypeLib(pTypeLib, bstrPath, szDir);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
}; //namespace ATL
|
|
|
|
#endif // _ATLBASE_IMPL
|
|
|
|
#pragma warning( pop )
|
|
|
|
#ifdef _ATL_ALL_WARNINGS
|
|
#pragma warning( pop )
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#endif // __ATLBASE_H__
|