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

#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);
}