|
|
#undef UNICODE
#include "urlmon.h"
#include "wininet.h"
#include "commctrl.h"
#include "windows.h"
#include <stdio.h>
#include "initguid.h"
#include "hlink.h"
///#include "hlguids.h"
#ifdef PRODUCT_PROF
extern "C" void _stdcall StartCAP(void); extern "C" void _stdcall StopCAP(void); extern "C" void _stdcall SuspendCAP(void); extern "C" void _stdcall ResumeCAP(void); extern "C" void _stdcall StartCAPAll(void); extern "C" void _stdcall StopCAPAll(void); #else
#define StartCAP()
#define StopCAP()
#define SuspendCAP()
#define ResumeCAP()
#define StartCAPAll()
#define StopCAPAll()
#endif
typedef BOOL (WINAPI *PFNSPA)(HANDLE, DWORD); typedef HRESULT (WINAPI * pfnCreateURLMoniker)(IMoniker *, LPCWSTR, IMoniker **); typedef HRESULT (WINAPI * pfnRegisterBindStatusCallback)(LPBC, IBindStatusCallback *, IBindStatusCallback **, DWORD);
typedef struct { TCHAR* pBuf; //Actual buffer to hold data
DWORD lNumRead; //number of bytes read in buffer
void* pNext; //Pointer to next buffer
} buffer;
HINSTANCE g_hUrlMon = NULL; pfnCreateURLMoniker g_pfnCreateURLMoniker = NULL; pfnRegisterBindStatusCallback g_pfnRegisterBindStatusCallback = NULL;
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
#define DO_DOWNLOAD WM_USER + 10
#define DOWNLOAD_DONE WM_USER + 11
#pragma warning(disable:4100)
// ---------------------------------------------------------------------------
#define DBG_ERROR 0x80000000
// verbose flags
#define DBG_RESULTS 0x01
#define DBG_DEBUG 0x02
#define DBG_INFO 0x04
#define DBG_STARTBINDING 0x08
#define DBG_STOPBINDING 0x10
#define DBG_ONPROGRESS 0x20
#define DBG_ONAVAIL 0x40
#define DBG_BREAKONERROR 0x80
#define DBG_ALLVALID DBG_RESULTS | DBG_DEBUG | DBG_STARTBINDING | DBG_STOPBINDING | DBG_ONPROGRESS | DBG_ONAVAIL
DWORD g_dwDbgFlags = DBG_RESULTS; // ---------------------------------------------------------------------------
const INT MAX_BUF_SIZE = 1024 * 16; const INT BUF_SIZE = 2 * 1024; const INT URL_MAX = 4; const INT BUF_NUM = 16*4; const DWORD TIMEOUT = 10000000; const INT LDG_DONE = 1; const INT LDG_STARTED = 0; const INT PRI_LOW = 1; const INT PRI_MED = 2; const INT PRI_HI = 3;
DWORD dwBegin_Time = 0; DWORD dwEnd_Time; DWORD dwTot_Time; BOOL bDelim = FALSE; DWORD dwNum_Opens = 1; DWORD dwBuf_Size = BUF_SIZE; DWORD dwBytes_Read = 0; DWORD dwMax_Simul_Downloads = URL_MAX; DWORD g_dwCacheFlag = BINDF_NOWRITECACHE | BINDF_GETNEWESTVERSION; char *pFilename = NULL; char *pInFile = NULL; char *g_pRunStr = NULL; char *g_pTestName = NULL; char g_CmdLine[1024]; TCHAR sUrl[(INTERNET_MAX_URL_LENGTH+1)]; TCHAR* g_pBuf = NULL;
// %%Classes: ----------------------------------------------------------------
class CInfo { public: CInfo(); ~CInfo(); INT incDownloads(void) { return m_iDownloads++; } INT decDownloads(void) { return m_iDownloads--; } INT getDownloads(void) { return m_iDownloads; }
HANDLE m_hCompleteEvent; CRITICAL_SECTION m_csInfo; //for critical section
HANDLE m_hMaxDownloadSem; buffer* m_pPool; //Pointer to current available buffer in pool
void* m_pdFirst; //pointer to the first element
private: INT m_iDownloads; //number of current downloads
};
class CDownload { public: CDownload(LPSTR sName, CInfo* pcInfo); ~CDownload(); HRESULT doDownload(void); INT getStatus(void) { return m_iStatus; } INT getPriority(void) { return m_iPriority; } #ifdef USE_POOL
INT releasePool(void); #endif
WCHAR m_pUrl[(INTERNET_MAX_URL_LENGTH+1)]; #ifdef USE_POOL
buffer* m_pbStartBuffer; //first buffer to hold data
buffer* m_pbCurBuffer; //Current Buffer
#endif
CInfo* m_pcInfo; void* m_pdNext; //pointer to next element
INT m_iStatus; //the url's status
INT m_iPriority; //the url's priority
DWORD lNumRead; //number of bytes read in buffer for this download
private: IMoniker* m_pMoniker; IBindCtx* m_pBindCtx; IBindStatusCallback* m_pBindCallback; };
class CBindStatusCallback : public IBindStatusCallback { public: // IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid,void ** ppv); STDMETHODIMP_(ULONG) AddRef() { return m_cRef++; } STDMETHODIMP_(ULONG) Release() { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; }
// IBindStatusCallback methods
STDMETHODIMP OnStartBinding(DWORD dwReserved, IBinding* pbinding); STDMETHODIMP GetPriority(LONG* pnPriority); STDMETHODIMP OnLowResource(DWORD dwReserved); STDMETHODIMP OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText); STDMETHODIMP OnStopBinding(HRESULT hrResult, LPCWSTR szError); STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo); STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc, STGMEDIUM* pstgmed); STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown* punk);
// constructors/destructors
CBindStatusCallback(CDownload* pcDownload); ~CBindStatusCallback();
// data members
DWORD m_cRef; IBinding* m_pBinding; IStream* m_pStream; DWORD m_cbOld; CDownload* m_pcDownload; };
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
INT dprintf(DWORD dwFlags, TCHAR *fmt, ... ) { INT ret = 0; va_list marker; TCHAR szBuffer[256];
if(dwFlags & (g_dwDbgFlags | DBG_ERROR)) { va_start( marker, fmt ); ret = vsprintf( szBuffer, fmt, marker ); OutputDebugString( szBuffer ); printf(szBuffer);
if(g_dwDbgFlags & DBG_BREAKONERROR) DebugBreak(); } return ret; }
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void SetSingleProcessorAffinity() { PFNSPA pfn;
pfn = (PFNSPA)GetProcAddress(GetModuleHandleA("KERNEL32.DLL"), "SetProcessAffinityMask");
if (pfn) { pfn(GetCurrentProcess(), 1); } }
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
HRESULT LoadUrlMon() { g_hUrlMon = (HINSTANCE)LoadLibraryA("URLMON.DLL");
if (g_hUrlMon == NULL) { dprintf(DBG_ERROR, "LoadLibraryA of URLMON.DLL failed\n"); return(E_FAIL); }
g_pfnCreateURLMoniker = (pfnCreateURLMoniker)GetProcAddress(g_hUrlMon, "CreateURLMoniker"); if (g_pfnCreateURLMoniker == NULL) { dprintf(DBG_ERROR, "GetProcAddress CreateURLMoniker failed\n"); return(E_FAIL); }
g_pfnRegisterBindStatusCallback = (pfnRegisterBindStatusCallback)GetProcAddress(g_hUrlMon, "RegisterBindStatusCallback");
if (g_pfnRegisterBindStatusCallback == NULL) { dprintf(DBG_ERROR, "GetProcAddress RegisterBindStatusCallback failed\n"); return(E_FAIL); }
return(S_OK); }
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void UnloadUrlMon() { if (g_hUrlMon) { FreeLibrary(g_hUrlMon); } }
// ===========================================================================
// CBindStatusCallback Implementation
// ===========================================================================
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::CBindStatusCallback
// ---------------------------------------------------------------------------
CBindStatusCallback::CBindStatusCallback(CDownload* pcDownload) { m_pBinding = NULL; m_pStream = NULL; m_cRef = 1; m_cbOld = 0; m_pcDownload = pcDownload; } // CBindStatusCallback
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::~CBindStatusCallback
// ---------------------------------------------------------------------------
CBindStatusCallback::~CBindStatusCallback() { } // ~CBindStatusCallback
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::QueryInterface
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::QueryInterface(REFIID riid, void** ppv) { *ppv = NULL;
if (riid==IID_IUnknown || riid==IID_IBindStatusCallback) { *ppv = this; AddRef(); return S_OK; } return E_NOINTERFACE; } // CBindStatusCallback::QueryInterface
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::OnStartBinding
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding* pBinding) { if (m_pBinding != NULL) m_pBinding->Release();
m_pBinding = pBinding;
if (m_pBinding != NULL) m_pBinding->AddRef();
m_pcDownload->m_pcInfo->incDownloads();
if(g_dwDbgFlags) dprintf(DBG_STOPBINDING, "OnStartBinding getDownloads()=%d\n", m_pcDownload->m_pcInfo->getDownloads()); return S_OK;
} // CBindStatusCallback::OnStartBinding
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::GetPriority
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::GetPriority(LONG* pnPriority) { return E_NOTIMPL; } // CBindStatusCallback::GetPriority
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::OnLowResource
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::OnLowResource(DWORD dwReserved) { return E_NOTIMPL; } // CBindStatusCallback::OnLowResource
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::OnProgress
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) { TCHAR sz[255]; if(szStatusText != NULL) { WideCharToMultiByte(CP_ACP, 0, szStatusText, -1, sz, 255,0,0); } if(g_dwDbgFlags) dprintf(DBG_ONPROGRESS, "OnProgress: %d(%s) %d of %d\n", ulStatusCode, sz, ulProgress, (ulProgress>ulProgressMax)?ulProgress:ulProgressMax); return(NOERROR); } // CBindStatusCallback::OnProgress
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::OnStopBinding
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::OnStopBinding(HRESULT hrStatus, LPCWSTR pszError) { if (hrStatus != S_OK) { if(g_dwDbgFlags & DBG_DEBUG) { TCHAR sUrl[(INTERNET_MAX_URL_LENGTH+1)]; TCHAR sErr[1024]; WideCharToMultiByte(CP_ACP, 0, m_pcDownload->m_pUrl, -1, sUrl, INTERNET_MAX_URL_LENGTH, 0, 0); WideCharToMultiByte(CP_ACP, 0, pszError, -1, sErr, 1024, 0, 0); dprintf(DBG_ERROR, "*** ERROR *** %s OnStopBinding download failed. Status=%x Err=%s\n", sUrl, hrStatus, sErr); } } if (m_pBinding) { m_pBinding->Release(); m_pBinding = NULL; } m_pcDownload->m_pcInfo->decDownloads(); if(g_dwDbgFlags) dprintf(DBG_STOPBINDING, "OnStopBinding hrStatus=%d getDownloads()=%d\n", hrStatus, m_pcDownload->m_pcInfo->getDownloads());
if(m_pcDownload->m_pcInfo->getDownloads() == 0) { SetEvent(m_pcDownload->m_pcInfo->m_hCompleteEvent); }
return S_OK; } // CBindStatusCallback::OnStopBinding
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::GetBindInfo
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pBindInfo) { *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; *pgrfBINDF |= g_dwCacheFlag; pBindInfo->cbSize = sizeof(BINDINFO); pBindInfo->szExtraInfo = NULL; memset(&pBindInfo->stgmedData, 0, sizeof(STGMEDIUM)); pBindInfo->grfBindInfoF = 0; pBindInfo->dwBindVerb = BINDVERB_GET; pBindInfo->szCustomVerb = NULL; return S_OK; } // CBindStatusCallback::GetBindInfo
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::OnDataAvailable
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed) { DWORD dwRead = dwSize - m_cbOld; // Amount to be read
HRESULT hr = S_OK;
// Get the Stream passed
if(g_dwDbgFlags) dprintf(DBG_ONAVAIL, "OnDataAvailable(grfBSCF=%d pStream=0x%x dwRead=%d dwSize=%d pfmtetc=0x%x, pstgmed=0x%x\n", grfBSCF, m_pStream, dwRead, dwSize, pfmtetc, pstgmed); if (!m_pStream && pstgmed->tymed == TYMED_ISTREAM) { m_pStream = pstgmed->pstm; }
// If there is some data to be read then go ahead and read
if (m_pStream && dwRead) { while(hr!=E_PENDING) { #ifdef USE_POOL
if(m_pcDownload->m_pcInfo->m_pPool) { //if pool ready
EnterCriticalSection(&(m_pcDownload->m_pcInfo->m_csInfo)); if(!m_pcDownload->m_pbStartBuffer) { // if the first time
m_pcDownload->m_pbStartBuffer = m_pcDownload->m_pbCurBuffer = m_pcDownload->m_pcInfo->m_pPool; m_pcDownload->m_pcInfo->m_pPool = (buffer *)m_pcDownload->m_pcInfo->m_pPool->pNext; m_pcDownload->m_pbStartBuffer->pNext = NULL; } else { m_pcDownload->m_pbCurBuffer->pNext = m_pcDownload->m_pcInfo->m_pPool; m_pcDownload->m_pcInfo->m_pPool = (buffer *)m_pcDownload->m_pcInfo->m_pPool->pNext; m_pcDownload->m_pbCurBuffer = (buffer *) m_pcDownload->m_pbCurBuffer->pNext; m_pcDownload->m_pbCurBuffer->pNext = NULL; } LeaveCriticalSection(&(m_pcDownload->m_pcInfo->m_csInfo)); } else { //allocate buffers on the fly
if(!m_pcDownload->m_pbStartBuffer) { // if the first time
m_pcDownload->m_pbStartBuffer = m_pcDownload->m_pbCurBuffer = new buffer; if(!m_pcDownload->m_pbCurBuffer) { dprintf(DBG_ERROR, "*** ERROR *** on buff alloc\n"); return S_FALSE; } m_pcDownload->m_pbCurBuffer->pBuf = new TCHAR[dwBuf_Size];
if(!m_pcDownload->m_pbCurBuffer->pBuf) { dprintf(DBG_ERROR, "*** ERROR *** on buf alloc\n"); return S_FALSE; } m_pcDownload->m_pbStartBuffer->pNext = NULL; } else { m_pcDownload->m_pbCurBuffer->pNext = new buffer; if(!m_pcDownload->m_pbCurBuffer->pNext) { dprintf(DBG_ERROR, "*** ERROR *** on buff alloc\n"); return S_FALSE; } m_pcDownload->m_pbCurBuffer = (buffer *) m_pcDownload->m_pbCurBuffer->pNext; m_pcDownload->m_pbCurBuffer->pBuf = new TCHAR[dwBuf_Size]; if(!m_pcDownload->m_pbCurBuffer->pBuf) { dprintf(DBG_ERROR, "*** ERROR *** on buf alloc\n"); return S_FALSE; } m_pcDownload->m_pbCurBuffer->pNext = NULL; } } #endif
if(dwBegin_Time == 0) dwBegin_Time = GetTickCount();
#ifdef USE_POOL
hr = m_pStream->Read(m_pcDownload->m_pbCurBuffer->pBuf, dwBuf_Size, &(m_pcDownload->m_pbCurBuffer->lNumRead)); if(g_dwDbgFlags) { dprintf(DBG_INFO & DBG_DEBUG, "Stream->Read Size=%d Read=%d hr=0x%x\n", dwBuf_Size, m_pcDownload->m_pbCurBuffer->lNumRead, hr); if(hr != S_OK && hr != E_PENDING && hr != S_FALSE) dprintf(DBG_ERROR, "************ Stream->Read hr=0x%x\n", hr); } #else
hr = m_pStream->Read(g_pBuf, dwBuf_Size, &(m_pcDownload->lNumRead)); if(g_dwDbgFlags) { dprintf(DBG_INFO & DBG_DEBUG, "Stream->Read Size=%d Read=%d hr=0x%x\n", dwBuf_Size, m_pcDownload->lNumRead, hr); if(hr != S_OK && hr != E_PENDING && hr != S_FALSE) dprintf(DBG_ERROR, "************ Stream->Read hr=0x%x\n", hr); } #endif
//need to check for error if read reaches end of stream
if(hr == S_FALSE) { break; } #ifdef USE_POOL
if (m_pcDownload->m_pbCurBuffer->lNumRead > 0) { m_cbOld += m_pcDownload->m_pbCurBuffer->lNumRead; } #else
if (m_pcDownload->lNumRead > 0) { m_cbOld += m_pcDownload->lNumRead; } #endif
} }// if(m_pstm && dwRead)
if (BSCF_LASTDATANOTIFICATION & grfBSCF) { WideCharToMultiByte(CP_ACP, 0, m_pcDownload->m_pUrl, -1, sUrl, INTERNET_MAX_URL_LENGTH, 0, 0); if(g_dwDbgFlags && !bDelim) dprintf(DBG_INFO, "Status: %s downloaded.\n", sUrl); // m_pcDownload->m_pcInfo->decDownloads();
m_pcDownload->m_iStatus = LDG_DONE;
if(!ReleaseSemaphore(m_pcDownload->m_pcInfo->m_hMaxDownloadSem,1,NULL)) { dprintf(DBG_ERROR, "*** ERROR *** ReleaseSemaphore failed!\n"); return S_FALSE; }
dwBytes_Read += m_cbOld; // accum buf size that was downloaded
} return S_OK; } // CBindStatusCallback::OnDataAvailable
// ---------------------------------------------------------------------------
// %%Function: CBindStatusCallback::OnObjectAvailable
// ---------------------------------------------------------------------------
STDMETHODIMP CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown* punk) { return E_NOTIMPL; } // CBindStatusCallback::OnObjectAvailable
// ===========================================================================
// CDownload Implementation
// ===========================================================================
// ---------------------------------------------------------------------------
// %%Function: CDownload::CDownload
// ---------------------------------------------------------------------------
CDownload::CDownload(LPSTR sName, CInfo* pcInfo) { MultiByteToWideChar(CP_ACP, 0, sName, -1, m_pUrl, INTERNET_MAX_URL_LENGTH); m_pMoniker = 0; m_pBindCtx = 0; m_pBindCallback = 0; m_pdNext = NULL;
m_iStatus = LDG_STARTED; m_iPriority = PRI_MED; m_pcInfo = pcInfo; #ifdef USE_POOL
m_pbStartBuffer = m_pbCurBuffer = NULL; #endif
} // CDownload
// ---------------------------------------------------------------------------
// %%Function: CDownload::~CDownload
// ---------------------------------------------------------------------------
CDownload::~CDownload() { buffer* pbLastBuf = NULL;
if (m_pMoniker) m_pMoniker->Release(); if (m_pBindCtx) m_pBindCtx->Release(); if (m_pBindCallback) m_pBindCallback->Release(); delete m_pcInfo;
#ifdef USE_POOL
if(m_pbStartBuffer) { while(m_pbStartBuffer->lNumRead != 0 && m_pbStartBuffer->lNumRead <= dwBuf_Size) { delete m_pbStartBuffer->pBuf; pbLastBuf = m_pbStartBuffer; m_pbStartBuffer = (buffer *)m_pbStartBuffer->pNext; delete pbLastBuf; } } #endif
GlobalFree(m_pUrl); } // ~CDownload
// ---------------------------------------------------------------------------
// %%Function: CDownload::DoDownload
// ---------------------------------------------------------------------------
HRESULT CDownload::doDownload(void) { IStream* pstm; HRESULT hr;
hr = g_pfnCreateURLMoniker(NULL, m_pUrl, &m_pMoniker); if (FAILED(hr)) { dprintf(DBG_ERROR, "*** ERROR *** doDownload CreateURLMoniker failed hr=0x%x\n", hr); goto LErrExit; } m_pBindCallback = new CBindStatusCallback(this);
if (m_pBindCallback == NULL) { dprintf(DBG_ERROR, "*** ERROR *** doDownload CBindStatusCallback failed hr=0x%x\n", hr); hr = E_OUTOFMEMORY; goto LErrExit; }
hr = CreateBindCtx(0, &m_pBindCtx); if (FAILED(hr)) { dprintf(DBG_ERROR, "*** ERROR *** doDownload CreateBindCtx failed hr=0x%x\n", hr); goto LErrExit; }
hr = g_pfnRegisterBindStatusCallback( m_pBindCtx, m_pBindCallback, 0, 0L); if (FAILED(hr)) { dprintf(DBG_ERROR, "*** ERROR *** doDownload RegisterBindStatusCallback failed hr=0x%x\n", hr); goto LErrExit; } hr = m_pMoniker->BindToStorage( m_pBindCtx, 0, IID_IStream, (void**)&pstm); if (FAILED(hr)) { dprintf(DBG_ERROR, "*** ERROR *** doDownload BindToStorage failed hr=0x%x\n", hr); goto LErrExit; } return(hr);
LErrExit: if (m_pBindCtx != NULL) { m_pBindCtx->Release(); m_pBindCtx = NULL; } if (m_pBindCallback != NULL) { m_pBindCallback->Release(); m_pBindCallback = NULL; } if (m_pMoniker != NULL) { m_pMoniker->Release(); m_pMoniker = NULL; } return hr; }
// ---------------------------------------------------------------------------
// %%Function: CDownload::releasePool
// ---------------------------------------------------------------------------
#ifdef USE_POOL
INT CDownload::releasePool() { buffer *pbStart;
EnterCriticalSection(&(m_pcInfo->m_csInfo));
while(m_pbStartBuffer) { // remember the start buf
pbStart = (buffer *) m_pbStartBuffer->pNext; // adjust the start
m_pbStartBuffer = (buffer *) m_pbStartBuffer->pNext;
//insert the buffer at the beginning of the pool
pbStart->pNext = m_pcInfo->m_pPool;
// update the pool
m_pcInfo->m_pPool = pbStart; }
LeaveCriticalSection(&(m_pcInfo->m_csInfo)); return TRUE; } #endif
// ===========================================================================
// CInfo Implementation
// ===========================================================================
// ---------------------------------------------------------------------------
// %%Function: CInfo::CInfo
// ---------------------------------------------------------------------------
CInfo::CInfo() { #ifdef USE_POOL
INT i;
buffer* pStartBuffer = NULL; #endif
m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!m_hCompleteEvent) { dprintf(DBG_ERROR, "*** ERROR *** on create Event!\n"); }
InitializeCriticalSection(&(m_csInfo));
m_hMaxDownloadSem = CreateSemaphore(NULL,dwMax_Simul_Downloads,dwMax_Simul_Downloads, NULL); if(!m_hMaxDownloadSem) { dprintf(DBG_ERROR, "*** ERROR *** CreateSem failed!\n"); }
#ifdef USE_POOL
pStartBuffer = m_pPool = new buffer; if(!m_pPool) return;
m_pPool->pBuf = new TCHAR[dwBuf_Size]; if (!m_pPool->pBuf) return;
m_pPool->lNumRead = 0; #endif
m_iDownloads = 0;
#ifdef USE_POOL
m_pPool->pNext = NULL; for(i=1; i<BUF_NUM; i++) { m_pPool->pNext = new buffer; if (!m_pPool->pNext) return;
m_pPool = (buffer *)m_pPool->pNext; m_pPool->pBuf = new TCHAR[dwBuf_Size]; if (!m_pPool->pBuf) return;
m_pPool->lNumRead = 0; m_pPool->pNext = NULL; }
m_pPool = pStartBuffer; #endif
return; } // CInfo
// ---------------------------------------------------------------------------
// %%Function: CInfo::~CInfo
// ---------------------------------------------------------------------------
CInfo::~CInfo() { buffer *pLastBuf;
while(m_pPool) { delete m_pPool->pBuf; pLastBuf = m_pPool; m_pPool = (buffer *)m_pPool->pNext; delete pLastBuf; } delete this; } // ~CInfo
// ===========================================================================
// User Interface and Initialization Routines
// ===========================================================================
//----------------------------------------------------------------------------
// Procedure: DownloadThread
// Purpose: Opens internet connection and downloads URL. Saves
// URL to pOutQ (one chunk per buffer).
// Arguments: outQ
// Return Val: TRUE or FALSE based on error
//----------------------------------------------------------------------------
DWORD DownloadThread(LPDWORD lpdwParam) {
INT retVal; MSG msg; CDownload *pcDownload = (CDownload *) lpdwParam;
SetEvent(pcDownload->m_pcInfo->m_hCompleteEvent); if(g_dwDbgFlags) dprintf(DBG_INFO, "DownloadThread: m_hCompleteEvent set.\n");
StartCAP();
for (;;) { SuspendCAP();
retVal = GetMessage(&msg, NULL, 0, 0);
ResumeCAP();
if(retVal == -1) { dprintf(DBG_ERROR, "*** ERROR *** on GetMessage\n"); break; } if(retVal == FALSE) { msg.message = DOWNLOAD_DONE; } pcDownload = (CDownload *) msg.wParam; switch(msg.message) { case DOWNLOAD_DONE: delete pcDownload; if(g_dwDbgFlags) dprintf(DBG_INFO, "DownloadThread: exit\n"); return TRUE; break; case DO_DOWNLOAD: if(FAILED(pcDownload->doDownload())) { return FALSE; } break; default: TranslateMessage(&msg); DispatchMessage(&msg); } } return TRUE; }
//==================================================================
void Display_Usage(char **argv) { printf("\nUsage: %s -fURLname [options]\n", argv[0]); printf("\n -iInputFileName [options]\n"); printf("\n\t options:\n"); printf("\t\t -l - read buffer length\n"); printf("\t\t -m - maximum number of simultaneous downloads\n"); printf("\t\t -n## - number of times to download\n"); printf("\t\t -z - comma delimited format\n"); printf("\t\t -c - write to cache (default is NOWRITECACHE)\n"); printf("\t\t -g - read from cache (default is GETNEWESTVERSION)\n"); printf("\t\t -d - direct read (default uses QueryDataAvailable)\n"); printf("\t\t -1 - single processor affinity (default multiprocessor)\n"); printf("\t\t -x# - verbose flags (default=0x%x)\n", g_dwDbgFlags); printf("\t\t\t Results 0x%02x\n",DBG_RESULTS); printf("\t\t\t Debug 0x%02x\n",DBG_DEBUG); printf("\t\t\t Info 0x%02x\n",DBG_INFO); printf("\t\t\t StartBinding 0x%02x\n",DBG_STARTBINDING); printf("\t\t\t StopBinding 0x%02x\n",DBG_STOPBINDING); printf("\t\t\t OnProgress 0x%02x\n",DBG_ONPROGRESS); printf("\t\t\t OnDataAvailable 0x%02x\n",DBG_ONAVAIL); printf("\t\t\t Break on Errors 0x%02x\n",DBG_BREAKONERROR); }
//==================================================================
BOOL Process_Command_Line(int argcIn, char **argvIn) { BOOL bRC = TRUE; int argc = argcIn; char **argv = argvIn; DWORD dwLen = 0;
*g_CmdLine = '\0'; argv++; argc--; while( argc > 0 && argv[0][0] == '-' ) { switch (argv[0][1]) { case 'c': g_dwCacheFlag &= ~BINDF_NOWRITECACHE; break; case 'g': g_dwCacheFlag &= ~BINDF_GETNEWESTVERSION; break; case 'd': g_dwCacheFlag |= BINDF_DIRECT_READ; break; case 'f': pFilename = &argv[0][2]; break; case 'i': pInFile = &argv[0][2]; break; case 'n': dwNum_Opens = atoi(&argv[0][2]); break; case 'l': dwBuf_Size = atoi(&argv[0][2]); if(dwBuf_Size > MAX_BUF_SIZE) dwBuf_Size = MAX_BUF_SIZE; break; case 'm': dwMax_Simul_Downloads = atoi(&argv[0][2]); break; case 'r': g_pRunStr = &argv[0][2]; break; case 't': g_pTestName = &argv[0][2]; break; case 'z': bDelim = TRUE; break; case '1': SetSingleProcessorAffinity(); break; case 'x': sscanf(&argv[0][2], "%x", &g_dwDbgFlags); if(!(g_dwDbgFlags & (DBG_ALLVALID))) { printf("Invalid verbose flags %x\n", g_dwDbgFlags); Display_Usage(argvIn); bRC = FALSE; } break; default: Display_Usage(argvIn); bRC = FALSE; } if(bRC) { dwLen += lstrlen(argv[0]) + 1; // length of arg and space
if(dwLen < ((sizeof(g_CmdLine)/sizeof(g_CmdLine[0]))-1)) { lstrcat(g_CmdLine, ","); lstrcat(g_CmdLine, argv[0]); } } argv++; argc--; }
if(!pFilename && !pInFile) { Display_Usage(argvIn); bRC = FALSE; }
return(bRC); }
//----------------------------------------------------------------------------
// Function: WinMain
// Purpose: main entry procedure
// Args: none
// RetVal: TRUE or FALSE based on error
//----------------------------------------------------------------------------
//int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
int __cdecl main(INT argc, TCHAR *argv[]) //for console
{ CDownload* pcDownload = NULL; CDownload* pcdFirst = NULL; CInfo* pcInfo = NULL; DWORD dwThreadID; DWORD dwCnt; HANDLE hDownloadThread; INT iError; char szName[MAX_PATH]; __int64 ibeg, iend, ifrq; float fKB; float fSec; float fKBSec;
if(!Process_Command_Line(argc, argv)) exit(0);
pcInfo = new CInfo(); g_pBuf = new TCHAR[dwBuf_Size];
if(!pcInfo) { dprintf(DBG_ERROR, "*** ERROR *** generating pool!\n"); return(0); }
dwCnt = 0; if(pFilename) { while(dwCnt++ < dwNum_Opens) {
if(g_dwCacheFlag & BINDF_NOWRITECACHE) lstrcpy(szName, pFilename); else wsprintf(szName, "%s.%d", pFilename, dwCnt);
if(!pcDownload) { pcdFirst = pcDownload = new CDownload(szName, pcInfo); pcDownload->m_pcInfo->m_pdFirst = pcDownload; } else { pcDownload->m_pdNext = new CDownload(szName, pcInfo); pcDownload = (CDownload *) pcDownload->m_pdNext; }
if(!pcDownload) { dprintf(DBG_ERROR, "*** ERROR *** initializing pcDownload!\n"); return(0); } } } else if(pInFile) // Process input file
{ FILE *fp;
while(dwCnt++ < dwNum_Opens) { if((fp = fopen(pInFile, "r")) == NULL) { dprintf(DBG_ERROR, "*** ERROR *** opening file\n"); return(0); }
while(fgets(szName, INTERNET_MAX_URL_LENGTH, fp) != NULL) { if(szName[0] != '#') { szName[strlen(szName) - sizeof(char)] = '\0';
if(!pcDownload) { pcdFirst = pcDownload = new CDownload(szName, pcInfo); pcDownload->m_pcInfo->m_pdFirst = pcDownload; } else { pcDownload->m_pdNext = new CDownload(szName, pcInfo); pcDownload = (CDownload *) pcDownload->m_pdNext; }
if(!pcDownload) { dprintf(DBG_ERROR, "*** ERROR *** initializing pcDownload!\n"); return(0); } } }
fclose(fp); } }
pcDownload = (CDownload *) pcDownload->m_pcInfo->m_pdFirst;
if (LoadUrlMon() != S_OK) { dprintf(DBG_ERROR, "*** ERROR *** LoadUrlMon() failed\n"); return(0); }
if (CoInitialize(NULL) != S_OK) { dprintf(DBG_ERROR, "*** ERROR *** CoInitialize() failed\n"); return(0); }
pcDownload->m_pcInfo->m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!pcDownload->m_pcInfo->m_hCompleteEvent) { dprintf(DBG_ERROR, "*** ERROR *** on create Event!\n"); }
hDownloadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DownloadThread, (LPVOID)pcDownload, 0, &dwThreadID );
if (!hDownloadThread) { dprintf(DBG_ERROR, "*** ERROR *** Could not create Thread\n"); return(0); }
if(WaitForSingleObject(pcDownload->m_pcInfo->m_hCompleteEvent, TIMEOUT) == WAIT_TIMEOUT) { dprintf(DBG_ERROR, "*** ERROR *** timeout on init\n"); } Sleep(100);
QueryPerformanceCounter((LARGE_INTEGER *)&ibeg);
while(pcDownload) { if(WaitForSingleObject(pcDownload->m_pcInfo->m_hMaxDownloadSem, TIMEOUT) == WAIT_TIMEOUT) { dprintf(DBG_ERROR, "*** ERROR *** timeout on Sem\n"); }
if(g_dwDbgFlags) { TCHAR sz[255]; WideCharToMultiByte(CP_ACP, 0, pcDownload->m_pUrl, -1, sz, 255,0,0); dprintf(DBG_INFO, "main: PostThreadMessage DO_DOWNLOAD %s\n", sz); } if(!PostThreadMessage(dwThreadID, DO_DOWNLOAD, (WPARAM) pcDownload, 0)) { iError = GetLastError(); dprintf(DBG_ERROR, "*** Error *** on PostThreadMessage(0x%X, %ld, 0x%lX, 0) [GLE=%d]\n", dwThreadID, DO_DOWNLOAD, pcDownload, iError); return(0); } pcDownload = (CDownload *) pcDownload->m_pdNext; } //wait for completion downloads at one time
if(WaitForSingleObject(pcdFirst->m_pcInfo->m_hCompleteEvent, TIMEOUT) == WAIT_TIMEOUT) { dprintf(DBG_ERROR, "*** ERROR *** timeout on Sem\n"); }
QueryPerformanceCounter((LARGE_INTEGER *) &iend); QueryPerformanceFrequency((LARGE_INTEGER *) &ifrq);
dwTot_Time = (DWORD)((iend - ibeg) * 1000 / ifrq); if(dwTot_Time == 0) dwTot_Time = 1; fKB = ((float)dwBytes_Read)/1024; fSec = ((float)dwTot_Time)/1000; fKBSec = fKB / fSec; if(!bDelim) { dprintf(DBG_RESULTS, "Downloaded: %s\r\n", sUrl); dprintf(DBG_RESULTS, "%ld Bytes in %ld Milliseconds = %2.0f KB/Sec\r\n", dwBytes_Read, dwTot_Time, fKBSec ); dprintf(DBG_RESULTS, "%ld Reads, %ld Downloads, %ld Byte Read Buffer\r\n", dwNum_Opens, dwMax_Simul_Downloads, dwBuf_Size); } else dprintf(DBG_RESULTS, "%s, %s, %ld, %ld, %2.0f %s\n", g_pTestName ?g_pTestName :"urlmon", g_pRunStr ?g_pRunStr :"1", dwTot_Time, dwBytes_Read, fKBSec, g_CmdLine );
if(g_dwDbgFlags) dprintf(DBG_INFO, "realized finished on data ready\n");
if(!PostThreadMessage(dwThreadID, DOWNLOAD_DONE, (WPARAM) pcDownload, 0)) { iError = GetLastError(); dprintf(DBG_ERROR, "*** Error *** on PostThreadMessage(0x%X, %ld, 0x%lX, 0) [GLE=%d]\n", dwThreadID, DOWNLOAD_DONE, pcDownload, iError); return(0); } if(WaitForSingleObject(hDownloadThread, TIMEOUT) == WAIT_TIMEOUT) { dprintf(DBG_ERROR, "*** ERROR *** timeout on DownloadThread exit\n"); } CloseHandle(hDownloadThread); CoUninitialize(); UnloadUrlMon();
if(g_dwDbgFlags) dprintf(DBG_INFO, "main: exit\n");
return(1); }
|