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.
 
 
 
 
 
 

754 lines
19 KiB

//
// Copyright (c) 2001 Microsoft Corporation
//
//
#include "activexmime.h"
#include <wininet.h>
#define GOBACKHACK
#ifdef GOBACKHACK
#include <exdisp.h> // for IWebBrowser2
#endif
#include "macros.h"
static const GUID CLSID_ActiveXMimePlayer =
{ 0xFDCDCCE0, 0xCBC4, 0x49FB, { 0x85, 0x8D, 0x92, 0x53, 0xA6, 0xB8, 0x16, 0x1F} };
extern ULONG DllAddRef(void);
extern ULONG DllRelease(void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
CActiveXMimeClassFactory::CActiveXMimeClassFactory()
{
_cRef = 1;
_hr = S_OK;
}
// ----------------------------------------------------------------------------
HRESULT
CActiveXMimeClassFactory::QueryInterface(REFIID iid, void **ppv)
{
_hr = S_OK;
*ppv = NULL;
if (iid == IID_IUnknown || iid == IID_IClassFactory)
{
*ppv = (IClassFactory *)this;
}
else
{
_hr = E_NOINTERFACE;
goto exit;
}
((IUnknown *)*ppv)->AddRef();
exit:
return _hr;
}
// ----------------------------------------------------------------------------
ULONG
CActiveXMimeClassFactory::AddRef()
{
return (ULONG) InterlockedIncrement(&_cRef);
}
ULONG
CActiveXMimeClassFactory::Release()
{
LONG ulCount = InterlockedDecrement(&_cRef);
if (ulCount <= 0)
{
delete this;
}
return (ULONG) ulCount;
}
HRESULT
CActiveXMimeClassFactory::LockServer(BOOL lock)
{
if (lock)
DllAddRef();
else
DllRelease();
return (_hr = S_OK);
}
// ----------------------------------------------------------------------------
HRESULT
CActiveXMimeClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID iid, void** ppv)
{
_hr = S_OK;
CActiveXMimePlayer *pMimePlayer = NULL;
*ppv = NULL;
IF_FALSE_EXIT(!pUnkOuter || iid == IID_IUnknown, CLASS_E_NOAGGREGATION);
pMimePlayer = new CActiveXMimePlayer();
IF_ALLOC_FAILED_EXIT(pMimePlayer);
if (iid == IID_IUnknown)
{
*ppv = (IOleObject *)pMimePlayer;
pMimePlayer->AddRef();
}
else
{
IF_FAILED_EXIT(pMimePlayer->QueryInterface(iid, ppv));
}
exit:
SAFERELEASE(pMimePlayer);
return _hr;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// CActiveXMimePlayer
CActiveXMimePlayer::CActiveXMimePlayer()
{
_cRef = 1;
_hr = S_OK;
}
CActiveXMimePlayer::~CActiveXMimePlayer()
{
}
// ----------------------------------------------------------------------------
HRESULT
CActiveXMimePlayer::QueryInterface(REFIID iid, void** ppv)
{
_hr = S_OK;
*ppv = NULL;
if (iid == IID_IOleObject ||
iid == IID_IUnknown)
{
*ppv = (IOleObject *)this;
}
else if (iid == IID_IObjectSafety)
{
*ppv = (IObjectSafety *)this;
}
else
{
_hr = E_NOINTERFACE;
goto exit;
}
((IUnknown *)*ppv)->AddRef();
exit:
return _hr;
}
// ----------------------------------------------------------------------------
ULONG
CActiveXMimePlayer::AddRef()
{
return (ULONG) InterlockedIncrement(&_cRef);
}
ULONG
CActiveXMimePlayer::Release()
{
LONG ulCount = InterlockedDecrement(&_cRef);
if (ulCount <= 0)
{
delete this;
}
return (ULONG) ulCount;
}
// ----------------------------------------------------------------------------
//////////////////////////////////////////////
// IOleObject interface
HRESULT
CActiveXMimePlayer::SetClientSite(IOleClientSite *pClientSite)
{
_hr = S_OK;
if (pClientSite != NULL)
{
// Obtain URL from container moniker.
IMoniker* pmk = NULL;
if (SUCCEEDED(_hr = pClientSite->GetMoniker(
OLEGETMONIKER_TEMPFORUSER,
OLEWHICHMK_CONTAINER,
&pmk)))
{
LPOLESTR pwzDisplayName = NULL;
if (SUCCEEDED(_hr = pmk->GetDisplayName(NULL, NULL, &pwzDisplayName)))
{
_hr = _sURL.Assign(pwzDisplayName);
CoTaskMemFree((LPVOID)pwzDisplayName);
// _hr from _sURL.Assign() above
if (SUCCEEDED(_hr) && FAILED(StartManifestHandler(_sURL)))
MessageBox(NULL, L"Error downloading manifest or starting manifest handler. Cannot continue.", L"ClickOnce", MB_OK | MB_ICONEXCLAMATION);
}
}
SAFERELEASE(pmk);
if (FAILED(_hr))
MessageBox(NULL, L"Error accessing manifest URL.", L"ClickOnce", MB_OK | MB_ICONEXCLAMATION);
#ifdef GOBACKHACK
// ask IE to go back instead of staying in the blank page
IServiceProvider* pISP = NULL;
if (SUCCEEDED(_hr = pClientSite->QueryInterface(IID_IServiceProvider, (void **)&pISP)))
{
IWebBrowser2* pIWebBrowser2 = NULL;
if (SUCCEEDED(_hr = pISP->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void **)&pIWebBrowser2)))
{
// if (FAILED(
_hr = pIWebBrowser2->GoBack();//))
// NOTICE-2002/03/12-felixybc Go back can fail if new IE window with no viewed page, Start Run url, or Internet Shortcut
// should close IE window instead?
}
SAFERELEASE(pIWebBrowser2);
}
SAFERELEASE(pISP);
#endif
}
return S_OK;
}
HRESULT
CActiveXMimePlayer::GetClientSite(IOleClientSite **ppClientSite)
{
_hr = S_OK;
if (ppClientSite == NULL)
_hr = E_INVALIDARG;
else
*ppClientSite = NULL; // return clientsite?
return _hr;
}
HRESULT
CActiveXMimePlayer::SetHostNames(LPCOLESTR szContainerApp,
/* [in] */
LPCOLESTR szContainerObj)
/* [unique][in] */
{
// note: can check the name of container app here
return (_hr = S_OK);
}
HRESULT
CActiveXMimePlayer::Close(DWORD dwSaveOption)
/* [in] */
{
return (_hr = S_OK);
}
HRESULT
CActiveXMimePlayer::SetMoniker(DWORD dwWhichMoniker,
/* [in] */
IMoniker *pmk)
/* [unique][in] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::GetMoniker(DWORD dwAssign,
/* [in] */
DWORD dwWhichMoniker,
/* [in] */
IMoniker **ppmk)
/* [out] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::InitFromData(IDataObject *pDataObject,
/* [unique][in] */
BOOL fCreation,
/* [in] */
DWORD dwReserved)
/* [in] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::GetClipboardData(DWORD dwReserved,
/* [in] */
IDataObject **ppDataObject)
/* [out] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::DoVerb(LONG iVerb,
/* [in] */
LPMSG lpmsg,
/* [unique][in] */
IOleClientSite *pActiveSite,
/* [unique][in] */
LONG lindex,
/* [in] */
HWND hwndParent,
/* [in] */
LPCRECT lprcPosRect)
/* [unique][in] */
{
return (_hr = OLEOBJ_E_NOVERBS); //E_NOTIMPL;
}
HRESULT
CActiveXMimePlayer::EnumVerbs(IEnumOLEVERB **ppEnumOleVerb)
/* [out] */
{
return (_hr = OLEOBJ_E_NOVERBS); //E_NOTIMPL;
}
HRESULT
CActiveXMimePlayer::Update( void)
{
return (_hr = S_OK);
}
HRESULT
CActiveXMimePlayer::IsUpToDate( void)
{
return (_hr = S_OK); //OLE_E_UNAVAILABLE;
}
HRESULT
CActiveXMimePlayer::GetUserClassID(CLSID *pClsid)
{
if (pClsid != NULL)
{
*pClsid = CLSID_ActiveXMimePlayer;
_hr = S_OK;
}
else
_hr = E_INVALIDARG;
return _hr;
}
HRESULT
CActiveXMimePlayer::GetUserType(DWORD dwFormOfType,
/* [in] */
LPOLESTR *pszUserType)
/* [out] */
{
return (_hr = OLE_S_USEREG); //E_NOTIMPL;
}
HRESULT
CActiveXMimePlayer::SetExtent(DWORD dwDrawAspect,
/* [in] */
SIZEL *psizel)
/* [in] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::GetExtent(DWORD dwDrawAspect,
/* [in] */
SIZEL *psizel)
/* [out] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::Advise(IAdviseSink *pAdvSink,
/* [unique][in] */
DWORD *pdwConnection)
/* [out] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::Unadvise(DWORD dwConnection)
/* [in] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::EnumAdvise(IEnumSTATDATA **ppenumAdvise)
/* [out] */
{
return (_hr = E_NOTIMPL);
}
HRESULT
CActiveXMimePlayer::GetMiscStatus(DWORD dwAspect,
DWORD *pdwStatus)
{
_hr = S_OK;
// ignore dwAspect
if (pdwStatus == NULL)
_hr = E_INVALIDARG;
else
*pdwStatus = OLEMISC_SETCLIENTSITEFIRST | OLEMISC_NOUIACTIVATE; //OLEMISC_INVISIBLEATRUNTIME
return _hr;
}
HRESULT
CActiveXMimePlayer::SetColorScheme(LOGPALETTE *pLogpal)
{
return (_hr = E_NOTIMPL);
}
//////////////////////////////////////////////
// IOjbectSafety interface
HRESULT
CActiveXMimePlayer::GetInterfaceSafetyOptions(REFIID riid,
DWORD* pdwSupportedOptions,
DWORD* pdwEnabledOptions)
{
_hr = S_OK;
// regardless riid
if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
_hr = E_INVALIDARG;
else
{
// do _not_ support safe for scripting - INTERFACESAFE_FOR_UNTRUSTED_CALLER
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
return _hr;
}
HRESULT
CActiveXMimePlayer::SetInterfaceSafetyOptions(REFIID riid,
DWORD dwOptionSetMask,
DWORD dwEnabledOptions)
{
_hr = E_FAIL;
if (riid == IID_IDispatch)
{
// do _not_ support IDispatch interface
// The dwOptionSetMask parameter specifies an option that is not supported by the object.
_hr = E_FAIL;
}
else //if (riid == IID_IPersist) // IID_IPersist*? what about IID_IUnknown?
{
// regardless riid
// only acknowledge if only INTERFACESAFE_FOR_UNTRUSTED_DATA is passed in
if (dwOptionSetMask == INTERFACESAFE_FOR_UNTRUSTED_DATA)
_hr = S_OK; // The object is safe for loading.
else
_hr = E_FAIL;
}
return _hr;
}
// ----------------------------------------------------------------------------
#define DEFAULT_PATH_LEN MAX_PATH
#define TEMP_FILE_NAME_LEN sizeof("preuuuu.TMP") // from msdn
HRESULT
CActiveXMimePlayer::StartManifestHandler(CString& sURL)
{
HKEY hkey = NULL;
DWORD dwcbData = 0;
DWORD dwType = 0;
LONG lReturn = 0;
CString sOpenCommand;
CString sCmdLine;
LPWSTR pwzOpenCommand = NULL;
CString sTempPath;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
// check if sURL empty (including ending L'\0')
// note: could do better check here, eg. check for http://
IF_FALSE_EXIT(sURL._cc > 1, E_INVALIDARG);
// assemble temp file path
IF_FAILED_EXIT(sTempPath.ResizeBuffer(DEFAULT_PATH_LEN));
{
// ISSUE-2002/03/12-felixybc GetTempPath can overrun the buffer?
DWORD dwLen = GetTempPath(DEFAULT_PATH_LEN, sTempPath._pwz);
IF_WIN32_FALSE_EXIT(dwLen);
if (dwLen >= DEFAULT_PATH_LEN)
{
// resize, add 1 for terminating null
IF_FAILED_EXIT(sTempPath.ResizeBuffer(dwLen+1));
DWORD dwLenNew = GetTempPath(dwLen+1, sTempPath._pwz);
IF_WIN32_FALSE_EXIT(dwLenNew);
IF_FALSE_EXIT(dwLenNew < dwLen+1, E_FAIL); // why is it still not enough?
}
}
// why is the temp file created already?
ASSERT(_sTempFile._pwz == NULL);
{
DWORD dwBufLen = lstrlen(sTempPath._pwz)+1;
// note: can do a better check here
IF_FALSE_EXIT(dwBufLen > 1, E_FAIL);
// allocate buffer large enough for temp path and temp file name
DWORD dwLenNew = (dwBufLen > DEFAULT_PATH_LEN)? dwBufLen : DEFAULT_PATH_LEN;
dwLenNew += TEMP_FILE_NAME_LEN;
// check for overflow
IF_FALSE_EXIT(dwLenNew > dwBufLen, E_FAIL);
IF_FAILED_EXIT(_sTempFile.ResizeBuffer(dwLenNew));
*(_sTempFile._pwz) = L'\0';
// note: temp file to be deleted by the child handler process created below
IF_WIN32_FALSE_EXIT(GetTempFileName(sTempPath._pwz, L"FMA", 0, _sTempFile._pwz)); // fusion manifest file
}
IF_FAILED_EXIT(DownloadInternetFile(sURL, _sTempFile._pwz));
// get the execution string (esp. path) from reg key
// ISSUE-2002/03/21-adriaanc
// This code should live in regclass.cpp and CRegImport/CRegEmit should accept
// a root hive handle and fall back to HKCU if not provided.
// HKEY_CLASSES_ROOT\manifestfile\shell\Open\command
lReturn = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"manifestfile\\shell\\Open\\command", 0,
KEY_EXECUTE | KEY_QUERY_VALUE, &hkey);
IF_WIN32_FAILED_EXIT(lReturn);
lReturn = RegQueryValueEx(hkey, NULL, NULL, &dwType, NULL, &dwcbData);
IF_WIN32_FAILED_EXIT(lReturn);
IF_FALSE_EXIT(dwcbData, E_FAIL);
// validate reg value type
IF_FALSE_EXIT(dwType == REG_SZ || dwType == REG_EXPAND_SZ, E_UNEXPECTED);
{
// Allocate for call to RQEX, with one extra char in case
// returned buffer is not null terminated.
LPWSTR pwz = NULL;
DWORD dwStrLen = dwcbData / sizeof(WCHAR);
DWORD dwBufLen = dwStrLen+1;
CStringAccessor<CString> acc;
// Allocate and call RQVEX
IF_ALLOC_FAILED_EXIT(pwzOpenCommand = new WCHAR[dwBufLen]);
lReturn = RegQueryValueEx(hkey, NULL, NULL,
&dwType, (LPBYTE) pwzOpenCommand, &dwcbData);
IF_WIN32_FAILED_EXIT(lReturn);
// Null terminate returned buffer.
*(pwzOpenCommand + dwStrLen) = L'\0';
// rundll32.exe fnsshell.dll,Start "%1" --> L"rundll32.exe fnsshell.dll,Start \"%s\" \"%s\""
pwz = wcsrchr(pwzOpenCommand, L'%');
IF_NULL_EXIT(pwz, E_FAIL);
*pwz = L'\0';
// Attach accessor, set buffer, detach with corrected length.
IF_FAILED_EXIT(acc.Attach(sOpenCommand));
*(&acc) = pwzOpenCommand;
// Could avoid the strlen if we bothered to track the strlen.
IF_FAILED_EXIT(acc.Detach());
// If Detach succeeds, reset pointer so that it is freed once.
pwzOpenCommand = NULL;
}
// NTRAID#NTBUG9-574001-2002/03/12-felixybc check format of the returned string value
// assemble the command line
IF_FAILED_EXIT(sCmdLine.Assign(sOpenCommand));
IF_FAILED_EXIT(sCmdLine.Append(_sTempFile._pwz));
IF_FAILED_EXIT(sCmdLine.Append(L"\" \""));
IF_FAILED_EXIT(sCmdLine.Append(sURL));
IF_FAILED_EXIT(sCmdLine.Append(L"\""));
// start the process
// NTRAID#NTBUG9-574001-2002/03/12-felixybc string value needs proper format
// need quotes if executable path contains spaces, or instead pass lpApplicationName for better security
// rundll32.exe should be in c:\windows\system32
IF_WIN32_FALSE_EXIT(CreateProcess(NULL, sCmdLine._pwz, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi));
exit:
if(pi.hThread) CloseHandle(pi.hThread);
if(pi.hProcess) CloseHandle(pi.hProcess);
if (hkey)
RegCloseKey(hkey);
if (FAILED(_hr) && _sTempFile._pwz != NULL)
{
if (*(_sTempFile._pwz) != L'\0')
{
// ignore if error deleting the file
DeleteFile(_sTempFile._pwz);
}
_sTempFile.FreeBuffer();
}
SAFEDELETEARRAY(pwzOpenCommand);
return _hr;
}
// ----------------------------------------------------------------------------
// download file from url into path
HRESULT
CActiveXMimePlayer::DownloadInternetFile(CString& sUrl,
LPCWSTR pwzPath)
{
HINTERNET hInternet = NULL;
HINTERNET hTransfer = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD bytesRead = 0;
DWORD bytesWritten = 0;
BYTE *buffer = NULL;
const DWORD dwBufferSize = 4096;
BOOL bReadOk = FALSE;
_hr = S_OK;
// check offline mode
/* DWORD dwState = 0;
DWORD dwSize = sizeof(DWORD);
if(InternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
{
if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
// error!
}*/
// Step 1: Create the file
// overwrites the file, if exists. file not shared
hFile = CreateFile(pwzPath, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|FILE_ATTRIBUTE_TEMPORARY,
NULL);
IF_WIN32_FALSE_EXIT((hFile != INVALID_HANDLE_VALUE));
// Step 2: Copy the files over the internet
hInternet = InternetOpen(L"ManifestHandler", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
IF_WIN32_FALSE_EXIT((hInternet != NULL));
// do not keep file in wininet cache
hTransfer = InternetOpenUrl(hInternet, sUrl._pwz, NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0);
IF_WIN32_FALSE_EXIT((hTransfer != NULL));
// need to check if there's any error, eg. not found (404)...
buffer = new BYTE[dwBufferSize];
IF_ALLOC_FAILED_EXIT(buffer);
// synchronous download
while((bReadOk = InternetReadFile(hTransfer, buffer, dwBufferSize, &bytesRead)) && bytesRead != 0)
{
IF_WIN32_FALSE_EXIT(!( !WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL) ||
bytesWritten != bytesRead ));
}
IF_WIN32_FALSE_EXIT(bReadOk);
exit:
SAFEDELETEARRAY(buffer);
// ensure file/internet handles are closed
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
if (hTransfer != NULL)
InternetCloseHandle(hTransfer);
if (hInternet != NULL)
InternetCloseHandle(hInternet);
hInternet = NULL;
hTransfer = NULL;
hFile = INVALID_HANDLE_VALUE;
// note: caller's responsibility to delete the file
return _hr;
}