Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2770 lines
94 KiB

  1. #include "priv.h"
  2. #include "bindcb.h"
  3. #include "resource.h"
  4. #include <vrsscan.h>
  5. #include "iface.h"
  6. #include "security.h"
  7. #include <wintrust.h>
  8. #include "iehelpid.h"
  9. #include <shlwapi.h>
  10. #include "inetreg.h"
  11. #include <varutil.h>
  12. #include "dochost.h"
  13. #include <mluisupp.h>
  14. #include <downloadmgr.h>
  15. #include "apithk.h"
  16. #include "richedit.h"
  17. #include <brutil.h>
  18. #define MIME
  19. #include "filetype.h"
  20. #define ALLFILE_WILDCARD TEXT("*.*")
  21. #define MAX_BYTES_STRLEN 64
  22. #define CALC_NOW 5 // Recalcs Estimated time left every this many'th call to OnProgress
  23. //
  24. // Enable WinVerifyTrust
  25. //
  26. #define CALL_WVT
  27. #ifdef CALL_WVT
  28. #include "wvtp.h"
  29. //
  30. // Note that this is a global variable. It means we don't call LoadLibrary
  31. // everytime we download an EXE (good), but the user need to reboot if
  32. // WINTRUST.DLL is added later (bad). Since WINTRUST.DLL is part of IE 3.0,
  33. // this is sufficient at this point.
  34. //
  35. Cwvt g_wvt;
  36. HWND g_hDlgActive = NULL; // get rid of this, not needed
  37. //
  38. // A named mutex is being used to determine if a critical operation exist, such as a file download.
  39. // When we detect this we can prevent things like going offline while a download is in progress.
  40. // To start the operation Create the named mutex. When the op is complete, close the handle.
  41. // To see if any pending operations are in progress, Open the named mutex. Success/fail will indicate
  42. // if any pending operations exist. This mechanism is being used to determine if a file download is
  43. // in progress when the user attempts to go offline. If so, we prompt them to let them know that going
  44. // offline will cancel the download(s).
  45. HANDLE g_hCritOpMutex = NULL;
  46. UINT _VerifyTrust(HWND hwnd, LPCTSTR pszFileName, LPCWSTR pszStatusText);
  47. #endif // CALL_WVT
  48. // Do strong typechecking on the parameters
  49. #ifdef SAFECAST
  50. #undef SAFECAST
  51. #endif
  52. #define SAFECAST(_src, _type) (((_type)(_src)==(_src)?0:0), (_type)(_src))
  53. extern HRESULT _GetRequestFlagFromPIB(IBinding *pib, DWORD *pdwOptions);
  54. extern HRESULT _PrepareURLForDisplayUTF8W(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcchOut, BOOL fUTF8Enabled, UINT uiCP);
  55. UINT IE_ErrorMsgBox(IShellBrowser* psb,
  56. HWND hwnd, HRESULT hrError, LPCWSTR szError, LPCTSTR szURL,
  57. UINT idResource, UINT wFlags);
  58. BOOL IsAssociatedWithIE(LPCWSTR pszFileName);
  59. extern "C" EXECUTION_STATE WINAPI pSetThreadExecutionState(EXECUTION_STATE esFlags); // Win2k+, Win98+ kernel32 API
  60. #define DM_DOWNLOAD TF_SHDPROGRESS
  61. #define DM_PROGRESS TF_SHDPROGRESS
  62. #define DM_WVT TF_SHDPROGRESS
  63. #define DWNLDMSG(psz, psz2) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %s", psz, psz2)
  64. #define DWNLDMSG2(psz, x) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %x", psz, x)
  65. #define DWNLDMSG3(psz, x, y) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %x %x", psz, x, y)
  66. #define DWNLDMSG4(psz, x, y, z) TraceMsg(DM_DOWNLOAD, "shd TR-DWNLD::%s %x %x %x", psz, x, y, z)
  67. #define SAFEMSG(psz, psz2) TraceMsg(0, "shd TR-SAFE::%s %s", psz, psz2)
  68. #define SAFEMSG2(psz, x) TraceMsg(0, "shd TR-SAFE::%s %x", psz, x)
  69. #define EXPMSG(psz, psz2) TraceMsg(0, "shd TR-EXP::%s %s", psz, psz2)
  70. #define MDLGMSG(psz, x) TraceMsg(0, "shd TR-MODELESS::%s %x", psz, x)
  71. #define MSGMSG(psz, x) TraceMsg(TF_SHDTHREAD, "ief MMSG::%s %x", psz, x)
  72. #define PARKMSG(psz, x) TraceMsg(TF_SHDTHREAD, "ief MPARK::%s %x", psz, x)
  73. // File name and 32 for the rest of the title string
  74. #define TITLE_LEN (256 + 32)
  75. #define MAX_DISPLAY_LEN 96
  76. #define MAX_SCHEME_STRING 16
  77. class CDownload : public IBindStatusCallback
  78. , public IAuthenticate
  79. , public IServiceProvider
  80. , public IHttpNegotiate
  81. , public IWindowForBindingUI
  82. {
  83. public:
  84. // *** IUnknown methods ***
  85. STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj);
  86. STDMETHODIMP_(ULONG) AddRef(void) ;
  87. STDMETHODIMP_(ULONG) Release(void);
  88. // *** IAuthenticate ***
  89. STDMETHODIMP Authenticate(
  90. HWND *phwnd,
  91. LPWSTR *pszUsername,
  92. LPWSTR *pszPassword);
  93. // *** IServiceProvider ***
  94. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObj);
  95. // *** IBindStatusCallback ***
  96. STDMETHODIMP OnStartBinding(
  97. /* [in] */ DWORD grfBSCOption,
  98. /* [in] */ IBinding *pib);
  99. STDMETHODIMP GetPriority(
  100. /* [out] */ LONG *pnPriority);
  101. STDMETHODIMP OnLowResource(
  102. /* [in] */ DWORD reserved);
  103. STDMETHODIMP OnProgress(
  104. /* [in] */ ULONG ulProgress,
  105. /* [in] */ ULONG ulProgressMax,
  106. /* [in] */ ULONG ulStatusCode,
  107. /* [in] */ LPCWSTR szStatusText);
  108. STDMETHODIMP OnStopBinding(
  109. /* [in] */ HRESULT hresult,
  110. /* [in] */ LPCWSTR szError);
  111. STDMETHODIMP GetBindInfo(
  112. /* [out] */ DWORD *grfBINDINFOF,
  113. /* [unique][out][in] */ BINDINFO *pbindinfo);
  114. STDMETHODIMP OnDataAvailable(
  115. /* [in] */ DWORD grfBSCF,
  116. /* [in] */ DWORD dwSize,
  117. /* [in] */ FORMATETC *pformatetc,
  118. /* [in] */ STGMEDIUM *pstgmed);
  119. STDMETHODIMP OnObjectAvailable(
  120. /* [in] */ REFIID riid,
  121. /* [iid_is][in] */ IUnknown *punk);
  122. /* *** IHttpNegotiate *** */
  123. STDMETHODIMP BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders,
  124. DWORD dwReserved, LPWSTR *pszAdditionalHeaders);
  125. STDMETHODIMP OnResponse(DWORD dwResponseCode,
  126. LPCWSTR szResponseHeaders,
  127. LPCWSTR szRequestHeaders,
  128. LPWSTR *pszAdditionalRequestHeaders);
  129. STDMETHODIMP GetWindow(REFGUID RefGUI, HWND* phWnd);
  130. protected:
  131. LONG _cRef;
  132. LONG _cRefDLD;
  133. IBinding* _pib;
  134. IBindCtx* _pbc;
  135. CDocObjectHost *_pdoh;
  136. HWND _hDlg;
  137. HWND _hwndToolTips;
  138. BOOL _fSaveAs : 1;
  139. BOOL _fGotFile : 1;
  140. BOOL _fFirstTickValid : 1;
  141. BOOL _fEndDialogCalled : 1;
  142. BOOL _fDontPostQuitMsg : 1; // Posts WM_QUIT message in destructor
  143. BOOL _fCallVerifyTrust : 1;
  144. BOOL _fStrsLoaded : 1;
  145. BOOL _fSafe : 1; // no need to call IsSafe dialog
  146. BOOL _fDownloadStarted : 1; // Have we started receiving data
  147. BOOL _fDownloadCompleted : 1; // We have received BSCF_LASTDATANOTIFICATION
  148. BOOL _fDeleteFromCache : 1; // Delete the file from cache when done
  149. BOOL _fWriteHistory : 1; // Should it be written to history? (SECURITY)
  150. BOOL _fDismissDialog : 1;
  151. BOOL _fUTF8Enabled : 1;
  152. DWORD _dwFirstTick;
  153. DWORD _dwFirstSize;
  154. DWORD _dwTotalSize; // Size of file downloaded so far
  155. DWORD _dwFileSize; // Size of file to download
  156. HICON _hicon;
  157. TCHAR _szPath[MAX_PATH]; // ok with MAX_PATH
  158. TCHAR _szSaveToFile[MAX_PATH]; // File to Save to
  159. TCHAR _szEstimateTime[MAX_PATH]; // ok with MAX_PATH
  160. TCHAR _szBytesCopied[MAX_PATH]; // ok with MAX_PATH
  161. TCHAR _szTitlePercent[TITLE_LEN];
  162. TCHAR _szTitleBytes[TITLE_LEN];
  163. TCHAR _szTransferRate[TITLE_LEN];
  164. TCHAR _szURL[MAX_URL_STRING];
  165. TCHAR _szDisplay[MAX_DISPLAY_LEN]; // URL to be displayed
  166. TCHAR _szDefDlgTitle[256];
  167. TCHAR _szExt[10];
  168. DWORD _grfBINDF;
  169. BINDINFO* _pbinfo;
  170. LPWSTR _pwzHeaders;
  171. IMoniker* _pmk; // WARNING: No ref-count (only for modal)
  172. LPWSTR _pwszDisplayName;
  173. DWORD _dwVerb;
  174. UINT _uiCP; // Code page
  175. DWORD _dwOldEst;
  176. ULONG _ulOldProgress;
  177. DWORD _dwOldRate;
  178. DWORD _dwOldPcent;
  179. DWORD _dwOldCur;
  180. BOOL _fConfirmed;
  181. void SetMoniker(IMoniker* pmk) { _pmk=pmk; }
  182. BOOL _IsModal(void) { return (bool)_pmk; }
  183. virtual ~CDownload();
  184. friend INT_PTR CALLBACK DownloadDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  185. friend INT_PTR CALLBACK SafeOpenDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  186. UINT _MayAskUserIsFileSafeToOpen(LPCTSTR pszMime);
  187. BOOL _GetSaveLocation(void);
  188. BOOL _SaveFile(void);
  189. void _DeleteFromCache(void);
  190. ULONG AddRefDLD(void);
  191. ULONG ReleaseDLD(void);
  192. HRESULT PerformVirusScan(LPCTSTR szFileName);
  193. public:
  194. CDownload(BOOL fSaveAs = FALSE, LPWSTR pwzHeaders = NULL,
  195. DWORD grfBINDF = BINDF_ASYNCHRONOUS, BINDINFO* pbinfo = NULL,
  196. BOOL fSafe = FALSE, DWORD dwVerb = BINDVERB_GET, LPCTSTR pszRedir=NULL, UINT uiCP=CP_ACP, BOOL fConfirmed = FALSE);
  197. 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);
  198. HRESULT StartBinding(IMoniker* pmk, IBindCtx *pbc = NULL);
  199. void EndDialogDLD(UINT id);
  200. void ShowStats(void);
  201. BOOL SetDismissDialogFlag(BOOL fDismiss) { return(_fDismissDialog = fDismiss); }
  202. BOOL GetDismissDialogFlag(void) { return(_fDismissDialog); }
  203. #ifdef USE_LOCKREQUEST
  204. HRESULT LockRequestHandle(void);
  205. #endif
  206. };
  207. CDownload::CDownload(BOOL fSaveAs, LPWSTR pwzHeaders, DWORD grfBINDF, BINDINFO* pbinfo, BOOL fSafe, DWORD dwVerb, LPCTSTR pszRedir, UINT uiCP, BOOL fConfirmed)
  208. : _cRef(1), _fSaveAs(fSaveAs), _fWriteHistory(1),
  209. _grfBINDF(grfBINDF), _pbinfo(pbinfo), _fSafe(fSafe), _pwzHeaders(pwzHeaders), _dwVerb(dwVerb), _uiCP(uiCP), _fConfirmed(fConfirmed)
  210. {
  211. ASSERT(_fStrsLoaded == FALSE);
  212. ASSERT(_fDownloadStarted == FALSE);
  213. ASSERT(_fDownloadCompleted == FALSE);
  214. ASSERT(_fGotFile == FALSE);
  215. ASSERT(_fUTF8Enabled == FALSE);
  216. ASSERT(_hDlg == NULL);
  217. ASSERT(_pwszDisplayName == NULL);
  218. ASSERT(_dwTotalSize == 0);
  219. ASSERT(_dwFileSize == 0);
  220. ASSERT(_dwFirstTick == 0);
  221. ASSERT(_ulOldProgress == 0);
  222. ASSERT(_dwOldRate == 0);
  223. ASSERT(_dwOldPcent == 0);
  224. ASSERT(_dwOldCur == 0);
  225. _dwOldEst = 0xffffffff;
  226. if (pszRedir && lstrlen(pszRedir))
  227. StrCpyN(_szURL, pszRedir, ARRAYSIZE(_szURL) - 1); // -1 ???
  228. TraceMsg(TF_SHDLIFE, "CDownload::CDownload being constructed");
  229. }
  230. void ProcessStartbindingError(HWND hWnd, LPTSTR pszTitle, LPTSTR pszText, UINT uiFlag, HRESULT hres)
  231. {
  232. if (E_ACCESSDENIED == hres)
  233. {
  234. pszText = MAKEINTRESOURCE(IDS_DOWNLOADDISALLOWED);
  235. pszTitle = MAKEINTRESOURCE(IDS_SECURITYALERT);
  236. uiFlag = MB_ICONWARNING;
  237. }
  238. MLShellMessageBox(hWnd, pszText, pszTitle, MB_OK | MB_SETFOREGROUND | uiFlag );
  239. if (IsValidHWND(hWnd))
  240. {
  241. FORWARD_WM_COMMAND(hWnd, IDCANCEL, NULL, 0, PostMessage);
  242. }
  243. }
  244. HRESULT SelectPidlInSFV(IShellFolderViewDual *psfv, LPCITEMIDLIST pidl, DWORD dwOpts)
  245. {
  246. VARIANT var;
  247. HRESULT hr = InitVariantFromIDList(&var, pidl);
  248. if (SUCCEEDED(hr))
  249. {
  250. hr = psfv->SelectItem(&var, dwOpts);
  251. VariantClear(&var);
  252. }
  253. return hr;
  254. }
  255. void OpenFolderPidl(LPCITEMIDLIST pidl)
  256. {
  257. SHELLEXECUTEINFO shei = { 0 };
  258. shei.cbSize = sizeof(shei);
  259. shei.fMask = SEE_MASK_INVOKEIDLIST;
  260. shei.nShow = SW_SHOWNORMAL;
  261. shei.lpIDList = (LPITEMIDLIST)pidl;
  262. ShellExecuteEx(&shei);
  263. }
  264. STDAPI OpenContainingFolderAndGetShellFolderView(HWND hwnd, LPCITEMIDLIST pidlFolder, IShellFolderViewDual **ppsfv)
  265. {
  266. *ppsfv = NULL;
  267. IWebBrowserApp *pauto;
  268. HRESULT hr = SHGetIDispatchForFolder(pidlFolder, &pauto);
  269. if (SUCCEEDED(hr))
  270. {
  271. // We have IDispatch for window, now try to get one for
  272. // the folder object...
  273. HWND hwnd;
  274. if (SUCCEEDED(pauto->get_HWND((LONG_PTR *)&hwnd)))
  275. {
  276. // Make sure we make this the active window
  277. SetForegroundWindow(hwnd);
  278. ShowWindow(hwnd, SW_SHOWNORMAL);
  279. }
  280. IDispatch * pautoDoc;
  281. hr = pauto->get_Document(&pautoDoc);
  282. if (SUCCEEDED(hr))
  283. {
  284. hr = pautoDoc->QueryInterface(IID_PPV_ARG(IShellFolderViewDual, ppsfv));
  285. pautoDoc->Release();
  286. }
  287. pauto->Release();
  288. }
  289. return hr;
  290. }
  291. //
  292. // Stolen (and modified) from shell\ext\mydocs2\prop.cpp which was from link.c in shell32.dll
  293. //
  294. void FindTarget(HWND hDlg, LPTSTR pPath)
  295. {
  296. USHORT uSave;
  297. LPITEMIDLIST pidl = ILCreateFromPath( pPath );
  298. if (!pidl)
  299. return;
  300. LPITEMIDLIST pidlLast = ILFindLastID(pidl);
  301. // get the folder, special case for root objects (My Computer, Network)
  302. // hack off the end if it is not the root item
  303. if (pidl != pidlLast)
  304. {
  305. uSave = pidlLast->mkid.cb;
  306. pidlLast->mkid.cb = 0;
  307. }
  308. else
  309. uSave = 0;
  310. LPITEMIDLIST pidlDesk;
  311. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidlDesk)))
  312. {
  313. BOOL fIsDesktopDir = pidlDesk && ILIsEqual(pidl, pidlDesk);
  314. if (fIsDesktopDir || !uSave) // if it's in the desktop dir or pidl == pidlLast (uSave == 0 from above)
  315. {
  316. //
  317. // It's on the desktop...
  318. //
  319. MLShellMessageBox(hDlg, (LPTSTR)IDS_ON_DESKTOP, (LPTSTR)IDS_FIND_TITLE,
  320. MB_OK | MB_ICONINFORMATION | MB_APPLMODAL | MB_TOPMOST);
  321. }
  322. else
  323. {
  324. if (WhichPlatform() == PLATFORM_BROWSERONLY)
  325. {
  326. OpenFolderPidl(pidl);
  327. }
  328. else
  329. {
  330. IShellFolderViewDual *psfv;
  331. if (SUCCEEDED(OpenContainingFolderAndGetShellFolderView(hDlg, uSave ? pidl : pidlDesk, &psfv)))
  332. {
  333. if (uSave)
  334. pidlLast->mkid.cb = uSave;
  335. SelectPidlInSFV(psfv, pidlLast, SVSI_SELECT | SVSI_FOCUSED | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
  336. psfv->Release();
  337. }
  338. }
  339. }
  340. ILFree(pidlDesk);
  341. }
  342. ILFree(pidl);
  343. }
  344. BOOL SetExemptDelta(LPCTSTR pszURL, DWORD dwExemptDelta)
  345. {
  346. BOOL fRC;
  347. INTERNET_CACHE_ENTRY_INFO icei;
  348. icei.dwStructSize = sizeof(icei);
  349. icei.dwExemptDelta = dwExemptDelta; // Number of seconds from last access time to keep entry
  350. // Retry setting the exempt delta if it fails since wininet may have either not have created the
  351. // entry yet or might have it locked.
  352. for (int i = 0; i < 5; i++)
  353. {
  354. if (fRC = SetUrlCacheEntryInfo(pszURL, &icei, CACHE_ENTRY_EXEMPT_DELTA_FC))
  355. break;
  356. Sleep(1000);
  357. }
  358. return fRC;
  359. }
  360. INT_PTR CALLBACK DownloadDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  361. {
  362. static fInBrowseDir = FALSE;
  363. CDownload* pdld = (CDownload*) GetWindowLongPtr(hDlg, DWLP_USER);
  364. DWORD dwExStyle = 0;
  365. TCHAR szURL[MAX_URL_STRING]; // make copies since EndDialog will delete CDownload obj
  366. BOOL fDownloadAborted;
  367. DWNLDMSG4("DownloadDlgProc ", uMsg, wParam, lParam);
  368. if ((pdld == NULL) && (uMsg != WM_INITDIALOG))
  369. {
  370. RIPMSG(TRUE, "CDownload freed (pdld == NULL) && (uMsg != WM_INITDIALOG)");
  371. return FALSE;
  372. }
  373. switch (uMsg) {
  374. case WM_INITDIALOG:
  375. {
  376. TCHAR szYesNo[20];
  377. DWORD dwType = REG_SZ;
  378. DWORD dwSize = ARRAYSIZE(szYesNo);
  379. if (lParam == NULL)
  380. return FALSE;
  381. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  382. pdld = (CDownload*)lParam;
  383. pdld->_hDlg = hDlg;
  384. EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
  385. EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
  386. EnableWindow(GetDlgItem(hDlg, IDD_OPENFILE), FALSE);
  387. EnableWindow(GetDlgItem(hDlg, IDD_BROWSEDIR), FALSE);
  388. // On BiDi Loc Win98 & NT5 mirroring will take care of that
  389. // Need to fix only on BiBi Win95 Loc
  390. if (g_bBiDiW95Loc)
  391. {
  392. SetWindowBits(GetDlgItem(hDlg, IDD_DIR), GWL_EXSTYLE, WS_EX_RTLREADING, WS_EX_RTLREADING);
  393. }
  394. MLLoadString(IDS_DEFDLGTITLE, pdld->_szDefDlgTitle, ARRAYSIZE(pdld->_szDefDlgTitle));
  395. if (pdld->_hwndToolTips = CreateWindowEx(dwExStyle, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP,
  396. CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
  397. hDlg, NULL, HINST_THISDLL, NULL))
  398. {
  399. TOOLINFO ti;
  400. ti.cbSize = sizeof(ti);
  401. ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  402. ti.hwnd = hDlg;
  403. ti.uId = (UINT_PTR) GetDlgItem(hDlg, IDD_NAME);
  404. ti.lpszText = LPSTR_TEXTCALLBACK;
  405. ti.hinst = HINST_THISDLL;
  406. GetWindowRect((HWND)ti.uId, &ti.rect);
  407. SendMessage(pdld->_hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
  408. }
  409. // make sure we support cross-lang platform
  410. SHSetDefaultDialogFont(hDlg, IDD_NAME);
  411. pdld->SetDismissDialogFlag(FALSE);
  412. if ( SHRegGetUSValue( TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
  413. TEXT("NotifyDownloadComplete"),
  414. &dwType, (void *)szYesNo, &dwSize, FALSE, NULL, 0 ) == ERROR_SUCCESS )
  415. {
  416. pdld->SetDismissDialogFlag(!StrCmpI(szYesNo, TEXT("No")));
  417. }
  418. CheckDlgButton(hDlg, IDD_DISMISS, pdld->GetDismissDialogFlag());
  419. DWNLDMSG("DownloadDlgProc", "Got WM_INITDIALOG");
  420. Animate_OpenEx(GetDlgItem(hDlg, IDD_ANIMATE), HINST_THISDLL, MAKEINTRESOURCE(IDA_DOWNLOAD));
  421. ShowWindow(GetDlgItem(hDlg, IDD_DOWNLOADICON), SW_HIDE);
  422. g_hCritOpMutex = CreateMutexA(NULL, TRUE, "CritOpMutex");
  423. // Automatically start binding if we are posting synchronously.
  424. if (pdld->_IsModal())
  425. {
  426. HRESULT hres = pdld->StartBinding(pdld->_pmk);
  427. ASSERT(pdld->_pmk);
  428. if (FAILED(hres))
  429. {
  430. ProcessStartbindingError(hDlg, MAKEINTRESOURCE(IDS_DOWNLOADFAILED),
  431. pdld->_szDisplay, MB_ICONWARNING, hres);
  432. }
  433. }
  434. return TRUE;
  435. }
  436. case WM_SIZE:
  437. if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
  438. SetWindowText(hDlg, pdld->_szDefDlgTitle);
  439. break;
  440. case WM_NOTIFY:
  441. {
  442. LPTOOLTIPTEXT lpTT = (LPTOOLTIPTEXT) lParam;
  443. if (lpTT->hdr.code == TTN_NEEDTEXT)
  444. {
  445. lpTT->lpszText = pdld->_szURL;
  446. lpTT->hinst = NULL;
  447. }
  448. }
  449. break;
  450. case WM_COMMAND:
  451. DWNLDMSG2("DownloadDlgProc WM_COMMAND id =", GET_WM_COMMAND_ID(wParam, lParam));
  452. switch (GET_WM_COMMAND_ID(wParam, lParam))
  453. {
  454. case IDD_SAVEAS:
  455. if (pdld)
  456. {
  457. pdld->AddRefDLD();
  458. BOOL fSuccess = FALSE;
  459. // Prevent someone from canceling dialog while the shell copy etc. is going on
  460. EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
  461. // If zone check fails or if we found virus, bail out and remove file from cache.
  462. if (pdld->PerformVirusScan(pdld->_szPath) != S_OK)
  463. {
  464. pdld->_fDeleteFromCache = TRUE;
  465. pdld->EndDialogDLD(IDCANCEL);
  466. break;
  467. }
  468. fSuccess = pdld->_SaveFile();
  469. AddUrlToUrlHistoryStg(pdld->_pwszDisplayName, NULL, NULL, pdld->_fWriteHistory, NULL, NULL, NULL);
  470. // -- BharatS --- Only add to history if Visible ?
  471. IEPlaySound(TEXT("SystemAsterisk"), TRUE);
  472. if (fSuccess)
  473. {
  474. if (pdld->SetDismissDialogFlag(IsDlgButtonChecked(hDlg, IDD_DISMISS) == BST_CHECKED))
  475. {
  476. StrCpyN(szURL, pdld->_szURL, ARRAYSIZE(szURL));
  477. pdld->EndDialogDLD(IDCANCEL);
  478. SetExemptDelta(szURL, 0);
  479. }
  480. else
  481. {
  482. TCHAR szStr[MAX_PATH];
  483. if (MLLoadString(IDS_CLOSE, szStr, ARRAYSIZE(szStr)))
  484. {
  485. SetWindowText(GetDlgItem(hDlg, IDCANCEL), szStr);
  486. }
  487. ShowWindow(GetDlgItem(hDlg, IDD_ANIMATE), SW_HIDE);
  488. ShowWindow(GetDlgItem(hDlg, IDD_DNLDESTTIME), SW_HIDE);
  489. ShowWindow(GetDlgItem(hDlg, IDD_DNLDCOMPLETEICON), SW_SHOW);
  490. ShowWindow(GetDlgItem(hDlg, IDD_DNLDCOMPLETETEXT), SW_SHOW);
  491. ShowWindow(GetDlgItem(hDlg, IDD_DNLDTIME), SW_SHOW);
  492. MLLoadString(IDS_SAVED, szStr, ARRAYSIZE(szStr));
  493. SetDlgItemText(hDlg, IDD_OPENIT, szStr);
  494. MLLoadString(IDS_DOWNLOADCOMPLETE, szStr, ARRAYSIZE(szStr));
  495. SetWindowText(hDlg, szStr);
  496. EnableWindow(GetDlgItem(hDlg, IDD_OPENFILE), TRUE);
  497. EnableWindow(GetDlgItem(hDlg, IDD_BROWSEDIR), TRUE);
  498. pdld->ShowStats();
  499. pdld->ReleaseDLD();
  500. }
  501. }
  502. else
  503. {
  504. pdld->ReleaseDLD();
  505. }
  506. EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
  507. }
  508. break;
  509. case IDCANCEL: // Cancel on abort, Close on dismiss
  510. if (pdld && IsWindowEnabled(GetDlgItem(hDlg, IDCANCEL)))
  511. {
  512. pdld->AddRefDLD();
  513. fDownloadAborted = pdld->_fDownloadStarted && !pdld->_fDownloadCompleted;
  514. StrCpyN(szURL, pdld->_szURL, ARRAYSIZE(szURL));
  515. if (pdld->_pib)
  516. {
  517. HRESULT hresT;
  518. hresT = pdld->_pib->Abort();
  519. TraceMsg(DM_DOWNLOAD, "DownloadDlgProc::IDCANCEL: called _pib->Abort() hres=%x", pdld->_pib, hresT);
  520. }
  521. pdld->EndDialogDLD(IDCANCEL);
  522. // Download was canceled. Increase exempt time to keep downloaded a bit in case download is resumed
  523. SetExemptDelta(szURL, fDownloadAborted ?60*60*24 :0);
  524. }
  525. break;
  526. case IDD_BROWSEDIR:
  527. if (!fInBrowseDir)
  528. {
  529. pdld->AddRefDLD();
  530. fInBrowseDir = TRUE;
  531. FindTarget(hDlg, pdld->_szSaveToFile);
  532. // Since EndDialogDLD will probably release our structure...
  533. HWND hwndToolTips = pdld->_hwndToolTips;
  534. pdld->_hwndToolTips = NULL;
  535. pdld->EndDialogDLD(IDOK);
  536. if (IsWindow(hwndToolTips))
  537. DestroyWindow(hwndToolTips);
  538. fInBrowseDir = FALSE;
  539. }
  540. #if DEBUG
  541. else
  542. {
  543. TraceMsg(DM_DOWNLOAD, "DownloadDlgProc rcvd IDD_BROWSEDIR msg while already processing IDD_BROWSEDIR");
  544. }
  545. #endif
  546. break;
  547. case IDD_OPENFILE:
  548. StrCpyN(pdld->_szPath, pdld->_szSaveToFile, ARRAYSIZE(pdld->_szPath));
  549. case IDOK:
  550. ShowWindow(GetDlgItem(hDlg, IDD_DISMISS), SW_HIDE);
  551. if (pdld)
  552. {
  553. pdld->AddRefDLD();
  554. if (pdld->_fGotFile)
  555. {
  556. // If zone check fails or if we found virus, bail out and remove file from cache.
  557. if ( pdld->PerformVirusScan(pdld->_szPath) != S_OK )
  558. {
  559. pdld->_fDeleteFromCache = TRUE;
  560. }
  561. else
  562. {
  563. TCHAR szQuotedPath[MAX_PATH];
  564. StrCpyN(szQuotedPath, pdld->_szPath, MAX_PATH);
  565. if (PLATFORM_INTEGRATED == WhichPlatform())
  566. {
  567. PathQuoteSpaces(szQuotedPath);
  568. }
  569. SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO),
  570. SEE_MASK_NOZONECHECKS, hDlg, NULL, szQuotedPath, NULL, NULL, SW_SHOWNORMAL, NULL};
  571. if (!ShellExecuteEx(&sei))
  572. {
  573. DWNLDMSG2("ShellExecute failed", GetLastError());
  574. }
  575. }
  576. }
  577. if (!pdld->_fDeleteFromCache)
  578. AddUrlToUrlHistoryStg(pdld->_pwszDisplayName, NULL, NULL, pdld->_fWriteHistory, NULL, NULL, NULL);
  579. // Since EndDialogDLD will probably release our structure...
  580. HWND hwndToolTips = pdld->_hwndToolTips;
  581. pdld->_hwndToolTips = NULL;
  582. StrCpyN(szURL, pdld->_szURL, ARRAYSIZE(szURL));
  583. pdld->EndDialogDLD(!pdld->_fDeleteFromCache ?IDOK :IDCANCEL);
  584. if (IsWindow(hwndToolTips))
  585. DestroyWindow(hwndToolTips);
  586. SetExemptDelta(szURL, 0);
  587. }
  588. break;
  589. }
  590. break;
  591. case WM_ACTIVATE:
  592. if (pdld && pdld->_IsModal())
  593. return FALSE;
  594. else
  595. {
  596. // There can be race conditions here. If the WA_ACTIVATE messages came in reverse
  597. // order, we might end up setting up the wrong hDlg as the active window. As of right now,
  598. // the only thing g_hDlgActive is being used for is for the IsDialogMessage in
  599. // CDownload_MayProcessMessage. And since there is only one tab-able control in this
  600. // dialog, a wrong hDlg in the g_hDlgActive should not hurt.
  601. ENTERCRITICAL;
  602. if (LOWORD(wParam) == WA_INACTIVE)
  603. {
  604. if (g_hDlgActive == hDlg)
  605. {
  606. MDLGMSG(TEXT("being inactivated"), hDlg);
  607. g_hDlgActive = NULL;
  608. }
  609. }
  610. else
  611. {
  612. MDLGMSG(TEXT("being activated"), hDlg);
  613. g_hDlgActive = hDlg;
  614. }
  615. LEAVECRITICAL;
  616. }
  617. break;
  618. case WM_NCDESTROY:
  619. MDLGMSG(TEXT("being destroyed"), hDlg);
  620. ASSERT((pdld && pdld->_IsModal()) || (g_hDlgActive != hDlg));
  621. SetWindowLongPtr(hDlg, DWLP_USER, NULL);
  622. return FALSE;
  623. case WM_DESTROY:
  624. SHRemoveDefaultDialogFont(hDlg);
  625. return FALSE;
  626. default:
  627. return FALSE;
  628. }
  629. return TRUE;
  630. }
  631. void CDownload::ShowStats(void)
  632. {
  633. TCHAR szStr[MAX_PATH];
  634. TCHAR szBytes[MAX_BYTES_STRLEN];
  635. TCHAR szTime[MAX_BYTES_STRLEN];
  636. TCHAR *pszTime = szTime;
  637. DWORD dwSpent = (GetTickCount() - _dwFirstTick);
  638. SetDlgItemText(_hDlg, IDD_NAME, _szDisplay);
  639. MLLoadString(IDS_BYTESTIME, _szBytesCopied, ARRAYSIZE(_szBytesCopied));
  640. StrFromTimeInterval(szTime, ARRAYSIZE(szTime), (dwSpent < 1000) ?1000 :dwSpent, 3);
  641. while(pszTime && *pszTime && *pszTime == TEXT(' '))
  642. pszTime++;
  643. _FormatMessage(_szBytesCopied, szStr, ARRAYSIZE(szStr),
  644. StrFormatByteSize(_dwTotalSize, szBytes, MAX_BYTES_STRLEN), pszTime);
  645. SetDlgItemText(_hDlg, IDD_TIMEEST, szStr);
  646. // division below requires at least 1/2 second to have elapsed.
  647. if (dwSpent < 500)
  648. dwSpent = 500;
  649. _FormatMessage(_szTransferRate, szStr, ARRAYSIZE(szStr),
  650. StrFormatByteSize(_dwTotalSize / ((dwSpent+500)/1000), szBytes, MAX_BYTES_STRLEN));
  651. SetDlgItemText(_hDlg, IDD_TRANSFERRATE, szStr);
  652. SetForegroundWindow(_hDlg);
  653. }
  654. void CDownload::EndDialogDLD(UINT id)
  655. {
  656. if (ReleaseDLD() != 0)
  657. return;
  658. ASSERT(!_fEndDialogCalled);
  659. _fEndDialogCalled = TRUE;
  660. DWNLDMSG2("EndDialogDLD cRef ==", _cRef);
  661. TraceMsg(TF_SHDREF, "CDownload::EndDialogDLD called when _cRef=%d", _cRef);
  662. _fDismissDialog = (IsDlgButtonChecked(_hDlg, IDD_DISMISS) == BST_CHECKED);
  663. if (SHRegSetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
  664. TEXT("NotifyDownloadComplete"),
  665. REG_SZ, _fDismissDialog ?TEXT("no") :TEXT("yes"), _fDismissDialog ?sizeof(TEXT("no")-sizeof(TCHAR)) :sizeof(TEXT("yes")-sizeof(TCHAR)), SHREGSET_FORCE_HKCU) != ERROR_SUCCESS)
  666. {
  667. DWNLDMSG2("SHRegSetUSValue NotifyDownloadComplete failed", GetLastError());
  668. }
  669. // HACK: USER does not send us WM_ACTIVATE when this dialog is
  670. // being destroyed when it was activated. We need to work around
  671. // this bug(?) by cleaning up g_hDlgActive.
  672. if (g_hDlgActive == _hDlg)
  673. {
  674. MDLGMSG(TEXT("EndDialogDLD putting NULL in g_hDlgActive"), _hDlg);
  675. g_hDlgActive = NULL;
  676. }
  677. DestroyWindow(_hDlg);
  678. Release();
  679. }
  680. #define SZEXPLORERKEY TEXT("Software\\Microsoft\\Internet Explorer")
  681. #define SZDOWNLOADDIRVAL TEXT("Download Directory")
  682. // _GetSaveLocation
  683. // - Tries to get the current download directory from the registry
  684. // default is the Desktop
  685. // - Shows the FileSave Dialog
  686. // - If the user changed the download location, save that off into
  687. // the registry for future downloads
  688. // - _szSaveToFile is updated (this will be used by _SaveFile()
  689. //
  690. // Returns TRUE, if successfully done.
  691. //
  692. BOOL _GetSaveLocation(HWND hDlg, LPTSTR pszPath, LPTSTR pszExt, LPTSTR pszSaveToFile, UINT cchSaveToFile, BOOL fUTF8Enabled, UINT uiCP)
  693. {
  694. BOOL fRet = FALSE;
  695. TCHAR * pszSaveTo = NULL;
  696. HKEY hKey;
  697. BOOL fRegFileType = FALSE;
  698. TCHAR szDownloadDir[MAX_PATH];
  699. TCHAR szBuffer[MAX_PATH];
  700. TCHAR szTemp[40];
  701. LPTSTR pszWalk = szBuffer;
  702. int cchWalk = ARRAYSIZE(szBuffer);
  703. int cch;
  704. szDownloadDir[0] = 0;
  705. // If we don't have a download directory in the registry, download to the desktop
  706. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZEXPLORERKEY, 0, KEY_READ, &hKey))
  707. {
  708. DWORD dwType, cbData = sizeof(szDownloadDir);
  709. RegQueryValueEx(hKey, SZDOWNLOADDIRVAL, NULL, &dwType, (LPBYTE)szDownloadDir, &cbData);
  710. RegCloseKey(hKey);
  711. }
  712. if (szDownloadDir[0] == 0)
  713. SHGetSpecialFolderPath(NULL, szDownloadDir, CSIDL_DESKTOPDIRECTORY, FALSE);
  714. // Get the file name. If there is no filename. create one called using the string resource in IDS_DOCUMENT
  715. pszSaveTo = PathFindFileName(pszPath);
  716. if (pszSaveTo)
  717. {
  718. DWORD cchData = cchSaveToFile;
  719. // Unescape the filename suggested by wininet.
  720. if (_PrepareURLForDisplayUTF8W(pszSaveTo, pszSaveToFile, &cchData, fUTF8Enabled, uiCP) != S_OK)
  721. StrCpyN(pszSaveToFile, pszSaveTo, cchSaveToFile);
  722. // Strip out any path that may have been encoded
  723. TCHAR * pszSaveToDst = pszSaveToFile;
  724. pszSaveTo = PathFindFileName(pszSaveToFile);
  725. if (pszSaveTo != pszSaveToFile)
  726. {
  727. while(*pszSaveTo)
  728. *pszSaveToDst++ = *pszSaveTo++;
  729. *pszSaveToDst = *pszSaveTo;
  730. }
  731. // Strip out the the cache's typical decoration of "(nn)"
  732. PathUndecorate (pszSaveToFile);
  733. }
  734. else
  735. MLLoadString(IDS_DOCUMENT, pszSaveToFile, cchSaveToFile);
  736. if (!g_fRunningOnNT) // Win9x isn't able to deal with DBCS chars in edit controls when UI lang is non-native OS lang
  737. {
  738. CHAR szBufA[MAX_PATH*2];
  739. int iRC = WideCharToMultiByte(CP_ACP, 0, pszSaveToFile, -1, szBufA, ARRAYSIZE(szBufA), NULL, NULL);
  740. if (iRC == 0) // If we are unable to convert using system code page
  741. *pszSaveToFile = TEXT('\0'); // make suggested file name blank
  742. }
  743. OPENFILENAME OFN = {0};
  744. OFN.lStructSize = sizeof(OFN);
  745. OFN.hwndOwner = hDlg;
  746. OFN.nMaxFile = cchSaveToFile;
  747. OFN.lpstrInitialDir = szDownloadDir;
  748. OFN.lpstrFile = pszSaveToFile;
  749. OFN.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER |
  750. OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
  751. if (!pszExt || !*pszExt)
  752. pszExt = PathFindExtension(pszPath);
  753. if (pszExt && *pszExt)
  754. OFN.lpstrDefExt = pszExt;
  755. // Try to get the file type name from the registry. To add to the filter pair strings
  756. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey))
  757. {
  758. DWORD dwType, cbData = sizeof(szBuffer);
  759. fRegFileType = (ERROR_SUCCESS == RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)szBuffer, &cbData));
  760. RegCloseKey(hKey);
  761. }
  762. if (fRegFileType)
  763. {
  764. fRegFileType = FALSE;
  765. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ, &hKey))
  766. {
  767. DWORD dwType, cbData = sizeof(szBuffer);
  768. szBuffer[0] = 0;
  769. fRegFileType = ERROR_SUCCESS == RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)szBuffer, &cbData);
  770. if (fRegFileType)
  771. {
  772. // Now tack on the second part of the filter pair
  773. int cchBuffer = lstrlen(szBuffer) + 1;
  774. pszWalk = szBuffer + cchBuffer;
  775. cchWalk = ARRAYSIZE(szBuffer) - cchBuffer;
  776. StrCpyN(pszWalk, TEXT("*"), cchWalk);
  777. StrCatBuff(pszWalk, pszExt, --cchWalk); // sub 1 for * above
  778. }
  779. RegCloseKey(hKey);
  780. }
  781. cch = lstrlen(pszWalk);
  782. }
  783. // There was no registry entry for the file type or the entry did not have a default value
  784. // So create the file name type - "<file extension> DOCUMENT"
  785. if (!fRegFileType || !(*szBuffer))
  786. {
  787. szBuffer[0] = 0;
  788. pszWalk = szBuffer;
  789. cchWalk = ARRAYSIZE(szBuffer);
  790. MLLoadString(IDS_EXTDOCUMENT, szTemp, ARRAYSIZE(szTemp));
  791. cch = wnsprintf(pszWalk, cchWalk, szTemp, pszExt, TEXT('\0'), pszExt);
  792. }
  793. // Add in the pair for "*.* All files"
  794. pszWalk += (cch + 1);
  795. cchWalk -= (cch + 1);
  796. MLLoadString(IDS_ALLFILES, szTemp, ARRAYSIZE(szTemp));
  797. StrCpyN(pszWalk, szTemp, cchWalk);
  798. cch = lstrlen(pszWalk) + 1;
  799. pszWalk += cch;
  800. cchWalk -= cch;
  801. StrCpyN(pszWalk, ALLFILE_WILDCARD, cchWalk);
  802. cch = (lstrlen( ALLFILE_WILDCARD )+1); //Add the second NULL to the end of the string
  803. pszWalk += cch;
  804. cchWalk -= cch;
  805. if (cchWalk > 0)
  806. *pszWalk = 0; //because we had some garbage put after memset.
  807. OFN.lpstrFilter = szBuffer;
  808. if ((fRet = (!SHIsRestricted2W(hDlg, REST_NoSelectDownloadDir, NULL, 0)))
  809. && (fRet = GetSaveFileName(&OFN)))
  810. {
  811. // If the download location was changed, save that off to the registry
  812. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZEXPLORERKEY, 0, KEY_WRITE, &hKey))
  813. {
  814. StrCpyN(szBuffer, pszSaveToFile, ARRAYSIZE(szBuffer));
  815. PathRemoveFileSpec(szBuffer);
  816. if (szBuffer[0])
  817. RegSetValueEx(hKey, SZDOWNLOADDIRVAL, 0, REG_SZ, (LPBYTE)szBuffer, CbFromCch(lstrlen(szBuffer) + 1));
  818. RegCloseKey(hKey);
  819. }
  820. }
  821. return fRet;
  822. }
  823. BOOL CDownload::_GetSaveLocation()
  824. {
  825. return ::_GetSaveLocation(_hDlg, _szPath, _szExt, _szSaveToFile, ARRAYSIZE(_szSaveToFile), _fUTF8Enabled, _uiCP);
  826. }
  827. BOOL CDownload::_SaveFile()
  828. {
  829. SHFILEOPSTRUCT fo = { _hDlg, FO_COPY, _szPath, _szSaveToFile, FOF_NOCONFIRMATION | FOF_NOCOPYSECURITYATTRIBS};
  830. // Be sure the strings are double terminated
  831. DWORD dwLen = (DWORD)min(ARRAYSIZE(_szPath), lstrlen(_szPath) + 1);
  832. if (dwLen == 0) // Not likely, but better to fail than trash someone else's data
  833. return FALSE;
  834. _szPath[dwLen] = TEXT('\0');
  835. _szPath[dwLen-1] = TEXT('\0');
  836. dwLen = (DWORD)min(ARRAYSIZE(_szSaveToFile), lstrlen(_szSaveToFile) + 1);
  837. if (dwLen == 0)
  838. return FALSE;
  839. _szSaveToFile[dwLen] = TEXT('\0');
  840. _szSaveToFile[dwLen-1] = TEXT('\0');
  841. // If the file is in the cache, we probably want to delete it from the
  842. // cache to free up some disk space rather than wait for it to be scavenged.
  843. // This is best done after _pib->Release called from ~CDownload.
  844. _fDeleteFromCache = TRUE;
  845. // Copy the file (which is locked, so can't move it) to its target destination.
  846. return !SHFileOperation(&fo);
  847. }
  848. void CDownload::_DeleteFromCache()
  849. {
  850. INTERNET_CACHE_CONFIG_INFO CCInfo;
  851. DWORD dwCCIBufSize = sizeof(CCInfo);
  852. // Obtain the cache directory path.
  853. if (!GetUrlCacheConfigInfo (&CCInfo, &dwCCIBufSize, CACHE_CONFIG_CONTENT_PATHS_FC))
  854. {
  855. ASSERT(FALSE);
  856. }
  857. else if (0 == StrCmpNI (_szPath,
  858. CCInfo.CachePaths[0].CachePath,
  859. lstrlen(CCInfo.CachePaths[0].CachePath)))
  860. {
  861. // Attempt to delete the file from the cache only if resides under
  862. // the cache directory, otherwise we could in theory nuke a preinstalled
  863. // or edited cache entry. Here a prefix match is also a string prefix
  864. // match since .CachePath will have a trailing slash ('/')
  865. DeleteUrlCacheEntry(_szURL);
  866. }
  867. }
  868. 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)
  869. {
  870. TraceMsg(DM_DOWNLOAD, "CDownLoad::OpenUI called with fSaveAs=%d, verb=%d", fSaveAs, dwVerb);
  871. // CDownload will take ownership pbinfo.
  872. CDownload* pdld = new CDownload(fSaveAs, pwzHeaders, grfBINDF, pbinfo, fSafe, dwVerb, pszRedir, uiCP, fConfirmed);
  873. if (pdld)
  874. {
  875. HWND hwnd = CreateDialogParam(MLGetHinst(),
  876. MAKEINTRESOURCE(DLG_DOWNLOADPROGRESS), NULL, DownloadDlgProc, (LPARAM)pdld);
  877. pwzHeaders = NULL; // Owner is now CDownload
  878. DWNLDMSG2("CDownLoad_OpenUI dialog created", hwnd);
  879. if (hwnd)
  880. {
  881. HRESULT hres = pdld->StartBinding(pmk, pbc);
  882. if (FAILED(hres))
  883. {
  884. TraceMsg(DM_DOWNLOAD, "CDownLoad::OpenUI() - StartBinding() Failed with hres=0x%x!", hres );
  885. ProcessStartbindingError(hwnd, MAKEINTRESOURCE(IDS_DOWNLOADFAILED),
  886. pdld->_szDisplay, MB_ICONWARNING, hres);
  887. }
  888. else
  889. {
  890. ShowWindow(hwnd, SW_SHOWNORMAL);
  891. }
  892. }
  893. else
  894. {
  895. delete pdld;
  896. pdld = NULL;
  897. }
  898. }
  899. if (pwzHeaders)
  900. {
  901. CoTaskMemFree(pwzHeaders);
  902. pwzHeaders = NULL;
  903. }
  904. }
  905. BOOL CDownload_MayProcessMessage(MSG* pmsg)
  906. {
  907. if (g_hDlgActive)
  908. return IsDialogMessage(g_hDlgActive, pmsg);
  909. return FALSE; // not processed
  910. }
  911. class CDownloadThreadParam {
  912. #ifdef DEBUG
  913. const DWORD* _pdwSigniture;
  914. static const DWORD s_dummy;
  915. #endif
  916. public:
  917. DWORD _dwVerb;
  918. DWORD _grfBINDF;
  919. BINDINFO *_pbinfo;
  920. LPWSTR _pszDisplayName;
  921. LPWSTR _pwzHeaders;
  922. BOOL _fSaveAs;
  923. BOOL _fSafe;
  924. BOOL _fConfirmed;
  925. IStream *_pStream;
  926. TCHAR _szRedirURL[MAX_URL_STRING];
  927. UINT _uiCP;
  928. ~CDownloadThreadParam()
  929. {
  930. OleFree(_pszDisplayName);
  931. if (_pwzHeaders)
  932. CoTaskMemFree(_pwzHeaders);
  933. if (_pStream)
  934. _pStream->Release();
  935. // CDownload releases our _pbinfo.
  936. }
  937. 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 )
  938. : _pszDisplayName(pszDisplayName), _fSaveAs(fSaveAs), _fSafe(fSafe), _pwzHeaders(pwzHeaders), _pStream(NULL), _dwVerb(dwVerb), _grfBINDF(grfBINDF), _pbinfo(pbinfo), _uiCP(uiCP), _fConfirmed(fConfirmed)
  939. {
  940. #ifdef DEBUG
  941. _pdwSigniture = &s_dummy;
  942. #endif
  943. if (pszRedir && lstrlen(pszRedir))
  944. StrCpyN(_szRedirURL, pszRedir, MAX_URL_STRING - 1);
  945. // CDownload releases our _pbinfo.
  946. }
  947. void SetStream(IStream *pStm)
  948. {
  949. if (_pStream)
  950. {
  951. _pStream->Release();
  952. }
  953. _pStream = pStm;
  954. if (_pStream)
  955. {
  956. _pStream->AddRef();
  957. }
  958. }
  959. };
  960. DWORD CALLBACK IEDownload_ThreadProc(void *pv)
  961. {
  962. CDownloadThreadParam* pdtp = (CDownloadThreadParam*)pv;
  963. HRESULT hr;
  964. IBindCtx *pbc = NULL;
  965. if (pdtp->_pStream)
  966. {
  967. pdtp->_pStream->AddRef();
  968. hr = pdtp->_pStream->Seek(c_li0,STREAM_SEEK_SET,0);
  969. hr = CoGetInterfaceAndReleaseStream(pdtp->_pStream, IID_PPV_ARG(IBindCtx, &pbc));
  970. pdtp->SetStream(NULL);
  971. }
  972. if (pbc == NULL)
  973. CreateBindCtx(0, &pbc);
  974. //winse#12726:Give other thread a chance to finish its work.
  975. Sleep(100);
  976. hr = CDownLoad_OpenUIURL(pdtp->_pszDisplayName, pbc, pdtp->_pwzHeaders, TRUE, pdtp->_fSaveAs, pdtp->_fSafe,
  977. pdtp->_dwVerb, pdtp->_grfBINDF, pdtp->_pbinfo, pdtp->_szRedirURL, pdtp->_uiCP, NULL, pdtp->_fConfirmed);
  978. if (SUCCEEDED(hr))
  979. {
  980. pdtp->_pwzHeaders = NULL; // CDownload owns freeing headers now
  981. pdtp->_pbinfo = NULL; // CDownload owns freeing pbinfo now.
  982. }
  983. delete pdtp;
  984. pdtp = NULL;
  985. if (pbc)
  986. {
  987. pbc->Release();
  988. pbc = NULL;
  989. }
  990. while (1)
  991. {
  992. MSG msg;
  993. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  994. {
  995. if (msg.message == WM_QUIT)
  996. break;
  997. // Note that for IE 3.0, the parking thread is also
  998. // the owner of all modeless download dialog.
  999. if (CDownload_MayProcessMessage(&msg))
  1000. continue;
  1001. TranslateMessage(&msg);
  1002. DispatchMessage(&msg);
  1003. continue;
  1004. }
  1005. WaitMessage();
  1006. }
  1007. return 0;
  1008. }
  1009. 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)
  1010. {
  1011. TraceMsg(DM_DOWNLOAD, "CDownLoad_OpenUI called with fSync=%d fSaveAs=%d", fSync, fSaveAs);
  1012. ASSERT(dwVerb == BINDVERB_GET || dwVerb == BINDVERB_POST);
  1013. if (fSync)
  1014. {
  1015. CDownload::OpenUI(pmk, pbc, fSaveAs, fSafe, pwzHeaders, dwVerb, grfBINDF, pbinfo, pszRedir, uiCP, fConfirmed);
  1016. pwzHeaders = NULL; // CDownload now owns headers
  1017. return;
  1018. }
  1019. IDownloadManager *pdlm;
  1020. HRESULT hr = IUnknown_QueryService(punk, SID_SDownloadManager, IID_PPV_ARG(IDownloadManager, &pdlm));
  1021. if (FAILED(hr))
  1022. {
  1023. hr = CreateFromRegKey(TSZIEPATH, TEXT("DownloadUI"), IID_PPV_ARG(IDownloadManager, &pdlm));
  1024. }
  1025. if (SUCCEEDED(hr))
  1026. {
  1027. hr = pdlm->Download(pmk, pbc, dwVerb, grfBINDF, pbinfo, pwzHeaders, pszRedir, uiCP);
  1028. pdlm->Release();
  1029. }
  1030. if (FAILED(hr))
  1031. {
  1032. if (pbc == NULL)
  1033. {
  1034. hr = CreateBindCtx(0, &pbc);
  1035. }
  1036. else
  1037. {
  1038. hr = S_OK;
  1039. pbc->AddRef();
  1040. }
  1041. if (SUCCEEDED(hr))
  1042. {
  1043. LPWSTR pszDisplayName = NULL;
  1044. hr = pmk->GetDisplayName(pbc, NULL, &pszDisplayName);
  1045. if (SUCCEEDED(hr))
  1046. {
  1047. CDownloadThreadParam* pdtp = new CDownloadThreadParam(pszDisplayName, pwzHeaders, fSaveAs, fSafe, dwVerb, grfBINDF, pbinfo, pszRedir, uiCP, fConfirmed);
  1048. if (pdtp)
  1049. {
  1050. pwzHeaders = NULL; // ownership is to CDTP
  1051. // Note: IAsyncBindCtx has identicial interface as IBindCtx
  1052. IBindCtx *pbcAsync;
  1053. hr = pbc->QueryInterface(IID_IAsyncBindCtx, (void **)&pbcAsync);
  1054. if (SUCCEEDED(hr))
  1055. {
  1056. // This introduces a double bind, but only for the mk: protocol and
  1057. // the fix is needed for displaying pdfs and other special mime types.
  1058. if (_tcsnicmp(pszDisplayName, _T("mk:"), 3) == 0)
  1059. {
  1060. pbcAsync->Release();
  1061. pbcAsync = NULL;
  1062. hr = CreateBindCtx(0, &pbcAsync);
  1063. }
  1064. if (SUCCEEDED(hr))
  1065. {
  1066. IStream *pStm;
  1067. hr = CoMarshalInterThreadInterfaceInStream(IID_IBindCtx, pbcAsync, &pStm);
  1068. if (hr == S_OK)
  1069. {
  1070. pdtp->SetStream(pStm);
  1071. pStm->Release();
  1072. }
  1073. pbcAsync->Release();
  1074. }
  1075. }
  1076. if (!SHCreateThread(IEDownload_ThreadProc, pdtp, CTF_PROCESS_REF | CTF_REF_COUNTED | CTF_COINIT, NULL))
  1077. {
  1078. delete pdtp;
  1079. pdtp = NULL;
  1080. }
  1081. }
  1082. else
  1083. {
  1084. OleFree(pszDisplayName);
  1085. }
  1086. }
  1087. pbc->Release();
  1088. }
  1089. }
  1090. CoTaskMemFree(pwzHeaders); // may be NULL, we consume this in all cases
  1091. }
  1092. 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)
  1093. {
  1094. HRESULT hr;
  1095. ASSERT(pwszURL);
  1096. if (pwszURL)
  1097. {
  1098. IMoniker* pmk = NULL;
  1099. hr = CreateURLMoniker(NULL, pwszURL, &pmk);
  1100. if (SUCCEEDED(hr))
  1101. {
  1102. CDownLoad_OpenUI(pmk, pbc, fSync, fSaveAs, fSafe, pwzHeaders, dwVerb, grfBINDF, pbinfo, pszRedir, uiCP, punk, fConfirmed);
  1103. pwzHeaders = NULL; // CDownload now owns headers
  1104. pmk->Release();
  1105. hr = S_OK;
  1106. }
  1107. if (pwzHeaders)
  1108. CoTaskMemFree(pwzHeaders);
  1109. }
  1110. else
  1111. hr = E_INVALIDARG;
  1112. return hr;
  1113. }
  1114. HRESULT CDownload::StartBinding(IMoniker* pmk, IBindCtx *pbc)
  1115. {
  1116. ASSERT(_pbc==NULL);
  1117. HRESULT hr = S_OK;
  1118. if (pbc == NULL)
  1119. {
  1120. hr = CreateBindCtx(0, &_pbc);
  1121. }
  1122. else
  1123. {
  1124. _pbc = pbc;
  1125. _pbc->AddRef();
  1126. }
  1127. if (SUCCEEDED(hr))
  1128. {
  1129. hr = RegisterBindStatusCallback(_pbc, this, 0, 0);
  1130. if (SUCCEEDED(hr))
  1131. {
  1132. hr = pmk->GetDisplayName(_pbc, NULL, &_pwszDisplayName);
  1133. if (SUCCEEDED(hr))
  1134. {
  1135. TCHAR szBuf[MAX_PATH];
  1136. DWORD dwSize = ARRAYSIZE(szBuf);
  1137. DWORD dwPUAF = PUAF_NOUI;
  1138. DWORD dwPolicy = 0, dwContext = 0;
  1139. int cch = lstrlen(_szURL);
  1140. if (!cch)
  1141. {
  1142. SHUnicodeToTChar(_pwszDisplayName, _szURL, ARRAYSIZE(_szURL));
  1143. }
  1144. TraceMsg(TF_SHDNAVIGATE, "CDld::StartBinding SHUnicodeToTChar returns %d (%s)", cch, _szURL);
  1145. // The URL from GetDisplayName() is always fully
  1146. // canonicalized and escaped. Prepare it for display.
  1147. if (PrepareURLForDisplay(_szURL, szBuf, &dwSize))
  1148. FormatUrlForDisplay(szBuf, _szDisplay, ARRAYSIZE(_szDisplay), NULL, 0, TRUE, _uiCP, NULL);
  1149. else
  1150. FormatUrlForDisplay(_szURL, _szDisplay, ARRAYSIZE(_szDisplay), NULL, 0, TRUE, _uiCP, NULL);
  1151. SetWindowText(GetDlgItem(_hDlg, IDD_NAME), _szDisplay);
  1152. if (_grfBINDF & BINDF_ENFORCERESTRICTED)
  1153. {
  1154. dwPUAF |= PUAF_ENFORCERESTRICTED;
  1155. }
  1156. ZoneCheckUrlEx(_szURL, &dwPolicy, sizeof(dwPolicy), &dwContext, sizeof(dwContext),
  1157. URLACTION_SHELL_FILE_DOWNLOAD, dwPUAF, NULL);
  1158. dwPolicy = GetUrlPolicyPermissions(dwPolicy);
  1159. if ((dwPolicy == URLPOLICY_ALLOW) || (dwPolicy == URLPOLICY_QUERY))
  1160. {
  1161. IUnknown* punk = NULL;
  1162. hr = pmk->BindToStorage(_pbc, NULL, IID_PPV_ARG(IUnknown, &punk));
  1163. DWNLDMSG3("StartBinding pmk->BindToStorage returned", hr, punk);
  1164. if (SUCCEEDED(hr) || hr == E_PENDING)
  1165. {
  1166. hr = S_OK;
  1167. if (punk)
  1168. {
  1169. ASSERT(0);
  1170. punk->Release();
  1171. }
  1172. }
  1173. else
  1174. {
  1175. TraceMsg(DM_ERROR, "CDld::StartBinding pmk->BindToStorage failed %x", hr);
  1176. HRESULT hrRevoke = RevokeBindStatusCallback( _pbc, this );
  1177. ASSERT( SUCCEEDED( hrRevoke ) );
  1178. }
  1179. }
  1180. else
  1181. {
  1182. TraceMsg(DM_ERROR, "CDld::StartBinding: Zone does not allow file download");
  1183. HRESULT hrRevoke = RevokeBindStatusCallback( _pbc, this );
  1184. ASSERT( SUCCEEDED( hrRevoke ) );
  1185. hr = E_ACCESSDENIED;
  1186. }
  1187. }
  1188. else
  1189. {
  1190. TraceMsg(DM_ERROR, "CDld::StartBinding pmk->GetDisplayName failed %x", hr);
  1191. HRESULT hrRevoke = RevokeBindStatusCallback( _pbc, this );
  1192. ASSERT( SUCCEEDED( hrRevoke ) );
  1193. }
  1194. }
  1195. else
  1196. {
  1197. TraceMsg(DM_ERROR, "CDld::StartBinding RegisterBSC failed %x", hr);
  1198. }
  1199. }
  1200. else
  1201. {
  1202. TraceMsg(DM_ERROR, "CDld::StartBinding CreateBindCtx failed %x", hr);
  1203. }
  1204. return hr;
  1205. }
  1206. HRESULT CDownload::QueryInterface(REFIID riid, void **ppvObj)
  1207. {
  1208. static const QITAB qit[] = {
  1209. QITABENT(CDownload, IBindStatusCallback), // IID_IBindStatusCallback
  1210. QITABENT(CDownload, IAuthenticate), // IID_IAuthenticate
  1211. QITABENT(CDownload, IServiceProvider), // IID_IServiceProvider
  1212. QITABENT(CDownload, IHttpNegotiate), // IID_IHttpNegotiate
  1213. QITABENT(CDownload, IWindowForBindingUI),
  1214. { 0 },
  1215. };
  1216. return QISearch(this, qit, riid, ppvObj);
  1217. }
  1218. ULONG CDownload::AddRef()
  1219. {
  1220. return InterlockedIncrement(&_cRef);
  1221. }
  1222. ULONG CDownload::Release()
  1223. {
  1224. DWNLDMSG2("CDownload::Release cRef=", _cRef);
  1225. if (InterlockedDecrement(&_cRef))
  1226. return _cRef;
  1227. CDownload* pdld = (CDownload*) GetWindowLongPtr(_hDlg, DWLP_USER);
  1228. if (pdld == this)
  1229. SetWindowLongPtr(_hDlg, DWLP_USER, NULL);
  1230. DWNLDMSG3("CDownload::Release delete this", pdld, this);
  1231. delete this;
  1232. return 0;
  1233. }
  1234. ULONG CDownload::AddRefDLD()
  1235. {
  1236. return InterlockedIncrement(&_cRefDLD);
  1237. }
  1238. ULONG CDownload::ReleaseDLD()
  1239. {
  1240. if (InterlockedDecrement(&_cRefDLD))
  1241. return _cRefDLD;
  1242. return 0;
  1243. }
  1244. CDownload::~CDownload()
  1245. {
  1246. if (_pbinfo) {
  1247. ReleaseBindInfo(_pbinfo);
  1248. LocalFree(_pbinfo);
  1249. _pbinfo = NULL;
  1250. }
  1251. if (_pib) {
  1252. _pib->Release();
  1253. }
  1254. if (_pbc) {
  1255. _pbc->Release();
  1256. }
  1257. if (_hicon) {
  1258. DestroyIcon(_hicon);
  1259. }
  1260. if (_pwszDisplayName)
  1261. OleFree(_pwszDisplayName);
  1262. if (_fDeleteFromCache)
  1263. _DeleteFromCache();
  1264. if ( _pwzHeaders )
  1265. CoTaskMemFree( _pwzHeaders );
  1266. TraceMsg(TF_SHDLIFE, "CDownload::~CDownload being destructed");
  1267. TraceMsg(TF_SHDTHREAD, "CDownload::EndDialogDLD calling PostQuitMessage");
  1268. // Post the quit message ONLY if this flag is set. The constructor for the
  1269. // derived class CDownloadURL resets the flag to FALSE because it doesn't
  1270. // need any quit messages.
  1271. if (!_fDontPostQuitMsg)
  1272. PostQuitMessage(0);
  1273. }
  1274. #ifdef USE_LOCKREQUEST
  1275. HRESULT CDownload::LockRequestHandle(void)
  1276. {
  1277. HRESULT hres = E_FAIL;
  1278. HANDLE hLock;
  1279. if (_pib)
  1280. {
  1281. IWinInetInfo* pwinet;
  1282. hres = _pib->QueryInterface(IID_PPV_ARG(IWinInetInfo, &pwinet));
  1283. if (SUCCEEDED(hres))
  1284. {
  1285. DWORD cbSize = sizeof(HANDLE);
  1286. hres = pwinet->QueryOption(WININETINFO_OPTION_LOCK_HANDLE, &hLock, &cbSize);
  1287. pwinet->Release();
  1288. }
  1289. }
  1290. return hres;
  1291. }
  1292. #endif
  1293. HRESULT CDownload::OnStartBinding(DWORD grfBSCOption, IBinding *pib)
  1294. {
  1295. DWNLDMSG3("OnStartBinding", _pib, pib);
  1296. if (_pib)
  1297. {
  1298. _pib->Release();
  1299. }
  1300. _pib = pib;
  1301. if (_pib)
  1302. {
  1303. _pib->AddRef();
  1304. }
  1305. SetQueryNetSessionCount(SESSION_INCREMENT);
  1306. _fUTF8Enabled = UTF8Enabled();
  1307. return S_OK;
  1308. }
  1309. HRESULT CDownload::GetPriority(LONG *pnPriority)
  1310. {
  1311. DWNLDMSG("GetPriority", "called");
  1312. *pnPriority = NORMAL_PRIORITY_CLASS;
  1313. return S_OK;
  1314. }
  1315. HRESULT CDownload::OnLowResource(DWORD reserved)
  1316. {
  1317. DWNLDMSG("OnLowResource", "called");
  1318. return S_OK;
  1319. }
  1320. #define WM_DIALMON_FIRST WM_USER+100
  1321. // message sent to dial monitor app window indicating that there has been
  1322. // winsock activity and dial monitor should reset its idle timer
  1323. #define WM_WINSOCK_ACTIVITY WM_DIALMON_FIRST + 0
  1324. #define MIN_ACTIVITY_MSG_INTERVAL 15000
  1325. void IndicateWinsockActivity(void)
  1326. {
  1327. // if there is an autodisconnect monitor, send it an activity message
  1328. // so that we don't get disconnected during long downloads. For perf's sake,
  1329. // don't send a message any more often than once every MIN_ACTIVITY_MSG_INTERVAL
  1330. // milliseconds (15 seconds). Use GetTickCount to determine interval;
  1331. // GetTickCount is very cheap.
  1332. DWORD dwTickCount = GetTickCount();
  1333. // Sharing this among multiple threads is OK
  1334. static DWORD dwLastActivityMsgTickCount = 0;
  1335. DWORD dwElapsed = dwTickCount - dwLastActivityMsgTickCount;
  1336. // have we sent an activity message recently?
  1337. if (dwElapsed > MIN_ACTIVITY_MSG_INTERVAL)
  1338. {
  1339. HWND hwndMonitorApp = FindWindow(TEXT("MS_AutodialMonitor"), NULL);
  1340. if (hwndMonitorApp)
  1341. {
  1342. PostMessage(hwndMonitorApp, WM_WINSOCK_ACTIVITY, 0, 0);
  1343. }
  1344. hwndMonitorApp = FindWindow(TEXT("MS_WebcheckMonitor"), NULL);
  1345. if (hwndMonitorApp)
  1346. {
  1347. PostMessage(hwndMonitorApp, WM_WINSOCK_ACTIVITY, 0, 0);
  1348. }
  1349. // record the tick count of the last time we sent an
  1350. // activity message
  1351. dwLastActivityMsgTickCount = dwTickCount;
  1352. }
  1353. }
  1354. #define MAXCALCCNT 5
  1355. HRESULT CDownload::OnProgress(
  1356. ULONG ulProgress,
  1357. ULONG ulProgressMax,
  1358. ULONG ulStatusCode,
  1359. LPCWSTR pwzStatusText)
  1360. {
  1361. DWNLDMSG4("OnProgress", ulProgress, ulProgressMax, ulStatusCode);
  1362. TCHAR szBytes[MAX_BYTES_STRLEN];
  1363. TCHAR szBytesMax[MAX_BYTES_STRLEN];
  1364. TCHAR szBuf[MAX_PATH]; // OK with MAX_PATH
  1365. LPTSTR pszFileName = NULL;
  1366. HWND hwndShow;
  1367. DWORD dwCur;
  1368. switch (ulStatusCode)
  1369. {
  1370. case BINDSTATUS_BEGINDOWNLOADDATA:
  1371. hwndShow = GetDlgItem(_hDlg, ulProgressMax ? IDD_PROBAR : IDD_NOFILESIZE);
  1372. if (!IsWindowVisible(hwndShow))
  1373. {
  1374. ShowWindow(GetDlgItem(_hDlg, ulProgressMax ? IDD_NOFILESIZE : IDD_PROBAR), SW_HIDE);
  1375. ShowWindow(hwndShow, SW_SHOW);
  1376. }
  1377. _ulOldProgress = ulProgress;
  1378. // fall thru
  1379. case BINDSTATUS_DOWNLOADINGDATA:
  1380. case BINDSTATUS_ENDDOWNLOADDATA:
  1381. // Prevent machines with APM enabled from suspending during download
  1382. _SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
  1383. _dwFileSize = max(ulProgressMax, ulProgress);
  1384. // every once in a while, send message
  1385. // to the hidden window that detects inactivity so that it doesn't
  1386. // think we are inactive during a long download
  1387. IndicateWinsockActivity();
  1388. // Sometimes OnProgress is called by folks who do not create a dialog
  1389. if (_hDlg )
  1390. {
  1391. if (!_fStrsLoaded)
  1392. {
  1393. MLLoadString(IDS_TITLEPERCENT, _szTitlePercent, ARRAYSIZE(_szTitlePercent));
  1394. MLLoadString(IDS_ESTIMATE, _szEstimateTime, ARRAYSIZE(_szEstimateTime));
  1395. MLLoadString(IDS_TITLEBYTES, _szTitleBytes, ARRAYSIZE(_szTitleBytes));
  1396. MLLoadString(IDS_BYTESCOPIED, _szBytesCopied, ARRAYSIZE(_szBytesCopied));
  1397. MLLoadString(IDS_TRANSFERRATE, _szTransferRate, ARRAYSIZE(_szTransferRate));
  1398. _fStrsLoaded = TRUE;
  1399. }
  1400. // Get the file name of the file being downloaded
  1401. pszFileName = PathFindFileName(_szURL);
  1402. dwCur = GetTickCount();
  1403. if (_dwOldCur == 0) // Allow the download to get started before displaying stats
  1404. _dwOldCur = dwCur;
  1405. if ((ulProgressMax > 0) && _fDownloadStarted)
  1406. {
  1407. if (_hDlg)
  1408. {
  1409. SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETRANGE32, 0, _dwFileSize);
  1410. SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETPOS, ulProgress, 0);
  1411. }
  1412. if (!_fFirstTickValid)
  1413. {
  1414. _dwFirstSize = ulProgress;
  1415. _fFirstTickValid = TRUE;
  1416. SetWindowText(GetDlgItem(_hDlg, IDD_NAME), _szDisplay);
  1417. }
  1418. else
  1419. {
  1420. if ((ulProgress - _dwFirstSize) && _hDlg)
  1421. {
  1422. // Recompute and display stats at least every second
  1423. if ((dwCur - _dwOldCur) >= 1000)
  1424. {
  1425. _dwOldCur = dwCur; // Save current tick count
  1426. TCHAR szTime[32];
  1427. DWORD dwSpent = ((dwCur - _dwFirstTick)+500) / 1000;
  1428. ULONG ulLeft = _dwFileSize - ulProgress;
  1429. DWORD dwRate = _dwOldRate;
  1430. dwRate = (ulProgress - _ulOldProgress) / (dwSpent ? dwSpent : 1);
  1431. TraceMsg(DM_PROGRESS, "OnProgress ulProgress=%d ulGot=%d dwSpent=%d ulLeft=%d", ulProgress, (ulProgress - _dwFirstSize), dwSpent, ulLeft);
  1432. // Compute & display estimated time left to download, bytes so far, total bytes
  1433. DWORD dwEst;
  1434. if (ulLeft > 0x100000L) // To avoid overflow, use KB for >1MB file.
  1435. dwEst = (ulLeft >> 10) / ((dwRate >> 10) ?(dwRate >> 10) :1);
  1436. else
  1437. dwEst = ulLeft / (dwRate ?dwRate :1);
  1438. if (dwEst == 0)
  1439. dwEst = 1;
  1440. TraceMsg(DM_PROGRESS, "OnProgress Estimated time left = %d", dwEst);
  1441. StrFromTimeInterval(szTime, ARRAYSIZE(szTime), dwEst * 1000, 3);
  1442. LPTSTR pszTime = szTime;
  1443. while(*pszTime && (*pszTime == ' '))
  1444. pszTime++;
  1445. _FormatMessage(_szEstimateTime, szBuf, ARRAYSIZE(szBuf), pszTime,
  1446. StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN),
  1447. StrFormatByteSize(_dwFileSize, szBytesMax, MAX_BYTES_STRLEN));
  1448. TraceMsg(DM_PROGRESS, "OnProgress Estimated string = %s", szBuf);
  1449. SetDlgItemText(_hDlg, IDD_TIMEEST, szBuf);
  1450. _dwOldEst = dwEst;
  1451. // Compute & display transfer rate
  1452. if (dwRate != _dwOldRate)
  1453. {
  1454. _dwOldRate = dwRate;
  1455. _FormatMessage(_szTransferRate, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(dwRate, szBytes, MAX_BYTES_STRLEN));
  1456. SetDlgItemText(_hDlg, IDD_TRANSFERRATE, szBuf);
  1457. }
  1458. }
  1459. // Compute & display percentage of download completed
  1460. DWORD dwPcent = (100 - MulDiv(_dwFileSize - ulProgress, 100, _dwFileSize));
  1461. if (dwPcent != _dwOldPcent)
  1462. {
  1463. _dwOldPcent = dwPcent;
  1464. if (dwPcent == 100) // Don't peg the meter until we've completed
  1465. dwPcent = 99;
  1466. TCHAR szBuf2[MAX_PATH];
  1467. DWORD dwSize = ARRAYSIZE(szBuf2);
  1468. if (PrepareURLForDisplay(pszFileName, szBuf2, &dwSize))
  1469. _FormatMessage(_szTitlePercent, szBuf, ARRAYSIZE(szBuf), (UINT)dwPcent, szBuf2);
  1470. else
  1471. _FormatMessage(_szTitlePercent, szBuf, ARRAYSIZE(szBuf), (UINT)dwPcent, pszFileName);
  1472. SetWindowText(_hDlg, szBuf);
  1473. }
  1474. }
  1475. }
  1476. }
  1477. else if (_hDlg && _fDownloadStarted) // Unknown file size, just show bytes and rate
  1478. {
  1479. // Recompute and display stats at most every second
  1480. if ((dwCur - _dwOldCur) >= 1000)
  1481. {
  1482. _dwOldCur = dwCur; // Save current tick count
  1483. DWORD dwSpent = ((dwCur - _dwFirstTick)+500) / 1000;
  1484. DWORD dwRate = ulProgress / (dwSpent ? dwSpent : 1);
  1485. _FormatMessage(_szBytesCopied, szBuf, ARRAYSIZE(szBuf),
  1486. StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN));
  1487. TraceMsg(DM_PROGRESS, "OnProgress string = %s", szBuf);
  1488. SetDlgItemText(_hDlg, IDD_TIMEEST, szBuf);
  1489. _FormatMessage(_szTransferRate, szBuf, ARRAYSIZE(szBuf), StrFormatByteSize(dwRate, szBytes, MAX_BYTES_STRLEN));
  1490. SetDlgItemText(_hDlg, IDD_TRANSFERRATE, szBuf);
  1491. {
  1492. TCHAR szBuf2[MAX_PATH];
  1493. DWORD dwSize = ARRAYSIZE(szBuf2);
  1494. if (PrepareURLForDisplay (pszFileName, szBuf2, &dwSize))
  1495. _FormatMessage(_szTitleBytes, szBuf, ARRAYSIZE(szBuf),
  1496. StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN),szBuf2);
  1497. else
  1498. _FormatMessage(_szTitleBytes, szBuf, ARRAYSIZE(szBuf),
  1499. StrFormatByteSize(ulProgress, szBytes, MAX_BYTES_STRLEN), pszFileName);
  1500. SetWindowText(_hDlg, szBuf);
  1501. }
  1502. }
  1503. }
  1504. }
  1505. break;
  1506. default: // ulStatusCode
  1507. break;
  1508. }
  1509. return S_OK;
  1510. }
  1511. HRESULT CDownload::OnStopBinding(HRESULT hrError, LPCWSTR szError)
  1512. {
  1513. TraceMsg(DM_DOWNLOAD, "OnStopBinding called with hrError==%x", hrError);
  1514. HRESULT hrDisplay = hrError;
  1515. AddRef(); // Guard against last Release by _RevokeObjectParam
  1516. HRESULT hres = RevokeBindStatusCallback(_pbc, this);
  1517. AssertMsg(SUCCEEDED(hres), TEXT("URLMON bug??? RevokeBindStatusCallback failed %x"), hres);
  1518. if (_pib)
  1519. {
  1520. CLSID clsid;
  1521. LPWSTR pwszError = NULL;
  1522. HRESULT hresT = _pib->GetBindResult(&clsid, (DWORD *)&hrDisplay, &pwszError, NULL);
  1523. TraceMsg(TF_SHDBINDING, "DLD::OnStopBinding called GetBindResult %x->%x (%x)", hrError, hrDisplay, hresT);
  1524. if (SUCCEEDED(hresT))
  1525. {
  1526. //
  1527. // URLMON returns a native Win32 error.
  1528. //
  1529. if (hrDisplay && SUCCEEDED(hrDisplay))
  1530. hrDisplay = HRESULT_FROM_WIN32(hrDisplay);
  1531. if (pwszError)
  1532. OleFree(pwszError);
  1533. }
  1534. // We don't call IBinding::Release until ~CDownload
  1535. // because we need to guarantee the download file
  1536. // exists until we have copied or executed it.
  1537. }
  1538. #ifdef DEBUG
  1539. if (hrError==S_OK && GetKeyState(VK_CONTROL) < 0)
  1540. {
  1541. hrError = E_FAIL;
  1542. }
  1543. #endif
  1544. if (FAILED(hrError) && hrError != E_ABORT)
  1545. {
  1546. IE_ErrorMsgBox(NULL, _hDlg, hrDisplay, szError,_szDisplay, IDS_CANTDOWNLOAD, MB_OK|MB_ICONSTOP);
  1547. }
  1548. if (g_hCritOpMutex != NULL)
  1549. {
  1550. CloseHandle(g_hCritOpMutex);
  1551. g_hCritOpMutex = NULL;
  1552. }
  1553. SetQueryNetSessionCount(SESSION_DECREMENT);
  1554. if (!_fGotFile || !_fDownloadCompleted)
  1555. {
  1556. AssertMsg(FAILED(hrError), TEXT("CDownload::OnStopBinding is called, but we've never got a file -- URLMON bug"));
  1557. if (!_fEndDialogCalled)
  1558. {
  1559. FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage);
  1560. }
  1561. }
  1562. Release(); // Guard against last Release by _RevokeObjectParam
  1563. return S_OK;
  1564. }
  1565. HRESULT CDownload::GetBindInfo(DWORD* grfBINDINFOF, BINDINFO *pbindinfo)
  1566. {
  1567. TraceMsg(DM_DOWNLOAD, "DWNLD::GetBindInfo called when _pbinfo==%x", _pbinfo);
  1568. if ( !grfBINDINFOF || !pbindinfo || !pbindinfo->cbSize )
  1569. return E_INVALIDARG;
  1570. if (_pbinfo) {
  1571. // Give the ownership to URLMON... shallow copy; don't use CopyBindInfo().
  1572. // Don't forget to keep pbindinfo cbSize!
  1573. DWORD cbSize = pbindinfo->cbSize;
  1574. CopyMemory( pbindinfo, _pbinfo, min(_pbinfo->cbSize, cbSize) );
  1575. pbindinfo->cbSize = cbSize;
  1576. if (pbindinfo->cbSize > _pbinfo->cbSize)
  1577. {
  1578. ZeroMemory((BYTE *)pbindinfo + _pbinfo->cbSize, pbindinfo->cbSize - _pbinfo->cbSize);
  1579. }
  1580. LocalFree(_pbinfo);
  1581. _pbinfo = NULL;
  1582. } else {
  1583. // We don't have a BINDINFO our selves so
  1584. // clear BINDINFO except cbSize
  1585. DWORD cbSize = pbindinfo->cbSize;
  1586. ZeroMemory( pbindinfo, cbSize );
  1587. pbindinfo->cbSize = cbSize;
  1588. if (UTF8Enabled())
  1589. pbindinfo->dwOptions = BINDINFO_OPTIONS_ENABLE_UTF8;
  1590. }
  1591. // #52524. With post build ~1100, If we do not return the following flags when URLMon calls
  1592. // GetBindInfo(), It will bind to the storage synchronously. (judej, danpoz)
  1593. *grfBINDINFOF = _grfBINDF | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
  1594. return S_OK;
  1595. }
  1596. HRESULT CDownload::OnDataAvailable(DWORD grfBSC, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
  1597. {
  1598. DWORD dwOptions = 0;
  1599. DWNLDMSG3("OnDataAvailable (grf,pstg)", grfBSC, pstgmed);
  1600. _dwTotalSize = dwSize; // keep track of number of bytes downloaded
  1601. if (SUCCEEDED(_GetRequestFlagFromPIB(_pib, &dwOptions)) && (dwOptions & INTERNET_REQFLAG_CACHE_WRITE_DISABLED))
  1602. {
  1603. _fWriteHistory = FALSE;
  1604. }
  1605. if (grfBSC & BSCF_LASTDATANOTIFICATION)
  1606. {
  1607. _fDownloadCompleted = TRUE;
  1608. }
  1609. //
  1610. // This code gets the file name from pstgmed, when it became
  1611. // available. URLMon is supposed to pass it even though the file
  1612. // is not completely ready yet.
  1613. //
  1614. if (!_fGotFile && pstgmed)
  1615. {
  1616. Animate_Stop(GetDlgItem(_hDlg, IDD_ANIMATE));
  1617. if (pstgmed->tymed == TYMED_FILE)
  1618. {
  1619. TCHAR szBuf[MAX_PATH]; // ok with MAX_PATH (because we truncate)
  1620. SHUnicodeToTChar(pstgmed->lpszFileName, _szPath, ARRAYSIZE(_szPath));
  1621. // Because of redirection the _szURL could be http://.../redir.dll or query.exe.
  1622. // Whereas the actual filename would be something else. The Cache filename is generated
  1623. // by wininet after it has figured out what the real filename is. However, it might contain
  1624. // a "(1)" or a "(2)" at the end of the file name.
  1625. TCHAR szURL[MAX_URL_STRING];
  1626. StrCpyN(szURL, _szURL, ARRAYSIZE(szURL));
  1627. TCHAR * pszURLFName = PathFindFileName(szURL);
  1628. TCHAR * pszCacheFName = PathFindFileName(_szPath);
  1629. // Unescape the filename suggested by wininet.
  1630. DWORD cch = ARRAYSIZE(szBuf);
  1631. if (_PrepareURLForDisplayUTF8W(pszCacheFName, szBuf, &cch, _fUTF8Enabled, _uiCP) != S_OK)
  1632. StrCpyN(szBuf, pszCacheFName, ARRAYSIZE(szBuf));
  1633. // Strip out any path that may have been encoded
  1634. pszCacheFName = szBuf;
  1635. TCHAR *pszSrc = PathFindFileName(szBuf);
  1636. if (pszSrc != szBuf)
  1637. {
  1638. while(*pszSrc)
  1639. *pszCacheFName++ = *pszSrc++;
  1640. *pszCacheFName = *pszSrc;
  1641. }
  1642. // Use the Cache name. pszURLFName point to the file name in szURL. Just overwrite it
  1643. if (pszURLFName && szBuf)
  1644. {
  1645. StrCpyN(pszURLFName, szBuf, ARRAYSIZE(szURL) - ((int)(pszURLFName-szURL)/sizeof(TCHAR)));
  1646. FormatUrlForDisplay(szURL, _szDisplay, ARRAYSIZE(_szDisplay), NULL, 0, TRUE, _uiCP, NULL);
  1647. }
  1648. DWNLDMSG("OnDataAvailable got TYMED_FILE", _szPath);
  1649. _fGotFile = TRUE;
  1650. TCHAR szMime[MAX_PATH];
  1651. if (GetClipboardFormatName(pformatetc->cfFormat, szMime, sizeof(szMime)/sizeof(szMime[0])))
  1652. {
  1653. MIME_GetExtension(szMime, (LPTSTR) _szExt, SIZECHARS(_szExt));
  1654. }
  1655. SetWindowText(GetDlgItem(_hDlg, IDD_NAME), _szDisplay);
  1656. UINT uRet = _MayAskUserIsFileSafeToOpen(szMime);
  1657. switch (uRet) {
  1658. case IDOK:
  1659. MLLoadString(IDS_OPENING, szBuf, ARRAYSIZE(szBuf));
  1660. break;
  1661. case IDD_SAVEAS:
  1662. _fSaveAs = TRUE;
  1663. _fCallVerifyTrust = FALSE;
  1664. MLLoadString(IDS_SAVING, szBuf, ARRAYSIZE(szBuf));
  1665. break;
  1666. case IDCANCEL:
  1667. FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage);
  1668. //
  1669. // HACK: Under a certain condition, we receive one more
  1670. // OnDataAvailable from URLMON with BSCF_LASTDATANOTIFICATION
  1671. // before this posted message is dispatched. It causes
  1672. // WinVerifyTrust call, which is wrong. To prevent it,
  1673. // we unset this flag.
  1674. //
  1675. // We still assumes that OnStopBinding will not happen before
  1676. // this message is dispatched. In IE 4.0, we should introduce
  1677. // another flag (_fCancelled) to make it more robust.
  1678. //
  1679. _fCallVerifyTrust = FALSE;
  1680. return S_OK;
  1681. }
  1682. SetDlgItemText(_hDlg, IDD_OPENIT, szBuf);
  1683. if (_fSaveAs)
  1684. {
  1685. if (!_GetSaveLocation())
  1686. {
  1687. FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage);
  1688. return S_OK;
  1689. }
  1690. StrCpyN(szBuf, _szSaveToFile, ARRAYSIZE(szBuf));
  1691. RECT rect;
  1692. GetClientRect(GetDlgItem(_hDlg, IDD_DIR), &rect);
  1693. PathCompactPath(NULL, szBuf, rect.right);
  1694. }
  1695. else
  1696. MLLoadString(IDS_DOWNLOADTOCACHE, szBuf, ARRAYSIZE(szBuf));
  1697. SetDlgItemText(_hDlg, IDD_DIR, szBuf);
  1698. Animate_Play(GetDlgItem(_hDlg, IDD_ANIMATE),0, -1, -1);
  1699. if (_dwFirstTick == 0) // Start the timer
  1700. _dwFirstTick = GetTickCount();
  1701. }
  1702. else
  1703. {
  1704. TraceMsg(DM_WARNING, "CDownload::OnDataAvailable pstgmed->tymed (%d) != TYMED_FILE", pstgmed->tymed);
  1705. }
  1706. _fDownloadStarted = TRUE;
  1707. }
  1708. if (_fDownloadCompleted)
  1709. {
  1710. #ifdef CALL_WVT
  1711. if (_fCallVerifyTrust)
  1712. {
  1713. ShowWindow(_hDlg, SW_HIDE);
  1714. UINT uRet = _VerifyTrust(_hDlg, _szPath, _szDisplay);
  1715. switch (uRet) {
  1716. case IDOK:
  1717. break;
  1718. default:
  1719. // We assume _VerifyTrust always is able to open the file
  1720. // passed from URLMON. If it fails, we bail with no UI.
  1721. ASSERT(0);
  1722. // Fall through
  1723. case IDCANCEL:
  1724. _fDeleteFromCache = TRUE;
  1725. FORWARD_WM_COMMAND(_hDlg, IDCANCEL, NULL, 0, PostMessage);
  1726. return S_OK;
  1727. }
  1728. }
  1729. #endif // CALL_WVT
  1730. DWNLDMSG3("OnDataAvailable calling Animate_Stop", _hDlg, GetDlgItem(_hDlg, IDD_ANIMATE));
  1731. Animate_Stop(GetDlgItem(_hDlg, IDD_ANIMATE));
  1732. SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETRANGE32, 0, 100);
  1733. SendMessage(GetDlgItem(_hDlg, IDD_PROBAR), PBM_SETPOS, 100, 0);
  1734. if (_fSaveAs) {
  1735. FORWARD_WM_COMMAND(_hDlg, IDD_SAVEAS, NULL, 0, PostMessage);
  1736. } else {
  1737. #ifdef USE_LOCKREQUEST
  1738. LockRequestHandle(); // Tell wininet that we want the file locked to allow the app to open it.
  1739. // This prevents wininet from deleting the file from the cache before the
  1740. // app gets a chance to use it. When wininet sees this file is locked, it
  1741. // will add the file to the scavenger leak list and attempt to delete the
  1742. // file in the future.
  1743. #endif
  1744. FORWARD_WM_COMMAND(_hDlg, IDOK, NULL, 0, PostMessage);
  1745. }
  1746. }
  1747. return S_OK;
  1748. }
  1749. HRESULT CDownload::OnObjectAvailable(REFIID riid, IUnknown *punk)
  1750. {
  1751. DWORD dwOptions = 0;
  1752. DWNLDMSG3("OnObjectAvailable (riid,punk)", riid, punk);
  1753. if (SUCCEEDED(_GetRequestFlagFromPIB(_pib, &dwOptions)) && (dwOptions & INTERNET_REQFLAG_CACHE_WRITE_DISABLED))
  1754. {
  1755. _fWriteHistory = FALSE;
  1756. }
  1757. return S_OK;
  1758. }
  1759. /* *** IHttpNegotiate *** */
  1760. HRESULT CDownload::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders,
  1761. DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
  1762. {
  1763. if ((!_pwzHeaders) || (!pszAdditionalHeaders))
  1764. return S_OK;
  1765. DWORD cbHeaders = (lstrlenW(_pwzHeaders) + 1) * sizeof(WCHAR);
  1766. LPWSTR pwzHeaders = (LPWSTR)CoTaskMemAlloc(cbHeaders + sizeof(WCHAR));
  1767. if (pwzHeaders)
  1768. {
  1769. memcpy (pwzHeaders, _pwzHeaders, cbHeaders);
  1770. *pszAdditionalHeaders = pwzHeaders;
  1771. }
  1772. // Caller owns freeing *pszAdditionalHeaders
  1773. return S_OK;
  1774. }
  1775. HRESULT CDownload::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders,
  1776. LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
  1777. {
  1778. return S_OK;
  1779. }
  1780. BOOL _RememberFileIsSafeToOpen(LPCTSTR szFileClass)
  1781. {
  1782. DWORD dwEditFlags;
  1783. ULONG cb = sizeof(dwEditFlags);
  1784. HRESULT hr;
  1785. IQueryAssociations *passoc = NULL;
  1786. BOOL bRet = FALSE;
  1787. hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &passoc));
  1788. if (SUCCEEDED(hr) && passoc)
  1789. {
  1790. hr = passoc->Init(NULL, szFileClass, NULL, NULL);
  1791. if (SUCCEEDED(hr))
  1792. {
  1793. hr = passoc->GetData(NULL, ASSOCDATA_EDITFLAGS, NULL, &dwEditFlags, &cb);
  1794. if (SUCCEEDED(hr))
  1795. {
  1796. dwEditFlags &= ~FTA_NoEdit;
  1797. dwEditFlags |= FTA_OpenIsSafe;
  1798. }
  1799. }
  1800. passoc->Release();
  1801. }
  1802. if (FAILED(hr))
  1803. dwEditFlags = FTA_OpenIsSafe;
  1804. return (SHSetValue(HKEY_CLASSES_ROOT, szFileClass, TEXT("EditFlags"),
  1805. REG_BINARY, (BYTE*)&dwEditFlags,
  1806. sizeof(dwEditFlags)) == ERROR_SUCCESS);
  1807. }
  1808. struct SAFEOPENDLGPARAM {
  1809. LPCTSTR pszFileClass;
  1810. LPCTSTR pszFriendlyURL;
  1811. LPCTSTR pszURL;
  1812. HWND hwndTT;
  1813. TCHAR* pszTTText;
  1814. LPCTSTR pszCacheFile;
  1815. DWORD uiCP;
  1816. BOOL fTypeMismatch;
  1817. BOOL fShellExecPrompt;
  1818. BOOL fPackagerCommandPrompt;
  1819. };
  1820. INT_PTR CALLBACK SafeOpenDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1821. {
  1822. UINT id;
  1823. static BOOL bCancelled;
  1824. SAFEOPENDLGPARAM* param = (SAFEOPENDLGPARAM*) GetWindowLongPtr(hDlg, DWLP_USER);
  1825. if ((param == NULL) && (uMsg != WM_INITDIALOG))
  1826. return FALSE;
  1827. switch (uMsg) {
  1828. case WM_INITDIALOG:
  1829. {
  1830. BOOL fUnsafeFile;
  1831. TCHAR szFriendlyName[MAX_DISPLAY_LEN] = {TEXT('\0')};
  1832. TCHAR szFriendlyFrom[MAX_DISPLAY_LEN] = {TEXT('\0')};
  1833. TCHAR szProcessedURL[MAX_URL_STRING] = {TEXT('\0')};
  1834. DWORD dwSize = ARRAYSIZE(szProcessedURL);
  1835. if (lParam == NULL)
  1836. return FALSE;
  1837. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1838. param = (SAFEOPENDLGPARAM*)lParam;
  1839. // init unsafe file to mismatch between progid and file
  1840. fUnsafeFile = param->fTypeMismatch;
  1841. // Determine whether or not to gray out the Always ask checkbox. We wil gray out in the following cases
  1842. // 1. If we were not told what the file class is
  1843. // 2. If the file class is in the unsafe extensions list
  1844. // 3. if the file extension in the URL is in the unsafe extensions list
  1845. // 4. if the cache file extension is in the unsafe extensions list (if we are redirected)
  1846. TCHAR * pszExt = NULL;
  1847. TCHAR * pszCacheExt = NULL;
  1848. if (param->pszURL)
  1849. pszExt = PathFindExtension(param->pszURL);
  1850. if (param->pszCacheFile)
  1851. pszCacheExt = PathFindExtension(param->pszCacheFile);
  1852. if(param->fPackagerCommandPrompt)
  1853. {
  1854. fUnsafeFile = TRUE;
  1855. }
  1856. else if (pszExt || pszCacheExt)
  1857. {
  1858. if (pszExt && AssocIsDangerous(pszExt))
  1859. fUnsafeFile = TRUE;
  1860. else if (pszCacheExt && AssocIsDangerous(pszCacheExt))
  1861. fUnsafeFile = TRUE;
  1862. }
  1863. else
  1864. {
  1865. fUnsafeFile = TRUE;
  1866. }
  1867. if (fUnsafeFile || SHRestricted2(REST_AlwaysPromptWhenDownload, NULL, 0))
  1868. EnableWindow(GetDlgItem(hDlg, IDC_SAFEOPEN_ALWAYS), FALSE);
  1869. // The check box is always checked by default
  1870. CheckDlgButton(hDlg, IDC_SAFEOPEN_ALWAYS, TRUE);
  1871. // adjust the warning
  1872. if (fUnsafeFile)
  1873. {
  1874. HICON hIcon = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_PRIVACY_WARN),
  1875. IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
  1876. if (hIcon != NULL)
  1877. SendDlgItemMessage(hDlg, IDC_SAFEOPEN_WARNICON, STM_SETICON, (WPARAM)hIcon, 0);
  1878. }
  1879. else
  1880. {
  1881. ShowWindow(GetDlgItem(hDlg, IDC_SAFEOPEN_WARNTEXT), SW_HIDE);
  1882. }
  1883. // cross-lang platform support
  1884. SHSetDefaultDialogFont(hDlg, IDC_SAFEOPEN_FILENAME);
  1885. SHSetDefaultDialogFont(hDlg, IDC_SAFEOPEN_FILETYPE);
  1886. SHSetDefaultDialogFont(hDlg, IDC_SAFEOPEN_FILEFROM);
  1887. // Get the URL for the tooltip. Also get URL for the display string if we weren't passed one
  1888. if (param->pszURL)
  1889. {
  1890. if (!PrepareURLForDisplay(param->pszURL, szProcessedURL, &dwSize))
  1891. {
  1892. dwSize = ARRAYSIZE(szProcessedURL);
  1893. StrCpyN(szProcessedURL, param->pszURL, dwSize);
  1894. }
  1895. }
  1896. // Now figure out what we want to display
  1897. if(param->fPackagerCommandPrompt)
  1898. {
  1899. // If this was a packager command line, then just display the full command as passed in param->pszURL
  1900. StrCpyN(szFriendlyName, param->pszURL, ARRAYSIZE(szFriendlyName));
  1901. }
  1902. else
  1903. {
  1904. FormatUrlForDisplay((LPTSTR)param->pszURL, szFriendlyName, ARRAYSIZE(szFriendlyName), szFriendlyFrom, ARRAYSIZE(szFriendlyFrom),
  1905. TRUE, param->uiCP, (PWSTR)param->pszCacheFile);
  1906. }
  1907. SetDlgItemText(hDlg, IDC_SAFEOPEN_FILENAME, szFriendlyName);
  1908. if(param->fPackagerCommandPrompt)
  1909. {
  1910. // If it was a packager command line, then display "Unknown" for the from
  1911. MLLoadString(IDS_VALUE_UNKNOWN, szFriendlyFrom, ARRAYSIZE(szFriendlyFrom));
  1912. SetDlgItemText(hDlg, IDC_SAFEOPEN_FILEFROM, szFriendlyFrom);
  1913. }
  1914. else
  1915. {
  1916. if (szFriendlyFrom[0] != '\0')
  1917. SetDlgItemText(hDlg, IDC_SAFEOPEN_FILEFROM, szFriendlyFrom);
  1918. }
  1919. if (param->pszFileClass || pszCacheExt)
  1920. {
  1921. DWORD cchName = ARRAYSIZE(szFriendlyName);
  1922. if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_FRIENDLYDOCNAME,
  1923. (param->pszFileClass ? param->pszFileClass : pszCacheExt), NULL, szFriendlyName, &cchName)))
  1924. {
  1925. SetDlgItemText(hDlg, IDC_SAFEOPEN_FILETYPE, szFriendlyName);
  1926. }
  1927. }
  1928. int cch = lstrlen(szProcessedURL) + 1;
  1929. param->pszTTText = (TCHAR*)LocalAlloc(LPTR, cch * sizeof(TCHAR));
  1930. if (param->pszTTText)
  1931. {
  1932. StrCpyN(param->pszTTText, szProcessedURL, cch);
  1933. if (param->hwndTT = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP,
  1934. CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
  1935. hDlg, NULL, HINST_THISDLL, NULL))
  1936. {
  1937. TOOLINFO ti;
  1938. ti.cbSize = sizeof(ti);
  1939. ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  1940. ti.hwnd = hDlg;
  1941. ti.uId = (UINT_PTR) GetDlgItem(hDlg, IDC_SAFEOPEN_FILENAME);
  1942. ti.lpszText = LPSTR_TEXTCALLBACK;
  1943. ti.hinst = HINST_THISDLL;
  1944. GetWindowRect((HWND)ti.uId, &ti.rect);
  1945. SendMessage(param->hwndTT, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
  1946. SendMessage(param->hwndTT, TTM_SETMAXTIPWIDTH, 0, 300);
  1947. }
  1948. }
  1949. if (param->fShellExecPrompt)
  1950. {
  1951. EnableWindow(GetDlgItem(hDlg, IDC_SAFEOPEN_AUTOSAVE), FALSE);
  1952. // make Cancel the default action
  1953. SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDCANCEL), TRUE);
  1954. }
  1955. else
  1956. {
  1957. // make Save the default action
  1958. SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDC_SAFEOPEN_AUTOSAVE), TRUE);
  1959. }
  1960. return FALSE;
  1961. }
  1962. case WM_NOTIFY:
  1963. {
  1964. LPTOOLTIPTEXT lpTT = (LPTOOLTIPTEXT) lParam;
  1965. if (lpTT->hdr.code == TTN_NEEDTEXT)
  1966. {
  1967. lpTT->lpszText = param->pszTTText;
  1968. lpTT->hinst = NULL;
  1969. }
  1970. break;
  1971. }
  1972. case WM_DESTROY:
  1973. //deal with checkbox
  1974. if ((!bCancelled) && (!IsDlgButtonChecked(hDlg, IDC_SAFEOPEN_ALWAYS)) && param->pszURL)
  1975. {
  1976. // Now save EditFlags at the key value value that the filetypes dialog will get/set.
  1977. TCHAR * pszExt = PathFindExtension(param->pszURL);
  1978. if (*pszExt)
  1979. {
  1980. TCHAR szFileClass[MAX_PATH];
  1981. ULONG cb = sizeof(szFileClass);
  1982. *szFileClass = TEXT('\0');
  1983. SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szFileClass, &cb);
  1984. if (*szFileClass)
  1985. _RememberFileIsSafeToOpen(szFileClass);
  1986. }
  1987. }
  1988. SHRemoveDefaultDialogFont(hDlg);
  1989. if (IsWindow(param->hwndTT))
  1990. DestroyWindow(param->hwndTT);
  1991. if (param->pszTTText)
  1992. {
  1993. LocalFree(param->pszTTText);
  1994. param->pszTTText = NULL;
  1995. }
  1996. return FALSE;
  1997. case WM_COMMAND:
  1998. id = GET_WM_COMMAND_ID(wParam, lParam);
  1999. switch (id)
  2000. {
  2001. case IDC_SAFEOPEN_AUTOOPEN:
  2002. EndDialog(hDlg, IDOK);
  2003. break;
  2004. case IDC_SAFEOPEN_AUTOSAVE:
  2005. EndDialog(hDlg, IDD_SAVEAS);
  2006. break;
  2007. case IDM_MOREINFO:
  2008. SHHtmlHelpOnDemandWrap(hDlg, TEXT("iexplore.chm > iedefault"), HH_DISPLAY_TOPIC, (DWORD_PTR) TEXT("filedown.htm"), ML_CROSSCODEPAGE);
  2009. break;
  2010. case IDCANCEL:
  2011. bCancelled = TRUE;
  2012. EndDialog(hDlg, id);
  2013. break;
  2014. }
  2015. break;
  2016. default:
  2017. return FALSE;
  2018. }
  2019. return TRUE;
  2020. }
  2021. UINT _ShowSafeOpenDialog(HWND hwnd, UINT idRes, SAFEOPENDLGPARAM *pparam)
  2022. {
  2023. UINT uRet = -1;
  2024. // is whistler ?
  2025. if (IsOS(OS_WHISTLERORGREATER))
  2026. {
  2027. HMODULE hmod = LoadLibrary(TEXT("xpsp1res.dll"));
  2028. if (hmod)
  2029. {
  2030. uRet = (UINT) DialogBoxParam(hmod, MAKEINTRESOURCE(idRes), hwnd, SafeOpenDlgProc, (LPARAM)pparam);
  2031. FreeLibrary(hmod);
  2032. }
  2033. }
  2034. if (uRet == -1)
  2035. uRet = (UINT) DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(idRes), hwnd, SafeOpenDlgProc, (LPARAM)pparam);
  2036. return uRet;
  2037. }
  2038. UINT OpenSafeOpenDialog(HWND hwnd, UINT idRes, LPCTSTR pszFileClass, LPCTSTR pszURL, LPCTSTR pszRedirURL, LPCTSTR pszCacheName, LPCTSTR pszDisplay, UINT uiCP, IUnknown *punk, BOOL fTypeMismatch)
  2039. {
  2040. IDownloadManager *pdlm;
  2041. HRESULT hr = IUnknown_QueryService(punk, SID_SDownloadManager, IID_PPV_ARG(IDownloadManager, &pdlm));
  2042. if (SUCCEEDED(hr))
  2043. {
  2044. pdlm->Release();
  2045. return IDD_SAVEAS;
  2046. }
  2047. LPCTSTR pszTemp = pszURL;
  2048. if (pszRedirURL && lstrlen(pszRedirURL))
  2049. pszTemp = pszRedirURL;
  2050. SAFEOPENDLGPARAM param = { pszFileClass, pszDisplay, pszTemp, 0, 0, pszCacheName, uiCP, fTypeMismatch, FALSE, FALSE};
  2051. return _ShowSafeOpenDialog(hwnd, idRes, &param);
  2052. }
  2053. STDAPI_(BOOL) SafeOpenPromptForShellExec(HWND hwnd, PCWSTR pszFile)
  2054. {
  2055. SAFEOPENDLGPARAM param = { PathFindExtension(pszFile), NULL, pszFile, 0, 0, NULL, CP_ACP, TRUE, TRUE, FALSE};
  2056. return IDOK == _ShowSafeOpenDialog(hwnd, DLG_SAFEOPEN, &param);
  2057. }
  2058. STDAPI_(BOOL) SafeOpenPromptForPackager(HWND hwnd, PCWSTR pszFile, BOOL bFromCommandLine)
  2059. {
  2060. SAFEOPENDLGPARAM param = { PathFindExtension(pszFile), NULL, pszFile, 0, 0, NULL, CP_ACP, TRUE, TRUE, bFromCommandLine};
  2061. return IDOK == _ShowSafeOpenDialog(hwnd, DLG_SAFEOPEN, &param);
  2062. }
  2063. BOOL _OpenIsSafe(LPCTSTR pszClass)
  2064. {
  2065. BOOL bRet = FALSE;
  2066. IQueryAssociations *passoc;
  2067. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &passoc));
  2068. if (SUCCEEDED(hr))
  2069. {
  2070. hr = passoc->Init(NULL, pszClass, NULL, NULL);
  2071. if (SUCCEEDED(hr))
  2072. {
  2073. DWORD dwEditFlags;
  2074. ULONG cb = sizeof(dwEditFlags);
  2075. hr = passoc->GetData(NULL, ASSOCDATA_EDITFLAGS, NULL, &dwEditFlags, &cb);
  2076. if (SUCCEEDED(hr))
  2077. {
  2078. if (dwEditFlags & FTA_OpenIsSafe)
  2079. bRet = TRUE;
  2080. }
  2081. }
  2082. passoc->Release();
  2083. }
  2084. return bRet;
  2085. }
  2086. UINT MayOpenSafeOpenDialog(HWND hwnd,
  2087. LPCTSTR pszFileClass,
  2088. LPCTSTR pszURL,
  2089. LPCTSTR pszCacheName,
  2090. LPCTSTR pszDisplay,
  2091. UINT uiCP,
  2092. IUnknown * punk,
  2093. IOleCommandTarget * pCmdTarget = NULL,
  2094. BOOL fDisableOpen = FALSE)
  2095. {
  2096. // Has some association
  2097. UINT uiRet = IDIGNORE; // default for no dlg displayed
  2098. const LPCTSTR c_szExcluded[] = {TEXT(".ins"),TEXT(".isp")};
  2099. const LPCTSTR c_szNoZoneCheckExtns[] = {TEXT(".cdf")};
  2100. BOOL fSafe = _OpenIsSafe(pszFileClass);
  2101. // We will not do Zone check on CDF files..#56297.
  2102. if (!IsTypeInList(pszFileClass, c_szNoZoneCheckExtns, ARRAYSIZE(c_szNoZoneCheckExtns)))
  2103. {
  2104. DWORD dwPolicy = 0, dwContext = 0;
  2105. ZoneCheckUrlEx(pszURL, &dwPolicy, sizeof(dwPolicy), &dwContext, sizeof(dwContext),
  2106. URLACTION_SHELL_FILE_DOWNLOAD, PUAF_NOUI, NULL);
  2107. dwPolicy = GetUrlPolicyPermissions(dwPolicy);
  2108. if ((dwPolicy != URLPOLICY_ALLOW) && (dwPolicy != URLPOLICY_QUERY))
  2109. {
  2110. ProcessStartbindingError(NULL, NULL, NULL, MB_ICONWARNING, E_ACCESSDENIED);
  2111. return IDCANCEL;
  2112. }
  2113. }
  2114. // Always ask for certain the types that we know to be unsafe. We will allow .ins and .isp
  2115. // files through for the ICW folks.
  2116. if (AssocIsDangerous(pszFileClass) &&
  2117. !IsTypeInList(pszFileClass, c_szExcluded, ARRAYSIZE(c_szExcluded)))
  2118. fSafe = FALSE;
  2119. if (!fSafe || SHRestricted2(REST_AlwaysPromptWhenDownload, NULL,0))
  2120. {
  2121. VARIANT varOut = {0};
  2122. if (pCmdTarget)
  2123. {
  2124. pCmdTarget->Exec(&CGID_ShellDocView, SHDVID_FIREFILEDOWNLOAD, 0, NULL, &varOut);
  2125. }
  2126. if ((V_VT(&varOut) != VT_BOOL) || (VARIANT_FALSE == V_BOOL(&varOut)))
  2127. {
  2128. uiRet = OpenSafeOpenDialog(hwnd,
  2129. DLG_SAFEOPEN,
  2130. pszFileClass,
  2131. pszURL,
  2132. NULL,
  2133. pszCacheName,
  2134. pszDisplay,
  2135. uiCP,
  2136. punk,
  2137. fDisableOpen);
  2138. }
  2139. }
  2140. if (uiRet != IDOK && uiRet != IDD_SAVEAS && uiRet != IDIGNORE)
  2141. DeleteUrlCacheEntry(pszURL);
  2142. return(uiRet);
  2143. }
  2144. #ifdef CALL_WVT
  2145. // Returns:
  2146. //
  2147. // IDOK -- If it's trusted
  2148. // IDNO -- If it's not known (warning dialog requried)
  2149. // IDCANCEL -- We need to stop download it
  2150. //
  2151. UINT _VerifyTrust(HWND hwnd, LPCTSTR pszFileName, LPCWSTR pszStatusText)
  2152. {
  2153. UINT uRet = IDNO; // assume unknown
  2154. HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ,
  2155. NULL, OPEN_EXISTING,
  2156. FILE_ATTRIBUTE_NORMAL, 0);
  2157. if (hFile != INVALID_HANDLE_VALUE)
  2158. {
  2159. HRESULT hres = g_wvt.VerifyTrust(hFile, hwnd, pszStatusText);
  2160. if (SUCCEEDED(hres))
  2161. {
  2162. uRet = IDOK;
  2163. }
  2164. else
  2165. {
  2166. ASSERT((hres != HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)) &&
  2167. (hres != HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND)));
  2168. uRet = IDCANCEL;
  2169. }
  2170. CloseHandle(hFile);
  2171. }
  2172. else
  2173. {
  2174. TraceMsg(DM_WARNING, "_VerifyTrust CreateFile failed %x", GetLastError());
  2175. }
  2176. TraceMsg(DM_WVT, "_VerifyTrust returning %d", uRet);
  2177. return uRet;
  2178. }
  2179. #endif // CALL_WVT
  2180. //
  2181. // Returns:
  2182. // IDOK: Continue download and open it
  2183. // IDD_SAVEAS: Save it as a file
  2184. // IDCANCEL: Stop downloading
  2185. //
  2186. UINT CDownload::_MayAskUserIsFileSafeToOpen(LPCTSTR pszMime)
  2187. {
  2188. if (_fSaveAs || _fSafe)
  2189. {
  2190. return (_fSaveAs ? IDD_SAVEAS : IDOK); // no need to ask
  2191. }
  2192. // Force save as dialog if we are using SSL and
  2193. // HKCU\software\microsoft\windows\currentversion\internet settings\DisableCachingOfSSLPages is set
  2194. DWORD dwValue;
  2195. DWORD dwDefault = 0;
  2196. DWORD dwSize;
  2197. dwSize = sizeof(dwValue);
  2198. SHRegGetUSValue(TSZWININETPATH, TEXT("DisableCachingOfSSLPages"), NULL, (LPBYTE)&dwValue, &dwSize, FALSE, (void *) &dwDefault, sizeof(dwDefault));
  2199. if (dwValue != 0 && URL_SCHEME_HTTPS == GetUrlScheme(_szURL))
  2200. {
  2201. return(IDD_SAVEAS);
  2202. }
  2203. if(_fConfirmed)
  2204. {
  2205. return IDOK;
  2206. }
  2207. BOOL fUnknownType = TRUE;
  2208. UINT uRet = IDNO; // assume no extension or no association
  2209. LPTSTR pszExt = PathFindExtension(_szPath);
  2210. if (*pszExt)
  2211. {
  2212. TCHAR szFileClass[MAX_PATH];
  2213. memset(szFileClass, 0, ARRAYSIZE(szFileClass));
  2214. #ifdef CALL_WVT
  2215. //
  2216. // If this is an EXE and we have WINTRUST ready to call,
  2217. // don't popup any UI here at this point.
  2218. if ((StrCmpI(pszExt, TEXT(".exe"))==0) && SUCCEEDED(g_wvt.Init()))
  2219. {
  2220. TraceMsg(DM_WVT, "_MayAskUIFSTO this is EXE, we call _VerifyTrust later");
  2221. _fCallVerifyTrust = TRUE;
  2222. }
  2223. #endif // CALL_WVT
  2224. ULONG cb = SIZEOF(szFileClass);
  2225. if ((RegQueryValue(HKEY_CLASSES_ROOT, pszExt, szFileClass, (LONG*)&cb)
  2226. == ERROR_SUCCESS) && * szFileClass)
  2227. {
  2228. fUnknownType = FALSE;
  2229. uRet = MayOpenSafeOpenDialog(_hDlg, szFileClass, _szURL, _szPath, _szDisplay, _uiCP, NULL, NULL, FALSE);
  2230. if (uRet == IDIGNORE) // caller doesn't recognize IDIGNORE
  2231. uRet = IDOK;
  2232. }
  2233. }
  2234. if (fUnknownType)
  2235. {
  2236. uRet = OpenSafeOpenDialog(_hDlg, DLG_SAFEOPEN, NULL, _szURL, NULL, _szPath, _szDisplay, _uiCP, NULL, FALSE);
  2237. }
  2238. return uRet;
  2239. }
  2240. // *** IAuthenticate ***
  2241. HRESULT CDownload::Authenticate(HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword)
  2242. {
  2243. if (!phwnd || !pszUsername || !pszPassword)
  2244. return E_POINTER;
  2245. *phwnd = _hDlg;
  2246. *pszUsername = NULL;
  2247. *pszPassword = NULL;
  2248. return S_OK;
  2249. }
  2250. HRESULT CDownload::GetWindow(REFGUID RefGUID, HWND *phWnd)
  2251. {
  2252. if (IsEqualGUID(RefGUID, IID_IHttpSecurity))
  2253. {
  2254. *phWnd = _hDlg;
  2255. return S_OK;
  2256. }
  2257. else
  2258. return E_FAIL;
  2259. }
  2260. // *** IServiceProvider ***
  2261. HRESULT CDownload::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  2262. {
  2263. *ppvObj = NULL;
  2264. if (IsEqualGUID(guidService, IID_IAuthenticate))
  2265. {
  2266. return QueryInterface(riid, ppvObj);
  2267. }
  2268. return E_FAIL;
  2269. }
  2270. // S_OK : continue with operation
  2271. // S_FALSE : cancel operation.
  2272. HRESULT CDownload::PerformVirusScan(LPCTSTR szFileName)
  2273. {
  2274. HRESULT hr = S_OK; // default to accepting the file
  2275. IVirusScanner *pvs;
  2276. if (SUCCEEDED(CreateFromRegKey(TSZIEPATH, TEXT("VirusScanner"), IID_PPV_ARG(IVirusScanner, &pvs))))
  2277. {
  2278. STGMEDIUM stg;
  2279. WCHAR wszFileName[MAX_PATH];
  2280. VIRUSINFO vi;
  2281. vi.cbSize = sizeof(VIRUSINFO);
  2282. //
  2283. // VIRUSINFO lpszFileName is not defined as 'const' so we need to copy
  2284. // szFileName into a buffer. If it really should be const get rid of
  2285. // this copy and use a cast.
  2286. //
  2287. StrCpyN(wszFileName, szFileName, ARRAYSIZE(wszFileName));
  2288. stg.tymed = TYMED_FILE;
  2289. stg.lpszFileName = wszFileName;
  2290. stg.pUnkForRelease = NULL;
  2291. hr = pvs->ScanForVirus(_hDlg, &stg, _pwszDisplayName, SFV_DELETE, &vi);
  2292. switch (hr) {
  2293. case S_OK:
  2294. break;
  2295. case VSCAN_E_NOPROVIDERS: //No virus scanning providers
  2296. case VSCAN_E_CHECKPARTIAL: //Atleast one of providers didn't work.
  2297. case VSCAN_E_CHECKFAIL: //No providers worked.
  2298. hr = S_OK;
  2299. break;
  2300. case VSCAN_E_DELETEFAIL: //Tried to delete virus file but failed.
  2301. case S_FALSE: // Virus found.
  2302. hr = E_FAIL;
  2303. break;
  2304. // If some bizarre result, continue on.
  2305. default:
  2306. hr = S_OK;
  2307. break;
  2308. }
  2309. pvs->Release();
  2310. }
  2311. return hr;
  2312. }
  2313. // Starts a download of a file in its own window.
  2314. // This function is exported and called by HTML doc object.
  2315. // Someday we probably want to put this in a COM interface.
  2316. // Currently it just calls the internal function CDownLoad_OpenUIURL.
  2317. STDAPI DoFileDownload(LPCWSTR pwszURL)
  2318. {
  2319. return CDownLoad_OpenUIURL(pwszURL, NULL, NULL, FALSE,TRUE);
  2320. }
  2321. STDAPI DoFileDownloadEx(LPCWSTR pwszURL, BOOL fSaveAs)
  2322. {
  2323. return CDownLoad_OpenUIURL(pwszURL, NULL, NULL, FALSE, fSaveAs);
  2324. }
  2325. #ifdef DEBUG
  2326. const DWORD CDownloadThreadParam::s_dummy = 0;
  2327. #endif