Leaked source code of windows server 2003
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.
 
 
 
 
 
 

623 lines
16 KiB

// CActCtx.cpp : Implementation of CActCtx
#include "stdinc.h"
#include "sxsoa.h"
#include "actctx.h"
#define NUMBER_OF(x) RTL_NUMBER_OF(x)
class CActivation
{
public:
CActivation(CActCtx &rActCtx, HANDLE hActCtx) : m_rActCtx(rActCtx), m_hActCtx(hActCtx), m_ulpCookie(0) { }
CActivation(CActCtx &rActCtx) : m_rActCtx(rActCtx), m_hActCtx(NULL), m_ulpCookie(0) { }
~CActivation() { if (m_ulpCookie != 0) { (*m_rActCtx.ms_pDeactivateActCtx)(0, m_ulpCookie); } }
void Attach(HANDLE hActCtx) { _ASSERTE(m_ulpCookie == 0); m_hActCtx = hActCtx; }
HRESULT Activate()
{
if (m_ulpCookie != 0)
return E_UNEXPECTED;
if (!(*m_rActCtx.ms_pActivateActCtx)(m_hActCtx, &m_ulpCookie))
return HRESULT_FROM_WIN32(::GetLastError());
return NOERROR;
}
HRESULT Deactivate()
{
ULONG_PTR ulpCookie = m_ulpCookie; // capture
m_ulpCookie = 0;
if (ulpCookie == 0)
return E_UNEXPECTED;
if (!(*m_rActCtx.ms_pDeactivateActCtx)(0, ulpCookie))
return HRESULT_FROM_WIN32(::GetLastError());
return NOERROR;
}
protected:
CActCtx &m_rActCtx;
HANDLE m_hActCtx;
ULONG_PTR m_ulpCookie;
};
/////////////////////////////////////////////////////////////////////////////
// CActCtx
HINSTANCE CActCtx::ms_hKERNEL32 = NULL;
CActCtx::PFNCreateActCtxW CActCtx::ms_pCreateActCtxW = NULL;
CActCtx::PFNAddRefActCtx CActCtx::ms_pAddRefActCtx = NULL;
CActCtx::PFNReleaseActCtx CActCtx::ms_pReleaseActCtx = NULL;
CActCtx::PFNActivateActCtx CActCtx::ms_pActivateActCtx = NULL;
CActCtx::PFNDeactivateActCtx CActCtx::ms_pDeactivateActCtx = NULL;
HRESULT CActCtx::FetchManifestInfo(ACTCTX_MANIFEST_INFO_TYPE infotype, BSTR *pVal)
{
HRESULT hr = E_FAIL;
BSTR bstrResult = NULL;
if (pVal != NULL)
*pVal = NULL;
if (pVal == NULL)
{
hr = E_INVALIDARG;
goto Exit;
}
if (infotype == ACTCTX_MANIFEST_FILE)
{
bstrResult = ::SysAllocString((m_bstrManifest.m_str == NULL) ? L"" : m_bstrManifest);
}
else if (infotype == ACTCTX_MANIFEST_TEXT)
{
bstrResult = ::SysAllocString((m_bstrManifestText.m_str == NULL) ? L"" : m_bstrManifestText);
}
else if (infotype == ACTCTX_MANIFEST_URL)
{
bstrResult = ::SysAllocString((m_bstrManifestURL.m_str == NULL) ? L"" : m_bstrManifestURL);
}
else
{
hr = E_INVALIDARG;
goto Exit;
}
if (bstrResult == NULL)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
*pVal = bstrResult;
bstrResult = NULL;
hr = NOERROR;
Exit:
if (bstrResult != NULL)
::SysFreeString(bstrResult);
return hr;
}
HRESULT MakeTemporaryFileName(CComBSTR & str)
{
// generate a temporary filename
HRESULT hr = E_FAIL;
BSTR bstrTempFileName = NULL;
WCHAR TempPath[MAX_PATH];
WCHAR TempFileName[MAX_PATH];
if ( 0 == GetTempPathW(MAX_PATH, TempPath))
goto SetHrErrorAndExit;
if ( 0 == GetTempFileNameW(TempPath, L"sxs", 0, TempFileName))
goto SetHrErrorAndExit;
bstrTempFileName = SysAllocString(TempFileName);
if (bstrTempFileName == NULL)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
str.Attach(bstrTempFileName);
bstrTempFileName = NULL;
hr = S_OK;
goto Exit;
SetHrErrorAndExit:
hr = HRESULT_FROM_WIN32(::GetLastError());
Exit:
if (bstrTempFileName != NULL)
SysFreeString(bstrTempFileName);
return hr;
}
HRESULT CActCtx::SetManifestInfo(ACTCTX_MANIFEST_INFO_TYPE infotype, BSTR newVal)
{
HRESULT hr = E_FAIL;
HANDLE hActCtx = INVALID_HANDLE_VALUE;
ACTCTXW acw = { sizeof(acw) };
CComBSTR bstrTemp;
CComBSTR bstrManifestFile;
HANDLE hTempFile = INVALID_HANDLE_VALUE;
if (newVal == NULL)
{
hr = E_INVALIDARG;
goto Exit;
}
if (infotype == ACTCTX_MANIFEST_FILE)
{
bstrManifestFile.Attach(newVal);
}
else if (infotype == ACTCTX_MANIFEST_TEXT)
{
DWORD NumberOfBytesWritten;
hr = MakeTemporaryFileName(bstrManifestFile);
if (FAILED(hr))
goto Exit;
hTempFile = CreateFileW((LPWSTR)bstrManifestFile,
GENERIC_READ | GENERIC_WRITE,
0, // do not share
NULL, // no security
CREATE_ALWAYS, // overwrite existing file
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hTempFile == INVALID_HANDLE_VALUE)
goto SetHrErrorAndExit;
// "TODO:" or "DO WE NEED TODO?":
// check the encoding of the manifest, if it is encoded as "UTF-8", we have to transfer the
// textual manifest into byte before writing into a file.
// be sure that your manifest is UCS-2
ULONG XML_UCS2_BOM=0xFEFF;
if ( FALSE == WriteFile(hTempFile, (LPCVOID)&XML_UCS2_BOM, 2, &NumberOfBytesWritten, NULL))
goto SetHrErrorAndExit;
if ( FALSE == WriteFile(hTempFile, (LPCVOID)((LPWSTR)newVal), SysStringByteLen(newVal), &NumberOfBytesWritten, NULL))
goto SetHrErrorAndExit;
if ( FALSE == CloseHandle(hTempFile))
goto SetHrErrorAndExit;
hTempFile = INVALID_HANDLE_VALUE;
}
else if (infotype == ACTCTX_MANIFEST_URL)
{
hr = MakeTemporaryFileName(bstrManifestFile);
if (FAILED(hr))
{
goto Exit;
}
if (FAILED(hr = URLDownloadToFileW(NULL, (LPWSTR)newVal, (LPWSTR)bstrManifestFile, 0, NULL)))
goto Exit;
}
else
{
hr = E_INVALIDARG;
goto Exit;
}
if (FAILED(hr = this->EnsureInitialized()))
goto Exit;
acw.lpSource = bstrManifestFile;
hActCtx = (*ms_pCreateActCtxW)(&acw);
if (hActCtx == INVALID_HANDLE_VALUE)
{
hr = HRESULT_FROM_WIN32(::GetLastError());
goto Exit;
}
bstrTemp.Attach(::SysAllocString(newVal));
if (bstrTemp == static_cast<BSTR>(NULL))
{
hr = E_OUTOFMEMORY;
goto Exit;
}
m_cs.Lock();
if (m_hActCtx != NULL)
(*ms_pReleaseActCtx)(m_hActCtx);
m_hActCtx = hActCtx;
hActCtx = NULL;
m_bstrManifest.Empty();
m_bstrManifestURL.Empty();
m_bstrManifestText.Empty();
switch (infotype)
{
case ACTCTX_MANIFEST_FILE:
m_bstrManifest.Attach(bstrTemp.Detach());
break;
case ACTCTX_MANIFEST_TEXT:
m_bstrManifestText.Attach(bstrTemp.Detach());
break;
case ACTCTX_MANIFEST_URL:
m_bstrManifestURL.Attach(bstrTemp.Detach());
break;
default: // impossible path because infotype has been checked at the beginning of the function
hr = E_INVALIDARG;
goto Exit;
}
m_cs.Unlock();
hr = NOERROR;
goto Exit;
SetHrErrorAndExit:
hr = HRESULT_FROM_WIN32(::GetLastError());
Exit:
if (hTempFile != INVALID_HANDLE_VALUE)
CloseHandle(hTempFile);
if (infotype == ACTCTX_MANIFEST_FILE)
bstrManifestFile.Detach();
if (hActCtx != NULL && hActCtx != INVALID_HANDLE_VALUE)
(*ms_pReleaseActCtx)(hActCtx);
return hr;
}
STDMETHODIMP CActCtx::CreateObject(BSTR bstrObjectReference, VARIANT *pvarLocation, IDispatch **ppObject)
{
HRESULT hr = E_FAIL;
CLSID clsid;
COSERVERINFO csi = { 0 };
MULTI_QI rgmqi[1];
ULONG cmqi = 0, imqiIDispatch, i;
HANDLE hActCtx = INVALID_HANDLE_VALUE;
CActivation act(*this);
BSTR bstrLocation = NULL;
if (ppObject != NULL)
*ppObject = NULL;
if (ppObject == NULL)
{
hr = E_INVALIDARG;
goto Exit;
}
if ((pvarLocation != NULL) &&
(pvarLocation->vt != VT_ERROR))
{
if (pvarLocation->vt != VT_BSTR)
{
hr = E_INVALIDARG;
goto Exit;
}
bstrLocation = pvarLocation->bstrVal;
}
if (FAILED(hr = this->EnsureInitialized()))
goto Exit;
m_cs.Lock();
hActCtx = m_hActCtx;
(*ms_pAddRefActCtx)(hActCtx);
m_cs.Unlock();
act.Attach(hActCtx);
act.Activate();
if (FAILED(hr = ::CLSIDFromProgID(bstrObjectReference, &clsid)))
goto Exit;
if (bstrLocation != NULL)
csi.pwszName = bstrLocation;
cmqi = 0;
_ASSERTE(cmqi < NUMBER_OF(rgmqi));
rgmqi[cmqi].hr = NOERROR;
rgmqi[cmqi].pIID = &IID_IDispatch;
rgmqi[cmqi].pItf = NULL;
imqiIDispatch = cmqi;
cmqi++;
if (FAILED(hr = ::CoCreateInstanceEx(
clsid,
NULL,
CLSCTX_SERVER,
&csi,
cmqi,
rgmqi)))
goto Exit;
// See if any of the QIs failed...
for (i=0; i<cmqi; i++)
{
if (FAILED(hr = rgmqi[i].hr))
goto Exit;
}
act.Deactivate();
*ppObject = static_cast<IDispatch *>(rgmqi[imqiIDispatch].pItf);
rgmqi[imqiIDispatch].pItf = NULL;
hr = NOERROR;
Exit:
for (i=0; i<cmqi; i++)
{
if (rgmqi[i].pItf != NULL)
rgmqi[i].pItf->Release();
}
if ((hActCtx != NULL) &&
(hActCtx != INVALID_HANDLE_VALUE))
(*ms_pReleaseActCtx)(hActCtx);
return hr;
}
STDMETHODIMP CActCtx::GetObject(VARIANT *pvarMoniker, VARIANT *pvarProgID, IDispatch **ppIDispatch)
{
HRESULT hr = E_FAIL;
CComPtr<IDispatch> srpIDispatch;
CComPtr<IBindCtx> srpIBindCtx;
CComPtr<IMoniker> srpIMoniker;
CComVariant svarProgId;
HANDLE hActCtx = INVALID_HANDLE_VALUE;
CActivation act(*this);
BSTR bstrMoniker = NULL;
if (ppIDispatch != NULL)
*ppIDispatch = NULL;
if (ppIDispatch == NULL)
{
hr = E_INVALIDARG;
goto Exit;
}
if (FAILED(hr = this->EnsureInitialized()))
goto Exit;
if (pvarMoniker != NULL)
{
if (pvarMoniker->vt != VT_ERROR)
{
if (pvarMoniker->vt != VT_BSTR)
{
hr = DISP_E_TYPEMISMATCH;
goto Exit;
}
bstrMoniker = pvarMoniker->bstrVal;
}
}
if ((bstrMoniker != NULL) && (bstrMoniker[0] == L'\0'))
bstrMoniker = NULL;
m_cs.Lock();
hActCtx = m_hActCtx;
(*ms_pAddRefActCtx)(hActCtx);
m_cs.Unlock();
act.Attach(hActCtx);
act.Activate();
if ((pvarProgID != NULL) && (pvarProgID->vt != VT_ERROR))
{
hr = svarProgId.ChangeType(VT_BSTR, pvarProgID);
if (FAILED(hr))
goto Exit;
hr = this->CreateObject(svarProgId.bstrVal, NULL, &srpIDispatch);
if (FAILED(hr))
goto Exit;
if (bstrMoniker != NULL)
{
CComPtr<IPersistFile> srpIPersistFile;
hr = srpIDispatch.QueryInterface(&srpIPersistFile);
if (FAILED(hr))
goto Exit;
hr = srpIPersistFile->Load(bstrMoniker, STGM_READWRITE);
if (FAILED(hr))
goto Exit;
}
}
else
{
PCWSTR pszColon = NULL;
ULONG cchEaten;
if (bstrMoniker == NULL)
{
hr = E_INVALIDARG;
goto Exit;
}
hr = ::CreateBindCtx(0, &srpIBindCtx);
if (FAILED(hr))
goto Exit;
pszColon = wcschr(bstrMoniker, L':');
if ((pszColon == NULL) || ((pszColon - bstrMoniker) == 1))
{
WCHAR rgwchFullPath[MAX_PATH];
DWORD dwRet;
PWSTR pszFilePart;
dwRet = ::GetFullPathNameW(bstrMoniker, NUMBER_OF(rgwchFullPath), rgwchFullPath, &pszFilePart);
if (dwRet == 0)
{
hr = HRESULT_FROM_WIN32(::GetLastError());
goto Exit;
}
hr = ::MkParseDisplayName(srpIBindCtx, bstrMoniker, &cchEaten, &srpIMoniker);
if (FAILED(hr))
goto Exit;
}
else
{
hr = ::CreateURLMoniker(NULL, bstrMoniker, &srpIMoniker);
if (FAILED(hr))
goto Exit;
}
hr = srpIMoniker->BindToObject(srpIBindCtx, NULL, IID_IDispatch, (PVOID *) &srpIDispatch);
if (hr == 0x800C0005)
hr = MK_E_CANTOPENFILE;
if (FAILED(hr))
goto Exit;
}
*ppIDispatch = srpIDispatch.Detach();
act.Deactivate();
hr = NOERROR;
Exit:
return hr;
}
template <typename T> static HRESULT LocalGetProcAddress(HINSTANCE hInstance, PCSTR pszFunction, T &rpfn, T pfnDefault)
{
HRESULT hr = E_FAIL;
if (rpfn == NULL)
{
T pfn = reinterpret_cast<T>(::GetProcAddress(hInstance, pszFunction));
if (pfn == NULL)
{
const DWORD dwLastError = ::GetLastError();
if (dwLastError != ERROR_PROC_NOT_FOUND)
{
hr = HRESULT_FROM_WIN32(dwLastError);
goto Exit;
}
pfn = pfnDefault;
}
#if defined(_X86_)
::InterlockedCompareExchange((LONG *) &rpfn, (LONG) pfn, 0);
#else
::InterlockedCompareExchangePointer((PVOID *) &rpfn, pfn, NULL);
#endif
}
hr = NOERROR;
Exit:
return hr;
}
HRESULT CActCtx::EnsureInitialized()
{
HRESULT hr = E_FAIL;
// Check last initialized pointer first for early exit
if (ms_pDeactivateActCtx != NULL)
{
hr = NOERROR;
goto Exit;
}
if (ms_hKERNEL32 == NULL)
{
HINSTANCE hKERNEL32 = ::GetModuleHandleA("KERNEL32.DLL");
if (hKERNEL32 == NULL)
{
hr = HRESULT_FROM_WIN32(::GetLastError());
goto Exit;
}
#if defined(_X86_)
if (::InterlockedExchange(reinterpret_cast<LONG *>(&ms_hKERNEL32), reinterpret_cast<LONG>(hKERNEL32)) != 0)
#else
if (::InterlockedExchangePointer(reinterpret_cast<PVOID *>(&ms_hKERNEL32), hKERNEL32) != NULL)
#endif
::FreeLibrary(hKERNEL32);
}
if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "CreateActCtxW", ms_pCreateActCtxW, &CActCtx::fakeCreateActCtxW)))
goto Exit;
if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "AddRefActCtx", ms_pAddRefActCtx, &CActCtx::fakeAddRefActCtx)))
goto Exit;
if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "ReleaseActCtx", ms_pReleaseActCtx, &CActCtx::fakeReleaseActCtx)))
goto Exit;
if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "ActivateActCtx", ms_pActivateActCtx, &CActCtx::fakeActivateActCtx)))
goto Exit;
if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "DeactivateActCtx", ms_pDeactivateActCtx, &CActCtx::fakeDeactivateActCtx)))
goto Exit;
hr = NOERROR;
Exit:
return hr;
}
STDMETHODIMP CActCtx::put_ManifestText(BSTR bstrManifestText)
{
return SetManifestInfo(ACTCTX_MANIFEST_TEXT, bstrManifestText);
}
STDMETHODIMP CActCtx::put_ManifestURL(BSTR bstrManifestURL)
{
return SetManifestInfo(ACTCTX_MANIFEST_URL, bstrManifestURL);
}
STDMETHODIMP CActCtx::put_Manifest(BSTR bstrManifestURL)
{
return SetManifestInfo(ACTCTX_MANIFEST_FILE, bstrManifestURL);
}
STDMETHODIMP CActCtx::get_Manifest(BSTR *pVal)
{
return FetchManifestInfo(ACTCTX_MANIFEST_FILE, pVal);
}
STDMETHODIMP CActCtx::get_ManifestText(BSTR *pVal)
{
return FetchManifestInfo(ACTCTX_MANIFEST_TEXT, pVal);
}
STDMETHODIMP CActCtx::get_ManifestURL(BSTR *pVal)
{
return FetchManifestInfo(ACTCTX_MANIFEST_URL, pVal);
}