#include "priv.h" #include "bindcb.h" #include "resource.h" #include #include "iface.h" #include "security.h" #include #include "iehelpid.h" #include #include "inetreg.h" #include #include "dochost.h" #include #include #include "apithk.h" #include "richedit.h" #include #define MIME #include "filetype.h" #define ALLFILE_WILDCARD TEXT("*.*") #define MAX_BYTES_STRLEN 64 #define CALC_NOW 5 // Recalcs Estimated time left every this many'th call to OnProgress // // Enable WinVerifyTrust // #define CALL_WVT #ifdef CALL_WVT #include "wvtp.h" // // Note that this is a global variable. It means we don't call LoadLibrary // everytime we download an EXE (good), but the user need to reboot if // WINTRUST.DLL is added later (bad). Since WINTRUST.DLL is part of IE 3.0, // this is sufficient at this point. // Cwvt g_wvt; HWND g_hDlgActive = NULL; // get rid of this, not needed // // A named mutex is being used to determine if a critical operation exist, such as a file download. // When we detect this we can prevent things like going offline while a download is in progress. // To start the operation Create the named mutex. When the op is complete, close the handle. // To see if any pending operations are in progress, Open the named mutex. Success/fail will indicate // if any pending operations exist. This mechanism is being used to determine if a file download is // in progress when the user attempts to go offline. If so, we prompt them to let them know that going // offline will cancel the download(s). HANDLE g_hCritOpMutex = NULL; UINT _VerifyTrust(HWND hwnd, LPCTSTR pszFileName, LPCWSTR pszStatusText); #endif // CALL_WVT // Do strong typechecking on the parameters #ifdef SAFECAST #undef SAFECAST #endif #define SAFECAST(_src, _type) (((_type)(_src)==(_src)?0:0), (_type)(_src)) extern HRESULT _GetRequestFlagFromPIB(IBinding *pib, DWORD *pdwOptions); extern HRESULT _PrepareURLForDisplayUTF8W(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcchOut, BOOL fUTF8Enabled, UINT uiCP); UINT IE_ErrorMsgBox(IShellBrowser* psb, HWND hwnd, HRESULT hrError, LPCWSTR szError, LPCTSTR szURL, UINT idResource, UINT wFlags); BOOL IsAssociatedWithIE(LPCWSTR pszFileName); extern "C" EXECUTION_STATE WINAPI pSetThreadExecutionState(EXECUTION_STATE esFlags); // Win2k+, Win98+ kernel32 API #define DM_DOWNLOAD TF_SHDPROGRESS #define DM_PROGRESS TF_SHDPROGRESS #define DM_WVT TF_SHDPROGRESS #define DWNLDMSG(psz, psz2) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %s", psz, psz2) #define DWNLDMSG2(psz, x) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %x", psz, x) #define DWNLDMSG3(psz, x, y) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %x %x", psz, x, y) #define DWNLDMSG4(psz, x, y, z) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %x %x %x", psz, x, y, z) #define SAFEMSG(psz, psz2) TraceMsg(0, "shd TR-SAFE::%s %s", psz, psz2) #define SAFEMSG2(psz, x) TraceMsg(0, "shd TR-SAFE::%s %x", psz, x) #define EXPMSG(psz, psz2) TraceMsg(0, "shd TR-EXP::%s %s", psz, psz2) #define MDLGMSG(psz, x) TraceMsg(0, "shd TR-MODELESS::%s %x", psz, x) #define MSGMSG(psz, x) TraceMsg(TF_SHDTHREAD, "ief MMSG::%s %x", psz, x) #define PARKMSG(psz, x) TraceMsg(TF_SHDTHREAD, "ief MPARK::%s %x", psz, x) // File name and 32 for the rest of the title string #define TITLE_LEN (256 + 32) #define MAX_DISPLAY_LEN 96 #define MAX_SCHEME_STRING 16 class CDownload : public IBindStatusCallback , public IAuthenticate , public IServiceProvider , public IHttpNegotiate , public IWindowForBindingUI { public: // *** IUnknown methods *** STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj); STDMETHODIMP_(ULONG) AddRef(void) ; STDMETHODIMP_(ULONG) Release(void); // *** IAuthenticate *** STDMETHODIMP Authenticate( HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword); // *** IServiceProvider *** STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObj); // *** IBindStatusCallback *** STDMETHODIMP OnStartBinding( /* [in] */ DWORD grfBSCOption, /* [in] */ IBinding *pib); STDMETHODIMP GetPriority( /* [out] */ LONG *pnPriority); STDMETHODIMP OnLowResource( /* [in] */ DWORD reserved); STDMETHODIMP OnProgress( /* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR szStatusText); STDMETHODIMP OnStopBinding( /* [in] */ HRESULT hresult, /* [in] */ LPCWSTR szError); STDMETHODIMP GetBindInfo( /* [out] */ DWORD *grfBINDINFOF, /* [unique][out][in] */ BINDINFO *pbindinfo); STDMETHODIMP OnDataAvailable( /* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC *pformatetc, /* [in] */ STGMEDIUM *pstgmed); STDMETHODIMP OnObjectAvailable( /* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown *punk); /* *** IHttpNegotiate *** */ STDMETHODIMP BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders); STDMETHODIMP OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders); STDMETHODIMP GetWindow(REFGUID RefGUI, HWND* phWnd); protected: LONG _cRef; LONG _cRefDLD; IBinding* _pib; IBindCtx* _pbc; CDocObjectHost *_pdoh; HWND _hDlg; HWND _hwndToolTips; BOOL _fSaveAs : 1; BOOL _fGotFile : 1; BOOL _fFirstTickValid : 1; BOOL _fEndDialogCalled : 1; BOOL _fDontPostQuitMsg : 1; // Posts WM_QUIT message in destructor BOOL _fCallVerifyTrust : 1; BOOL _fStrsLoaded : 1; BOOL _fSafe : 1; // no need to call IsSafe dialog BOOL _fDownloadStarted : 1; // Have we started receiving data BOOL _fDownloadCompleted : 1; // We have received BSCF_LASTDATANOTIFICATION BOOL _fDeleteFromCache : 1; // Delete the file from cache when done BOOL _fWriteHistory : 1; // Should it be written to history? (SECURITY) BOOL _fDismissDialog : 1; BOOL _fUTF8Enabled : 1; DWORD _dwFirstTick; DWORD _dwFirstSize; DWORD _dwTotalSize; // Size of file downloaded so far DWORD _dwFileSize; // Size of file to download HICON _hicon; TCHAR _szPath[MAX_PATH]; // ok with MAX_PATH TCHAR _szSaveToFile[MAX_PATH]; // File to Save to TCHAR _szEstimateTime[MAX_PATH]; // ok with MAX_PATH TCHAR _szBytesCopied[MAX_PATH]; // ok with MAX_PATH TCHAR _szTitlePercent[TITLE_LEN]; TCHAR _szTitleBytes[TITLE_LEN]; TCHAR _szTransferRate[TITLE_LEN]; TCHAR _szURL[MAX_URL_STRING]; TCHAR _szDisplay[MAX_DISPLAY_LEN]; // URL to be displayed TCHAR _szDefDlgTitle[256]; TCHAR _szExt[10]; DWORD _grfBINDF; BINDINFO* _pbinfo; LPWSTR _pwzHeaders; IMoniker* _pmk; // WARNING: No ref-count (only for modal) LPWSTR _pwszDisplayName; DWORD _dwVerb; UINT _uiCP; // Code page DWORD _dwOldEst; ULONG _ulOldProgress; DWORD _dwOldRate; DWORD _dwOldPcent; DWORD _dwOldCur; BOOL _fConfirmed; void SetMoniker(IMoniker* pmk) { _pmk=pmk; } BOOL _IsModal(void) { return (bool)_pmk; } virtual ~CDownload(); friend INT_PTR CALLBACK DownloadDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); friend INT_PTR CALLBACK SafeOpenDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); UINT _MayAskUserIsFileSafeToOpen(LPCTSTR pszMime); BOOL _GetSaveLocation(void); BOOL _SaveFile(void); void _DeleteFromCache(void); ULONG AddRefDLD(void); ULONG ReleaseDLD(void); HRESULT PerformVirusScan(LPCTSTR szFileName); public: CDownload(BOOL fSaveAs = FALSE, LPWSTR pwzHeaders = NULL, DWORD grfBINDF = BINDF_ASYNCHRONOUS, BINDINFO* pbinfo = NULL, BOOL fSafe = FALSE, DWORD dwVerb = BINDVERB_GET, LPCTSTR pszRedir=NULL, UINT uiCP=CP_ACP, BOOL fConfirmed = FALSE); static void OpenUI(IMoniker* pmk, IBindCtx *pbc, BOOL fSaveAs = FALSE, BOOL fSafe = FALSE, LPWSTR pwzHeaders = NULL, DWORD dwVerb = BINDVERB_GET, DWORD grfBINDF = 0, BINDINFO* pbinfo = NULL, LPCTSTR pszRedir=NULL, UINT uiCP=CP_ACP, BOOL fConfirmed = FALSE); HRESULT StartBinding(IMoniker* pmk, IBindCtx *pbc = NULL); void EndDialogDLD(UINT id); void ShowStats(void); BOOL SetDismissDialogFlag(BOOL fDismiss) { return(_fDismissDialog = fDismiss); } BOOL GetDismissDialogFlag(void) { return(_fDismissDialog); } #ifdef USE_LOCKREQUEST HRESULT LockRequestHandle(void); #endif }; CDownload::CDownload(BOOL fSaveAs, LPWSTR pwzHeaders, DWORD grfBINDF, BINDINFO* pbinfo, BOOL fSafe, DWORD dwVerb, LPCTSTR pszRedir, UINT uiCP, BOOL fConfirmed) : _cRef(1), _fSaveAs(fSaveAs), _fWriteHistory(1), _grfBINDF(grfBINDF), _pbinfo(pbinfo), _fSafe(fSafe), _pwzHeaders(pwzHeaders), _dwVerb(dwVerb), _uiCP(uiCP), _fConfirmed(fConfirmed) { ASSERT(_fStrsLoaded == FALSE); ASSERT(_fDownloadStarted == FALSE); ASSERT(_fDownloadCompleted == FALSE); ASSERT(_fGotFile == FALSE); ASSERT(_fUTF8Enabled == FALSE); ASSERT(_hDlg == NULL); ASSERT(_pwszDisplayName == NULL); ASSERT(_dwTotalSize == 0); ASSERT(_dwFileSize == 0); ASSERT(_dwFirstTick == 0); ASSERT(_ulOldProgress == 0); ASSERT(_dwOldRate == 0); ASSERT(_dwOldPcent == 0); ASSERT(_dwOldCur == 0); _dwOldEst = 0xffffffff; if (pszRedir && lstrlen(pszRedir)) StrCpyN(_szURL, pszRedir, ARRAYSIZE(_szURL) - 1); // -1 ??? TraceMsg(TF_SHDLIFE, "CDownload::CDownload being constructed"); } void ProcessStartbindingError(HWND hWnd, LPTSTR pszTitle, LPTSTR pszText, UINT uiFlag, HRESULT hres) { if (E_ACCESSDENIED == hres) { pszText = MAKEINTRESOURCE(IDS_DOWNLOADDISALLOWED); pszTitle = MAKEINTRESOURCE(IDS_SECURITYALERT); uiFlag = MB_ICONWARNING; } MLShellMessageBox(hWnd, pszText, pszTitle, MB_OK | MB_SETFOREGROUND | uiFlag ); if (IsValidHWND(hWnd)) { FORWARD_WM_COMMAND(hWnd, IDCANCEL, NULL, 0, PostMessage); } } HRESULT SelectPidlInSFV(IShellFolderViewDual *psfv, LPCITEMIDLIST pidl, DWORD dwOpts) { VARIANT var; HRESULT hr = InitVariantFromIDList(&var, pidl); if (SUCCEEDED(hr)) { hr = psfv->SelectItem(&var, dwOpts); VariantClear(&var); } return hr; } void OpenFolderPidl(LPCITEMIDLIST pidl) { SHELLEXECUTEINFO shei = { 0 }; shei.cbSize = sizeof(shei); shei.fMask = SEE_MASK_INVOKEIDLIST; shei.nShow = SW_SHOWNORMAL; shei.lpIDList = (LPITEMIDLIST)pidl; ShellExecuteEx(&shei); } STDAPI OpenContainingFolderAndGetShellFolderView(HWND hwnd, LPCITEMIDLIST pidlFolder, IShellFolderViewDual **ppsfv) { *ppsfv = NULL; IWebBrowserApp *pauto; HRESULT hr = SHGetIDispatchForFolder(pidlFolder, &pauto); if (SUCCEEDED(hr)) { // We have IDispatch for window, now try to get one for // the folder object... HWND hwnd; if (SUCCEEDED(pauto->get_HWND((LONG_PTR *)&hwnd))) { // Make sure we make this the active window SetForegroundWindow(hwnd); ShowWindow(hwnd, SW_SHOWNORMAL); } IDispatch * pautoDoc; hr = pauto->get_Document(&pautoDoc); if (SUCCEEDED(hr)) { hr = pautoDoc->QueryInterface(IID_PPV_ARG(IShellFolderViewDual, ppsfv)); pautoDoc->Release(); } pauto->Release(); } return hr; } // // Stolen (and modified) from shell\ext\mydocs2\prop.cpp which was from link.c in shell32.dll // void FindTarget(HWND hDlg, LPTSTR pPath) { USHORT uSave; LPITEMIDLIST pidl = ILCreateFromPath( pPath ); if (!pidl) return; LPITEMIDLIST pidlLast = ILFindLastID(pidl); // get the folder, special case for root objects (My Computer, Network) // hack off the end if it is not the root item if (pidl != pidlLast) { uSave = pidlLast->mkid.cb; pidlLast->mkid.cb = 0; } else uSave = 0; LPITEMIDLIST pidlDesk; if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidlDesk))) { BOOL fIsDesktopDir = pidlDesk && ILIsEqual(pidl, pidlDesk); if (fIsDesktopDir || !uSave) // if it's in the desktop dir or pidl == pidlLast (uSave == 0 from above) { // // It's on the desktop... // MLShellMessageBox(hDlg, (LPTSTR)IDS_ON_DESKTOP, (LPTSTR)IDS_FIND_TITLE, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL | MB_TOPMOST); } else { if (WhichPlatform() == PLATFORM_BROWSERONLY) { OpenFolderPidl(pidl); } else { IShellFolderViewDual *psfv; if (SUCCEEDED(OpenContainingFolderAndGetShellFolderView(hDlg, uSave ? pidl : pidlDesk, &psfv))) { if (uSave) pidlLast->mkid.cb = uSave; SelectPidlInSFV(psfv, pidlLast, SVSI_SELECT | SVSI_FOCUSED | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE); psfv->Release(); } } } ILFree(pidlDesk); } ILFree(pidl); } BOOL SetExemptDelta(LPCTSTR pszURL, DWORD dwExemptDelta) { BOOL fRC; INTERNET_CACHE_ENTRY_INFO icei; icei.dwStructSize = sizeof(icei); icei.dwExemptDelta = dwExemptDelta; // Number of seconds from last access time to keep entry // Retry setting the exempt delta if it fails since wininet may have either not have created the // entry yet or might have it locked. for (int i = 0; i < 5; i++) { if (fRC = SetUrlCacheEntryInfo(pszURL, &icei, CACHE_ENTRY_EXEMPT_DELTA_FC)) break; Sleep(1000); } return fRC; } INT_PTR CALLBACK DownloadDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static fInBrowseDir = FALSE; CDownload* pdld = (CDownload*) GetWindowLongPtr(hDlg, DWLP_USER); DWORD dwExStyle = 0; TCHAR szURL[MAX_URL_STRING]; // make copies since EndDialog will delete CDownload obj BOOL fDownloadAborted; DWNLDMSG4("DownloadDlgProc ", uMsg, wParam, lParam); if ((pdld == NULL) && (uMsg != WM_INITDIALOG)) { RIPMSG(TRUE, "CDownload freed (pdld == NULL) && (uMsg != WM_INITDIALOG)"); return FALSE; } switch (uMsg) { case WM_INITDIALOG: { TCHAR szYesNo[20]; DWORD dwType = REG_SZ; DWORD dwSize = ARRAYSIZE(szYesNo); if (lParam == NULL) return FALSE; SetWindowLongPtr(hDlg, DWLP_USER, lParam); pdld = (CDownload*)lParam; pdld->_hDlg = hDlg; EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_SIZE, MF_BYCOMMAND | MF_GRAYED); EnableWindow(GetDlgItem(hDlg, IDD_OPENFILE), FALSE); EnableWindow(GetDlgItem(hDlg, IDD_BROWSEDIR), FALSE); // On BiDi Loc Win98 & NT5 mirroring will take care of that // Need to fix only on BiBi Win95 Loc if (g_bBiDiW95Loc) { SetWindowBits(GetDlgItem(hDlg, IDD_DIR), GWL_EXSTYLE, WS_EX_RTLREADING, WS_EX_RTLREADING); } MLLoadString(IDS_DEFDLGTITLE, pdld->_szDefDlgTitle, ARRAYSIZE(pdld->_szDefDlgTitle)); if (pdld->_hwndToolTips = CreateWindowEx(dwExStyle, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hDlg, NULL, HINST_THISDLL, NULL)) { TOOLINFO ti; ti.cbSize = sizeof(ti); ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; ti.hwnd = hDlg; ti.uId = (UINT_PTR) GetDlgItem(hDlg, IDD_NAME); ti.lpszText = LPSTR_TEXTCALLBACK; ti.hinst = HINST_THISDLL; GetWindowRect((HWND)ti.uId, &ti.rect); SendMessage(pdld->_hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti); } // make sure we support cross-lang platform SHSetDefaultDialogFont(hDlg, IDD_NAME); pdld->SetDismissDialogFlag(FALSE); if ( SHRegGetUSValue( TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("NotifyDownloadComplete"), &dwType, (void *)szYesNo, &dwSize, FALSE, NULL, 0 ) == ERROR_SUCCESS ) { pdld->SetDismissDialogFlag(!StrCmpI(szYesNo, TEXT("No"))); } CheckDlgButton(hDlg, IDD_DISMISS, pdld->GetDismissDialogFlag()); DWNLDMSG("DownloadDlgProc", "Got WM_INITDIALOG"); Animate_OpenEx(GetDlgItem(hDlg, IDD_ANIMATE), HINST_THISDLL, MAKEINTRESOURCE(IDA_DOWNLOAD)); ShowWindow(GetDlgItem(hDlg, IDD_DOWNLOADICON), SW_HIDE); g_hCritOpMutex = CreateMutexA(NULL, TRUE, "CritOpMutex"); // Automatically start binding if we are posting synchronously. if (pdld->_IsModal()) { HRESULT hres = pdld->StartBinding(pdld->_pmk); ASSERT(pdld->_pmk); if (FAILED(hres)) { ProcessStartbindingError(hDlg, MAKEINTRESOURCE(IDS_DOWNLOADFAILED), pdld->_szDisplay, MB_ICONWARNING, hres); } } return TRUE; } case WM_SIZE: if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) SetWindowText(hDlg, pdld->_szDefDlgTitle); break; case WM_NOTIFY: { LPTOOLTIPTEXT lpTT = (LPTOOLTIPTEXT) lParam; if (lpTT->hdr.code == TTN_NEEDTEXT) { lpTT->lpszText = pdld->_szURL; lpTT->hinst = NULL; } } break; case WM_COMMAND: DWNLDMSG2("DownloadDlgProc WM_COMMAND id =", GET_WM_COMMAND_ID(wParam, lParam)); switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDD_SAVEAS: if (pdld) { pdld->AddRefDLD(); BOOL fSuccess = FALSE; // Prevent someone from canceling dialog while the shell copy etc. is going on EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); // If zone check fails or if we found virus, bail out and remove file from cache. if (pdld->PerformVirusScan(pdld->_szPath) != S_OK) { pdld->_fDeleteFromCache = TRUE; pdld->EndDialogDLD(IDCANCEL); break; } fSuccess = pdld->_SaveFile(); AddUrlToUrlHistoryStg(pdld->_pwszDisplayName, NULL, NULL, pdld->_fWriteHistory, NULL, NULL, NULL); // -- BharatS --- Only add to history if Visible ? IEPlaySound(TEXT("SystemAsterisk"), TRUE); if (fSuccess) { if (pdld->SetDismissDialogFlag(IsDlgButtonChecked(hDlg, IDD_DISMISS) == BST_CHECKED)) { StrCpyN(szURL, pdld->_szURL, ARRAYSIZE(szURL)); pdld->EndDialogDLD(IDCANCEL); SetExemptDelta(szURL, 0); } else { TCHAR szStr[MAX_PATH]; if (MLLoadString(IDS_CLOSE, szStr, ARRAYSIZE(szStr))) { SetWindowText(GetDlgItem(hDlg, IDCANCEL), szStr); } ShowWindow(GetDlgItem(hDlg, IDD_ANIMATE), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDD_DNLDESTTIME), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDD_DNLDCOMPLETEICON), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDD_DNLDCOMPLETETEXT), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDD_DNLDTIME), SW_SHOW); MLLoadString(IDS_SAVED, szStr, ARRAYSIZE(szStr)); SetDlgItemText(hDlg, IDD_OPENIT, szStr); MLLoadString(IDS_DOWNLOADCOMPLETE, szStr, ARRAYSIZE(szStr)); SetWindowText(hDlg, szStr); EnableWindow(GetDlgItem(hDlg, IDD_OPENFILE), TRUE); EnableWindow(GetDlgItem(hDlg, IDD_BROWSEDIR), TRUE); pdld->ShowStats(); pdld->ReleaseDLD(); } } else { pdld->ReleaseDLD(); } EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); } break; case IDCANCEL: // Cancel on abort, Close on dismiss if (pdld && IsWindowEnabled(GetDlgItem(hDlg, IDCANCEL))) { pdld->AddRefDLD(); fDownloadAborted = pdld->_fDownloadStarted && !pdld->_fDownloadCompleted; StrCpyN(szURL, pdld->_szURL, ARRAYSIZE(szURL)); if (pdld->_pib) { HRESULT hresT; hresT = pdld->_pib->Abort(); TraceMsg(DM_DOWNLOAD, "DownloadDlgProc::IDCANCEL: called _pib->Abort() hres=%x", pdld->_pib, hresT); } pdld->EndDialogDLD(IDCANCEL); // Download was canceled. Increase exempt time to keep downloaded a bit in case download is resumed SetExemptDelta(szURL, fDownloadAborted ?60*60*24 :0); } break; case IDD_BROWSEDIR: if (!fInBrowseDir) { pdld->AddRefDLD(); fInBrowseDir = TRUE; FindTarget(hDlg, pdld->_szSaveToFile); // Since EndDialogDLD will probably release our structure... HWND hwndToolTips = pdld->_hwndToolTips; pdld->_hwndToolTips = NULL; pdld->EndDialogDLD(IDOK); if (IsWindow(hwndToolTips)) DestroyWindow(hwndToolTips); fInBrowseDir = FALSE; } #if DEBUG else { TraceMsg(DM_DOWNLOAD, "DownloadDlgProc rcvd IDD_BROWSEDIR msg while already processing IDD_BROWSEDIR"); } #endif break; case IDD_OPENFILE: StrCpyN(pdld->_szPath, pdld->_szSaveToFile, ARRAYSIZE(pdld->_szPath)); case IDOK: ShowWindow(GetDlgItem(hDlg, IDD_DISMISS), SW_HIDE); if (pdld) { pdld->AddRefDLD(); if (pdld->_fGotFile) { // If zone check fails or if we found virus, bail out and remove file from cache. if ( pdld->PerformVirusScan(pdld->_szPath) != S_OK ) { pdld->_fDeleteFromCache = TRUE; } else { TCHAR szQuotedPath[MAX_PATH]; StrCpyN(szQuotedPath, pdld->_szPath, MAX_PATH); if (PLATFORM_INTEGRATED == WhichPlatform()) { PathQuoteSpaces(szQuotedPath); } SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO), SEE_MASK_NOZONECHECKS, hDlg, NULL, szQuotedPath, NULL, NULL, SW_SHOWNORMAL, NULL}; if (!ShellExecuteEx(&sei)) { DWNLDMSG2("ShellExecute failed", GetLastError()); } } } if (!pdld->_fDeleteFromCache) AddUrlToUrlHistoryStg(pdld->_pwszDisplayName, NULL, NULL, pdld->_fWriteHistory, NULL, NULL, NULL); // Since EndDialogDLD will probably release our structure... HWND hwndToolTips = pdld->_hwndToolTips; pdld->_hwndToolTips = NULL; StrCpyN(szURL, pdld->_szURL, ARRAYSIZE(szURL)); pdld->EndDialogDLD(!pdld->_fDeleteFromCache ?IDOK :IDCANCEL); if (IsWindow(hwndToolTips)) DestroyWindow(hwndToolTips); SetExemptDelta(szURL, 0); } break; } break; case WM_ACTIVATE: if (pdld && pdld->_IsModal()) return FALSE; else { // There can be race conditions here. If the WA_ACTIVATE messages came in reverse // order, we might end up setting up the wrong hDlg as the active window. As of right now, // the only thing g_hDlgActive is being used for is for the IsDialogMessage in // CDownload_MayProcessMessage. And since there is only one tab-able control in this // dialog, a wrong hDlg in the g_hDlgActive should not hurt. ENTERCRITICAL; if (LOWORD(wParam) == WA_INACTIVE) { if (g_hDlgActive == hDlg) { MDLGMSG(TEXT("being inactivated"), hDlg); g_hDlgActive = NULL; } } else { MDLGMSG(TEXT("being activated"), hDlg); g_hDlgActive = hDlg; } LEAVECRITICAL; } break; case WM_NCDESTROY: MDLGMSG(TEXT("being destroyed"), hDlg); ASSERT((pdld && pdld->_IsModal()) || (g_hDlgActive != hDlg)); SetWindowLongPtr(hDlg, DWLP_USER, NULL); return FALSE; case WM_DESTROY: SHRemoveDefaultDialogFont(hDlg); return FALSE; default: return FALSE; } return TRUE; } void CDownload::ShowStats(void) { TCHAR szStr[MAX_PATH]; TCHAR szBytes[MAX_BYTES_STRLEN]; TCHAR szTime[MAX_BYTES_STRLEN]; TCHAR *pszTime = szTime; DWORD dwSpent = (GetTickCount() - _dwFirstTick); SetDlgItemText(_hDlg, IDD_NAME, _szDisplay); MLLoadString(IDS_BYTESTIME, _szBytesCopied, ARRAYSIZE(_szBytesCopied)); StrFromTimeInterval(szTime, ARRAYSIZE(szTime), (dwSpent < 1000) ?1000 :dwSpent, 3); while(pszTime && *pszTime && *pszTime == TEXT(' ')) pszTime++; _FormatMessage(_szBytesCopied, szStr, ARRAYSIZE(szStr), StrFormatByteSize(_dwTotalSize, szBytes, MAX_BYTES_STRLEN), pszTime); SetDlgItemText(_hDlg, IDD_TIMEEST, szStr); // division below requires at least 1/2 second to have elapsed. if (dwSpent < 500) dwSpent = 500; _FormatMessage(_szTransferRate, szStr, ARRAYSIZE(szStr), StrFormatByteSize(_dwTotalSize / ((dwSpent+500)/1000), szBytes, MAX_BYTES_STRLEN)); SetDlgItemText(_hDlg, IDD_TRANSFERRATE, szStr); SetForegroundWindow(_hDlg); } void CDownload::EndDialogDLD(UINT id) { if (ReleaseDLD() != 0) return; ASSERT(!_fEndDialogCalled); _fEndDialogCalled = TRUE; DWNLDMSG2("EndDialogDLD cRef ==", _cRef); TraceMsg(TF_SHDREF, "CDownload::EndDialogDLD called when _cRef=%d", _cRef); _fDismissDialog = (IsDlgButtonChecked(_hDlg, IDD_DISMISS) == BST_CHECKED); if (SHRegSetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("NotifyDownloadComplete"), REG_SZ, _fDismissDialog ?TEXT("no") :TEXT("yes"), _fDismissDialog ?sizeof(TEXT("no")-sizeof(TCHAR)) :sizeof(TEXT("yes")-sizeof(TCHAR)), SHREGSET_FORCE_HKCU) != ERROR_SUCCESS) { DWNLDMSG2("SHRegSetUSValue NotifyDownloadComplete failed", GetLastError()); } // HACK: USER does not send us WM_ACTIVATE when this dialog is // being destroyed when it was activated. We need to work around // this bug(?) by cleaning up g_hDlgActive. if (g_hDlgActive == _hDlg) { MDLGMSG(TEXT("EndDialogDLD putting NULL in g_hDlgActive"), _hDlg); g_hDlgActive = NULL; } DestroyWindow(_hDlg); Release(); } #define SZEXPLORERKEY TEXT("Software\\Microsoft\\Internet Explorer") #define SZDOWNLOADDIRVAL TEXT("Download Directory") // _GetSaveLocation // - Tries to get the current download directory from the registry // default is the Desktop // - Shows the FileSave Dialog // - If the user changed the download location, save that off into // the registry for future downloads // - _szSaveToFile is updated (this will be used by _SaveFile() // // Returns TRUE, if successfully done. // BOOL _GetSaveLocation(HWND hDlg, LPTSTR pszPath, LPTSTR pszExt, LPTSTR pszSaveToFile, UINT cchSaveToFile, BOOL fUTF8Enabled, UINT uiCP) { BOOL fRet = FALSE; TCHAR * pszSaveTo = NULL; HKEY hKey; BOOL fRegFileType = FALSE; TCHAR szDownloadDir[MAX_PATH]; TCHAR szBuffer[MAX_PATH]; TCHAR szTemp[40]; LPTSTR pszWalk = szBuffer; int cchWalk = ARRAYSIZE(szBuffer); int cch; szDownloadDir[0] = 0; // If we don't have a download directory in the registry, download to the desktop if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZEXPLORERKEY, 0, KEY_READ, &hKey)) { DWORD dwType, cbData = sizeof(szDownloadDir); RegQueryValueEx(hKey, SZDOWNLOADDIRVAL, NULL, &dwType, (LPBYTE)szDownloadDir, &cbData); RegCloseKey(hKey); } if (szDownloadDir[0] == 0) SHGetSpecialFolderPath(NULL, szDownloadDir, CSIDL_DESKTOPDIRECTORY, FALSE); // Get the file name. If there is no filename. create one called using the string resource in IDS_DOCUMENT pszSaveTo = PathFindFileName(pszPath); if (pszSaveTo) { DWORD cchData = cchSaveToFile; // Unescape the filename suggested by wininet. if (_PrepareURLForDisplayUTF8W(pszSaveTo, pszSaveToFile, &cchData, fUTF8Enabled, uiCP) != S_OK) StrCpyN(pszSaveToFile, pszSaveTo, cchSaveToFile); // Strip out any path that may have been encoded TCHAR * pszSaveToDst = pszSaveToFile; pszSaveTo = PathFindFileName(pszSaveToFile); if (pszSaveTo != pszSaveToFile) { while(*pszSaveTo) *pszSaveToDst++ = *pszSaveTo++; *pszSaveToDst = *pszSaveTo; } // Strip out the the cache's typical decoration of "(nn)" PathUndecorate (pszSaveToFile); } else MLLoadString(IDS_DOCUMENT, pszSaveToFile, cchSaveToFile); if (!g_fRunningOnNT) // Win9x isn't able to deal with DBCS chars in edit controls when UI lang is non-native OS lang { CHAR szBufA[MAX_PATH*2]; int iRC = WideCharToMultiByte(CP_ACP, 0, pszSaveToFile, -1, szBufA, ARRAYSIZE(szBufA), NULL, NULL); if (iRC == 0) // If we are unable to convert using system code page *pszSaveToFile = TEXT('\0'); // make suggested file name blank } OPENFILENAME OFN = {0}; OFN.lStructSize = sizeof(OFN); OFN.hwndOwner = hDlg; OFN.nMaxFile = cchSaveToFile; OFN.lpstrInitialDir = szDownloadDir; OFN.lpstrFile = pszSaveToFile; OFN.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; if (!pszExt || !*pszExt) pszExt = PathFindExtension(pszPath); if (pszExt && *pszExt) OFN.lpstrDefExt = pszExt; // Try to get the file type name from the registry. To add to the filter pair strings if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey)) { DWORD dwType, cbData = sizeof(szBuffer); fRegFileType = (ERROR_SUCCESS == RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)szBuffer, &cbData)); RegCloseKey(hKey); } if (fRegFileType) { fRegFileType = FALSE; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ, &hKey)) { DWORD dwType, cbData = sizeof(szBuffer); szBuffer[0] = 0; fRegFileType = ERROR_SUCCESS == RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)szBuffer, &cbData); if (fRegFileType) { // Now tack on the second part of the filter pair int cchBuffer = lstrlen(szBuffer) + 1; pszWalk = szBuffer + cchBuffer; cchWalk = ARRAYSIZE(szBuffer) - cchBuffer; StrCpyN(pszWalk, TEXT("*"), cchWalk); StrCatBuff(pszWalk, pszExt, --cchWalk); // sub 1 for * above } RegCloseKey(hKey); } cch = lstrlen(pszWalk); } // There was no registry entry for the file type or the entry did not have a default value // So create the file name type - " DOCUMENT" if (!fRegFileType || !(*szBuffer)) { szBuffer[0] = 0; pszWalk = szBuffer; cchWalk = ARRAYSIZE(szBuffer); MLLoadString(IDS_EXTDOCUMENT, szTemp, ARRAYSIZE(szTemp)); cch = wnsprintf(pszWalk, cchWalk, szTemp, pszExt, TEXT('\0'), pszExt); } // Add in the pair for "*.* All files" pszWalk += (cch + 1); cchWalk -= (cch + 1); MLLoadString(IDS_ALLFILES, szTemp, ARRAYSIZE(szTemp)); StrCpyN(pszWalk, szTemp, cchWalk); cch = lstrlen(pszWalk) + 1; pszWalk += cch; cchWalk -= cch; StrCpyN(pszWalk, ALLFILE_WILDCARD, cchWalk); cch = (lstrlen( ALLFILE_WILDCARD )+1); //Add the second NULL to the end of the string pszWalk += cch; cchWalk -= cch; if (cchWalk > 0) *pszWalk = 0; //because we had some garbage put after memset. OFN.lpstrFilter = szBuffer; if ((fRet = (!SHIsRestricted2W(hDlg, REST_NoSelectDownloadDir, NULL, 0))) && (fRet = GetSaveFileName(&OFN))) { // If the download location was changed, save that off to the registry if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZEXPLORERKEY, 0, KEY_WRITE, &hKey)) { StrCpyN(szBuffer, pszSaveToFile, ARRAYSIZE(szBuffer)); PathRemoveFileSpec(szBuffer); if (szBuffer[0]) RegSetValueEx(hKey, SZDOWNLOADDIRVAL, 0, REG_SZ, (LPBYTE)szBuffer, CbFromCch(lstrlen(szBuffer) + 1)); RegCloseKey(hKey); } } return fRet; } BOOL CDownload::_GetSaveLocation() { return ::_GetSaveLocation(_hDlg, _szPath, _szExt, _szSaveToFile, ARRAYSIZE(_szSaveToFile), _fUTF8Enabled, _uiCP); } BOOL CDownload::_SaveFile() { SHFILEOPSTRUCT fo = { _hDlg, FO_COPY, _szPath, _szSaveToFile, FOF_NOCONFIRMATION | FOF_NOCOPYSECURITYATTRIBS}; // Be sure the strings are double terminated DWORD dwLen = (DWORD)min(ARRAYSIZE(_szPath), lstrlen(_szPath) + 1); if (dwLen == 0) // Not likely, but better to fail than trash someone else's data return FALSE; _szPath[dwLen] = TEXT('\0'); _szPath[dwLen-1] = TEXT('\0'); dwLen = (DWORD)min(ARRAYSIZE(_szSaveToFile), lstrlen(_szSaveToFile) + 1); if (dwLen == 0) return FALSE; _szSaveToFile[dwLen] = TEXT('\0'); _szSaveToFile[dwLen-1] = TEXT('\0'); // If the file is in the cache, we probably want to delete it from the // cache to free up some disk space rather than wait for it to be scavenged. // This is best done after _pib->Release called from ~CDownload. _fDeleteFromCache = TRUE; // Copy the file (which is locked, so can't move it) to its target destination. return !SHFileOperation(&fo); } void CDownload::_DeleteFromCache() { INTERNET_CACHE_CONFIG_INFO CCInfo; DWORD dwCCIBufSize = sizeof(CCInfo); // Obtain the cache directory path. if (!GetUrlCacheConfigInfo (&CCInfo, &dwCCIBufSize, CACHE_CONFIG_CONTENT_PATHS_FC)) { ASSERT(FALSE); } else if (0 == StrCmpNI (_szPath, CCInfo.CachePaths[0].CachePath, lstrlen(CCInfo.CachePaths[0].CachePath))) { // Attempt to delete the file from the cache only if resides under // the cache directory, otherwise we could in theory nuke a preinstalled // or edited cache entry. Here a prefix match is also a string prefix // match since .CachePath will have a trailing slash ('/') DeleteUrlCacheEntry(_szURL); } } void CDownload::OpenUI(IMoniker* pmk, IBindCtx *pbc, BOOL fSaveAs, BOOL fSafe, LPWSTR pwzHeaders, DWORD dwVerb, DWORD grfBINDF, BINDINFO* pbinfo, LPCTSTR pszRedir, UINT uiCP, BOOL fConfirmed) { TraceMsg(DM_DOWNLOAD, "CDownLoad::OpenUI called with fSaveAs=%d, verb=%d", fSaveAs, dwVerb); // CDownload will take ownership pbinfo. CDownload* pdld = new CDownload(fSaveAs, pwzHeaders, grfBINDF, pbinfo, fSafe, dwVerb, pszRedir, uiCP, fConfirmed); if (pdld) { HWND hwnd = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(DLG_DOWNLOADPROGRESS), NULL, DownloadDlgProc, (LPARAM)pdld); pwzHeaders = NULL; // Owner is now CDownload DWNLDMSG2("CDownLoad_OpenUI dialog created", hwnd); if (hwnd) { HRESULT hres = pdld->StartBinding(pmk, pbc); if (FAILED(hres)) { TraceMsg(DM_DOWNLOAD, "CDownLoad::OpenUI() - StartBinding() Failed with hres=0x%x!", hres ); ProcessStartbindingError(hwnd, MAKEINTRESOURCE(IDS_DOWNLOADFAILED), pdld->_szDisplay, MB_ICONWARNING, hres); } else { ShowWindow(hwnd, SW_SHOWNORMAL); } } else { delete pdld; pdld = NULL; } } if (pwzHeaders) { CoTaskMemFree(pwzHeaders); pwzHeaders = NULL; } } BOOL CDownload_MayProcessMessage(MSG* pmsg) { if (g_hDlgActive) return IsDialogMessage(g_hDlgActive, pmsg); return FALSE; // not processed } class CDownloadThreadParam { #ifdef DEBUG const DWORD* _pdwSigniture; static const DWORD s_dummy; #endif public: DWORD _dwVerb; DWORD _grfBINDF; BINDINFO *_pbinfo; LPWSTR _pszDisplayName; LPWSTR _pwzHeaders; BOOL _fSaveAs; BOOL _fSafe; BOOL _fConfirmed; IStream *_pStream; TCHAR _szRedirURL[MAX_URL_STRING]; UINT _uiCP; ~CDownloadThreadParam() { OleFree(_pszDisplayName); if (_pwzHeaders) CoTaskMemFree(_pwzHeaders); if (_pStream) _pStream->Release(); // CDownload releases our _pbinfo. } CDownloadThreadParam(LPWSTR pszDisplayName, LPWSTR pwzHeaders, BOOL fSaveAs, BOOL fSafe=FALSE, DWORD dwVerb=BINDVERB_GET, DWORD grfBINDF = 0, BINDINFO* pbinfo = NULL, LPCTSTR pszRedir=NULL, UINT uiCP=CP_ACP, BOOL fConfirmed=FALSE ) : _pszDisplayName(pszDisplayName), _fSaveAs(fSaveAs), _fSafe(fSafe), _pwzHeaders(pwzHeaders), _pStream(NULL), _dwVerb(dwVerb), _grfBINDF(grfBINDF), _pbinfo(pbinfo), _uiCP(uiCP), _fConfirmed(fConfirmed) { #ifdef DEBUG _pdwSigniture = &s_dummy; #endif if (pszRedir && lstrlen(pszRedir)) StrCpyN(_szRedirURL, pszRedir, MAX_URL_STRING - 1); // CDownload releases our _pbinfo. } void SetStream(IStream *pStm) { if (_pStream) { _pStream->Release(); } _pStream = pStm; if (_pStream) { _pStream->AddRef(); } } }; DWORD CALLBACK IEDownload_ThreadProc(void *pv) { CDownloadThreadParam* pdtp = (CDownloadThreadParam*)pv; HRESULT hr; IBindCtx *pbc = NULL; if (pdtp->_pStream) { pdtp->_pStream->AddRef(); hr = pdtp->_pStream->Seek(c_li0,STREAM_SEEK_SET,0); hr = CoGetInterfaceAndReleaseStream(pdtp->_pStream, IID_PPV_ARG(IBindCtx, &pbc)); pdtp->SetStream(NULL); } if (pbc == NULL) CreateBindCtx(0, &pbc); //winse#12726:Give other thread a chance to finish its work. Sleep(100); hr = CDownLoad_OpenUIURL(pdtp->_pszDisplayName, pbc, pdtp->_pwzHeaders, TRUE, pdtp->_fSaveAs, pdtp->_fSafe, pdtp->_dwVerb, pdtp->_grfBINDF, pdtp->_pbinfo, pdtp->_szRedirURL, pdtp->_uiCP, NULL, pdtp->_fConfirmed); if (SUCCEEDED(hr)) { pdtp->_pwzHeaders = NULL; // CDownload owns freeing headers now pdtp->_pbinfo = NULL; // CDownload owns freeing pbinfo now. } delete pdtp; pdtp = NULL; if (pbc) { pbc->Release(); pbc = NULL; } while (1) { MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; // Note that for IE 3.0, the parking thread is also // the owner of all modeless download dialog. if (CDownload_MayProcessMessage(&msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); continue; } WaitMessage(); } return 0; } void CDownLoad_OpenUI(IMoniker *pmk, IBindCtx *pbc, BOOL fSync, BOOL fSaveAs, BOOL fSafe, LPWSTR pwzHeaders, DWORD dwVerb, DWORD grfBINDF, BINDINFO* pbinfo, LPCTSTR pszRedir, UINT uiCP, IUnknown *punk, BOOL fConfirmed) { TraceMsg(DM_DOWNLOAD, "CDownLoad_OpenUI called with fSync=%d fSaveAs=%d", fSync, fSaveAs); ASSERT(dwVerb == BINDVERB_GET || dwVerb == BINDVERB_POST); if (fSync) { CDownload::OpenUI(pmk, pbc, fSaveAs, fSafe, pwzHeaders, dwVerb, grfBINDF, pbinfo, pszRedir, uiCP, fConfirmed); pwzHeaders = NULL; // CDownload now owns headers return; } IDownloadManager *pdlm; HRESULT hr = IUnknown_QueryService(punk, SID_SDownloadManager, IID_PPV_ARG(IDownloadManager, &pdlm)); if (FAILED(hr)) { hr = CreateFromRegKey(TSZIEPATH, TEXT("DownloadUI"), IID_PPV_ARG(IDownloadManager, &pdlm)); } if (SUCCEEDED(hr)) { hr = pdlm->Download(pmk, pbc, dwVerb, grfBINDF, pbinfo, pwzHeaders, pszRedir, uiCP); pdlm->Release(); } if (FAILED(hr)) { if (pbc == NULL) { hr = CreateBindCtx(0, &pbc); } else { hr = S_OK; pbc->AddRef(); } if (SUCCEEDED(hr)) { LPWSTR pszDisplayName = NULL; hr = pmk->GetDisplayName(pbc, NULL, &pszDisplayName); if (SUCCEEDED(hr)) { CDownloadThreadParam* pdtp = new CDownloadThreadParam(pszDisplayName, pwzHeaders, fSaveAs, fSafe, dwVerb, grfBINDF, pbinfo, pszRedir, uiCP, fConfirmed); if (pdtp) { pwzHeaders = NULL; // ownership is to CDTP // Note: IAsyncBindCtx has identicial interface as IBindCtx IBindCtx *pbcAsync; hr = pbc->QueryInterface(IID_IAsyncBindCtx, (void **)&pbcAsync); if (SUCCEEDED(hr)) { // This introduces a double bind, but only for the mk: protocol and // the fix is needed for displaying pdfs and other special mime types. if (_tcsnicmp(pszDisplayName, _T("mk:"), 3) == 0) { pbcAsync->Release(); pbcAsync = NULL; hr = CreateBindCtx(0, &pbcAsync); } if (SUCCEEDED(hr)) { IStream *pStm; hr = CoMarshalInterThreadInterfaceInStream(IID_IBindCtx, pbcAsync, &pStm); if (hr == S_OK) { pdtp->SetStream(pStm); pStm->Release(); } pbcAsync->Release(); } } if (!SHCreateThread(IEDownload_ThreadProc, pdtp, CTF_PROCESS_REF | CTF_REF_COUNTED | CTF_COINIT, NULL)) { delete pdtp; pdtp = NULL; } } else { OleFree(pszDisplayName); } } pbc->Release(); } } CoTaskMemFree(pwzHeaders); // may be NULL, we consume this in all cases } HRESULT CDownLoad_OpenUIURL(LPCWSTR pwszURL, IBindCtx *pbc, LPWSTR pwzHeaders, BOOL fSync,BOOL fSaveAs, BOOL fSafe, DWORD dwVerb, DWORD grfBINDF, BINDINFO* pbinfo, LPCTSTR pszRedir, UINT uiCP, IUnknown *punk, BOOL fConfirmed) { HRESULT hr; ASSERT(pwszURL); if (pwszURL) { IMoniker* pmk = NULL; hr = CreateURLMoniker(NULL, pwszURL, &pmk); if (SUCCEEDED(hr)) { CDownLoad_OpenUI(pmk, pbc, fSync, fSaveAs, fSafe, pwzHeaders, dwVerb, grfBINDF, pbinfo, pszRedir, uiCP, punk, fConfirmed); pwzHeaders = NULL; // CDownload now owns headers pmk->Release(); hr = S_OK; } if (pwzHeaders) CoTaskMemFree(pwzHeaders); } else hr = E_INVALIDARG; return hr; } HRESULT CDownload::StartBinding(IMoniker* pmk, IBindCtx *pbc) { ASSERT(_pbc==NULL); HRESULT hr = S_OK; if (pbc == NULL) { hr = CreateBindCtx(0, &_pbc); } else { _pbc = pbc; _pbc->AddRef(); } if (SUCCEEDED(hr)) { hr = RegisterBindStatusCallback(_pbc, this, 0, 0); if (SUCCEEDED(hr)) { hr = pmk->GetDisplayName(_pbc, NULL, &_pwszDisplayName); if (SUCCEEDED(hr)) { TCHAR szBuf[MAX_PATH]; DWORD dwSize = ARRAYSIZE(szBuf); DWORD dwPUAF = PUAF_NOUI; DWORD dwPolicy = 0, dwContext = 0; int cch = lstrlen(_szURL); if (!cch) { SHUnicodeToTChar(_pwszDisplayName, _szURL, ARRAYSIZE(_szURL)); } TraceMsg(TF_SHDNAVIGATE, "CDld::StartBinding SHUnicodeToTChar returns %d (%s)", cch, _szURL); // The URL from GetDisplayName() is always fully // canonicalized and escaped. Prepare it for display. if (PrepareURLForDisplay(_szURL, szBuf, &dwSize)) FormatUrlForDisplay(szBuf, _szDisplay, ARRAYSIZE(_szDisplay), NULL, 0, TRUE, _uiCP, NULL); else FormatUrlForDisplay(_szURL, _szDisplay, ARRAYSIZE(_szDisplay), NULL, 0, TRUE, _uiCP, NULL); SetWindowText(GetDlgItem(_hDlg, IDD_NAME), _szDisplay); if (_grfBINDF & BINDF_ENFORCERESTRICTED) { dwPUAF |= PUAF_ENFORCERESTRICTED; } ZoneCheckUrlEx(_szURL, &dwPolicy, sizeof(dwPolicy), &dwContext, sizeof(dwContext), URLACTION_SHELL_FILE_DOWNLOAD, dwPUAF, NULL); dwPolicy = GetUrlPolicyPermissions(dwPolicy); if ((dwPolicy == URLPOLICY_ALLOW) || (dwPolicy == URLPOLICY_QUERY)) { IUnknown* punk = NULL; hr = pmk->BindToStorage(_pbc, NULL, IID_PPV_ARG(IUnknown, &punk)); DWNLDMSG3("StartBinding pmk->BindToStorage returned", hr, punk); if (SUCCEEDED(hr) || hr == E_PENDING) { hr = S_OK; if (punk) { ASSERT(0); punk->Release(); } } else { TraceMsg(DM_ERROR, "CDld::StartBinding pmk->BindToStorage failed %x", hr); HRESULT hrRevoke = RevokeBindStatusCallback( _pbc, this ); ASSERT( SUCCEEDED( hrRevoke ) ); } } else { TraceMsg(DM_ERROR, "CDld::StartBinding: Zone does not allow file download"); HRESULT hrRevoke = RevokeBindStatusCallback( _pbc, this ); ASSERT( SUCCEEDED( hrRevoke ) ); hr = E_ACCESSDENIED; } } else { TraceMsg(DM_ERROR, "CDld::StartBinding pmk->GetDisplayName failed %x", hr); HRESULT hrRevoke = RevokeBindStatusCallback( _pbc, this ); ASSERT( SUCCEEDED( hrRevoke ) ); } } else { TraceMsg(DM_ERROR, "CDld::StartBinding RegisterBSC failed %x", hr); } } else { TraceMsg(DM_ERROR, "CDld::StartBinding CreateBindCtx failed %x", hr); } return hr; } HRESULT CDownload::QueryInterface(REFIID riid, void **ppvObj) { static const QITAB qit[] = { QITABENT(CDownload, IBindStatusCallback), // IID_IBindStatusCallback QITABENT(CDownload, IAuthenticate), // IID_IAuthenticate QITABENT(CDownload, IServiceProvider), // IID_IServiceProvider QITABENT(CDownload, IHttpNegotiate), // IID_IHttpNegotiate QITABENT(CDownload, IWindowForBindingUI), { 0 }, }; return QISearch(this, qit, riid, ppvObj); } ULONG CDownload::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CDownload::Release() { DWNLDMSG2("CDownload::Release cRef=", _cRef); if (InterlockedDecrement(&_cRef)) return _cRef; CDownload* pdld = (CDownload*) GetWindowLongPtr(_hDlg, DWLP_USER); if (pdld == this) SetWindowLongPtr(_hDlg, DWLP_USER, NULL); DWNLDMSG3("CDownload::Release delete this", pdld, this); delete this; return 0; } ULONG CDownload::AddRefDLD() { return InterlockedIncrement(&_cRefDLD); } ULONG CDownload::ReleaseDLD() { if (InterlockedDecrement(&_cRefDLD)) return _cRefDLD; return 0; } CDownload::~CDownload() { if (_pbinfo) { ReleaseBindInfo(_pbinfo); LocalFree(_pbinfo); _pbinfo = NULL; } if (_pib) { _pib->Release(); } if (_pbc) { _pbc->Release(); } if (_hicon) { DestroyIcon(_hicon); } if (_pwszDisplayName) OleFree(_pwszDisplayName); if (_fDeleteFromCache) _DeleteFromCache(); if ( _pwzHeaders ) CoTaskMemFree( _pwzHeaders ); TraceMsg(TF_SHDLIFE, "CDownload::~CDownload being destructed"); TraceMsg(TF_SHDTHREAD, "CDownload::EndDialogDLD calling PostQuitMessage"); // Post the quit message ONLY if this flag is set. The constructor for the // derived class CDownloadURL resets the flag to FALSE because it doesn't // need any quit messages. if (!_fDontPostQuitMsg) PostQuitMessage(0); } #ifdef USE_LOCKREQUEST HRESULT CDownload::LockRequestHandle(void) { HRESULT hres = E_FAIL; HANDLE hLock; if (_pib) { IWinInetInfo* pwinet; hres = _pib->QueryInterface(IID_PPV_ARG(IWinInetInfo, &pwinet)); if (SUCCEEDED(hres)) { DWORD cbSize = sizeof(HANDLE); hres = pwinet->QueryOption(WININETINFO_OPTION_LOCK_HANDLE, &hLock, &cbSize); pwinet->Release(); } } return hres; } #endif HRESULT CDownload::OnStartBinding(DWORD grfBSCOption, IBinding *pib) { DWNLDMSG3("OnStartBinding", _pib, pib); if (_pib) { _pib->Release(); } _pib = pib; if (_pib) { _pib->AddRef(); } SetQueryNetSessionCount(SESSION_INCREMENT); _fUTF8Enabled = UTF8Enabled(); return S_OK; } HRESULT CDownload::GetPriority(LONG *pnPriority) { DWNLDMSG("GetPriority", "called"); *pnPriority = NORMAL_PRIORITY_CLASS; return S_OK; } HRESULT CDownload::OnLowResource(DWORD reserved) { DWNLDMSG("OnLowResource", "called"); return S_OK; } #define WM_DIALMON_FIRST WM_USER+100 // message sent to dial monitor app window indicating that there has been // winsock activity and dial monitor should reset its idle timer #define WM_WINSOCK_ACTIVITY WM_DIALMON_FIRST + 0 #define MIN_ACTIVITY_MSG_INTERVAL 15000 void IndicateWinsockActivity(void) { // if there is an autodisconnect monitor, send it an activity message // so that we don't get disconnected during long downloads. For perf's sake, // don't send a message any more often than once every MIN_ACTIVITY_MSG_INTERVAL // milliseconds (15 seconds). Use GetTickCount to determine interval; // GetTickCount is very cheap. DWORD dwTickCount = GetTickCount(); // Sharing this among multiple threads is OK static DWORD dwLastActivityMsgTickCount = 0; DWORD dwElapsed = dwTickCount - dwLastActivityMsgTickCount; // have we sent an activity message recently? if (dwElapsed > MIN_ACTIVITY_MSG_INTERVAL) { HWND hwndMonitorApp = FindWindow(TEXT("MS_AutodialMonitor"), NULL); if (hwndMonitorApp) { PostMessage(hwndMonitorApp, WM_WINSOCK_ACTIVITY, 0, 0); } hwndMonitorApp = FindWindow(TEXT("MS_WebcheckMonitor"), NULL); if (hwndMonitorApp) { PostMessage(hwndMonitorApp, WM_WINSOCK_ACTIVITY, 0, 0); } // record the tick count of the last time we sent an // activity message dwLastActivityMsgTickCount = dwTickCount; } } #define MAXCALCCNT 5 HRESULT CDownload::OnProgress( ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText) { DWNLDMSG4("OnProgress", ulProgress, ulProgressMax, ulStatusCode); TCHAR szBytes[MAX_BYTES_STRLEN]; TCHAR szBytesMax[MAX_BYTES_STRLEN]; TCHAR szBuf[MAX_PATH]; // OK with MAX_PATH LPTSTR pszFileName = NULL; HWND hwndShow; DWORD dwCur; switch (ulStatusCode) { case BINDSTATUS_BEGINDOWNLOADDATA: hwndShow = GetDlgItem(_hDlg, ulProgressMax ? IDD_PROBAR : IDD_NOFILESIZE); if (!IsWindowVisible(hwndShow)) { ShowWindow(GetDlgItem(_hDlg, ulProgressMax ? IDD_NOFILESIZE : IDD_PROBAR), SW_HIDE); ShowWindow(hwndShow, SW_SHOW); } _ulOldProgress = ulProgress; // fall thru case BINDSTATUS_DOWNLOADINGDATA: case BINDSTATUS_ENDDOWNLOADDATA: // Prevent machines with APM enabled from suspending during download _SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); _dwFileSize = max(ulProgressMax, ulProgress); // every once in a while, send message // to the hidden window that detects inactivity so that it doesn't // think we are inactive during a long download IndicateWinsockActivity(); // Sometimes OnProgress is called by folks who do not create a dialog if (_hDlg ) { if (!_fStrsLoaded) { MLLoadString(IDS_TITLEPERCENT, _szTitlePercent, ARRAYSIZE(_szTitlePercent)); MLLoadString(IDS_ESTIMATE, _szEstimateTime, ARRAYSIZE(_szEstimateTime)); MLLoadString(IDS_TITLEBYTES, _szTitleBytes, ARRAYSIZE(_szTitleBytes)); MLLoadString(IDS_BYTESCOPIED, _szBytesCopied, ARRAYSIZE(_szBytesCopied)); MLLoadString(IDS_TRANSFERRATE, _szTransferRate, ARRAYSIZE(_szTransferRate)); _fStrsLoaded = TRUE; } // Get the file name of the file being downloaded pszFileName = PathFindFileName(_szURL); dwCur = GetTickCount(); if (_dwOldCur == 0) // Allow the download to get started before displaying stats _dwOldCur = dwCur; if ((ulProgressMax > 0) && _fDownloadStarted) { if (_hDlg) { SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETRANGE32, 0, _dwFileSize); SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETPOS, ulProgress, 0); } if (!_fFirstTickValid) { _dwFirstSize = ulProgress; _fFirstTickValid = TRUE; SetWindowText(GetDlgItem(_hDlg, IDD_NAME), _szDisplay); } else { if ((ulProgress - _dwFirstSize) && _hDlg) { // Recompute and display stats at least every second if ((dwCur - _dwOldCur) >= 1000) { _dwOldCur = dwCur; // Save current tick count TCHAR szTime[32]; DWORD dwSpent = ((dwCur - _dwFirstTick)+500) / 1000; ULONG ulLeft = _dwFileSize - ulProgress; DWORD dwRate = _dwOldRate; dwRate = (ulProgress - _ulOldProgress) / (dwSpent ? dwSpent : 1); TraceMsg(DM_PROGRESS, "OnProgress ulProgress=%d ulGot=%d dwSpent=%d ulLeft=%d", ulProgress, (ulProgress - _dwFirstSize), dwSpent, ulLeft); // Compute & display estimated time left to download, bytes so far, total bytes DWORD dwEst; if (ulLeft > 0x100000L) // To avoid overflow, use KB for >1MB file. dwEst = (ulLeft >> 10) / ((dwRate >> 10) ?(dwRate >> 10) :1); else dwEst = ulLeft / (dwRate ?dwRate :1); if (dwEst == 0) dwEst = 1; TraceMsg(DM_PROGRESS, "OnProgress Estimated time left = %d", dwEst); StrFromTimeInterval(szTime, ARRAYSIZE(szTime), dwEst * 1000, 3); LPTSTR pszTime = szTime; while(*pszTime && (*pszTime == ' ')) pszTime++; _FormatMessage(_szEstimateTime, szBuf, ARRAYSIZE(szBuf), pszTime, StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN), StrFormatByteSize(_dwFileSize, szBytesMax, MAX_BYTES_STRLEN)); TraceMsg(DM_PROGRESS, "OnProgress Estimated string = %s", szBuf); SetDlgItemText(_hDlg, IDD_TIMEEST, szBuf); _dwOldEst = dwEst; // Compute & display transfer rate if (dwRate != _dwOldRate) { _dwOldRate = dwRate; _FormatMessage(_szTransferRate, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(dwRate, szBytes, MAX_BYTES_STRLEN)); SetDlgItemText(_hDlg, IDD_TRANSFERRATE, szBuf); } } // Compute & display percentage of download completed DWORD dwPcent = (100 - MulDiv(_dwFileSize - ulProgress, 100, _dwFileSize)); if (dwPcent != _dwOldPcent) { _dwOldPcent = dwPcent; if (dwPcent == 100) // Don't peg the meter until we've completed dwPcent = 99; TCHAR szBuf2[MAX_PATH]; DWORD dwSize = ARRAYSIZE(szBuf2); if (PrepareURLForDisplay(pszFileName, szBuf2, &dwSize)) _FormatMessage(_szTitlePercent, szBuf, ARRAYSIZE(szBuf), (UINT)dwPcent, szBuf2); else _FormatMessage(_szTitlePercent, szBuf, ARRAYSIZE(szBuf), (UINT)dwPcent, pszFileName); SetWindowText(_hDlg, szBuf); } } } } else if (_hDlg && _fDownloadStarted) // Unknown file size, just show bytes and rate { // Recompute and display stats at most every second if ((dwCur - _dwOldCur) >= 1000) { _dwOldCur = dwCur; // Save current tick count DWORD dwSpent = ((dwCur - _dwFirstTick)+500) / 1000; DWORD dwRate = ulProgress / (dwSpent ? dwSpent : 1); _FormatMessage(_szBytesCopied, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN)); TraceMsg(DM_PROGRESS, "OnProgress string = %s", szBuf); SetDlgItemText(_hDlg, IDD_TIMEEST, szBuf); _FormatMessage(_szTransferRate, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(dwRate, szBytes, MAX_BYTES_STRLEN)); SetDlgItemText(_hDlg, IDD_TRANSFERRATE, szBuf); { TCHAR szBuf2[MAX_PATH]; DWORD dwSize = ARRAYSIZE(szBuf2); if (PrepareURLForDisplay (pszFileName, szBuf2, &dwSize)) _FormatMessage(_szTitleBytes, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN),szBuf2); else _FormatMessage(_szTitleBytes, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN), pszFileName); SetWindowText(_hDlg, szBuf); } } } } break; default: // ulStatusCode break; } return S_OK; } HRESULT CDownload::OnStopBinding(HRESULT hrError, LPCWSTR szError) { TraceMsg(DM_DOWNLOAD, "OnStopBinding called with hrError==%x", hrError); HRESULT hrDisplay = hrError; AddRef(); // Guard against last Release by _RevokeObjectParam HRESULT hres = RevokeBindStatusCallback(_pbc, this); AssertMsg(SUCCEEDED(hres), TEXT("URLMON bug??? RevokeBindStatusCallback failed %x"), hres); if (_pib) { CLSID clsid; LPWSTR pwszError = NULL; HRESULT hresT = _pib->GetBindResult(&clsid, (DWORD *)&hrDisplay, &pwszError, NULL); TraceMsg(TF_SHDBINDING, "DLD::OnStopBinding called GetBindResult %x->%x (%x)", hrError, hrDisplay, hresT); if (SUCCEEDED(hresT)) { // // URLMON returns a native Win32 error. // if (hrDisplay && SUCCEEDED(hrDisplay)) hrDisplay = HRESULT_FROM_WIN32(hrDisplay); if (pwszError) OleFree(pwszError); } // We don't call IBinding::Release until ~CDownload // because we need to guarantee the download file // exists until we have copied or executed it. } #ifdef DEBUG if (hrError==S_OK && GetKeyState(VK_CONTROL) < 0) { hrError = E_FAIL; } #endif if (FAILED(hrError) && hrError != E_ABORT) { IE_ErrorMsgBox(NULL, _hDlg, hrDisplay, szError,_szDisplay, IDS_CANTDOWNLOAD, MB_OK|MB_ICONSTOP); } if (g_hCritOpMutex != NULL) { CloseHandle(g_hCritOpMutex); g_hCritOpMutex = NULL; } SetQueryNetSessionCount(SESSION_DECREMENT); if (!_fGotFile || !_fDownloadCompleted) { AssertMsg(FAILED(hrError), TEXT("CDownload::OnStopBinding is called, but we've never got a file -- URLMON bug")); if (!_fEndDialogCalled) { FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage); } } Release(); // Guard against last Release by _RevokeObjectParam return S_OK; } HRESULT CDownload::GetBindInfo(DWORD* grfBINDINFOF, BINDINFO *pbindinfo) { TraceMsg(DM_DOWNLOAD, "DWNLD::GetBindInfo called when _pbinfo==%x", _pbinfo); if ( !grfBINDINFOF || !pbindinfo || !pbindinfo->cbSize ) return E_INVALIDARG; if (_pbinfo) { // Give the ownership to URLMON... shallow copy; don't use CopyBindInfo(). // Don't forget to keep pbindinfo cbSize! DWORD cbSize = pbindinfo->cbSize; CopyMemory( pbindinfo, _pbinfo, min(_pbinfo->cbSize, cbSize) ); pbindinfo->cbSize = cbSize; if (pbindinfo->cbSize > _pbinfo->cbSize) { ZeroMemory((BYTE *)pbindinfo + _pbinfo->cbSize, pbindinfo->cbSize - _pbinfo->cbSize); } LocalFree(_pbinfo); _pbinfo = NULL; } else { // We don't have a BINDINFO our selves so // clear BINDINFO except cbSize DWORD cbSize = pbindinfo->cbSize; ZeroMemory( pbindinfo, cbSize ); pbindinfo->cbSize = cbSize; if (UTF8Enabled()) pbindinfo->dwOptions = BINDINFO_OPTIONS_ENABLE_UTF8; } // #52524. With post build ~1100, If we do not return the following flags when URLMon calls // GetBindInfo(), It will bind to the storage synchronously. (judej, danpoz) *grfBINDINFOF = _grfBINDF | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; return S_OK; } HRESULT CDownload::OnDataAvailable(DWORD grfBSC, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) { DWORD dwOptions = 0; DWNLDMSG3("OnDataAvailable (grf,pstg)", grfBSC, pstgmed); _dwTotalSize = dwSize; // keep track of number of bytes downloaded if (SUCCEEDED(_GetRequestFlagFromPIB(_pib, &dwOptions)) && (dwOptions & INTERNET_REQFLAG_CACHE_WRITE_DISABLED)) { _fWriteHistory = FALSE; } if (grfBSC & BSCF_LASTDATANOTIFICATION) { _fDownloadCompleted = TRUE; } // // This code gets the file name from pstgmed, when it became // available. URLMon is supposed to pass it even though the file // is not completely ready yet. // if (!_fGotFile && pstgmed) { Animate_Stop(GetDlgItem(_hDlg, IDD_ANIMATE)); if (pstgmed->tymed == TYMED_FILE) { TCHAR szBuf[MAX_PATH]; // ok with MAX_PATH (because we truncate) SHUnicodeToTChar(pstgmed->lpszFileName, _szPath, ARRAYSIZE(_szPath)); // Because of redirection the _szURL could be http://.../redir.dll or query.exe. // Whereas the actual filename would be something else. The Cache filename is generated // by wininet after it has figured out what the real filename is. However, it might contain // a "(1)" or a "(2)" at the end of the file name. TCHAR szURL[MAX_URL_STRING]; StrCpyN(szURL, _szURL, ARRAYSIZE(szURL)); TCHAR * pszURLFName = PathFindFileName(szURL); TCHAR * pszCacheFName = PathFindFileName(_szPath); // Unescape the filename suggested by wininet. DWORD cch = ARRAYSIZE(szBuf); if (_PrepareURLForDisplayUTF8W(pszCacheFName, szBuf, &cch, _fUTF8Enabled, _uiCP) != S_OK) StrCpyN(szBuf, pszCacheFName, ARRAYSIZE(szBuf)); // Strip out any path that may have been encoded pszCacheFName = szBuf; TCHAR *pszSrc = PathFindFileName(szBuf); if (pszSrc != szBuf) { while(*pszSrc) *pszCacheFName++ = *pszSrc++; *pszCacheFName = *pszSrc; } // Use the Cache name. pszURLFName point to the file name in szURL. Just overwrite it if (pszURLFName && szBuf) { StrCpyN(pszURLFName, szBuf, ARRAYSIZE(szURL) - ((int)(pszURLFName-szURL)/sizeof(TCHAR))); FormatUrlForDisplay(szURL, _szDisplay, ARRAYSIZE(_szDisplay), NULL, 0, TRUE, _uiCP, NULL); } DWNLDMSG("OnDataAvailable got TYMED_FILE", _szPath); _fGotFile = TRUE; TCHAR szMime[MAX_PATH]; if (GetClipboardFormatName(pformatetc->cfFormat, szMime, sizeof(szMime)/sizeof(szMime[0]))) { MIME_GetExtension(szMime, (LPTSTR) _szExt, SIZECHARS(_szExt)); } SetWindowText(GetDlgItem(_hDlg, IDD_NAME), _szDisplay); UINT uRet = _MayAskUserIsFileSafeToOpen(szMime); switch (uRet) { case IDOK: MLLoadString(IDS_OPENING, szBuf, ARRAYSIZE(szBuf)); break; case IDD_SAVEAS: _fSaveAs = TRUE; _fCallVerifyTrust = FALSE; MLLoadString(IDS_SAVING, szBuf, ARRAYSIZE(szBuf)); break; case IDCANCEL: FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage); // // HACK: Under a certain condition, we receive one more // OnDataAvailable from URLMON with BSCF_LASTDATANOTIFICATION // before this posted message is dispatched. It causes // WinVerifyTrust call, which is wrong. To prevent it, // we unset this flag. // // We still assumes that OnStopBinding will not happen before // this message is dispatched. In IE 4.0, we should introduce // another flag (_fCancelled) to make it more robust. // _fCallVerifyTrust = FALSE; return S_OK; } SetDlgItemText(_hDlg, IDD_OPENIT, szBuf); if (_fSaveAs) { if (!_GetSaveLocation()) { FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage); return S_OK; } StrCpyN(szBuf, _szSaveToFile, ARRAYSIZE(szBuf)); RECT rect; GetClientRect(GetDlgItem(_hDlg, IDD_DIR), &rect); PathCompactPath(NULL, szBuf, rect.right); } else MLLoadString(IDS_DOWNLOADTOCACHE, szBuf, ARRAYSIZE(szBuf)); SetDlgItemText(_hDlg, IDD_DIR, szBuf); Animate_Play(GetDlgItem(_hDlg, IDD_ANIMATE),0, -1, -1); if (_dwFirstTick == 0) // Start the timer _dwFirstTick = GetTickCount(); } else { TraceMsg(DM_WARNING, "CDownload::OnDataAvailable pstgmed->tymed (%d) != TYMED_FILE", pstgmed->tymed); } _fDownloadStarted = TRUE; } if (_fDownloadCompleted) { #ifdef CALL_WVT if (_fCallVerifyTrust) { ShowWindow(_hDlg, SW_HIDE); UINT uRet = _VerifyTrust(_hDlg, _szPath, _szDisplay); switch (uRet) { case IDOK: break; default: // We assume _VerifyTrust always is able to open the file // passed from URLMON. If it fails, we bail with no UI. ASSERT(0); // Fall through case IDCANCEL: _fDeleteFromCache = TRUE; FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage); return S_OK; } } #endif // CALL_WVT DWNLDMSG3("OnDataAvailable calling Animate_Stop", _hDlg, GetDlgItem(_hDlg, IDD_ANIMATE)); Animate_Stop(GetDlgItem(_hDlg, IDD_ANIMATE)); SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETRANGE32, 0, 100); SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETPOS, 100, 0); if (_fSaveAs) { FORWARD_WM_COMMAND(_hDlg, IDD_SAVEAS, NULL, 0, PostMessage); } else { #ifdef USE_LOCKREQUEST LockRequestHandle(); // Tell wininet that we want the file locked to allow the app to open it. // This prevents wininet from deleting the file from the cache before the // app gets a chance to use it. When wininet sees this file is locked, it // will add the file to the scavenger leak list and attempt to delete the // file in the future. #endif FORWARD_WM_COMMAND(_hDlg, IDOK, NULL, 0, PostMessage); } } return S_OK; } HRESULT CDownload::OnObjectAvailable(REFIID riid, IUnknown *punk) { DWORD dwOptions = 0; DWNLDMSG3("OnObjectAvailable (riid,punk)", riid, punk); if (SUCCEEDED(_GetRequestFlagFromPIB(_pib, &dwOptions)) && (dwOptions & INTERNET_REQFLAG_CACHE_WRITE_DISABLED)) { _fWriteHistory = FALSE; } return S_OK; } /* *** IHttpNegotiate *** */ HRESULT CDownload::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders) { if ((!_pwzHeaders) || (!pszAdditionalHeaders)) return S_OK; DWORD cbHeaders = (lstrlenW(_pwzHeaders) + 1) * sizeof(WCHAR); LPWSTR pwzHeaders = (LPWSTR)CoTaskMemAlloc(cbHeaders + sizeof(WCHAR)); if (pwzHeaders) { memcpy (pwzHeaders, _pwzHeaders, cbHeaders); *pszAdditionalHeaders = pwzHeaders; } // Caller owns freeing *pszAdditionalHeaders return S_OK; } HRESULT CDownload::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) { return S_OK; } BOOL _RememberFileIsSafeToOpen(LPCTSTR szFileClass) { DWORD dwEditFlags; ULONG cb = sizeof(dwEditFlags); HRESULT hr; IQueryAssociations *passoc = NULL; BOOL bRet = FALSE; hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &passoc)); if (SUCCEEDED(hr) && passoc) { hr = passoc->Init(NULL, szFileClass, NULL, NULL); if (SUCCEEDED(hr)) { hr = passoc->GetData(NULL, ASSOCDATA_EDITFLAGS, NULL, &dwEditFlags, &cb); if (SUCCEEDED(hr)) { dwEditFlags &= ~FTA_NoEdit; dwEditFlags |= FTA_OpenIsSafe; } } passoc->Release(); } if (FAILED(hr)) dwEditFlags = FTA_OpenIsSafe; return (SHSetValue(HKEY_CLASSES_ROOT, szFileClass, TEXT("EditFlags"), REG_BINARY, (BYTE*)&dwEditFlags, sizeof(dwEditFlags)) == ERROR_SUCCESS); } struct SAFEOPENDLGPARAM { LPCTSTR pszFileClass; LPCTSTR pszFriendlyURL; LPCTSTR pszURL; HWND hwndTT; TCHAR* pszTTText; LPCTSTR pszCacheFile; DWORD uiCP; BOOL fTypeMismatch; BOOL fShellExecPrompt; BOOL fPackagerCommandPrompt; }; INT_PTR CALLBACK SafeOpenDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { UINT id; static BOOL bCancelled; SAFEOPENDLGPARAM* param = (SAFEOPENDLGPARAM*) GetWindowLongPtr(hDlg, DWLP_USER); if ((param == NULL) && (uMsg != WM_INITDIALOG)) return FALSE; switch (uMsg) { case WM_INITDIALOG: { BOOL fUnsafeFile; TCHAR szFriendlyName[MAX_DISPLAY_LEN] = {TEXT('\0')}; TCHAR szFriendlyFrom[MAX_DISPLAY_LEN] = {TEXT('\0')}; TCHAR szProcessedURL[MAX_URL_STRING] = {TEXT('\0')}; DWORD dwSize = ARRAYSIZE(szProcessedURL); if (lParam == NULL) return FALSE; SetWindowLongPtr(hDlg, DWLP_USER, lParam); param = (SAFEOPENDLGPARAM*)lParam; // init unsafe file to mismatch between progid and file fUnsafeFile = param->fTypeMismatch; // Determine whether or not to gray out the Always ask checkbox. We wil gray out in the following cases // 1. If we were not told what the file class is // 2. If the file class is in the unsafe extensions list // 3. if the file extension in the URL is in the unsafe extensions list // 4. if the cache file extension is in the unsafe extensions list (if we are redirected) TCHAR * pszExt = NULL; TCHAR * pszCacheExt = NULL; if (param->pszURL) pszExt = PathFindExtension(param->pszURL); if (param->pszCacheFile) pszCacheExt = PathFindExtension(param->pszCacheFile); if(param->fPackagerCommandPrompt) { fUnsafeFile = TRUE; } else if (pszExt || pszCacheExt) { if (pszExt && AssocIsDangerous(pszExt)) fUnsafeFile = TRUE; else if (pszCacheExt && AssocIsDangerous(pszCacheExt)) fUnsafeFile = TRUE; } else { fUnsafeFile = TRUE; } if (fUnsafeFile || SHRestricted2(REST_AlwaysPromptWhenDownload, NULL, 0)) EnableWindow(GetDlgItem(hDlg, IDC_SAFEOPEN_ALWAYS), FALSE); // The check box is always checked by default CheckDlgButton(hDlg, IDC_SAFEOPEN_ALWAYS, TRUE); // adjust the warning if (fUnsafeFile) { HICON hIcon = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_PRIVACY_WARN), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); if (hIcon != NULL) SendDlgItemMessage(hDlg, IDC_SAFEOPEN_WARNICON, STM_SETICON, (WPARAM)hIcon, 0); } else { ShowWindow(GetDlgItem(hDlg, IDC_SAFEOPEN_WARNTEXT), SW_HIDE); } // cross-lang platform support SHSetDefaultDialogFont(hDlg, IDC_SAFEOPEN_FILENAME); SHSetDefaultDialogFont(hDlg, IDC_SAFEOPEN_FILETYPE); SHSetDefaultDialogFont(hDlg, IDC_SAFEOPEN_FILEFROM); // Get the URL for the tooltip. Also get URL for the display string if we weren't passed one if (param->pszURL) { if (!PrepareURLForDisplay(param->pszURL, szProcessedURL, &dwSize)) { dwSize = ARRAYSIZE(szProcessedURL); StrCpyN(szProcessedURL, param->pszURL, dwSize); } } // Now figure out what we want to display if(param->fPackagerCommandPrompt) { // If this was a packager command line, then just display the full command as passed in param->pszURL StrCpyN(szFriendlyName, param->pszURL, ARRAYSIZE(szFriendlyName)); } else { FormatUrlForDisplay((LPTSTR)param->pszURL, szFriendlyName, ARRAYSIZE(szFriendlyName), szFriendlyFrom, ARRAYSIZE(szFriendlyFrom), TRUE, param->uiCP, (PWSTR)param->pszCacheFile); } SetDlgItemText(hDlg, IDC_SAFEOPEN_FILENAME, szFriendlyName); if(param->fPackagerCommandPrompt) { // If it was a packager command line, then display "Unknown" for the from MLLoadString(IDS_VALUE_UNKNOWN, szFriendlyFrom, ARRAYSIZE(szFriendlyFrom)); SetDlgItemText(hDlg, IDC_SAFEOPEN_FILEFROM, szFriendlyFrom); } else { if (szFriendlyFrom[0] != '\0') SetDlgItemText(hDlg, IDC_SAFEOPEN_FILEFROM, szFriendlyFrom); } if (param->pszFileClass || pszCacheExt) { DWORD cchName = ARRAYSIZE(szFriendlyName); if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_FRIENDLYDOCNAME, (param->pszFileClass ? param->pszFileClass : pszCacheExt), NULL, szFriendlyName, &cchName))) { SetDlgItemText(hDlg, IDC_SAFEOPEN_FILETYPE, szFriendlyName); } } int cch = lstrlen(szProcessedURL) + 1; param->pszTTText = (TCHAR*)LocalAlloc(LPTR, cch * sizeof(TCHAR)); if (param->pszTTText) { StrCpyN(param->pszTTText, szProcessedURL, cch); if (param->hwndTT = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hDlg, NULL, HINST_THISDLL, NULL)) { TOOLINFO ti; ti.cbSize = sizeof(ti); ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; ti.hwnd = hDlg; ti.uId = (UINT_PTR) GetDlgItem(hDlg, IDC_SAFEOPEN_FILENAME); ti.lpszText = LPSTR_TEXTCALLBACK; ti.hinst = HINST_THISDLL; GetWindowRect((HWND)ti.uId, &ti.rect); SendMessage(param->hwndTT, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti); SendMessage(param->hwndTT, TTM_SETMAXTIPWIDTH, 0, 300); } } if (param->fShellExecPrompt) { EnableWindow(GetDlgItem(hDlg, IDC_SAFEOPEN_AUTOSAVE), FALSE); // make Cancel the default action SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDCANCEL), TRUE); } else { // make Save the default action SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDC_SAFEOPEN_AUTOSAVE), TRUE); } return FALSE; } case WM_NOTIFY: { LPTOOLTIPTEXT lpTT = (LPTOOLTIPTEXT) lParam; if (lpTT->hdr.code == TTN_NEEDTEXT) { lpTT->lpszText = param->pszTTText; lpTT->hinst = NULL; } break; } case WM_DESTROY: //deal with checkbox if ((!bCancelled) && (!IsDlgButtonChecked(hDlg, IDC_SAFEOPEN_ALWAYS)) && param->pszURL) { // Now save EditFlags at the key value value that the filetypes dialog will get/set. TCHAR * pszExt = PathFindExtension(param->pszURL); if (*pszExt) { TCHAR szFileClass[MAX_PATH]; ULONG cb = sizeof(szFileClass); *szFileClass = TEXT('\0'); SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szFileClass, &cb); if (*szFileClass) _RememberFileIsSafeToOpen(szFileClass); } } SHRemoveDefaultDialogFont(hDlg); if (IsWindow(param->hwndTT)) DestroyWindow(param->hwndTT); if (param->pszTTText) { LocalFree(param->pszTTText); param->pszTTText = NULL; } return FALSE; case WM_COMMAND: id = GET_WM_COMMAND_ID(wParam, lParam); switch (id) { case IDC_SAFEOPEN_AUTOOPEN: EndDialog(hDlg, IDOK); break; case IDC_SAFEOPEN_AUTOSAVE: EndDialog(hDlg, IDD_SAVEAS); break; case IDM_MOREINFO: SHHtmlHelpOnDemandWrap(hDlg, TEXT("iexplore.chm > iedefault"), HH_DISPLAY_TOPIC, (DWORD_PTR) TEXT("filedown.htm"), ML_CROSSCODEPAGE); break; case IDCANCEL: bCancelled = TRUE; EndDialog(hDlg, id); break; } break; default: return FALSE; } return TRUE; } UINT _ShowSafeOpenDialog(HWND hwnd, UINT idRes, SAFEOPENDLGPARAM *pparam) { UINT uRet = -1; // is whistler ? if (IsOS(OS_WHISTLERORGREATER)) { HMODULE hmod = LoadLibrary(TEXT("xpsp1res.dll")); if (hmod) { uRet = (UINT) DialogBoxParam(hmod, MAKEINTRESOURCE(idRes), hwnd, SafeOpenDlgProc, (LPARAM)pparam); FreeLibrary(hmod); } } if (uRet == -1) uRet = (UINT) DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(idRes), hwnd, SafeOpenDlgProc, (LPARAM)pparam); return uRet; } UINT OpenSafeOpenDialog(HWND hwnd, UINT idRes, LPCTSTR pszFileClass, LPCTSTR pszURL, LPCTSTR pszRedirURL, LPCTSTR pszCacheName, LPCTSTR pszDisplay, UINT uiCP, IUnknown *punk, BOOL fTypeMismatch) { IDownloadManager *pdlm; HRESULT hr = IUnknown_QueryService(punk, SID_SDownloadManager, IID_PPV_ARG(IDownloadManager, &pdlm)); if (SUCCEEDED(hr)) { pdlm->Release(); return IDD_SAVEAS; } LPCTSTR pszTemp = pszURL; if (pszRedirURL && lstrlen(pszRedirURL)) pszTemp = pszRedirURL; SAFEOPENDLGPARAM param = { pszFileClass, pszDisplay, pszTemp, 0, 0, pszCacheName, uiCP, fTypeMismatch, FALSE, FALSE}; return _ShowSafeOpenDialog(hwnd, idRes, ¶m); } STDAPI_(BOOL) SafeOpenPromptForShellExec(HWND hwnd, PCWSTR pszFile) { SAFEOPENDLGPARAM param = { PathFindExtension(pszFile), NULL, pszFile, 0, 0, NULL, CP_ACP, TRUE, TRUE, FALSE}; return IDOK == _ShowSafeOpenDialog(hwnd, DLG_SAFEOPEN, ¶m); } STDAPI_(BOOL) SafeOpenPromptForPackager(HWND hwnd, PCWSTR pszFile, BOOL bFromCommandLine) { SAFEOPENDLGPARAM param = { PathFindExtension(pszFile), NULL, pszFile, 0, 0, NULL, CP_ACP, TRUE, TRUE, bFromCommandLine}; return IDOK == _ShowSafeOpenDialog(hwnd, DLG_SAFEOPEN, ¶m); } BOOL _OpenIsSafe(LPCTSTR pszClass) { BOOL bRet = FALSE; IQueryAssociations *passoc; HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &passoc)); if (SUCCEEDED(hr)) { hr = passoc->Init(NULL, pszClass, NULL, NULL); if (SUCCEEDED(hr)) { DWORD dwEditFlags; ULONG cb = sizeof(dwEditFlags); hr = passoc->GetData(NULL, ASSOCDATA_EDITFLAGS, NULL, &dwEditFlags, &cb); if (SUCCEEDED(hr)) { if (dwEditFlags & FTA_OpenIsSafe) bRet = TRUE; } } passoc->Release(); } return bRet; } UINT MayOpenSafeOpenDialog(HWND hwnd, LPCTSTR pszFileClass, LPCTSTR pszURL, LPCTSTR pszCacheName, LPCTSTR pszDisplay, UINT uiCP, IUnknown * punk, IOleCommandTarget * pCmdTarget = NULL, BOOL fDisableOpen = FALSE) { // Has some association UINT uiRet = IDIGNORE; // default for no dlg displayed const LPCTSTR c_szExcluded[] = {TEXT(".ins"),TEXT(".isp")}; const LPCTSTR c_szNoZoneCheckExtns[] = {TEXT(".cdf")}; BOOL fSafe = _OpenIsSafe(pszFileClass); // We will not do Zone check on CDF files..#56297. if (!IsTypeInList(pszFileClass, c_szNoZoneCheckExtns, ARRAYSIZE(c_szNoZoneCheckExtns))) { DWORD dwPolicy = 0, dwContext = 0; ZoneCheckUrlEx(pszURL, &dwPolicy, sizeof(dwPolicy), &dwContext, sizeof(dwContext), URLACTION_SHELL_FILE_DOWNLOAD, PUAF_NOUI, NULL); dwPolicy = GetUrlPolicyPermissions(dwPolicy); if ((dwPolicy != URLPOLICY_ALLOW) && (dwPolicy != URLPOLICY_QUERY)) { ProcessStartbindingError(NULL, NULL, NULL, MB_ICONWARNING, E_ACCESSDENIED); return IDCANCEL; } } // Always ask for certain the types that we know to be unsafe. We will allow .ins and .isp // files through for the ICW folks. if (AssocIsDangerous(pszFileClass) && !IsTypeInList(pszFileClass, c_szExcluded, ARRAYSIZE(c_szExcluded))) fSafe = FALSE; if (!fSafe || SHRestricted2(REST_AlwaysPromptWhenDownload, NULL,0)) { VARIANT varOut = {0}; if (pCmdTarget) { pCmdTarget->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut); } if ((V_VT(&varOut) != VT_BOOL) || (VARIANT_FALSE == V_BOOL(&varOut))) { uiRet = OpenSafeOpenDialog(hwnd, DLG_SAFEOPEN, pszFileClass, pszURL, NULL, pszCacheName, pszDisplay, uiCP, punk, fDisableOpen); } } if (uiRet != IDOK && uiRet != IDD_SAVEAS && uiRet != IDIGNORE) DeleteUrlCacheEntry(pszURL); return(uiRet); } #ifdef CALL_WVT // Returns: // // IDOK -- If it's trusted // IDNO -- If it's not known (warning dialog requried) // IDCANCEL -- We need to stop download it // UINT _VerifyTrust(HWND hwnd, LPCTSTR pszFileName, LPCWSTR pszStatusText) { UINT uRet = IDNO; // assume unknown HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile != INVALID_HANDLE_VALUE) { HRESULT hres = g_wvt.VerifyTrust(hFile, hwnd, pszStatusText); if (SUCCEEDED(hres)) { uRet = IDOK; } else { ASSERT((hres != HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)) && (hres != HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND))); uRet = IDCANCEL; } CloseHandle(hFile); } else { TraceMsg(DM_WARNING, "_VerifyTrust CreateFile failed %x", GetLastError()); } TraceMsg(DM_WVT, "_VerifyTrust returning %d", uRet); return uRet; } #endif // CALL_WVT // // Returns: // IDOK: Continue download and open it // IDD_SAVEAS: Save it as a file // IDCANCEL: Stop downloading // UINT CDownload::_MayAskUserIsFileSafeToOpen(LPCTSTR pszMime) { if (_fSaveAs || _fSafe) { return (_fSaveAs ? IDD_SAVEAS : IDOK); // no need to ask } // Force save as dialog if we are using SSL and // HKCU\software\microsoft\windows\currentversion\internet settings\DisableCachingOfSSLPages is set DWORD dwValue; DWORD dwDefault = 0; DWORD dwSize; dwSize = sizeof(dwValue); SHRegGetUSValue(TSZWININETPATH, TEXT("DisableCachingOfSSLPages"), NULL, (LPBYTE)&dwValue, &dwSize, FALSE, (void *) &dwDefault, sizeof(dwDefault)); if (dwValue != 0 && URL_SCHEME_HTTPS == GetUrlScheme(_szURL)) { return(IDD_SAVEAS); } if(_fConfirmed) { return IDOK; } BOOL fUnknownType = TRUE; UINT uRet = IDNO; // assume no extension or no association LPTSTR pszExt = PathFindExtension(_szPath); if (*pszExt) { TCHAR szFileClass[MAX_PATH]; memset(szFileClass, 0, ARRAYSIZE(szFileClass)); #ifdef CALL_WVT // // If this is an EXE and we have WINTRUST ready to call, // don't popup any UI here at this point. if ((StrCmpI(pszExt, TEXT(".exe"))==0) && SUCCEEDED(g_wvt.Init())) { TraceMsg(DM_WVT, "_MayAskUIFSTO this is EXE, we call _VerifyTrust later"); _fCallVerifyTrust = TRUE; } #endif // CALL_WVT ULONG cb = SIZEOF(szFileClass); if ((RegQueryValue(HKEY_CLASSES_ROOT, pszExt, szFileClass, (LONG*)&cb) == ERROR_SUCCESS) && * szFileClass) { fUnknownType = FALSE; uRet = MayOpenSafeOpenDialog(_hDlg, szFileClass, _szURL, _szPath, _szDisplay, _uiCP, NULL, NULL, FALSE); if (uRet == IDIGNORE) // caller doesn't recognize IDIGNORE uRet = IDOK; } } if (fUnknownType) { uRet = OpenSafeOpenDialog(_hDlg, DLG_SAFEOPEN, NULL, _szURL, NULL, _szPath, _szDisplay, _uiCP, NULL, FALSE); } return uRet; } // *** IAuthenticate *** HRESULT CDownload::Authenticate(HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword) { if (!phwnd || !pszUsername || !pszPassword) return E_POINTER; *phwnd = _hDlg; *pszUsername = NULL; *pszPassword = NULL; return S_OK; } HRESULT CDownload::GetWindow(REFGUID RefGUID, HWND *phWnd) { if (IsEqualGUID(RefGUID, IID_IHttpSecurity)) { *phWnd = _hDlg; return S_OK; } else return E_FAIL; } // *** IServiceProvider *** HRESULT CDownload::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { *ppvObj = NULL; if (IsEqualGUID(guidService, IID_IAuthenticate)) { return QueryInterface(riid, ppvObj); } return E_FAIL; } // S_OK : continue with operation // S_FALSE : cancel operation. HRESULT CDownload::PerformVirusScan(LPCTSTR szFileName) { HRESULT hr = S_OK; // default to accepting the file IVirusScanner *pvs; if (SUCCEEDED(CreateFromRegKey(TSZIEPATH, TEXT("VirusScanner"), IID_PPV_ARG(IVirusScanner, &pvs)))) { STGMEDIUM stg; WCHAR wszFileName[MAX_PATH]; VIRUSINFO vi; vi.cbSize = sizeof(VIRUSINFO); // // VIRUSINFO lpszFileName is not defined as 'const' so we need to copy // szFileName into a buffer. If it really should be const get rid of // this copy and use a cast. // StrCpyN(wszFileName, szFileName, ARRAYSIZE(wszFileName)); stg.tymed = TYMED_FILE; stg.lpszFileName = wszFileName; stg.pUnkForRelease = NULL; hr = pvs->ScanForVirus(_hDlg, &stg, _pwszDisplayName, SFV_DELETE, &vi); switch (hr) { case S_OK: break; case VSCAN_E_NOPROVIDERS: //No virus scanning providers case VSCAN_E_CHECKPARTIAL: //Atleast one of providers didn't work. case VSCAN_E_CHECKFAIL: //No providers worked. hr = S_OK; break; case VSCAN_E_DELETEFAIL: //Tried to delete virus file but failed. case S_FALSE: // Virus found. hr = E_FAIL; break; // If some bizarre result, continue on. default: hr = S_OK; break; } pvs->Release(); } return hr; } // Starts a download of a file in its own window. // This function is exported and called by HTML doc object. // Someday we probably want to put this in a COM interface. // Currently it just calls the internal function CDownLoad_OpenUIURL. STDAPI DoFileDownload(LPCWSTR pwszURL) { return CDownLoad_OpenUIURL(pwszURL, NULL, NULL, FALSE,TRUE); } STDAPI DoFileDownloadEx(LPCWSTR pwszURL, BOOL fSaveAs) { return CDownLoad_OpenUIURL(pwszURL, NULL, NULL, FALSE, fSaveAs); } #ifdef DEBUG const DWORD CDownloadThreadParam::s_dummy = 0; #endif