ATLIMPL.CPP
// This is a part of the Active Template Library. 
// Copyright (C) 1996-1997 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__ 
#error atlimpl.cpp requires atlbase.h to be included first 
#endif 
 
extern "C" const IID IID_IRegistrar = {0x44EC053B,0x400F,0x11D0,{0x9D,0xCD,0x00,0xA0,0xC9,0x03,0x91,0xD3}}; 
#ifndef _ATL_DLL_IMPL 
extern "C" const CLSID CLSID_Registrar = {0x44EC053A,0x400F,0x11D0,{0x9D,0xCD,0x00,0xA0,0xC9,0x03,0x91,0xD3}}; 
#endif 
 
#include <atlconv.cpp> 
#ifdef _DEBUG 
#include <stdio.h> 
#include <stdarg.h> 
#endif 
 
#ifndef ATL_NO_NAMESPACE 
namespace ATL 
{ 
#endif 
 
// used in thread pooling 
UINT CComApartment::ATL_CREATE_OBJECT = 0; 
 
#ifdef __ATLCOM_H__ 
 
///////////////////////////////////////////////////////////////////////////// 
// AtlReportError 
 
HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, const IID& iid, 
HRESULT hRes, HINSTANCE hInst) 
{ 
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst); 
} 
 
HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID, 
LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes, HINSTANCE hInst) 
{ 
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID, 
lpszHelpFile, iid, hRes, hInst); 
} 
 
#ifndef OLE2ANSI 
HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc, 
DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid, HRESULT hRes) 
{ 
_ASSERTE(lpszDesc != NULL); 
USES_CONVERSION; 
return AtlSetErrorInfo(clsid, A2COLE(lpszDesc), dwHelpID, A2CW(lpszHelpFile), 
iid, hRes, NULL); 
} 
 
HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc, 
const IID& iid, HRESULT hRes) 
{ 
_ASSERTE(lpszDesc != NULL); 
USES_CONVERSION; 
return AtlSetErrorInfo(clsid, A2COLE(lpszDesc), 0, NULL, iid, hRes, NULL); 
} 
#endif 
 
HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, 
const IID& iid, HRESULT hRes) 
{ 
return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL); 
} 
 
HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID, 
LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes) 
{ 
return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL); 
} 
 
#endif //__ATLCOM_H__ 
 
///////////////////////////////////////////////////////////////////////////// 
// CComBSTR 
 
CComBSTR& CComBSTR::operator=(const CComBSTR& src) 
{ 
if (m_str != src.m_str) 
{ 
if (m_str) 
::SysFreeString(m_str); 
m_str = src.Copy(); 
} 
return *this; 
} 
 
CComBSTR& CComBSTR::operator=(LPCOLESTR pSrc) 
{ 
::SysFreeString(m_str); 
m_str = ::SysAllocString(pSrc); 
return *this; 
} 
 
void CComBSTR::Append(LPCOLESTR lpsz, int nLen) 
{ 
int n1 = Length(); 
BSTR b = SysAllocStringLen(NULL, n1+nLen); 
memcpy(b, m_str, n1*sizeof(OLECHAR)); 
memcpy(b+n1, lpsz, nLen*sizeof(OLECHAR)); 
b[n1+nLen] = NULL; 
SysFreeString(m_str); 
m_str = b; 
} 
 
#ifndef OLE2ANSI 
void CComBSTR::Append(LPCSTR lpsz) 
{ 
USES_CONVERSION; 
LPCOLESTR lpo = A2COLE(lpsz); 
Append(lpo, ocslen(lpo)); 
} 
 
CComBSTR::CComBSTR(LPCSTR pSrc) 
{ 
USES_CONVERSION; 
m_str = ::SysAllocString(A2COLE(pSrc)); 
} 
 
CComBSTR::CComBSTR(int nSize, LPCSTR sz) 
{ 
USES_CONVERSION; 
m_str = ::SysAllocStringLen(A2COLE(sz), nSize); 
} 
 
CComBSTR& CComBSTR::operator=(LPCSTR pSrc) 
{ 
USES_CONVERSION; 
::SysFreeString(m_str); 
m_str = ::SysAllocString(A2COLE(pSrc)); 
return *this; 
} 
#endif 
 
HRESULT CComBSTR::ReadFromStream(IStream* pStream) 
{ 
_ASSERTE(pStream != NULL); 
_ASSERTE(m_str == NULL); // should be empty 
ULONG cb; 
ULONG cbStrLen; 
HRESULT hr = pStream->Read((void*) &cbStrLen, sizeof(cbStrLen), &cb); 
if (FAILED(hr)) 
return hr; 
m_str = SysAllocStringByteLen(NULL, cbStrLen+sizeof(OLECHAR)); 
if (m_str == NULL) 
hr = E_OUTOFMEMORY; 
else 
{ 
hr = pStream->Read((void*) m_str, cbStrLen, &cb); 
*(OLECHAR*)&((BYTE*)m_str)[cb] = (OLECHAR)NULL; 
} 
return hr; 
} 
 
HRESULT CComBSTR::WriteToStream(IStream* pStream) 
{ 
_ASSERTE(pStream != NULL); 
ULONG cb; 
ULONG cbStrLen = SysStringByteLen(m_str); 
HRESULT hr = pStream->Write((void*) &cbStrLen, sizeof(cbStrLen), &cb); 
if (FAILED(hr)) 
return hr; 
return pStream->Write((void*) m_str, cbStrLen, &cb); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CComVariant 
 
CComVariant& CComVariant::operator=(BSTR bstrSrc) 
{ 
InternalClear(); 
vt = VT_BSTR; 
bstrVal = ::SysAllocString(bstrSrc); 
if (bstrVal == NULL) 
{ 
vt = VT_ERROR; 
scode = E_OUTOFMEMORY; 
} 
return *this; 
} 
 
CComVariant& CComVariant::operator=(LPCOLESTR lpszSrc) 
{ 
InternalClear(); 
vt = VT_BSTR; 
bstrVal = ::SysAllocString(lpszSrc); 
 
if (bstrVal == NULL) 
{ 
vt = VT_ERROR; 
scode = E_OUTOFMEMORY; 
} 
return *this; 
} 
 
#ifndef OLE2ANSI 
CComVariant& CComVariant::operator=(LPCSTR lpszSrc) 
{ 
USES_CONVERSION; 
InternalClear(); 
vt = VT_BSTR; 
bstrVal = ::SysAllocString(A2COLE(lpszSrc)); 
 
if (bstrVal == NULL) 
{ 
vt = VT_ERROR; 
scode = E_OUTOFMEMORY; 
} 
return *this; 
} 
#endif 
 
#if _MSC_VER>1020 
CComVariant& CComVariant::operator=(bool bSrc) 
{ 
if (vt != VT_BOOL) 
{ 
InternalClear(); 
vt = VT_BOOL; 
} 
#pragma warning(disable: 4310) // cast truncates constant value 
boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; 
#pragma warning(default: 4310) // cast truncates constant value 
return *this; 
} 
#endif 
 
CComVariant& CComVariant::operator=(int nSrc) 
{ 
if (vt != VT_I4) 
{ 
InternalClear(); 
vt = VT_I4; 
} 
lVal = nSrc; 
 
return *this; 
} 
 
CComVariant& CComVariant::operator=(BYTE nSrc) 
{ 
if (vt != VT_UI1) 
{ 
InternalClear(); 
vt = VT_UI1; 
} 
bVal = nSrc; 
return *this; 
} 
 
CComVariant& CComVariant::operator=(short nSrc) 
{ 
if (vt != VT_I2) 
{ 
InternalClear(); 
vt = VT_I2; 
} 
iVal = nSrc; 
return *this; 
} 
 
CComVariant& CComVariant::operator=(long nSrc) 
{ 
if (vt != VT_I4) 
{ 
InternalClear(); 
vt = VT_I4; 
} 
lVal = nSrc; 
return *this; 
} 
 
CComVariant& CComVariant::operator=(float fltSrc) 
{ 
if (vt != VT_R4) 
{ 
InternalClear(); 
vt = VT_R4; 
} 
fltVal = fltSrc; 
return *this; 
} 
 
CComVariant& CComVariant::operator=(double dblSrc) 
{ 
if (vt != VT_R8) 
{ 
InternalClear(); 
vt = VT_R8; 
} 
dblVal = dblSrc; 
return *this; 
} 
 
CComVariant& CComVariant::operator=(CY cySrc) 
{ 
if (vt != VT_CY) 
{ 
InternalClear(); 
vt = VT_CY; 
} 
cyVal.Hi = cySrc.Hi; 
cyVal.Lo = cySrc.Lo; 
return *this; 
} 
 
CComVariant& CComVariant::operator=(IDispatch* pSrc) 
{ 
InternalClear(); 
vt = VT_DISPATCH; 
pdispVal = pSrc; 
// Need to AddRef as VariantClear will Release 
if (pdispVal != NULL) 
pdispVal->AddRef(); 
return *this; 
} 
 
CComVariant& CComVariant::operator=(IUnknown* pSrc) 
{ 
InternalClear(); 
vt = VT_UNKNOWN; 
punkVal = pSrc; 
 
// Need to AddRef as VariantClear will Release 
if (punkVal != NULL) 
punkVal->AddRef(); 
return *this; 
} 
 
#if _MSC_VER>1020 
bool CComVariant::operator==(const VARIANT& varSrc) 
{ 
if (this == &varSrc) 
return true; 
 
// Variants not equal if types don't match 
if (vt != varSrc.vt) 
return false; 
 
// Check type specific values 
switch (vt) 
{ 
case VT_EMPTY: 
case VT_NULL: 
return true; 
 
case VT_BOOL: 
return boolVal == varSrc.boolVal; 
 
case VT_UI1: 
return bVal == varSrc.bVal; 
 
case VT_I2: 
return iVal == varSrc.iVal; 
 
case VT_I4: 
return lVal == varSrc.lVal; 
 
case VT_R4: 
return fltVal == varSrc.fltVal; 
 
case VT_R8: 
return dblVal == varSrc.dblVal; 
 
case VT_BSTR: 
return (::SysStringByteLen(bstrVal) == ::SysStringByteLen(varSrc.bstrVal)) && 
(::memcmp(bstrVal, varSrc.bstrVal, ::SysStringByteLen(bstrVal)) == 0); 
 
case VT_ERROR: 
return scode == varSrc.scode; 
 
case VT_DISPATCH: 
return pdispVal == varSrc.pdispVal; 
 
case VT_UNKNOWN: 
return punkVal == varSrc.punkVal; 
 
default: 
_ASSERTE(false); 
// fall through 
} 
 
return false; 
} 
#else 
BOOL CComVariant::operator==(const VARIANT& varSrc) 
{ 
if (this == &varSrc) 
return TRUE; 
 
// Variants not equal if types don't match 
if (vt != varSrc.vt) 
return FALSE; 
 
// Check type specific values 
switch (vt) 
{ 
case VT_EMPTY: 
case VT_NULL: 
return TRUE; 
 
case VT_BOOL: 
return boolVal == varSrc.boolVal; 
 
case VT_UI1: 
return bVal == varSrc.bVal; 
 
case VT_I2: 
return iVal == varSrc.iVal; 
 
case VT_I4: 
return lVal == varSrc.lVal; 
 
case VT_R4: 
return fltVal == varSrc.fltVal; 
 
case VT_R8: 
return dblVal == varSrc.dblVal; 
 
case VT_BSTR: 
return (::SysStringByteLen(bstrVal) == ::SysStringByteLen(varSrc.bstrVal)) && 
(::memcmp(bstrVal, varSrc.bstrVal, ::SysStringByteLen(bstrVal)) == 0); 
 
case VT_ERROR: 
return scode == varSrc.scode; 
 
case VT_DISPATCH: 
return pdispVal == varSrc.pdispVal; 
 
case VT_UNKNOWN: 
return punkVal == varSrc.punkVal; 
 
default: 
_ASSERTE(FALSE); 
// fall through 
} 
 
return FALSE; 
} 
#endif 
 
HRESULT CComVariant::Attach(VARIANT* pSrc) 
{ 
// Clear out the variant 
HRESULT hr = Clear(); 
if (!FAILED(hr)) 
{ 
// Copy the contents and give control to CComVariant 
memcpy(this, pSrc, sizeof(VARIANT)); 
VariantInit(pSrc); 
hr = S_OK; 
} 
return hr; 
} 
 
HRESULT CComVariant::Detach(VARIANT* pDest) 
{ 
// 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; 
} 
 
HRESULT CComVariant::ChangeType(VARTYPE vtNew, const VARIANT* pSrc) 
{ 
VARIANT* pVar = const_cast<VARIANT*>(pSrc); 
// Convert in place if pSrc is NULL 
if (pVar == NULL) 
pVar = this; 
// Do nothing if doing in place convert and vts not different 
return ::VariantChangeType(this, pVar, 0, vtNew); 
} 
 
HRESULT CComVariant::InternalClear() 
{ 
HRESULT hr = Clear(); 
_ASSERTE(SUCCEEDED(hr)); 
if (FAILED(hr)) 
{ 
vt = VT_ERROR; 
scode = hr; 
} 
return hr; 
} 
 
void CComVariant::InternalCopy(const VARIANT* pSrc) 
{ 
HRESULT hr = Copy(pSrc); 
if (FAILED(hr)) 
{ 
vt = VT_ERROR; 
scode = hr; 
} 
} 
 
HRESULT CComVariant::WriteToStream(IStream* pStream) 
{ 
HRESULT hr = pStream->Write(&vt, sizeof(VARTYPE), NULL); 
if (FAILED(hr)) 
return hr; 
 
if (vt == VT_UNKNOWN || vt == VT_DISPATCH) 
{ 
CComPtr<IPersistStream> spStream; 
hr = punkVal->QueryInterface(IID_IPersistStream, (void**)&spStream); 
if (FAILED(hr)) 
return hr; 
CLSID       clsid; 
LPOLESTR    szClsid; 
 
if (FAILED(spStream->GetClassID(&clsid))) 
return E_FAIL; 
hr = StringFromCLSID(clsid, &szClsid); 
if (FAILED(hr)) 
return hr; 
 
hr = pStream->Write(szClsid, ocslen(szClsid), NULL); 
if (FAILED(hr)) 
return hr; 
 
return spStream->Save(pStream, TRUE); 
} 
 
CComBSTR bstrWrite; 
CComVariant varBSTR; 
if (vt != VT_BSTR) 
{ 
hr = VariantChangeType(&varBSTR, this, VARIANT_NOVALUEPROP, VT_BSTR); 
if (FAILED(hr)) 
return hr; 
bstrWrite = varBSTR.bstrVal; 
} 
else 
bstrWrite = bstrVal; 
 
 
_ASSERTE(bstrWrite != NULL); 
return bstrWrite.WriteToStream(pStream); 
} 
 
HRESULT CComVariant::ReadFromStream(IStream* pStream) 
{ 
_ASSERTE(pStream != NULL); 
HRESULT hr; 
hr = VariantClear(this); 
if (FAILED(hr)) 
return hr; 
VARTYPE vt; 
hr = pStream->Read(&vt, sizeof(VARTYPE), NULL); 
if (FAILED(hr)) 
return hr; 
 
if (vt == VT_UNKNOWN || vt == VT_DISPATCH) 
{ 
CLSID clsid; 
CComBSTR bstrClsid; 
hr = bstrClsid.ReadFromStream(pStream); 
if (FAILED(hr)) 
return hr; 
if (FAILED(CLSIDFromString(bstrClsid, &clsid))) 
return E_FAIL; 
CComPtr<IPersistStream> spPStream; 
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, 
  IID_IPersistStream, (void**)&spPStream); 
if (FAILED(hr)) 
return E_FAIL; 
hr = spPStream->Load(pStream); 
if (FAILED(hr)) 
return hr; 
if (vt == VT_UNKNOWN) 
return spPStream->QueryInterface(IID_IUnknown, (void**)&punkVal); 
return spPStream->QueryInterface(IID_IDispatch, (void**)&punkVal); 
} 
 
CComBSTR bstrRead; 
 
hr = bstrRead.ReadFromStream(pStream); 
if (FAILED(hr)) 
return hr; 
CComVariant var = bstrRead; 
return VariantChangeType(this, &var, VARIANT_NOVALUEPROP, vt); 
} 
 
#ifdef __ATLCOM_H__ 
 
///////////////////////////////////////////////////////////////////////////// 
// CComTypeInfoHolder 
 
void CComTypeInfoHolder::AddRef() 
{ 
EnterCriticalSection(&_Module.m_csTypeInfoHolder); 
m_dwRef++; 
LeaveCriticalSection(&_Module.m_csTypeInfoHolder); 
} 
 
void CComTypeInfoHolder::Release() 
{ 
EnterCriticalSection(&_Module.m_csTypeInfoHolder); 
if (--m_dwRef == 0) 
{ 
if (m_pInfo != NULL) 
m_pInfo->Release(); 
m_pInfo = NULL; 
} 
LeaveCriticalSection(&_Module.m_csTypeInfoHolder); 
} 
 
HRESULT CComTypeInfoHolder::GetTI(LCID lcid, ITypeInfo** ppInfo) 
{ 
//If this assert occurs then most likely didn't initialize properly 
_ASSERTE(m_plibid != NULL && m_pguid != NULL); 
_ASSERTE(ppInfo != NULL); 
*ppInfo = NULL; 
 
HRESULT hRes = E_FAIL; 
EnterCriticalSection(&_Module.m_csTypeInfoHolder); 
if (m_pInfo == NULL) 
{ 
ITypeLib* pTypeLib; 
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib); 
if (SUCCEEDED(hRes)) 
{ 
ITypeInfo* pTypeInfo; 
hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &pTypeInfo); 
if (SUCCEEDED(hRes)) 
m_pInfo = pTypeInfo; 
pTypeLib->Release(); 
} 
} 
*ppInfo = m_pInfo; 
if (m_pInfo != NULL) 
{ 
m_pInfo->AddRef(); 
hRes = S_OK; 
} 
LeaveCriticalSection(&_Module.m_csTypeInfoHolder); 
return hRes; 
} 
 
HRESULT CComTypeInfoHolder::GetTypeInfo(UINT /*itinfo*/, LCID lcid, 
ITypeInfo** pptinfo) 
{ 
HRESULT hRes = E_POINTER; 
if (pptinfo != NULL) 
hRes = GetTI(lcid, pptinfo); 
return hRes; 
} 
 
HRESULT CComTypeInfoHolder::GetIDsOfNames(REFIID /*riid*/, LPOLESTR* rgszNames, 
UINT cNames, LCID lcid, DISPID* rgdispid) 
{ 
ITypeInfo* pInfo; 
HRESULT hRes = GetTI(lcid, &pInfo); 
if (pInfo != NULL) 
{ 
hRes = pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid); 
pInfo->Release(); 
} 
return hRes; 
} 
 
HRESULT CComTypeInfoHolder::Invoke(IDispatch* p, DISPID dispidMember, REFIID /*riid*/, 
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, 
EXCEPINFO* pexcepinfo, UINT* puArgErr) 
{ 
SetErrorInfo(0, NULL); 
ITypeInfo* pInfo; 
HRESULT hRes = GetTI(lcid, &pInfo); 
if (pInfo != NULL) 
{ 
hRes = pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); 
pInfo->Release(); 
} 
return hRes; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// QI implementation 
 
#ifdef _ATL_DEBUG_QI 
HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr) 
{ 
USES_CONVERSION; 
CRegKey key; 
TCHAR szName[100]; 
DWORD dwType,dw = sizeof(szName); 
 
LPOLESTR pszGUID = NULL; 
StringFromCLSID(iid, &pszGUID); 
OutputDebugString(pszClassName); 
OutputDebugString(_T(" - ")); 
 
// Attempt to find it in the interfaces section 
key.Open(HKEY_CLASSES_ROOT, _T("Interface")); 
if (key.Open(key, OLE2T(pszGUID)) == S_OK) 
{ 
*szName = 0; 
RegQueryValueEx(key.m_hKey, (LPTSTR)NULL, NULL, &dwType, (LPBYTE)szName, &dw); 
OutputDebugString(szName); 
goto cleanup; 
} 
// Attempt to find it in the clsid section 
key.Open(HKEY_CLASSES_ROOT, _T("CLSID")); 
if (key.Open(key, OLE2T(pszGUID)) == S_OK) 
{ 
*szName = 0; 
RegQueryValueEx(key.m_hKey, (LPTSTR)NULL, NULL, &dwType, (LPBYTE)szName, &dw); 
OutputDebugString(_T("(CLSID\?\?\?) ")); 
OutputDebugString(szName); 
goto cleanup; 
} 
OutputDebugString(OLE2T(pszGUID)); 
cleanup: 
if (hr != S_OK) 
OutputDebugString(_T(" - failed")); 
OutputDebugString(_T("\n")); 
CoTaskMemFree(pszGUID); 
return hr; 
} 
#endif 
 
HRESULT WINAPI CComObjectRootBase::_Break(void* /* pv */, REFIID iid, void** /* ppvObject */, DWORD /* dw */) 
{ 
iid; 
_ATLDUMPIID(iid, _T("Break due to QI for interface "), S_OK); 
DebugBreak(); 
return S_FALSE; 
} 
 
HRESULT WINAPI CComObjectRootBase::_NoInterface(void* /* pv */, REFIID /* iid */, void** /* ppvObject */, DWORD /* dw */) 
{ 
return E_NOINTERFACE; 
} 
 
HRESULT WINAPI CComObjectRootBase::_Creator(void* pv, REFIID iid, void** ppvObject, DWORD dw) 
{ 
_ATL_CREATORDATA* pcd = (_ATL_CREATORDATA*)dw; 
return pcd->pFunc(pv, iid, ppvObject); 
} 
 
HRESULT WINAPI CComObjectRootBase::_Delegate(void* pv, REFIID iid, void** ppvObject, DWORD dw) 
{ 
HRESULT hRes = E_NOINTERFACE; 
IUnknown* p = *(IUnknown**)((DWORD)pv + dw); 
if (p != NULL) 
hRes = p->QueryInterface(iid, ppvObject); 
return hRes; 
} 
 
HRESULT WINAPI CComObjectRootBase::_Chain(void* pv, REFIID iid, void** ppvObject, DWORD dw) 
{ 
_ATL_CHAINDATA* pcd = (_ATL_CHAINDATA*)dw; 
void* p = (void*)((DWORD)pv + pcd->dwOffset); 
return InternalQueryInterface(p, pcd->pFunc(), iid, ppvObject); 
} 
 
HRESULT WINAPI CComObjectRootBase::_Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw) 
{ 
HRESULT hRes = E_NOINTERFACE; 
_ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw; 
IUnknown** pp = (IUnknown**)((DWORD)pv + pcd->dwOffsetVar); 
if (*pp == NULL) 
hRes = pcd->pFunc(pv, IID_IUnknown, (void**)pp); 
if (*pp != NULL) 
hRes = (*pp)->QueryInterface(iid, ppvObject); 
return hRes; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CComClassFactory 
 
STDMETHODIMP CComClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, 
REFIID riid, void** ppvObj) 
{ 
_ASSERTE(m_pfnCreateInstance != NULL); 
HRESULT hRes = E_POINTER; 
if (ppvObj != NULL) 
{ 
*ppvObj = NULL; 
// can't ask for anything other than IUnknown when aggregating 
_ASSERTE((pUnkOuter == NULL) || InlineIsEqualUnknown(riid)); 
if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) 
hRes = CLASS_E_NOAGGREGATION; 
else 
hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); 
} 
return hRes; 
} 
 
STDMETHODIMP CComClassFactory::LockServer(BOOL fLock) 
{ 
if (fLock) 
_Module.Lock(); 
else 
_Module.Unlock(); 
return S_OK; 
} 
 
STDMETHODIMP CComClassFactory2Base::LockServer(BOOL fLock) 
{ 
if (fLock) 
_Module.Lock(); 
else 
_Module.Unlock(); 
return S_OK; 
} 
 
#ifndef _ATL_NO_CONNECTION_POINTS 
///////////////////////////////////////////////////////////////////////////// 
// Connection Points 
 
DWORD CComDynamicUnkArray::Add(IUnknown* pUnk) 
{ 
IUnknown** pp = NULL; 
if (m_nSize == 0) // no connections 
{ 
m_pUnk = pUnk; 
m_nSize = 1; 
return (DWORD)m_pUnk; 
} 
else if (m_nSize == 1) 
{ 
//create array 
pp = (IUnknown**)malloc(sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH); 
if (pp == NULL) 
return 0; 
memset(pp, 0, sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH); 
*pp = m_pUnk; 
m_ppUnk = pp; 
m_nSize = _DEFAULT_VECTORLENGTH; 
} 
for (pp = begin();pp<end();pp++) 
{ 
if (*pp == NULL) 
{ 
*pp = pUnk; 
return (DWORD)pUnk; 
} 
} 
int nAlloc = m_nSize*2; 
pp = (IUnknown**)realloc(m_ppUnk, sizeof(IUnknown*)*nAlloc); 
if (pp == NULL) 
return 0; 
m_ppUnk = pp; 
memset(&m_ppUnk[m_nSize], 0, sizeof(IUnknown*)*m_nSize); 
m_ppUnk[m_nSize] = pUnk; 
m_nSize = nAlloc; 
return (DWORD)pUnk; 
} 
 
BOOL CComDynamicUnkArray::Remove(DWORD dwCookie) 
{ 
IUnknown** pp; 
if (dwCookie == NULL) 
return FALSE; 
if (m_nSize == 0) 
return FALSE; 
if (m_nSize == 1) 
{ 
if ((DWORD)m_pUnk == dwCookie) 
{ 
m_nSize = 0; 
return TRUE; 
} 
return FALSE; 
} 
for (pp=begin();pp<end();pp++) 
{ 
if ((DWORD)*pp == dwCookie) 
{ 
*pp = NULL; 
return TRUE; 
} 
} 
return FALSE; 
} 
 
#endif //!_ATL_NO_CONNECTION_POINTS 
 
#endif //__ATLCOM_H__ 
 
///////////////////////////////////////////////////////////////////////////// 
// Object Registry Support 
 
static HRESULT WINAPI AtlRegisterProgID(LPCTSTR lpszCLSID, LPCTSTR lpszProgID, LPCTSTR lpszUserDesc) 
{ 
CRegKey keyProgID; 
LONG lRes = keyProgID.Create(HKEY_CLASSES_ROOT, lpszProgID); 
if (lRes == ERROR_SUCCESS) 
{ 
keyProgID.SetValue(lpszUserDesc); 
keyProgID.SetKeyValue(_T("CLSID"), lpszCLSID); 
return S_OK; 
} 
return HRESULT_FROM_WIN32(lRes); 
} 
 
void CComModule::AddCreateWndData(_AtlCreateWndData* pData, void* pObject) 
{ 
pData->m_pThis = pObject; 
pData->m_dwThreadID = ::GetCurrentThreadId(); 
::EnterCriticalSection(&m_csWindowCreate); 
pData->m_pNext = m_pCreateWndList; 
m_pCreateWndList = pData; 
::LeaveCriticalSection(&m_csWindowCreate); 
} 
 
void* CComModule::ExtractCreateWndData() 
{ 
::EnterCriticalSection(&m_csWindowCreate); 
_AtlCreateWndData* pEntry = m_pCreateWndList; 
if(pEntry == NULL) 
{ 
::LeaveCriticalSection(&m_csWindowCreate); 
return NULL; 
} 
 
DWORD dwThreadID = ::GetCurrentThreadId(); 
_AtlCreateWndData* pPrev = NULL; 
while(pEntry != NULL) 
{ 
if(pEntry->m_dwThreadID == dwThreadID) 
{ 
if(pPrev == NULL) 
m_pCreateWndList = pEntry->m_pNext; 
else 
pPrev->m_pNext = pEntry->m_pNext; 
::LeaveCriticalSection(&m_csWindowCreate); 
return pEntry->m_pThis; 
} 
pPrev = pEntry; 
pEntry = pEntry->m_pNext; 
} 
 
::LeaveCriticalSection(&m_csWindowCreate); 
return NULL; 
} 
 
#ifdef _ATL_STATIC_REGISTRY 
// Statically linking to Registry Ponent 
HRESULT WINAPI CComModule::UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister, 
struct _ATL_REGMAP_ENTRY* pMapEntries) 
{ 
USES_CONVERSION; 
CRegObject ro; 
TCHAR szModule[_MAX_PATH]; 
GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH); 
LPOLESTR pszModule = T2OLE(szModule); 
ro.AddReplacement(OLESTR("Module"), pszModule); 
if (NULL != pMapEntries) 
{ 
while (NULL != pMapEntries->szKey) 
{ 
_ASSERTE(NULL != pMapEntries->szData); 
ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData); 
pMapEntries++; 
} 
} 
 
LPCOLESTR szType = OLESTR("REGISTRY"); 
return (bRegister) ? ro.ResourceRegister(pszModule, nResID, szType) : 
ro.ResourceUnregister(pszModule, nResID, szType); 
} 
 
HRESULT WINAPI CComModule::UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister, 
struct _ATL_REGMAP_ENTRY* pMapEntries) 
{ 
USES_CONVERSION; 
CRegObject ro; 
TCHAR szModule[_MAX_PATH]; 
GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH); 
LPOLESTR pszModule = T2OLE(szModule); 
ro.AddReplacement(OLESTR("Module"), pszModule); 
if (NULL != pMapEntries) 
{ 
while (NULL != pMapEntries->szKey) 
{ 
_ASSERTE(NULL != pMapEntries->szData); 
ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData); 
pMapEntries++; 
} 
} 
 
LPCOLESTR szType = OLESTR("REGISTRY"); 
LPCOLESTR pszRes = T2COLE(lpszRes); 
return (bRegister) ? ro.ResourceRegisterSz(pszModule, pszRes, szType) : 
ro.ResourceUnregisterSz(pszModule, pszRes, szType); 
} 
#endif // _ATL_STATIC_REGISTRY 
 
HRESULT WINAPI CComModule::UpdateRegistryClass(const CLSID& clsid, LPCTSTR lpszProgID, 
LPCTSTR lpszVerIndProgID, UINT nDescID, DWORD dwFlags, BOOL bRegister) 
{ 
if (bRegister) 
{ 
return RegisterClassHelper(clsid, lpszProgID, lpszVerIndProgID, nDescID, 
dwFlags); 
} 
else 
return UnregisterClassHelper(clsid, lpszProgID, lpszVerIndProgID); 
} 
 
HRESULT WINAPI CComModule::RegisterClassHelper(const CLSID& clsid, LPCTSTR lpszProgID, 
LPCTSTR lpszVerIndProgID, UINT nDescID, DWORD dwFlags) 
{ 
static const TCHAR szProgID[] = _T("ProgID"); 
static const TCHAR szVIProgID[] = _T("VersionIndependentProgID"); 
static const TCHAR szLS32[] = _T("LocalServer32"); 
static const TCHAR szIPS32[] = _T("InprocServer32"); 
static const TCHAR szThreadingModel[] = _T("ThreadingModel"); 
static const TCHAR szAUTPRX32[] = _T("AUTPRX32.DLL"); 
static const TCHAR szApartment[] = _T("Apartment"); 
static const TCHAR szBoth[] = _T("both"); 
USES_CONVERSION; 
HRESULT hRes = S_OK; 
TCHAR szDesc[256]; 
LoadString(m_hInst, nDescID, szDesc, 256); 
TCHAR szModule[_MAX_PATH]; 
GetModuleFileName(m_hInst, szModule, _MAX_PATH); 
 
LPOLESTR lpOleStr; 
StringFromCLSID(clsid, &lpOleStr); 
LPTSTR lpsz = OLE2T(lpOleStr); 
 
hRes = AtlRegisterProgID(lpsz, lpszProgID, szDesc); 
if (hRes == S_OK) 
hRes = AtlRegisterProgID(lpsz, lpszVerIndProgID, szDesc); 
LONG lRes = ERROR_SUCCESS; 
if (hRes == S_OK) 
{ 
CRegKey key; 
LONG lRes = key.Open(HKEY_CLASSES_ROOT, _T("CLSID")); 
if (lRes == ERROR_SUCCESS) 
{ 
lRes = key.Create(key, lpsz); 
if (lRes == ERROR_SUCCESS) 
{ 
key.SetValue(szDesc); 
key.SetKeyValue(szProgID, lpszProgID); 
key.SetKeyValue(szVIProgID, lpszVerIndProgID); 
 
if ((m_hInst == NULL) || (m_hInst == GetModuleHandle(NULL))) // register as EXE 
key.SetKeyValue(szLS32, szModule); 
else 
{ 
key.SetKeyValue(szIPS32, (dwFlags & AUTPRXFLAG) ? szAUTPRX32 : szModule); 
LPCTSTR lpszModel = (dwFlags & THREADFLAGS_BOTH) ? szBoth : 
(dwFlags & THREADFLAGS_APARTMENT) ? szApartment : NULL; 
if (lpszModel != NULL) 
key.SetKeyValue(szIPS32, lpszModel, szThreadingModel); 
} 
} 
} 
} 
CoTaskMemFree(lpOleStr); 
if (lRes != ERROR_SUCCESS) 
hRes = HRESULT_FROM_WIN32(lRes); 
return hRes; 
} 
 
HRESULT WINAPI CComModule::UnregisterClassHelper(const CLSID& clsid, LPCTSTR lpszProgID, 
LPCTSTR lpszVerIndProgID) 
{ 
USES_CONVERSION; 
CRegKey key; 
 
key.Attach(HKEY_CLASSES_ROOT); 
if (lpszProgID != NULL && lstrcmpi(lpszProgID, _T(""))) 
key.RecurseDeleteKey(lpszProgID); 
if (lpszVerIndProgID != NULL && lstrcmpi(lpszVerIndProgID, _T(""))) 
key.RecurseDeleteKey(lpszVerIndProgID); 
LPOLESTR lpOleStr; 
StringFromCLSID(clsid, &lpOleStr); 
LPTSTR lpsz = OLE2T(lpOleStr); 
if (key.Open(key, _T("CLSID")) == ERROR_SUCCESS) 
key.RecurseDeleteKey(lpsz); 
CoTaskMemFree(lpOleStr); 
return S_OK; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CRegKey 
 
LONG CRegKey::Close() 
{ 
LONG lRes = ERROR_SUCCESS; 
if (m_hKey != NULL) 
{ 
lRes = RegCloseKey(m_hKey); 
m_hKey = NULL; 
} 
return lRes; 
} 
 
LONG CRegKey::Create(HKEY hKeyParent, LPCTSTR lpszKeyName, 
LPTSTR lpszClass, DWORD dwOptions, REGSAM samDesired, 
LPSECURITY_ATTRIBUTES lpSecAttr, LPDWORD lpdwDisposition) 
{ 
_ASSERTE(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; 
} 
 
LONG CRegKey::Open(HKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired) 
{ 
_ASSERTE(hKeyParent != NULL); 
HKEY hKey = NULL; 
LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyName, 0, samDesired, &hKey); 
if (lRes == ERROR_SUCCESS) 
{ 
lRes = Close(); 
_ASSERTE(lRes == ERROR_SUCCESS); 
m_hKey = hKey; 
} 
return lRes; 
} 
 
LONG CRegKey::QueryValue(DWORD& dwValue, LPCTSTR lpszValueName) 
{ 
DWORD dwType = NULL; 
DWORD dwCount = sizeof(DWORD); 
LONG lRes = RegQueryValueEx(m_hKey, (LPTSTR)lpszValueName, NULL, &dwType, 
(LPBYTE)&dwValue, &dwCount); 
_ASSERTE((lRes!=ERROR_SUCCESS) || (dwType == REG_DWORD)); 
_ASSERTE((lRes!=ERROR_SUCCESS) || (dwCount == sizeof(DWORD))); 
return lRes; 
} 
 
LONG CRegKey::QueryValue(LPTSTR szValue, LPCTSTR lpszValueName, DWORD* pdwCount) 
{ 
_ASSERTE(pdwCount != NULL); 
DWORD dwType = NULL; 
LONG lRes = RegQueryValueEx(m_hKey, (LPTSTR)lpszValueName, NULL, &dwType, 
(LPBYTE)szValue, pdwCount); 
_ASSERTE((lRes!=ERROR_SUCCESS) || (dwType == REG_SZ) || 
 (dwType == REG_MULTI_SZ) || (dwType == REG_EXPAND_SZ)); 
return lRes; 
} 
 
LONG WINAPI CRegKey::SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName) 
{ 
_ASSERTE(lpszValue != NULL); 
CRegKey key; 
LONG lRes = key.Create(hKeyParent, lpszKeyName); 
if (lRes == ERROR_SUCCESS) 
lRes = key.SetValue(lpszValue, lpszValueName); 
return lRes; 
} 
 
LONG CRegKey::SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName) 
{ 
_ASSERTE(lpszValue != NULL); 
CRegKey key; 
LONG lRes = key.Create(m_hKey, lpszKeyName); 
if (lRes == ERROR_SUCCESS) 
lRes = key.SetValue(lpszValue, lpszValueName); 
return lRes; 
} 
 
LONG CRegKey::SetValue(DWORD dwValue, LPCTSTR lpszValueName) 
{ 
_ASSERTE(m_hKey != NULL); 
return RegSetValueEx(m_hKey, lpszValueName, NULL, REG_DWORD, 
(BYTE * const)&dwValue, sizeof(DWORD)); 
} 
 
HRESULT CRegKey::SetValue(LPCTSTR lpszValue, LPCTSTR lpszValueName) 
{ 
_ASSERTE(lpszValue != NULL); 
_ASSERTE(m_hKey != NULL); 
return RegSetValueEx(m_hKey, lpszValueName, NULL, REG_SZ, 
(BYTE * const)lpszValue, (lstrlen(lpszValue)+1)*sizeof(TCHAR)); 
} 
 
//RecurseDeleteKey is necessary because on NT RegDeleteKey doesn't work if the 
//specified key has subkeys 
LONG CRegKey::RecurseDeleteKey(LPCTSTR lpszKey) 
{ 
CRegKey key; 
LONG lRes = key.Open(m_hKey, lpszKey); 
if (lRes != ERROR_SUCCESS) 
return lRes; 
FILETIME time; 
TCHAR szBuffer[256]; 
DWORD dwSize = 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 __ATLCOM_H__ 
#ifndef _ATL_NO_SECURITY 
 
CSecurityDescriptor::CSecurityDescriptor() 
{ 
m_pSD = NULL; 
m_pOwner = NULL; 
m_pGroup = NULL; 
m_pDACL = NULL; 
m_pSACL= NULL; 
} 
 
CSecurityDescriptor::~CSecurityDescriptor() 
{ 
if (m_pSD) 
delete m_pSD; 
if (m_pOwner) 
free(m_pOwner); 
if (m_pGroup) 
free(m_pGroup); 
if (m_pDACL) 
free(m_pDACL); 
if (m_pSACL) 
free(m_pSACL); 
} 
 
HRESULT CSecurityDescriptor::Initialize() 
{ 
if (m_pSD) 
{ 
delete m_pSD; 
m_pSD = NULL; 
} 
if (m_pOwner) 
{ 
free(m_pOwner); 
m_pOwner = NULL; 
} 
if (m_pGroup) 
{ 
free(m_pGroup); 
m_pGroup = NULL; 
} 
if (m_pDACL) 
{ 
free(m_pDACL); 
m_pDACL = NULL; 
} 
if (m_pSACL) 
{ 
free(m_pSACL); 
m_pSACL = NULL; 
} 
 
ATLTRY(m_pSD = new SECURITY_DESCRIPTOR); 
if (!m_pSD) 
return E_OUTOFMEMORY; 
if (!InitializeSecurityDescriptor(m_pSD, SECURITY_DESCRIPTOR_REVISION)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
delete m_pSD; 
m_pSD = NULL; 
_ASSERTE(FALSE); 
return hr; 
} 
// Set the DACL to allow EVERYONE 
SetSecurityDescriptorDacl(m_pSD, TRUE, NULL, FALSE); 
return S_OK; 
} 
 
HRESULT CSecurityDescriptor::InitializeFromProcessToken(BOOL bDefaulted) 
{ 
PSID pUserSid; 
PSID pGroupSid; 
HRESULT hr; 
 
Initialize(); 
hr = GetProcessSids(&pUserSid, &pGroupSid); 
if (FAILED(hr)) 
return hr; 
hr = SetOwner(pUserSid, bDefaulted); 
if (FAILED(hr)) 
return hr; 
hr = SetGroup(pGroupSid, bDefaulted); 
if (FAILED(hr)) 
return hr; 
return S_OK; 
} 
 
HRESULT CSecurityDescriptor::InitializeFromThreadToken(BOOL bDefaulted, BOOL bRevertToProcessToken) 
{ 
PSID pUserSid; 
PSID pGroupSid; 
HRESULT hr; 
 
Initialize(); 
hr = GetThreadSids(&pUserSid, &pGroupSid); 
if (HRESULT_CODE(hr) == ERROR_NO_TOKEN && bRevertToProcessToken) 
hr = GetProcessSids(&pUserSid, &pGroupSid); 
if (FAILED(hr)) 
return hr; 
hr = SetOwner(pUserSid, bDefaulted); 
if (FAILED(hr)) 
return hr; 
hr = SetGroup(pGroupSid, bDefaulted); 
if (FAILED(hr)) 
return hr; 
return S_OK; 
} 
 
HRESULT CSecurityDescriptor::SetOwner(PSID pOwnerSid, BOOL bDefaulted) 
{ 
_ASSERTE(m_pSD); 
 
// Mark the SD as having no owner 
if (!SetSecurityDescriptorOwner(m_pSD, NULL, bDefaulted)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
 
if (m_pOwner) 
{ 
free(m_pOwner); 
m_pOwner = NULL; 
} 
 
// If they asked for no owner don't do the copy 
if (pOwnerSid == NULL) 
return S_OK; 
 
// Make a copy of the Sid for the return value 
DWORD dwSize = GetLengthSid(pOwnerSid); 
 
m_pOwner = (PSID) malloc(dwSize); 
if (!m_pOwner) 
{ 
// Insufficient memory to allocate Sid 
_ASSERTE(FALSE); 
return E_OUTOFMEMORY; 
} 
if (!CopySid(dwSize, m_pOwner, pOwnerSid)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
free(m_pOwner); 
m_pOwner = NULL; 
return hr; 
} 
 
_ASSERTE(IsValidSid(m_pOwner)); 
 
if (!SetSecurityDescriptorOwner(m_pSD, m_pOwner, bDefaulted)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
free(m_pOwner); 
m_pOwner = NULL; 
return hr; 
} 
 
return S_OK; 
} 
 
HRESULT CSecurityDescriptor::SetGroup(PSID pGroupSid, BOOL bDefaulted) 
{ 
_ASSERTE(m_pSD); 
 
// Mark the SD as having no Group 
if (!SetSecurityDescriptorGroup(m_pSD, NULL, bDefaulted)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
 
if (m_pGroup) 
{ 
free(m_pGroup); 
m_pGroup = NULL; 
} 
 
// If they asked for no Group don't do the copy 
if (pGroupSid == NULL) 
return S_OK; 
 
// Make a copy of the Sid for the return value 
DWORD dwSize = GetLengthSid(pGroupSid); 
 
m_pGroup = (PSID) malloc(dwSize); 
if (!m_pGroup) 
{ 
// Insufficient memory to allocate Sid 
_ASSERTE(FALSE); 
return E_OUTOFMEMORY; 
} 
if (!CopySid(dwSize, m_pGroup, pGroupSid)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
free(m_pGroup); 
m_pGroup = NULL; 
return hr; 
} 
 
_ASSERTE(IsValidSid(m_pGroup)); 
 
if (!SetSecurityDescriptorGroup(m_pSD, m_pGroup, bDefaulted)) 
{ 
HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
free(m_pGroup); 
m_pGroup = NULL; 
return hr; 
} 
 
return S_OK; 
} 
 
HRESULT CSecurityDescriptor::Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask) 
{ 
HRESULT hr = AddAccessAllowedACEToACL(&m_pDACL, pszPrincipal, dwAccessMask); 
if (SUCCEEDED(hr)) 
SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE); 
return hr; 
} 
 
HRESULT CSecurityDescriptor::Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask) 
{ 
HRESULT hr = AddAccessDeniedACEToACL(&m_pDACL, pszPrincipal, dwAccessMask); 
if (SUCCEEDED(hr)) 
SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE); 
return hr; 
} 
 
HRESULT CSecurityDescriptor::Revoke(LPCTSTR pszPrincipal) 
{ 
HRESULT hr = RemovePrincipalFromACL(m_pDACL, pszPrincipal); 
if (SUCCEEDED(hr)) 
SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE); 
return hr; 
} 
 
HRESULT CSecurityDescriptor::GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid) 
{ 
BOOL bRes; 
HRESULT hr; 
HANDLE hToken = NULL; 
if (ppUserSid) 
*ppUserSid = NULL; 
if (ppGroupSid) 
*ppGroupSid = NULL; 
bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); 
if (!bRes) 
{ 
// Couldn't open process token 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
hr = GetTokenSids(hToken, ppUserSid, ppGroupSid); 
return hr; 
} 
 
HRESULT CSecurityDescriptor::GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid, BOOL bOpenAsSelf) 
{ 
BOOL bRes; 
HRESULT hr; 
HANDLE hToken = NULL; 
if (ppUserSid) 
*ppUserSid = NULL; 
if (ppGroupSid) 
*ppGroupSid = NULL; 
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, bOpenAsSelf, &hToken); 
if (!bRes) 
{ 
// Couldn't open thread token 
hr = HRESULT_FROM_WIN32(GetLastError()); 
return hr; 
} 
hr = GetTokenSids(hToken, ppUserSid, ppGroupSid); 
return hr; 
} 
 
 
HRESULT CSecurityDescriptor::GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid) 
{ 
DWORD dwSize; 
HRESULT hr; 
PTOKEN_USER ptkUser = NULL; 
PTOKEN_PRIMARY_GROUP ptkGroup = NULL; 
 
if (ppUserSid) 
*ppUserSid = NULL; 
if (ppGroupSid) 
*ppGroupSid = NULL; 
 
if (ppUserSid) 
{ 
// Get length required for TokenUser by specifying buffer length of 0 
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize); 
hr = GetLastError(); 
if (hr != ERROR_INSUFFICIENT_BUFFER) 
{ 
// Expected ERROR_INSUFFICIENT_BUFFER 
_ASSERTE(FALSE); 
hr = HRESULT_FROM_WIN32(hr); 
goto failed; 
} 
 
ptkUser = (TOKEN_USER*) malloc(dwSize); 
if (!ptkUser) 
{ 
// Insufficient memory to allocate TOKEN_USER 
_ASSERTE(FALSE); 
hr = E_OUTOFMEMORY; 
goto failed; 
} 
// Get Sid of process token. 
if (!GetTokenInformation(hToken, TokenUser, ptkUser, dwSize, &dwSize)) 
{ 
// Couldn't get user info 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
goto failed; 
} 
 
// Make a copy of the Sid for the return value 
dwSize = GetLengthSid(ptkUser->User.Sid); 
 
PSID pSid = (PSID) malloc(dwSize); 
if (!pSid) 
{ 
// Insufficient memory to allocate Sid 
_ASSERTE(FALSE); 
hr = E_OUTOFMEMORY; 
goto failed; 
} 
if (!CopySid(dwSize, pSid, ptkUser->User.Sid)) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
goto failed; 
} 
 
_ASSERTE(IsValidSid(pSid)); 
*ppUserSid = pSid; 
free(ptkUser); 
} 
if (ppGroupSid) 
{ 
// Get length required for TokenPrimaryGroup by specifying buffer length of 0 
GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwSize); 
hr = GetLastError(); 
if (hr != ERROR_INSUFFICIENT_BUFFER) 
{ 
// Expected ERROR_INSUFFICIENT_BUFFER 
_ASSERTE(FALSE); 
hr = HRESULT_FROM_WIN32(hr); 
goto failed; 
} 
 
ptkGroup = (TOKEN_PRIMARY_GROUP*) malloc(dwSize); 
if (!ptkGroup) 
{ 
// Insufficient memory to allocate TOKEN_USER 
_ASSERTE(FALSE); 
hr = E_OUTOFMEMORY; 
goto failed; 
} 
// Get Sid of process token. 
if (!GetTokenInformation(hToken, TokenPrimaryGroup, ptkGroup, dwSize, &dwSize)) 
{ 
// Couldn't get user info 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
goto failed; 
} 
 
// Make a copy of the Sid for the return value 
dwSize = GetLengthSid(ptkGroup->PrimaryGroup); 
 
PSID pSid = (PSID) malloc(dwSize); 
if (!pSid) 
{ 
// Insufficient memory to allocate Sid 
_ASSERTE(FALSE); 
hr = E_OUTOFMEMORY; 
goto failed; 
} 
if (!CopySid(dwSize, pSid, ptkGroup->PrimaryGroup)) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
goto failed; 
} 
 
_ASSERTE(IsValidSid(pSid)); 
 
*ppGroupSid = pSid; 
free(ptkGroup); 
} 
 
return S_OK; 
 
failed: 
if (ptkUser) 
free(ptkUser); 
if (ptkGroup) 
free (ptkGroup); 
return hr; 
} 
 
 
HRESULT CSecurityDescriptor::GetCurrentUserSID(PSID *ppSid) 
{ 
HANDLE tkHandle; 
 
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkHandle)) 
{ 
TOKEN_USER *tkUser; 
DWORD tkSize; 
DWORD sidLength; 
 
// Call to get size information for alloc 
GetTokenInformation(tkHandle, TokenUser, NULL, 0, &tkSize); 
tkUser = (TOKEN_USER *) malloc(tkSize); 
 
// Now make the real call 
if (GetTokenInformation(tkHandle, TokenUser, tkUser, tkSize, &tkSize)) 
{ 
sidLength = GetLengthSid(tkUser->User.Sid); 
*ppSid = (PSID) malloc(sidLength); 
 
memcpy(*ppSid, tkUser->User.Sid, sidLength); 
CloseHandle(tkHandle); 
 
free(tkUser); 
return S_OK; 
} 
else 
{ 
free(tkUser); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
} 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
 
HRESULT CSecurityDescriptor::GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid) 
{ 
HRESULT hr; 
LPTSTR pszRefDomain = NULL; 
DWORD dwDomainSize = 0; 
DWORD dwSidSize = 0; 
SID_NAME_USE snu; 
 
// Call to get size info for alloc 
LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu); 
 
hr = GetLastError(); 
if (hr != ERROR_INSUFFICIENT_BUFFER) 
return HRESULT_FROM_WIN32(hr); 
 
ATLTRY(pszRefDomain = new TCHAR[dwDomainSize]); 
if (pszRefDomain == NULL) 
return E_OUTOFMEMORY; 
 
*ppSid = (PSID) malloc(dwSidSize); 
if (*ppSid != NULL) 
{ 
if (!LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu)) 
{ 
free(*ppSid); 
*ppSid = NULL; 
delete[] pszRefDomain; 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
delete[] pszRefDomain; 
return S_OK; 
} 
delete[] pszRefDomain; 
return E_OUTOFMEMORY; 
} 
 
 
HRESULT CSecurityDescriptor::Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD) 
{ 
PACL    pDACL = NULL; 
PACL    pSACL = NULL; 
BOOL    bDACLPresent, bSACLPresent; 
BOOL    bDefaulted; 
PACL    m_pDACL = NULL; 
ACCESS_ALLOWED_ACE* pACE; 
HRESULT hr; 
PSID    pUserSid; 
PSID    pGroupSid; 
 
hr = Initialize(); 
if(FAILED(hr)) 
return hr; 
 
// get the existing DACL. 
if (!GetSecurityDescriptorDacl(pSelfRelativeSD, &bDACLPresent, &pDACL, &bDefaulted)) 
goto failed; 
 
if (bDACLPresent) 
{ 
if (pDACL) 
{ 
// allocate new DACL. 
m_pDACL = (PACL) malloc(pDACL->AclSize); 
if (!m_pDACL) 
goto failed; 
 
// initialize the DACL 
if (!InitializeAcl(m_pDACL, pDACL->AclSize, ACL_REVISION)) 
goto failed; 
 
// copy the ACES 
for (int i = 0; i < pDACL->AceCount; i++) 
{ 
if (!GetAce(pDACL, i, (void **)&pACE)) 
goto failed; 
 
if (!AddAccessAllowedAce(m_pDACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart))) 
goto failed; 
} 
 
if (!IsValidAcl(m_pDACL)) 
goto failed; 
} 
 
// set the DACL 
if (!SetSecurityDescriptorDacl(m_pSD, m_pDACL ? TRUE : FALSE, m_pDACL, bDefaulted)) 
goto failed; 
} 
 
// get the existing SACL. 
if (!GetSecurityDescriptorSacl(pSelfRelativeSD, &bSACLPresent, &pSACL, &bDefaulted)) 
goto failed; 
 
if (bSACLPresent) 
{ 
if (pSACL) 
{ 
// allocate new SACL. 
m_pSACL = (PACL) malloc(pSACL->AclSize); 
if (!m_pSACL) 
goto failed; 
 
// initialize the SACL 
if (!InitializeAcl(m_pSACL, pSACL->AclSize, ACL_REVISION)) 
goto failed; 
 
// copy the ACES 
for (int i = 0; i < pSACL->AceCount; i++) 
{ 
if (!GetAce(pSACL, i, (void **)&pACE)) 
goto failed; 
 
if (!AddAccessAllowedAce(m_pSACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart))) 
goto failed; 
} 
 
if (!IsValidAcl(m_pSACL)) 
goto failed; 
} 
 
// set the SACL 
if (!SetSecurityDescriptorSacl(m_pSD, m_pSACL ? TRUE : FALSE, m_pSACL, bDefaulted)) 
goto failed; 
} 
 
if (!GetSecurityDescriptorOwner(m_pSD, &pUserSid, &bDefaulted)) 
goto failed; 
 
if (FAILED(SetOwner(pUserSid, bDefaulted))) 
goto failed; 
 
if (!GetSecurityDescriptorGroup(m_pSD, &pGroupSid, &bDefaulted)) 
goto failed; 
 
if (FAILED(SetGroup(pGroupSid, bDefaulted))) 
goto failed; 
 
if (!IsValidSecurityDescriptor(m_pSD)) 
goto failed; 
 
return hr; 
 
failed: 
if (m_pDACL) 
free(m_pDACL); 
if (m_pSD) 
free(m_pSD); 
return E_UNEXPECTED; 
} 
 
HRESULT CSecurityDescriptor::AttachObject(HANDLE hObject) 
{ 
HRESULT hr; 
DWORD dwSize = 0; 
PSECURITY_DESCRIPTOR pSD = NULL; 
 
GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
DACL_SECURITY_INFORMATION, pSD, 0, &dwSize); 
 
hr = GetLastError(); 
if (hr != ERROR_INSUFFICIENT_BUFFER) 
return HRESULT_FROM_WIN32(hr); 
 
pSD = (PSECURITY_DESCRIPTOR) malloc(dwSize); 
 
if (!GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize)) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
free(pSD); 
return hr; 
} 
 
hr = Attach(pSD); 
free(pSD); 
return hr; 
} 
 
 
HRESULT CSecurityDescriptor::CopyACL(PACL pDest, PACL pSrc) 
{ 
ACL_SIZE_INFORMATION aclSizeInfo; 
LPVOID pAce; 
ACE_HEADER *aceHeader; 
 
if (pSrc == NULL) 
return S_OK; 
 
if (!GetAclInformation(pSrc, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) 
return HRESULT_FROM_WIN32(GetLastError()); 
 
// Copy all of the ACEs to the new ACL 
for (UINT i = 0; i < aclSizeInfo.AceCount; i++) 
{ 
if (!GetAce(pSrc, i, &pAce)) 
return HRESULT_FROM_WIN32(GetLastError()); 
 
aceHeader = (ACE_HEADER *) pAce; 
 
if (!AddAce(pDest, ACL_REVISION, 0xffffffff, pAce, aceHeader->AceSize)) 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
return S_OK; 
} 
 
HRESULT CSecurityDescriptor::AddAccessDeniedACEToACL(PACL *ppAcl, LPCTSTR pszPrincipal, DWORD dwAccessMask) 
{ 
ACL_SIZE_INFORMATION aclSizeInfo; 
int aclSize; 
DWORD returnValue; 
PSID principalSID; 
PACL oldACL, newACL; 
 
oldACL = *ppAcl; 
 
returnValue = GetPrincipalSID(pszPrincipal, &principalSID); 
if (FAILED(returnValue)) 
return returnValue; 
 
aclSizeInfo.AclBytesInUse = 0; 
if (*ppAcl != NULL) 
GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation); 
 
aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD); 
 
ATLTRY(newACL = (PACL) new BYTE[aclSize]); 
 
if (!InitializeAcl(newACL, aclSize, ACL_REVISION)) 
{ 
free(principalSID); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
if (!AddAccessDeniedAce(newACL, ACL_REVISION2, dwAccessMask, principalSID)) 
{ 
free(principalSID); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
returnValue = CopyACL(newACL, oldACL); 
if (FAILED(returnValue)) 
{ 
free(principalSID); 
return returnValue; 
} 
 
*ppAcl = newACL; 
 
if (oldACL != NULL) 
free(oldACL); 
free(principalSID); 
return S_OK; 
} 
 
 
HRESULT CSecurityDescriptor::AddAccessAllowedACEToACL(PACL *ppAcl, LPCTSTR pszPrincipal, DWORD dwAccessMask) 
{ 
ACL_SIZE_INFORMATION aclSizeInfo; 
int aclSize; 
DWORD returnValue; 
PSID principalSID; 
PACL oldACL, newACL; 
 
oldACL = *ppAcl; 
 
returnValue = GetPrincipalSID(pszPrincipal, &principalSID); 
if (FAILED(returnValue)) 
return returnValue; 
 
aclSizeInfo.AclBytesInUse = 0; 
if (*ppAcl != NULL) 
GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation); 
 
aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD); 
 
ATLTRY(newACL = (PACL) new BYTE[aclSize]); 
 
if (!InitializeAcl(newACL, aclSize, ACL_REVISION)) 
{ 
free(principalSID); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
returnValue = CopyACL(newACL, oldACL); 
if (FAILED(returnValue)) 
{ 
free(principalSID); 
return returnValue; 
} 
 
if (!AddAccessAllowedAce(newACL, ACL_REVISION2, dwAccessMask, principalSID)) 
{ 
free(principalSID); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
*ppAcl = newACL; 
 
if (oldACL != NULL) 
free(oldACL); 
free(principalSID); 
return S_OK; 
} 
 
 
HRESULT CSecurityDescriptor::RemovePrincipalFromACL(PACL pAcl, LPCTSTR pszPrincipal) 
{ 
ACL_SIZE_INFORMATION aclSizeInfo; 
ULONG i; 
LPVOID ace; 
ACCESS_ALLOWED_ACE *accessAllowedAce; 
ACCESS_DENIED_ACE *accessDeniedAce; 
SYSTEM_AUDIT_ACE *systemAuditAce; 
PSID principalSID; 
DWORD returnValue; 
ACE_HEADER *aceHeader; 
 
returnValue = GetPrincipalSID(pszPrincipal, &principalSID); 
if (FAILED(returnValue)) 
return returnValue; 
 
GetAclInformation(pAcl, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation); 
 
for (i = 0; i < aclSizeInfo.AceCount; i++) 
{ 
if (!GetAce(pAcl, i, &ace)) 
{ 
free(principalSID); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
aceHeader = (ACE_HEADER *) ace; 
 
if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) 
{ 
accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace; 
 
if (EqualSid(principalSID, (PSID) &accessAllowedAce->SidStart)) 
{ 
DeleteAce(pAcl, i); 
free(principalSID); 
return S_OK; 
} 
} else 
 
if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE) 
{ 
accessDeniedAce = (ACCESS_DENIED_ACE *) ace; 
 
if (EqualSid(principalSID, (PSID) &accessDeniedAce->SidStart)) 
{ 
DeleteAce(pAcl, i); 
free(principalSID); 
return S_OK; 
} 
} else 
 
if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE) 
{ 
systemAuditAce = (SYSTEM_AUDIT_ACE *) ace; 
 
if (EqualSid(principalSID, (PSID) &systemAuditAce->SidStart)) 
{ 
DeleteAce(pAcl, i); 
free(principalSID); 
return S_OK; 
} 
} 
} 
free(principalSID); 
return S_OK; 
} 
 
 
HRESULT CSecurityDescriptor::SetPrivilege(LPCTSTR privilege, BOOL bEnable, HANDLE hToken) 
{ 
HRESULT hr; 
TOKEN_PRIVILEGES tpPrevious; 
TOKEN_PRIVILEGES tp; 
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); 
LUID luid; 
 
// if no token specified open process token 
if (hToken == 0) 
{ 
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
} 
 
if (!LookupPrivilegeValue(NULL, privilege, &luid )) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
 
tp.PrivilegeCount = 1; 
tp.Privileges[0].Luid = luid; 
tp.Privileges[0].Attributes = 0; 
 
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious)) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
 
tpPrevious.PrivilegeCount = 1; 
tpPrevious.Privileges[0].Luid = luid; 
 
if (bEnable) 
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); 
else 
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); 
 
if (!AdjustTokenPrivileges(hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL)) 
{ 
hr = HRESULT_FROM_WIN32(GetLastError()); 
_ASSERTE(FALSE); 
return hr; 
} 
return S_OK; 
} 
 
#endif //_ATL_NO_SECURITY 
#endif //__ATLCOM_H__ 
 
#ifdef _DEBUG 
 
void _cdecl AtlTrace(LPCTSTR lpszFormat, ...) 
{ 
va_list args; 
va_start(args, lpszFormat); 
 
int nBuf; 
TCHAR szBuffer[512]; 
 
nBuf = _vstprintf(szBuffer, lpszFormat, args); 
_ASSERTE(nBuf < sizeof(szBuffer)); 
 
OutputDebugString(szBuffer); 
va_end(args); 
} 
#endif 
 
#ifndef ATL_NO_NAMESPACE 
}; //namespace ATL 
#endif 
 
/////////////////////////////////////////////////////////////////////////////// 
//All Global stuff goes below this line 
/////////////////////////////////////////////////////////////////////////////// 
 
///////////////////////////////////////////////////////////////////////////// 
// Minimize CRT 
// Specify DllMain as EntryPoint 
// Turn off exception handling 
// Define _ATL_MIN_CRT 
 
#ifdef _ATL_MIN_CRT 
///////////////////////////////////////////////////////////////////////////// 
// Heap Allocation 
 
#ifndef _DEBUG 
 
#ifndef _MERGE_PROXYSTUB 
//rpcproxy.h does the same thing as this 
int __cdecl _purecall() 
{ 
DebugBreak(); 
return 0; 
} 
#endif 
 
extern "C" const int _fltused = 0; 
 
void* __cdecl malloc(size_t n) 
{ 
if (_Module.m_hHeap == NULL) 
{ 
_Module.m_hHeap = HeapCreate(0, 0, 0); 
if (_Module.m_hHeap == NULL) 
return NULL; 
} 
_ASSERTE(_Module.m_hHeap != NULL); 
 
#ifdef _MALLOC_ZEROINIT 
return HeapAlloc(_Module.m_hHeap, HEAP_ZERO_MEMORY, n); 
#else 
return HeapAlloc(_Module.m_hHeap, 0, n); 
#endif 
} 
 
void* __cdecl calloc(size_t n, size_t s) 
{ 
return malloc(n * s); 
} 
 
void* __cdecl realloc(void* p, size_t n) 
{ 
_ASSERTE(_Module.m_hHeap != NULL); 
#ifdef _MALLOC_ZEROINIT 
return (p == NULL) ? malloc(n) : HeapReAlloc(_Module.m_hHeap, HEAP_ZERO_MEMORY, p, n); 
#else 
return (p == NULL) ? malloc(n) : HeapReAlloc(_Module.m_hHeap, 0, p, n); 
#endif 
} 
 
void __cdecl free(void* p) 
{ 
_ASSERTE(_Module.m_hHeap != NULL); 
HeapFree(_Module.m_hHeap, 0, p); 
} 
 
void* __cdecl operator new(size_t n) 
{ 
return malloc(n); 
} 
 
void __cdecl operator delete(void* p) 
{ 
free(p); 
} 
 
#endif  //_DEBUG 
 
#endif //_ATL_MIN_CRT 
 
#ifndef _ATL_DLL 
 
#ifndef ATL_NO_NAMESPACE 
#ifndef _ATL_DLL_IMPL 
namespace ATL 
{ 
#endif 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// statics 
 
static UINT WINAPI AtlGetDirLen(LPCOLESTR lpszPathName) 
{ 
_ASSERTE(lpszPathName != NULL); 
 
// always capture the complete file name including extension (if present) 
LPCOLESTR lpszTemp = lpszPathName; 
for (LPCOLESTR lpsz = lpszPathName; *lpsz != NULL; ) 
{ 
LPCOLESTR lp = CharNextO(lpsz); 
// remember last directory/drive separator 
if (*lpsz == OLESTR('\\') || *lpsz == OLESTR('/') || *lpsz == OLESTR(':')) 
lpszTemp = lp; 
lpsz = lp; 
} 
 
return lpszTemp-lpszPathName; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// QI support 
 
ATLAPI AtlInternalQueryInterface(void* pThis, 
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject) 
{ 
_ASSERTE(pThis != NULL); 
// First entry in the com map should be a simple map entry 
_ASSERTE(pEntries->pFunc == _ATL_SIMPLEMAPENTRY); 
if (ppvObject == NULL) 
return E_POINTER; 
*ppvObject = NULL; 
if (InlineIsEqualUnknown(iid)) // use first interface 
{ 
IUnknown* pUnk = (IUnknown*)((int)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 
{ 
_ASSERTE(!bBlind); 
IUnknown* pUnk = (IUnknown*)((int)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; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Smart Pointer helpers 
 
ATLAPI_(IUnknown*) AtlComPtrAssign(IUnknown** pp, IUnknown* lp) 
{ 
if (lp != NULL) 
lp->AddRef(); 
if (*pp) 
(*pp)->Release(); 
*pp = lp; 
return lp; 
} 
 
ATLAPI_(IUnknown*) AtlComQIPtrAssign(IUnknown** pp, IUnknown* lp, REFIID riid) 
{ 
IUnknown* pTemp = *pp; 
lp->QueryInterface(riid, (void**)pp); 
if (pTemp) 
pTemp->Release(); 
return *pp; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Inproc Marshaling helpers 
 
ATLAPI AtlFreeMarshalStream(IStream* pStream) 
{ 
if (pStream != NULL) 
{ 
CoReleaseMarshalData(pStream); 
pStream->Release(); 
} 
return S_OK; 
} 
 
ATLAPI AtlMarshalPtrInProc(IUnknown* pUnk, const IID& iid, IStream** ppStream) 
{ 
HRESULT hRes = CreateStreamOnHGlobal(NULL, TRUE, ppStream); 
if (SUCCEEDED(hRes)) 
{ 
hRes = CoMarshalInterface(*ppStream, iid, 
pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); 
if (FAILED(hRes)) 
{ 
(*ppStream)->Release(); 
*ppStream = NULL; 
} 
} 
return hRes; 
} 
 
ATLAPI AtlUnmarshalPtr(IStream* pStream, const IID& iid, IUnknown** ppUnk) 
{ 
*ppUnk = NULL; 
HRESULT hRes = E_INVALIDARG; 
if (pStream != NULL) 
{ 
LARGE_INTEGER l; 
l.QuadPart = 0; 
pStream->Seek(l, STREAM_SEEK_SET, NULL); 
hRes = CoUnmarshalInterface(pStream, iid, (void**)ppUnk); 
} 
return hRes; 
} 
 
ATLAPI_(BOOL) AtlWaitWithMessageLoop(HANDLE hEvent) 
{ 
DWORD dwRet; 
MSG msg; 
 
while(1) 
{ 
dwRet = MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT); 
 
if (dwRet == WAIT_OBJECT_0) 
return TRUE;    // The event was signaled 
 
if (dwRet != WAIT_OBJECT_0 + 1) 
break;          // Something else happened 
 
// There is one or more window message available. Dispatch them 
while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) 
{ 
TranslateMessage(&msg); 
DispatchMessage(&msg); 
if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) 
return TRUE; // Event is now signaled. 
} 
} 
return FALSE; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Connection Point Helpers 
 
ATLAPI AtlAdvise(IUnknown* pUnkCP, IUnknown* pUnk, const IID& iid, LPDWORD pdw) 
{ 
CComPtr<IConnectionPointContainer> pCPC; 
CComPtr<IConnectionPoint> pCP; 
HRESULT hRes = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC); 
if (SUCCEEDED(hRes)) 
hRes = pCPC->FindConnectionPoint(iid, &pCP); 
if (SUCCEEDED(hRes)) 
hRes = pCP->Advise(pUnk, pdw); 
return hRes; 
} 
 
ATLAPI AtlUnadvise(IUnknown* pUnkCP, const IID& iid, DWORD dw) 
{ 
CComPtr<IConnectionPointContainer> pCPC; 
CComPtr<IConnectionPoint> pCP; 
HRESULT hRes = pUnkCP->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC); 
if (SUCCEEDED(hRes)) 
hRes = pCPC->FindConnectionPoint(iid, &pCP); 
if (SUCCEEDED(hRes)) 
hRes = pCP->Unadvise(dw); 
return hRes; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// IDispatch Error handling 
 
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 (HIWORD(lpszDesc) == 0) //id 
{ 
UINT nID = LOWORD((DWORD)lpszDesc); 
_ASSERTE((nID >= 0x0200 && nID <= 0xffff) || hRes != 0); 
if (LoadString(hInst, nID, szDesc, 1024) == 0) 
{ 
_ASSERTE(FALSE); 
lstrcpy(szDesc, _T("Unknown Error")); 
} 
lpszDesc = T2OLE(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(IID_IErrorInfo, (void**)&pErrorInfo))) 
SetErrorInfo(0, pErrorInfo); 
} 
//#ifdef _DEBUG 
//  USES_CONVERSION; 
//  ATLTRACE(_T("AtlReportError: Description=\"%s\" returning %x\n"), OLE2CT(lpszDesc), hRes); 
//#endif 
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. 
 
ATLAPI AtlModuleInit(_ATL_MODULE* pM, _ATL_OBJMAP_ENTRY* p, HINSTANCE h) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
if (pM->cbSize < sizeof(_ATL_MODULE)) 
return E_INVALIDARG; 
pM->m_pObjMap = p; 
pM->m_hInst = pM->m_hInstTypeLib = pM->m_hInstResource = h; 
pM->m_nLockCnt=0L; 
pM->m_hHeap = NULL; 
InitializeCriticalSection(&pM->m_csTypeInfoHolder); 
InitializeCriticalSection(&pM->m_csWindowCreate); 
InitializeCriticalSection(&pM->m_csObjMap); 
return S_OK; 
} 
 
ATLAPI AtlModuleRegisterClassObjects(_ATL_MODULE* pM, DWORD dwClsContext, DWORD dwFlags) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
_ASSERTE(pM->m_pObjMap != NULL); 
_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap; 
HRESULT hRes = S_OK; 
while (pEntry->pclsid != NULL && hRes == S_OK) 
{ 
hRes = pEntry->RegisterClassObject(dwClsContext, dwFlags); 
pEntry++; 
} 
return hRes; 
} 
 
ATLAPI AtlModuleRevokeClassObjects(_ATL_MODULE* pM) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
_ASSERTE(pM->m_pObjMap != NULL); 
_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap; 
HRESULT hRes = S_OK; 
while (pEntry->pclsid != NULL && hRes == S_OK) 
{ 
hRes = pEntry->RevokeClassObject(); 
pEntry++; 
} 
return hRes; 
} 
 
ATLAPI AtlModuleGetClassObject(_ATL_MODULE* pM, REFCLSID rclsid, REFIID riid, LPVOID* ppv) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
_ASSERTE(pM->m_pObjMap != NULL); 
_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap; 
HRESULT hRes = S_OK; 
if (ppv == NULL) 
return E_POINTER; 
while (pEntry->pclsid != NULL) 
{ 
if (InlineIsEqualGUID(rclsid, *pEntry->pclsid)) 
{ 
if (pEntry->pCF == NULL) 
{ 
EnterCriticalSection(&pM->m_csObjMap); 
if (pEntry->pCF == NULL) 
hRes = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, IID_IUnknown, (LPVOID*)&pEntry->pCF); 
LeaveCriticalSection(&pM->m_csObjMap); 
} 
if (pEntry->pCF != NULL) 
hRes = pEntry->pCF->QueryInterface(riid, ppv); 
break; 
} 
pEntry++; 
} 
if (*ppv == NULL && hRes == S_OK) 
hRes = CLASS_E_CLASSNOTAVAILABLE; 
return hRes; 
} 
 
ATLAPI AtlModuleTerm(_ATL_MODULE* pM) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
_ASSERTE(pM->m_hInst != NULL); 
if (pM->m_pObjMap != NULL) 
{ 
_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap; 
while (pEntry->pclsid != NULL) 
{ 
if (pEntry->pCF != NULL) 
pEntry->pCF->Release(); 
pEntry->pCF = NULL; 
pEntry++; 
} 
} 
DeleteCriticalSection(&pM->m_csTypeInfoHolder); 
DeleteCriticalSection(&pM->m_csWindowCreate); 
DeleteCriticalSection(&pM->m_csObjMap); 
if (pM->m_hHeap != NULL) 
HeapDestroy(pM->m_hHeap); 
return S_OK; 
} 
 
ATLAPI AtlModuleRegisterServer(_ATL_MODULE* pM, BOOL bRegTypeLib, CLSID* pCLSID) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
_ASSERTE(pM->m_hInst != NULL); 
_ASSERTE(pM->m_pObjMap != NULL); 
_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap; 
HRESULT hRes = S_OK; 
for (;pEntry->pclsid != NULL; pEntry++) 
{ 
if (pCLSID == NULL) 
{ 
if (pEntry->pfnGetObjectDescription() != NULL) 
continue; 
} 
else 
{ 
if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) 
continue; 
} 
hRes = pEntry->pfnUpdateRegistry(TRUE); 
if (FAILED(hRes)) 
break; 
} 
if (SUCCEEDED(hRes) && bRegTypeLib) 
hRes = AtlModuleRegisterTypeLib(pM, 0); 
return hRes; 
} 
 
ATLAPI AtlModuleUnregisterServer(_ATL_MODULE* pM, CLSID* pCLSID) 
{ 
_ASSERTE(pM != NULL); 
if (pM == NULL) 
return E_INVALIDARG; 
_ASSERTE(pM->m_hInst != NULL); 
_ASSERTE(pM->m_pObjMap != NULL); 
_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap; 
for (;pEntry->pclsid != NULL; pEntry++) 
{ 
if (pCLSID == NULL) 
{ 
if (pEntry->pfnGetObjectDescription() != NULL) 
continue; 
} 
else 
{ 
if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) 
continue; 
} 
pEntry->pfnUpdateRegistry(FALSE); //unregister 
} 
return S_OK; 
} 
 
ATLAPI AtlModuleUpdateRegistryFromResourceD(_ATL_MODULE* pM, LPCOLESTR lpszRes, 
BOOL bRegister, struct _ATL_REGMAP_ENTRY* pMapEntries, IRegistrar* pReg) 
{ 
USES_CONVERSION; 
_ASSERTE(pM != NULL); 
HRESULT hRes = S_OK; 
CComPtr<IRegistrar> p; 
if (pReg != NULL) 
p = pReg; 
else 
{ 
hRes = CoCreateInstance(CLSID_Registrar, NULL, 
CLSCTX_INPROC_SERVER, IID_IRegistrar, (void**)&p); 
} 
if (SUCCEEDED(hRes)) 
{ 
TCHAR szModule[_MAX_PATH]; 
GetModuleFileName(pM->m_hInst, szModule, _MAX_PATH); 
p->AddReplacement(OLESTR("Module"), T2OLE(szModule)); 
 
if (NULL != pMapEntries) 
{ 
while (NULL != pMapEntries->szKey) 
{ 
_ASSERTE(NULL != pMapEntries->szData); 
p->AddReplacement((LPOLESTR)pMapEntries->szKey, (LPOLESTR)pMapEntries->szData); 
pMapEntries++; 
} 
} 
LPCOLESTR szType = OLESTR("REGISTRY"); 
GetModuleFileName(pM->m_hInstResource, szModule, _MAX_PATH); 
LPOLESTR pszModule = T2OLE(szModule); 
if (HIWORD(lpszRes)==0) 
{ 
if (bRegister) 
hRes = p->ResourceRegister(pszModule, ((UINT)LOWORD((DWORD)lpszRes)), szType); 
else 
hRes = p->ResourceUnregister(pszModule, ((UINT)LOWORD((DWORD)lpszRes)), szType); 
} 
else 
{ 
if (bRegister) 
hRes = p->ResourceRegisterSz(pszModule, lpszRes, szType); 
else 
hRes = p->ResourceUnregisterSz(pszModule, lpszRes, szType); 
} 
 
} 
return hRes; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// TypeLib Support 
 
ATLAPI AtlModuleRegisterTypeLib(_ATL_MODULE* pM, LPCOLESTR lpszIndex) 
{ 
_ASSERTE(pM != NULL); 
USES_CONVERSION; 
_ASSERTE(pM->m_hInstTypeLib != NULL); 
TCHAR szModule[_MAX_PATH+10]; 
OLECHAR szDir[_MAX_PATH]; 
GetModuleFileName(pM->m_hInstTypeLib, szModule, _MAX_PATH); 
if (lpszIndex != NULL) 
lstrcat(szModule, OLE2CT(lpszIndex)); 
ITypeLib* pTypeLib; 
LPOLESTR lpszModule = T2OLE(szModule); 
HRESULT hr = LoadTypeLib(lpszModule, &pTypeLib); 
if (!SUCCEEDED(hr)) 
{ 
// typelib not in module, try <module>.tlb instead 
LPTSTR lpszExt = NULL; 
LPTSTR lpsz; 
for (lpsz = szModule; *lpsz != NULL; lpsz = CharNext(lpsz)) 
{ 
if (*lpsz == _T('.')) 
lpszExt = lpsz; 
} 
if (lpszExt == NULL) 
lpszExt = lpsz; 
lstrcpy(lpszExt, _T(".tlb")); 
lpszModule = T2OLE(szModule); 
hr = LoadTypeLib(lpszModule, &pTypeLib); 
} 
if (SUCCEEDED(hr)) 
{ 
ocscpy(szDir, lpszModule); 
szDir[AtlGetDirLen(szDir)] = 0; 
hr = ::RegisterTypeLib(pTypeLib, lpszModule, szDir); 
} 
if (pTypeLib != NULL) 
pTypeLib->Release(); 
return hr; 
} 
 
#ifndef ATL_NO_NAMESPACE 
#ifndef _ATL_DLL_IMPL 
}; //namespace ATL 
#endif 
#endif 
 
#endif //!_ATL_DLL