|
|
#include "priv.h"
#include "bindcb.h"
#include "resource.h"
#include <vrsscan.h>
#include "iface.h"
#include "security.h"
#include <wintrust.h>
#include "iehelpid.h"
#include <shlwapi.h>
#include "inetreg.h"
#include <varutil.h>
#include "dochost.h"
#include <mluisupp.h>
#include <downloadmgr.h>
#include "apithk.h"
#include "richedit.h"
#include <brutil.h>
#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 - "<file extension> 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
|