Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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