// // Copyright (c) 2001 Microsoft Corporation // // #include "activexmime.h" #include #define GOBACKHACK #ifdef GOBACKHACK #include // 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 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; }