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.

1215 lines
39 KiB

  1. #undef UNICODE
  2. #include "urlmon.h"
  3. #include "wininet.h"
  4. #include "commctrl.h"
  5. #include "windows.h"
  6. #include <stdio.h>
  7. #include "initguid.h"
  8. #include "hlink.h"
  9. ///#include "hlguids.h"
  10. #ifdef PRODUCT_PROF
  11. extern "C" void _stdcall StartCAP(void);
  12. extern "C" void _stdcall StopCAP(void);
  13. extern "C" void _stdcall SuspendCAP(void);
  14. extern "C" void _stdcall ResumeCAP(void);
  15. extern "C" void _stdcall StartCAPAll(void);
  16. extern "C" void _stdcall StopCAPAll(void);
  17. #else
  18. #define StartCAP()
  19. #define StopCAP()
  20. #define SuspendCAP()
  21. #define ResumeCAP()
  22. #define StartCAPAll()
  23. #define StopCAPAll()
  24. #endif
  25. typedef BOOL (WINAPI *PFNSPA)(HANDLE, DWORD);
  26. typedef HRESULT (WINAPI * pfnCreateURLMoniker)(IMoniker *, LPCWSTR, IMoniker **);
  27. typedef HRESULT (WINAPI * pfnRegisterBindStatusCallback)(LPBC, IBindStatusCallback *, IBindStatusCallback **, DWORD);
  28. typedef struct
  29. {
  30. TCHAR* pBuf; //Actual buffer to hold data
  31. DWORD lNumRead; //number of bytes read in buffer
  32. void* pNext; //Pointer to next buffer
  33. } buffer;
  34. HINSTANCE g_hUrlMon = NULL;
  35. pfnCreateURLMoniker g_pfnCreateURLMoniker = NULL;
  36. pfnRegisterBindStatusCallback g_pfnRegisterBindStatusCallback = NULL;
  37. #define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
  38. #define DO_DOWNLOAD WM_USER + 10
  39. #define DOWNLOAD_DONE WM_USER + 11
  40. #pragma warning(disable:4100)
  41. // ---------------------------------------------------------------------------
  42. #define DBG_ERROR 0x80000000
  43. // verbose flags
  44. #define DBG_RESULTS 0x01
  45. #define DBG_DEBUG 0x02
  46. #define DBG_INFO 0x04
  47. #define DBG_STARTBINDING 0x08
  48. #define DBG_STOPBINDING 0x10
  49. #define DBG_ONPROGRESS 0x20
  50. #define DBG_ONAVAIL 0x40
  51. #define DBG_BREAKONERROR 0x80
  52. #define DBG_ALLVALID DBG_RESULTS | DBG_DEBUG | DBG_STARTBINDING | DBG_STOPBINDING | DBG_ONPROGRESS | DBG_ONAVAIL
  53. DWORD g_dwDbgFlags = DBG_RESULTS;
  54. // ---------------------------------------------------------------------------
  55. const INT MAX_BUF_SIZE = 1024 * 16;
  56. const INT BUF_SIZE = 2 * 1024;
  57. const INT URL_MAX = 4;
  58. const INT BUF_NUM = 16*4;
  59. const DWORD TIMEOUT = 10000000;
  60. const INT LDG_DONE = 1;
  61. const INT LDG_STARTED = 0;
  62. const INT PRI_LOW = 1;
  63. const INT PRI_MED = 2;
  64. const INT PRI_HI = 3;
  65. DWORD dwBegin_Time = 0;
  66. DWORD dwEnd_Time;
  67. DWORD dwTot_Time;
  68. BOOL bDelim = FALSE;
  69. DWORD dwNum_Opens = 1;
  70. DWORD dwBuf_Size = BUF_SIZE;
  71. DWORD dwBytes_Read = 0;
  72. DWORD dwMax_Simul_Downloads = URL_MAX;
  73. DWORD g_dwCacheFlag = BINDF_NOWRITECACHE | BINDF_GETNEWESTVERSION;
  74. char *pFilename = NULL;
  75. char *pInFile = NULL;
  76. char *g_pRunStr = NULL;
  77. char *g_pTestName = NULL;
  78. char g_CmdLine[1024];
  79. TCHAR sUrl[(INTERNET_MAX_URL_LENGTH+1)];
  80. TCHAR* g_pBuf = NULL;
  81. // %%Classes: ----------------------------------------------------------------
  82. class CInfo
  83. {
  84. public:
  85. CInfo();
  86. ~CInfo();
  87. INT incDownloads(void) { return m_iDownloads++; }
  88. INT decDownloads(void) { return m_iDownloads--; }
  89. INT getDownloads(void) { return m_iDownloads; }
  90. HANDLE m_hCompleteEvent;
  91. CRITICAL_SECTION m_csInfo; //for critical section
  92. HANDLE m_hMaxDownloadSem;
  93. buffer* m_pPool; //Pointer to current available buffer in pool
  94. void* m_pdFirst; //pointer to the first element
  95. private:
  96. INT m_iDownloads; //number of current downloads
  97. };
  98. class CDownload
  99. {
  100. public:
  101. CDownload(LPSTR sName, CInfo* pcInfo);
  102. ~CDownload();
  103. HRESULT doDownload(void);
  104. INT getStatus(void) { return m_iStatus; }
  105. INT getPriority(void) { return m_iPriority; }
  106. #ifdef USE_POOL
  107. INT releasePool(void);
  108. #endif
  109. WCHAR m_pUrl[(INTERNET_MAX_URL_LENGTH+1)];
  110. #ifdef USE_POOL
  111. buffer* m_pbStartBuffer; //first buffer to hold data
  112. buffer* m_pbCurBuffer; //Current Buffer
  113. #endif
  114. CInfo* m_pcInfo;
  115. void* m_pdNext; //pointer to next element
  116. INT m_iStatus; //the url's status
  117. INT m_iPriority; //the url's priority
  118. DWORD lNumRead; //number of bytes read in buffer for this download
  119. private:
  120. IMoniker* m_pMoniker;
  121. IBindCtx* m_pBindCtx;
  122. IBindStatusCallback* m_pBindCallback;
  123. };
  124. class CBindStatusCallback : public IBindStatusCallback
  125. {
  126. public:
  127. // IUnknown methods
  128. STDMETHODIMP QueryInterface(REFIID riid,void ** ppv);
  129. STDMETHODIMP_(ULONG) AddRef() { return m_cRef++; }
  130. STDMETHODIMP_(ULONG) Release() { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; }
  131. // IBindStatusCallback methods
  132. STDMETHODIMP OnStartBinding(DWORD dwReserved, IBinding* pbinding);
  133. STDMETHODIMP GetPriority(LONG* pnPriority);
  134. STDMETHODIMP OnLowResource(DWORD dwReserved);
  135. STDMETHODIMP OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode,
  136. LPCWSTR pwzStatusText);
  137. STDMETHODIMP OnStopBinding(HRESULT hrResult, LPCWSTR szError);
  138. STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo);
  139. STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc,
  140. STGMEDIUM* pstgmed);
  141. STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown* punk);
  142. // constructors/destructors
  143. CBindStatusCallback(CDownload* pcDownload);
  144. ~CBindStatusCallback();
  145. // data members
  146. DWORD m_cRef;
  147. IBinding* m_pBinding;
  148. IStream* m_pStream;
  149. DWORD m_cbOld;
  150. CDownload* m_pcDownload;
  151. };
  152. // ---------------------------------------------------------------------------
  153. // ---------------------------------------------------------------------------
  154. INT dprintf(DWORD dwFlags, TCHAR *fmt, ... )
  155. {
  156. INT ret = 0;
  157. va_list marker;
  158. TCHAR szBuffer[256];
  159. if(dwFlags & (g_dwDbgFlags | DBG_ERROR))
  160. {
  161. va_start( marker, fmt );
  162. ret = vsprintf( szBuffer, fmt, marker );
  163. OutputDebugString( szBuffer );
  164. printf(szBuffer);
  165. if(g_dwDbgFlags & DBG_BREAKONERROR)
  166. DebugBreak();
  167. }
  168. return ret;
  169. }
  170. // ---------------------------------------------------------------------------
  171. // ---------------------------------------------------------------------------
  172. void SetSingleProcessorAffinity()
  173. {
  174. PFNSPA pfn;
  175. pfn = (PFNSPA)GetProcAddress(GetModuleHandleA("KERNEL32.DLL"),
  176. "SetProcessAffinityMask");
  177. if (pfn)
  178. {
  179. pfn(GetCurrentProcess(), 1);
  180. }
  181. }
  182. // ---------------------------------------------------------------------------
  183. // ---------------------------------------------------------------------------
  184. HRESULT LoadUrlMon()
  185. {
  186. g_hUrlMon = (HINSTANCE)LoadLibraryA("URLMON.DLL");
  187. if (g_hUrlMon == NULL)
  188. {
  189. dprintf(DBG_ERROR, "LoadLibraryA of URLMON.DLL failed\n");
  190. return(E_FAIL);
  191. }
  192. g_pfnCreateURLMoniker = (pfnCreateURLMoniker)GetProcAddress(g_hUrlMon, "CreateURLMoniker");
  193. if (g_pfnCreateURLMoniker == NULL)
  194. {
  195. dprintf(DBG_ERROR, "GetProcAddress CreateURLMoniker failed\n");
  196. return(E_FAIL);
  197. }
  198. g_pfnRegisterBindStatusCallback = (pfnRegisterBindStatusCallback)GetProcAddress(g_hUrlMon, "RegisterBindStatusCallback");
  199. if (g_pfnRegisterBindStatusCallback == NULL)
  200. {
  201. dprintf(DBG_ERROR, "GetProcAddress RegisterBindStatusCallback failed\n");
  202. return(E_FAIL);
  203. }
  204. return(S_OK);
  205. }
  206. // ---------------------------------------------------------------------------
  207. // ---------------------------------------------------------------------------
  208. void UnloadUrlMon()
  209. {
  210. if (g_hUrlMon)
  211. {
  212. FreeLibrary(g_hUrlMon);
  213. }
  214. }
  215. // ===========================================================================
  216. // CBindStatusCallback Implementation
  217. // ===========================================================================
  218. // ---------------------------------------------------------------------------
  219. // %%Function: CBindStatusCallback::CBindStatusCallback
  220. // ---------------------------------------------------------------------------
  221. CBindStatusCallback::CBindStatusCallback(CDownload* pcDownload)
  222. {
  223. m_pBinding = NULL;
  224. m_pStream = NULL;
  225. m_cRef = 1;
  226. m_cbOld = 0;
  227. m_pcDownload = pcDownload;
  228. } // CBindStatusCallback
  229. // ---------------------------------------------------------------------------
  230. // %%Function: CBindStatusCallback::~CBindStatusCallback
  231. // ---------------------------------------------------------------------------
  232. CBindStatusCallback::~CBindStatusCallback()
  233. {
  234. } // ~CBindStatusCallback
  235. // ---------------------------------------------------------------------------
  236. // %%Function: CBindStatusCallback::QueryInterface
  237. // ---------------------------------------------------------------------------
  238. STDMETHODIMP
  239. CBindStatusCallback::QueryInterface(REFIID riid, void** ppv)
  240. {
  241. *ppv = NULL;
  242. if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
  243. {
  244. *ppv = this;
  245. AddRef();
  246. return S_OK;
  247. }
  248. return E_NOINTERFACE;
  249. } // CBindStatusCallback::QueryInterface
  250. // ---------------------------------------------------------------------------
  251. // %%Function: CBindStatusCallback::OnStartBinding
  252. // ---------------------------------------------------------------------------
  253. STDMETHODIMP CBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding* pBinding)
  254. {
  255. if (m_pBinding != NULL)
  256. m_pBinding->Release();
  257. m_pBinding = pBinding;
  258. if (m_pBinding != NULL)
  259. m_pBinding->AddRef();
  260. m_pcDownload->m_pcInfo->incDownloads();
  261. if(g_dwDbgFlags)
  262. dprintf(DBG_STOPBINDING, "OnStartBinding getDownloads()=%d\n", m_pcDownload->m_pcInfo->getDownloads());
  263. return S_OK;
  264. } // CBindStatusCallback::OnStartBinding
  265. // ---------------------------------------------------------------------------
  266. // %%Function: CBindStatusCallback::GetPriority
  267. // ---------------------------------------------------------------------------
  268. STDMETHODIMP CBindStatusCallback::GetPriority(LONG* pnPriority)
  269. {
  270. return E_NOTIMPL;
  271. } // CBindStatusCallback::GetPriority
  272. // ---------------------------------------------------------------------------
  273. // %%Function: CBindStatusCallback::OnLowResource
  274. // ---------------------------------------------------------------------------
  275. STDMETHODIMP CBindStatusCallback::OnLowResource(DWORD dwReserved)
  276. {
  277. return E_NOTIMPL;
  278. } // CBindStatusCallback::OnLowResource
  279. // ---------------------------------------------------------------------------
  280. // %%Function: CBindStatusCallback::OnProgress
  281. // ---------------------------------------------------------------------------
  282. STDMETHODIMP CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
  283. {
  284. TCHAR sz[255];
  285. if(szStatusText != NULL) {
  286. WideCharToMultiByte(CP_ACP, 0, szStatusText, -1, sz, 255,0,0);
  287. }
  288. if(g_dwDbgFlags)
  289. dprintf(DBG_ONPROGRESS, "OnProgress: %d(%s) %d of %d\n", ulStatusCode, sz, ulProgress, (ulProgress>ulProgressMax)?ulProgress:ulProgressMax);
  290. return(NOERROR);
  291. } // CBindStatusCallback::OnProgress
  292. // ---------------------------------------------------------------------------
  293. // %%Function: CBindStatusCallback::OnStopBinding
  294. // ---------------------------------------------------------------------------
  295. STDMETHODIMP CBindStatusCallback::OnStopBinding(HRESULT hrStatus, LPCWSTR pszError)
  296. {
  297. if (hrStatus != S_OK)
  298. {
  299. if(g_dwDbgFlags & DBG_DEBUG)
  300. {
  301. TCHAR sUrl[(INTERNET_MAX_URL_LENGTH+1)];
  302. TCHAR sErr[1024];
  303. WideCharToMultiByte(CP_ACP, 0, m_pcDownload->m_pUrl, -1,
  304. sUrl, INTERNET_MAX_URL_LENGTH, 0, 0);
  305. WideCharToMultiByte(CP_ACP, 0, pszError, -1,
  306. sErr, 1024, 0, 0);
  307. dprintf(DBG_ERROR, "*** ERROR *** %s OnStopBinding download failed. Status=%x Err=%s\n", sUrl, hrStatus, sErr);
  308. }
  309. }
  310. if (m_pBinding)
  311. {
  312. m_pBinding->Release();
  313. m_pBinding = NULL;
  314. }
  315. m_pcDownload->m_pcInfo->decDownloads();
  316. if(g_dwDbgFlags)
  317. dprintf(DBG_STOPBINDING, "OnStopBinding hrStatus=%d getDownloads()=%d\n", hrStatus, m_pcDownload->m_pcInfo->getDownloads());
  318. if(m_pcDownload->m_pcInfo->getDownloads() == 0)
  319. {
  320. SetEvent(m_pcDownload->m_pcInfo->m_hCompleteEvent);
  321. }
  322. return S_OK;
  323. } // CBindStatusCallback::OnStopBinding
  324. // ---------------------------------------------------------------------------
  325. // %%Function: CBindStatusCallback::GetBindInfo
  326. // ---------------------------------------------------------------------------
  327. STDMETHODIMP CBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pBindInfo)
  328. {
  329. *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
  330. *pgrfBINDF |= g_dwCacheFlag;
  331. pBindInfo->cbSize = sizeof(BINDINFO);
  332. pBindInfo->szExtraInfo = NULL;
  333. memset(&pBindInfo->stgmedData, 0, sizeof(STGMEDIUM));
  334. pBindInfo->grfBindInfoF = 0;
  335. pBindInfo->dwBindVerb = BINDVERB_GET;
  336. pBindInfo->szCustomVerb = NULL;
  337. return S_OK;
  338. } // CBindStatusCallback::GetBindInfo
  339. // ---------------------------------------------------------------------------
  340. // %%Function: CBindStatusCallback::OnDataAvailable
  341. // ---------------------------------------------------------------------------
  342. STDMETHODIMP CBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed)
  343. {
  344. DWORD dwRead = dwSize - m_cbOld; // Amount to be read
  345. HRESULT hr = S_OK;
  346. // Get the Stream passed
  347. if(g_dwDbgFlags)
  348. dprintf(DBG_ONAVAIL, "OnDataAvailable(grfBSCF=%d pStream=0x%x dwRead=%d dwSize=%d pfmtetc=0x%x, pstgmed=0x%x\n",
  349. grfBSCF, m_pStream, dwRead, dwSize, pfmtetc, pstgmed);
  350. if (!m_pStream && pstgmed->tymed == TYMED_ISTREAM)
  351. {
  352. m_pStream = pstgmed->pstm;
  353. }
  354. // If there is some data to be read then go ahead and read
  355. if (m_pStream && dwRead)
  356. {
  357. while(hr!=E_PENDING)
  358. {
  359. #ifdef USE_POOL
  360. if(m_pcDownload->m_pcInfo->m_pPool)
  361. {
  362. //if pool ready
  363. EnterCriticalSection(&(m_pcDownload->m_pcInfo->m_csInfo));
  364. if(!m_pcDownload->m_pbStartBuffer)
  365. {
  366. // if the first time
  367. m_pcDownload->m_pbStartBuffer =
  368. m_pcDownload->m_pbCurBuffer =
  369. m_pcDownload->m_pcInfo->m_pPool;
  370. m_pcDownload->m_pcInfo->m_pPool =
  371. (buffer *)m_pcDownload->m_pcInfo->m_pPool->pNext;
  372. m_pcDownload->m_pbStartBuffer->pNext = NULL;
  373. }
  374. else
  375. {
  376. m_pcDownload->m_pbCurBuffer->pNext =
  377. m_pcDownload->m_pcInfo->m_pPool;
  378. m_pcDownload->m_pcInfo->m_pPool =
  379. (buffer *)m_pcDownload->m_pcInfo->m_pPool->pNext;
  380. m_pcDownload->m_pbCurBuffer = (buffer *) m_pcDownload->m_pbCurBuffer->pNext;
  381. m_pcDownload->m_pbCurBuffer->pNext = NULL;
  382. }
  383. LeaveCriticalSection(&(m_pcDownload->m_pcInfo->m_csInfo));
  384. }
  385. else
  386. {
  387. //allocate buffers on the fly
  388. if(!m_pcDownload->m_pbStartBuffer)
  389. {
  390. // if the first time
  391. m_pcDownload->m_pbStartBuffer = m_pcDownload->m_pbCurBuffer = new buffer;
  392. if(!m_pcDownload->m_pbCurBuffer)
  393. {
  394. dprintf(DBG_ERROR, "*** ERROR *** on buff alloc\n");
  395. return S_FALSE;
  396. }
  397. m_pcDownload->m_pbCurBuffer->pBuf = new TCHAR[dwBuf_Size];
  398. if(!m_pcDownload->m_pbCurBuffer->pBuf)
  399. {
  400. dprintf(DBG_ERROR, "*** ERROR *** on buf alloc\n");
  401. return S_FALSE;
  402. }
  403. m_pcDownload->m_pbStartBuffer->pNext = NULL;
  404. }
  405. else
  406. {
  407. m_pcDownload->m_pbCurBuffer->pNext = new buffer;
  408. if(!m_pcDownload->m_pbCurBuffer->pNext)
  409. {
  410. dprintf(DBG_ERROR, "*** ERROR *** on buff alloc\n");
  411. return S_FALSE;
  412. }
  413. m_pcDownload->m_pbCurBuffer = (buffer *) m_pcDownload->m_pbCurBuffer->pNext;
  414. m_pcDownload->m_pbCurBuffer->pBuf = new TCHAR[dwBuf_Size];
  415. if(!m_pcDownload->m_pbCurBuffer->pBuf)
  416. {
  417. dprintf(DBG_ERROR, "*** ERROR *** on buf alloc\n");
  418. return S_FALSE;
  419. }
  420. m_pcDownload->m_pbCurBuffer->pNext = NULL;
  421. }
  422. }
  423. #endif
  424. if(dwBegin_Time == 0)
  425. dwBegin_Time = GetTickCount();
  426. #ifdef USE_POOL
  427. hr = m_pStream->Read(m_pcDownload->m_pbCurBuffer->pBuf,
  428. dwBuf_Size, &(m_pcDownload->m_pbCurBuffer->lNumRead));
  429. if(g_dwDbgFlags)
  430. {
  431. dprintf(DBG_INFO & DBG_DEBUG, "Stream->Read Size=%d Read=%d hr=0x%x\n", dwBuf_Size, m_pcDownload->m_pbCurBuffer->lNumRead, hr);
  432. if(hr != S_OK && hr != E_PENDING && hr != S_FALSE)
  433. dprintf(DBG_ERROR, "************ Stream->Read hr=0x%x\n", hr);
  434. }
  435. #else
  436. hr = m_pStream->Read(g_pBuf, dwBuf_Size, &(m_pcDownload->lNumRead));
  437. if(g_dwDbgFlags)
  438. {
  439. dprintf(DBG_INFO & DBG_DEBUG, "Stream->Read Size=%d Read=%d hr=0x%x\n", dwBuf_Size, m_pcDownload->lNumRead, hr);
  440. if(hr != S_OK && hr != E_PENDING && hr != S_FALSE)
  441. dprintf(DBG_ERROR, "************ Stream->Read hr=0x%x\n", hr);
  442. }
  443. #endif
  444. //need to check for error if read reaches end of stream
  445. if(hr == S_FALSE)
  446. {
  447. break;
  448. }
  449. #ifdef USE_POOL
  450. if (m_pcDownload->m_pbCurBuffer->lNumRead > 0)
  451. {
  452. m_cbOld += m_pcDownload->m_pbCurBuffer->lNumRead;
  453. }
  454. #else
  455. if (m_pcDownload->lNumRead > 0)
  456. {
  457. m_cbOld += m_pcDownload->lNumRead;
  458. }
  459. #endif
  460. }
  461. }// if(m_pstm && dwRead)
  462. if (BSCF_LASTDATANOTIFICATION & grfBSCF)
  463. {
  464. WideCharToMultiByte(CP_ACP, 0, m_pcDownload->m_pUrl, -1,
  465. sUrl, INTERNET_MAX_URL_LENGTH, 0, 0);
  466. if(g_dwDbgFlags && !bDelim)
  467. dprintf(DBG_INFO, "Status: %s downloaded.\n", sUrl);
  468. // m_pcDownload->m_pcInfo->decDownloads();
  469. m_pcDownload->m_iStatus = LDG_DONE;
  470. if(!ReleaseSemaphore(m_pcDownload->m_pcInfo->m_hMaxDownloadSem,1,NULL))
  471. {
  472. dprintf(DBG_ERROR, "*** ERROR *** ReleaseSemaphore failed!\n");
  473. return S_FALSE;
  474. }
  475. dwBytes_Read += m_cbOld; // accum buf size that was downloaded
  476. }
  477. return S_OK;
  478. } // CBindStatusCallback::OnDataAvailable
  479. // ---------------------------------------------------------------------------
  480. // %%Function: CBindStatusCallback::OnObjectAvailable
  481. // ---------------------------------------------------------------------------
  482. STDMETHODIMP
  483. CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown* punk)
  484. {
  485. return E_NOTIMPL;
  486. } // CBindStatusCallback::OnObjectAvailable
  487. // ===========================================================================
  488. // CDownload Implementation
  489. // ===========================================================================
  490. // ---------------------------------------------------------------------------
  491. // %%Function: CDownload::CDownload
  492. // ---------------------------------------------------------------------------
  493. CDownload::CDownload(LPSTR sName, CInfo* pcInfo)
  494. {
  495. MultiByteToWideChar(CP_ACP, 0, sName, -1, m_pUrl, INTERNET_MAX_URL_LENGTH);
  496. m_pMoniker = 0;
  497. m_pBindCtx = 0;
  498. m_pBindCallback = 0;
  499. m_pdNext = NULL;
  500. m_iStatus = LDG_STARTED;
  501. m_iPriority = PRI_MED;
  502. m_pcInfo = pcInfo;
  503. #ifdef USE_POOL
  504. m_pbStartBuffer = m_pbCurBuffer = NULL;
  505. #endif
  506. } // CDownload
  507. // ---------------------------------------------------------------------------
  508. // %%Function: CDownload::~CDownload
  509. // ---------------------------------------------------------------------------
  510. CDownload::~CDownload()
  511. {
  512. buffer* pbLastBuf = NULL;
  513. if (m_pMoniker)
  514. m_pMoniker->Release();
  515. if (m_pBindCtx)
  516. m_pBindCtx->Release();
  517. if (m_pBindCallback)
  518. m_pBindCallback->Release();
  519. delete m_pcInfo;
  520. #ifdef USE_POOL
  521. if(m_pbStartBuffer)
  522. {
  523. while(m_pbStartBuffer->lNumRead != 0 &&
  524. m_pbStartBuffer->lNumRead <= dwBuf_Size)
  525. {
  526. delete m_pbStartBuffer->pBuf;
  527. pbLastBuf = m_pbStartBuffer;
  528. m_pbStartBuffer = (buffer *)m_pbStartBuffer->pNext;
  529. delete pbLastBuf;
  530. }
  531. }
  532. #endif
  533. GlobalFree(m_pUrl);
  534. } // ~CDownload
  535. // ---------------------------------------------------------------------------
  536. // %%Function: CDownload::DoDownload
  537. // ---------------------------------------------------------------------------
  538. HRESULT CDownload::doDownload(void)
  539. {
  540. IStream* pstm;
  541. HRESULT hr;
  542. hr = g_pfnCreateURLMoniker(NULL, m_pUrl, &m_pMoniker);
  543. if (FAILED(hr))
  544. {
  545. dprintf(DBG_ERROR, "*** ERROR *** doDownload CreateURLMoniker failed hr=0x%x\n", hr);
  546. goto LErrExit;
  547. }
  548. m_pBindCallback = new CBindStatusCallback(this);
  549. if (m_pBindCallback == NULL)
  550. {
  551. dprintf(DBG_ERROR, "*** ERROR *** doDownload CBindStatusCallback failed hr=0x%x\n", hr);
  552. hr = E_OUTOFMEMORY;
  553. goto LErrExit;
  554. }
  555. hr = CreateBindCtx(0, &m_pBindCtx);
  556. if (FAILED(hr))
  557. {
  558. dprintf(DBG_ERROR, "*** ERROR *** doDownload CreateBindCtx failed hr=0x%x\n", hr);
  559. goto LErrExit;
  560. }
  561. hr = g_pfnRegisterBindStatusCallback(
  562. m_pBindCtx,
  563. m_pBindCallback,
  564. 0, 0L);
  565. if (FAILED(hr))
  566. {
  567. dprintf(DBG_ERROR, "*** ERROR *** doDownload RegisterBindStatusCallback failed hr=0x%x\n", hr);
  568. goto LErrExit;
  569. }
  570. hr = m_pMoniker->BindToStorage(
  571. m_pBindCtx,
  572. 0,
  573. IID_IStream,
  574. (void**)&pstm);
  575. if (FAILED(hr))
  576. {
  577. dprintf(DBG_ERROR, "*** ERROR *** doDownload BindToStorage failed hr=0x%x\n", hr);
  578. goto LErrExit;
  579. }
  580. return(hr);
  581. LErrExit:
  582. if (m_pBindCtx != NULL)
  583. {
  584. m_pBindCtx->Release();
  585. m_pBindCtx = NULL;
  586. }
  587. if (m_pBindCallback != NULL)
  588. {
  589. m_pBindCallback->Release();
  590. m_pBindCallback = NULL;
  591. }
  592. if (m_pMoniker != NULL)
  593. {
  594. m_pMoniker->Release();
  595. m_pMoniker = NULL;
  596. }
  597. return hr;
  598. }
  599. // ---------------------------------------------------------------------------
  600. // %%Function: CDownload::releasePool
  601. // ---------------------------------------------------------------------------
  602. #ifdef USE_POOL
  603. INT CDownload::releasePool()
  604. {
  605. buffer *pbStart;
  606. EnterCriticalSection(&(m_pcInfo->m_csInfo));
  607. while(m_pbStartBuffer)
  608. {
  609. // remember the start buf
  610. pbStart = (buffer *) m_pbStartBuffer->pNext;
  611. // adjust the start
  612. m_pbStartBuffer = (buffer *) m_pbStartBuffer->pNext;
  613. //insert the buffer at the beginning of the pool
  614. pbStart->pNext = m_pcInfo->m_pPool;
  615. // update the pool
  616. m_pcInfo->m_pPool = pbStart;
  617. }
  618. LeaveCriticalSection(&(m_pcInfo->m_csInfo));
  619. return TRUE;
  620. }
  621. #endif
  622. // ===========================================================================
  623. // CInfo Implementation
  624. // ===========================================================================
  625. // ---------------------------------------------------------------------------
  626. // %%Function: CInfo::CInfo
  627. // ---------------------------------------------------------------------------
  628. CInfo::CInfo()
  629. {
  630. #ifdef USE_POOL
  631. INT i;
  632. buffer* pStartBuffer = NULL;
  633. #endif
  634. m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  635. if (!m_hCompleteEvent)
  636. {
  637. dprintf(DBG_ERROR, "*** ERROR *** on create Event!\n");
  638. }
  639. InitializeCriticalSection(&(m_csInfo));
  640. m_hMaxDownloadSem = CreateSemaphore(NULL,dwMax_Simul_Downloads,dwMax_Simul_Downloads, NULL);
  641. if(!m_hMaxDownloadSem)
  642. {
  643. dprintf(DBG_ERROR, "*** ERROR *** CreateSem failed!\n");
  644. }
  645. #ifdef USE_POOL
  646. pStartBuffer = m_pPool = new buffer;
  647. if(!m_pPool)
  648. return;
  649. m_pPool->pBuf = new TCHAR[dwBuf_Size];
  650. if (!m_pPool->pBuf)
  651. return;
  652. m_pPool->lNumRead = 0;
  653. #endif
  654. m_iDownloads = 0;
  655. #ifdef USE_POOL
  656. m_pPool->pNext = NULL;
  657. for(i=1; i<BUF_NUM; i++)
  658. {
  659. m_pPool->pNext = new buffer;
  660. if (!m_pPool->pNext)
  661. return;
  662. m_pPool = (buffer *)m_pPool->pNext;
  663. m_pPool->pBuf = new TCHAR[dwBuf_Size];
  664. if (!m_pPool->pBuf)
  665. return;
  666. m_pPool->lNumRead = 0;
  667. m_pPool->pNext = NULL;
  668. }
  669. m_pPool = pStartBuffer;
  670. #endif
  671. return;
  672. } // CInfo
  673. // ---------------------------------------------------------------------------
  674. // %%Function: CInfo::~CInfo
  675. // ---------------------------------------------------------------------------
  676. CInfo::~CInfo()
  677. {
  678. buffer *pLastBuf;
  679. while(m_pPool)
  680. {
  681. delete m_pPool->pBuf;
  682. pLastBuf = m_pPool;
  683. m_pPool = (buffer *)m_pPool->pNext;
  684. delete pLastBuf;
  685. }
  686. delete this;
  687. } // ~CInfo
  688. // ===========================================================================
  689. // User Interface and Initialization Routines
  690. // ===========================================================================
  691. //----------------------------------------------------------------------------
  692. // Procedure: DownloadThread
  693. // Purpose: Opens internet connection and downloads URL. Saves
  694. // URL to pOutQ (one chunk per buffer).
  695. // Arguments: outQ
  696. // Return Val: TRUE or FALSE based on error
  697. //----------------------------------------------------------------------------
  698. DWORD DownloadThread(LPDWORD lpdwParam)
  699. {
  700. INT retVal;
  701. MSG msg;
  702. CDownload *pcDownload = (CDownload *) lpdwParam;
  703. SetEvent(pcDownload->m_pcInfo->m_hCompleteEvent);
  704. if(g_dwDbgFlags)
  705. dprintf(DBG_INFO, "DownloadThread: m_hCompleteEvent set.\n");
  706. StartCAP();
  707. for (;;)
  708. {
  709. SuspendCAP();
  710. retVal = GetMessage(&msg, NULL, 0, 0);
  711. ResumeCAP();
  712. if(retVal == -1)
  713. {
  714. dprintf(DBG_ERROR, "*** ERROR *** on GetMessage\n");
  715. break;
  716. }
  717. if(retVal == FALSE)
  718. {
  719. msg.message = DOWNLOAD_DONE;
  720. }
  721. pcDownload = (CDownload *) msg.wParam;
  722. switch(msg.message)
  723. {
  724. case DOWNLOAD_DONE:
  725. delete pcDownload;
  726. if(g_dwDbgFlags)
  727. dprintf(DBG_INFO, "DownloadThread: exit\n");
  728. return TRUE;
  729. break;
  730. case DO_DOWNLOAD:
  731. if(FAILED(pcDownload->doDownload()))
  732. {
  733. return FALSE;
  734. }
  735. break;
  736. default:
  737. TranslateMessage(&msg);
  738. DispatchMessage(&msg);
  739. }
  740. }
  741. return TRUE;
  742. }
  743. //==================================================================
  744. void Display_Usage(char **argv)
  745. {
  746. printf("\nUsage: %s -fURLname [options]\n", argv[0]);
  747. printf("\n -iInputFileName [options]\n");
  748. printf("\n\t options:\n");
  749. printf("\t\t -l - read buffer length\n");
  750. printf("\t\t -m - maximum number of simultaneous downloads\n");
  751. printf("\t\t -n## - number of times to download\n");
  752. printf("\t\t -z - comma delimited format\n");
  753. printf("\t\t -c - write to cache (default is NOWRITECACHE)\n");
  754. printf("\t\t -g - read from cache (default is GETNEWESTVERSION)\n");
  755. printf("\t\t -d - direct read (default uses QueryDataAvailable)\n");
  756. printf("\t\t -1 - single processor affinity (default multiprocessor)\n");
  757. printf("\t\t -x# - verbose flags (default=0x%x)\n", g_dwDbgFlags);
  758. printf("\t\t\t Results 0x%02x\n",DBG_RESULTS);
  759. printf("\t\t\t Debug 0x%02x\n",DBG_DEBUG);
  760. printf("\t\t\t Info 0x%02x\n",DBG_INFO);
  761. printf("\t\t\t StartBinding 0x%02x\n",DBG_STARTBINDING);
  762. printf("\t\t\t StopBinding 0x%02x\n",DBG_STOPBINDING);
  763. printf("\t\t\t OnProgress 0x%02x\n",DBG_ONPROGRESS);
  764. printf("\t\t\t OnDataAvailable 0x%02x\n",DBG_ONAVAIL);
  765. printf("\t\t\t Break on Errors 0x%02x\n",DBG_BREAKONERROR);
  766. }
  767. //==================================================================
  768. BOOL Process_Command_Line(int argcIn, char **argvIn)
  769. {
  770. BOOL bRC = TRUE;
  771. int argc = argcIn;
  772. char **argv = argvIn;
  773. DWORD dwLen = 0;
  774. *g_CmdLine = '\0';
  775. argv++; argc--;
  776. while( argc > 0 && argv[0][0] == '-' )
  777. {
  778. switch (argv[0][1])
  779. {
  780. case 'c':
  781. g_dwCacheFlag &= ~BINDF_NOWRITECACHE;
  782. break;
  783. case 'g':
  784. g_dwCacheFlag &= ~BINDF_GETNEWESTVERSION;
  785. break;
  786. case 'd':
  787. g_dwCacheFlag |= BINDF_DIRECT_READ;
  788. break;
  789. case 'f':
  790. pFilename = &argv[0][2];
  791. break;
  792. case 'i':
  793. pInFile = &argv[0][2];
  794. break;
  795. case 'n':
  796. dwNum_Opens = atoi(&argv[0][2]);
  797. break;
  798. case 'l':
  799. dwBuf_Size = atoi(&argv[0][2]);
  800. if(dwBuf_Size > MAX_BUF_SIZE)
  801. dwBuf_Size = MAX_BUF_SIZE;
  802. break;
  803. case 'm':
  804. dwMax_Simul_Downloads = atoi(&argv[0][2]);
  805. break;
  806. case 'r':
  807. g_pRunStr = &argv[0][2];
  808. break;
  809. case 't':
  810. g_pTestName = &argv[0][2];
  811. break;
  812. case 'z':
  813. bDelim = TRUE;
  814. break;
  815. case '1':
  816. SetSingleProcessorAffinity();
  817. break;
  818. case 'x':
  819. sscanf(&argv[0][2], "%x", &g_dwDbgFlags);
  820. if(!(g_dwDbgFlags & (DBG_ALLVALID)))
  821. {
  822. printf("Invalid verbose flags %x\n", g_dwDbgFlags);
  823. Display_Usage(argvIn);
  824. bRC = FALSE;
  825. }
  826. break;
  827. default:
  828. Display_Usage(argvIn);
  829. bRC = FALSE;
  830. }
  831. if(bRC)
  832. {
  833. dwLen += lstrlen(argv[0]) + 1; // length of arg and space
  834. if(dwLen < ((sizeof(g_CmdLine)/sizeof(g_CmdLine[0]))-1))
  835. {
  836. lstrcat(g_CmdLine, ",");
  837. lstrcat(g_CmdLine, argv[0]);
  838. }
  839. }
  840. argv++; argc--;
  841. }
  842. if(!pFilename && !pInFile)
  843. {
  844. Display_Usage(argvIn);
  845. bRC = FALSE;
  846. }
  847. return(bRC);
  848. }
  849. //----------------------------------------------------------------------------
  850. // Function: WinMain
  851. // Purpose: main entry procedure
  852. // Args: none
  853. // RetVal: TRUE or FALSE based on error
  854. //----------------------------------------------------------------------------
  855. //int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  856. int __cdecl main(INT argc, TCHAR *argv[]) //for console
  857. {
  858. CDownload* pcDownload = NULL;
  859. CDownload* pcdFirst = NULL;
  860. CInfo* pcInfo = NULL;
  861. DWORD dwThreadID;
  862. DWORD dwCnt;
  863. HANDLE hDownloadThread;
  864. INT iError;
  865. char szName[MAX_PATH];
  866. __int64 ibeg, iend, ifrq;
  867. float fKB;
  868. float fSec;
  869. float fKBSec;
  870. if(!Process_Command_Line(argc, argv))
  871. exit(0);
  872. pcInfo = new CInfo();
  873. g_pBuf = new TCHAR[dwBuf_Size];
  874. if(!pcInfo)
  875. {
  876. dprintf(DBG_ERROR, "*** ERROR *** generating pool!\n");
  877. return(0);
  878. }
  879. dwCnt = 0;
  880. if(pFilename)
  881. {
  882. while(dwCnt++ < dwNum_Opens)
  883. {
  884. if(g_dwCacheFlag & BINDF_NOWRITECACHE)
  885. lstrcpy(szName, pFilename);
  886. else
  887. wsprintf(szName, "%s.%d", pFilename, dwCnt);
  888. if(!pcDownload)
  889. {
  890. pcdFirst = pcDownload = new CDownload(szName, pcInfo);
  891. pcDownload->m_pcInfo->m_pdFirst = pcDownload;
  892. }
  893. else
  894. {
  895. pcDownload->m_pdNext = new CDownload(szName, pcInfo);
  896. pcDownload = (CDownload *) pcDownload->m_pdNext;
  897. }
  898. if(!pcDownload)
  899. {
  900. dprintf(DBG_ERROR, "*** ERROR *** initializing pcDownload!\n");
  901. return(0);
  902. }
  903. }
  904. }
  905. else if(pInFile) // Process input file
  906. {
  907. FILE *fp;
  908. while(dwCnt++ < dwNum_Opens)
  909. {
  910. if((fp = fopen(pInFile, "r")) == NULL)
  911. {
  912. dprintf(DBG_ERROR, "*** ERROR *** opening file\n");
  913. return(0);
  914. }
  915. while(fgets(szName, INTERNET_MAX_URL_LENGTH, fp) != NULL)
  916. {
  917. if(szName[0] != '#')
  918. {
  919. szName[strlen(szName) - sizeof(char)] = '\0';
  920. if(!pcDownload)
  921. {
  922. pcdFirst = pcDownload = new CDownload(szName, pcInfo);
  923. pcDownload->m_pcInfo->m_pdFirst = pcDownload;
  924. }
  925. else
  926. {
  927. pcDownload->m_pdNext = new CDownload(szName, pcInfo);
  928. pcDownload = (CDownload *) pcDownload->m_pdNext;
  929. }
  930. if(!pcDownload)
  931. {
  932. dprintf(DBG_ERROR, "*** ERROR *** initializing pcDownload!\n");
  933. return(0);
  934. }
  935. }
  936. }
  937. fclose(fp);
  938. }
  939. }
  940. pcDownload = (CDownload *) pcDownload->m_pcInfo->m_pdFirst;
  941. if (LoadUrlMon() != S_OK)
  942. {
  943. dprintf(DBG_ERROR, "*** ERROR *** LoadUrlMon() failed\n");
  944. return(0);
  945. }
  946. if (CoInitialize(NULL) != S_OK)
  947. {
  948. dprintf(DBG_ERROR, "*** ERROR *** CoInitialize() failed\n");
  949. return(0);
  950. }
  951. pcDownload->m_pcInfo->m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  952. if (!pcDownload->m_pcInfo->m_hCompleteEvent)
  953. {
  954. dprintf(DBG_ERROR, "*** ERROR *** on create Event!\n");
  955. }
  956. hDownloadThread = CreateThread(NULL,
  957. 0,
  958. (LPTHREAD_START_ROUTINE)DownloadThread,
  959. (LPVOID)pcDownload,
  960. 0,
  961. &dwThreadID );
  962. if (!hDownloadThread)
  963. {
  964. dprintf(DBG_ERROR, "*** ERROR *** Could not create Thread\n");
  965. return(0);
  966. }
  967. if(WaitForSingleObject(pcDownload->m_pcInfo->m_hCompleteEvent, TIMEOUT)
  968. == WAIT_TIMEOUT)
  969. {
  970. dprintf(DBG_ERROR, "*** ERROR *** timeout on init\n");
  971. }
  972. Sleep(100);
  973. QueryPerformanceCounter((LARGE_INTEGER *)&ibeg);
  974. while(pcDownload)
  975. {
  976. if(WaitForSingleObject(pcDownload->m_pcInfo->m_hMaxDownloadSem, TIMEOUT)
  977. == WAIT_TIMEOUT)
  978. {
  979. dprintf(DBG_ERROR, "*** ERROR *** timeout on Sem\n");
  980. }
  981. if(g_dwDbgFlags)
  982. {
  983. TCHAR sz[255];
  984. WideCharToMultiByte(CP_ACP, 0, pcDownload->m_pUrl, -1, sz, 255,0,0);
  985. dprintf(DBG_INFO, "main: PostThreadMessage DO_DOWNLOAD %s\n", sz);
  986. }
  987. if(!PostThreadMessage(dwThreadID, DO_DOWNLOAD, (WPARAM) pcDownload, 0))
  988. {
  989. iError = GetLastError();
  990. dprintf(DBG_ERROR, "*** Error *** on PostThreadMessage(0x%X, %ld, 0x%lX, 0) [GLE=%d]\n",
  991. dwThreadID, DO_DOWNLOAD, pcDownload, iError);
  992. return(0);
  993. }
  994. pcDownload = (CDownload *) pcDownload->m_pdNext;
  995. }
  996. //wait for completion downloads at one time
  997. if(WaitForSingleObject(pcdFirst->m_pcInfo->m_hCompleteEvent, TIMEOUT) == WAIT_TIMEOUT)
  998. {
  999. dprintf(DBG_ERROR, "*** ERROR *** timeout on Sem\n");
  1000. }
  1001. QueryPerformanceCounter((LARGE_INTEGER *) &iend);
  1002. QueryPerformanceFrequency((LARGE_INTEGER *) &ifrq);
  1003. dwTot_Time = (DWORD)((iend - ibeg) * 1000 / ifrq);
  1004. if(dwTot_Time == 0)
  1005. dwTot_Time = 1;
  1006. fKB = ((float)dwBytes_Read)/1024;
  1007. fSec = ((float)dwTot_Time)/1000;
  1008. fKBSec = fKB / fSec;
  1009. if(!bDelim)
  1010. {
  1011. dprintf(DBG_RESULTS, "Downloaded: %s\r\n", sUrl);
  1012. dprintf(DBG_RESULTS, "%ld Bytes in %ld Milliseconds = %2.0f KB/Sec\r\n", dwBytes_Read, dwTot_Time, fKBSec );
  1013. dprintf(DBG_RESULTS, "%ld Reads, %ld Downloads, %ld Byte Read Buffer\r\n",
  1014. dwNum_Opens, dwMax_Simul_Downloads, dwBuf_Size);
  1015. }
  1016. else
  1017. dprintf(DBG_RESULTS, "%s, %s, %ld, %ld, %2.0f %s\n",
  1018. g_pTestName ?g_pTestName :"urlmon",
  1019. g_pRunStr ?g_pRunStr :"1",
  1020. dwTot_Time, dwBytes_Read, fKBSec, g_CmdLine );
  1021. if(g_dwDbgFlags)
  1022. dprintf(DBG_INFO, "realized finished on data ready\n");
  1023. if(!PostThreadMessage(dwThreadID, DOWNLOAD_DONE, (WPARAM) pcDownload, 0))
  1024. {
  1025. iError = GetLastError();
  1026. dprintf(DBG_ERROR, "*** Error *** on PostThreadMessage(0x%X, %ld, 0x%lX, 0) [GLE=%d]\n",
  1027. dwThreadID, DOWNLOAD_DONE, pcDownload, iError);
  1028. return(0);
  1029. }
  1030. if(WaitForSingleObject(hDownloadThread, TIMEOUT) == WAIT_TIMEOUT)
  1031. {
  1032. dprintf(DBG_ERROR, "*** ERROR *** timeout on DownloadThread exit\n");
  1033. }
  1034. CloseHandle(hDownloadThread);
  1035. CoUninitialize();
  1036. UnloadUrlMon();
  1037. if(g_dwDbgFlags)
  1038. dprintf(DBG_INFO, "main: exit\n");
  1039. return(1);
  1040. }