1261 lines
34 KiB
C++
1261 lines
34 KiB
C++
#define _OLEAUT32_ // get DECLSPEC_IMPORT stuff right for oleaut32.h, we are defing these
|
|
#define _WINMM_ // get DECLSPEC_IMPORT stuff right for mmsystem.h, we are defing these
|
|
#define _INTSHCUT_ // get DECLSPEC_IMPORT stuff right for intshcut.h, we are defing these
|
|
#define _WINX32_ // get DECLSPEC_IMPORT stuff right for wininet.h, we are defing these
|
|
#define _URLCACHEAPI_ // get DECLSPEC_IMPORT stuff right for wininet.h, we are defing these
|
|
|
|
#define INC_OLE2
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <stdio.h>
|
|
#include <ccstock.h>
|
|
#include <ole2.h>
|
|
#include <ole2ver.h>
|
|
#include <oleauto.h>
|
|
#include <docobj.h>
|
|
#include <shlwapi.h>
|
|
#include <wininet.h> // INTERNET_MAX_URL_LENGTH. Must be before shlobjp.h!
|
|
#include <shlobj.h>
|
|
#include <shlobjp.h>
|
|
#include <msxml.h>
|
|
#include <subsmgr.h>
|
|
#include <webcheck.h>
|
|
#include "iimgctx.h"
|
|
|
|
#ifdef _DEBUG
|
|
#ifdef _X86_
|
|
// Use int 3 so we stop immediately in the source
|
|
#define DEBUG_BREAK do { _try { _asm int 3 } _except (EXCEPTION_EXECUTE_HANDLER) {;} } while (0)
|
|
#else
|
|
#define DEBUG_BREAK do { _try { DebugBreak(); } _except (EXCEPTION_EXECUTE_HANDLER) {;} } while (0)
|
|
#endif
|
|
|
|
#define ASSERT(exp) \
|
|
if(!exp) \
|
|
{ \
|
|
printf("ASSERT: %s %s (%s) failed\r\n", __FILE__, __LINE__, TEXT(#exp)); \
|
|
DEBUG_BREAK; \
|
|
} \
|
|
|
|
#else
|
|
#define ASSERT(exp)
|
|
#endif
|
|
|
|
#define DBGOUT(s) printf("%s\r\n", s)
|
|
|
|
#ifndef SAFERELEASE
|
|
#define SAFERELEASE(p) if ((p) != NULL) { (p)->Release(); (p) = NULL; } else
|
|
#endif
|
|
#ifndef SAFEFREEBSTR
|
|
#define SAFEFREEBSTR(p) if ((p) != NULL) { SysFreeString(p); (p) = NULL; } else
|
|
#endif
|
|
#ifndef SAFEFREEOLESTR
|
|
#define SAFEFREEOLESTR(p) if ((p) != NULL) { CoTaskMemFree(p); (p) = NULL; } else
|
|
#endif
|
|
#ifndef SAFELOCALFREE
|
|
#define SAFELOCALFREE(p) if ((p) != NULL) { LocalFree(p); (p) = NULL; } else
|
|
#endif
|
|
#ifndef SAFEDELETE
|
|
#define SAFEDELETE(p) if ((p) != NULL) { delete (p); (p) = NULL; } else
|
|
#endif
|
|
|
|
#define ON_FAILURE_RETURN(HR) {if(FAILED(HR)) return (HR);}
|
|
#define MAX_RES_STRING_LEN 128 // max resource string len for WriteStringRes
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////
|
|
// Notification property names
|
|
// Agent Start
|
|
extern const WCHAR c_szPropURL[] = L"URL";
|
|
extern const WCHAR c_szPropBaseURL[] = L"BaseURL";
|
|
extern const WCHAR c_szPropName[] = L"Name";
|
|
extern const WCHAR c_szPropPriority[] = L"Priority"; // FEATURE: remove this soon
|
|
extern const WCHAR c_szPropAgentFlags[] = L"AgentFlags";
|
|
extern const WCHAR c_szPropCrawlLevels[] = L"RecurseLevels";
|
|
extern const WCHAR c_szPropCrawlFlags[] = L"RecurseFlags";
|
|
extern const WCHAR c_szPropCrawlMaxSize[] = L"MaxSizeKB";
|
|
extern const WCHAR c_szPropCrawlChangesOnly[] = L"CheckChangesOnly";
|
|
extern const WCHAR c_szPropCrawlExemptPeriod[] = L"ExemptPeriod";
|
|
extern const WCHAR c_szPropCrawlUsername[] = L"Username";
|
|
extern const WCHAR c_szPropCrawlPassword[] = L"Password";
|
|
extern const WCHAR c_szPropEmailNotf[] = L"EmailNotification";
|
|
extern const WCHAR c_szPropCrawlLocalDest[] = L"LocalDest";
|
|
extern const WCHAR c_szPropCrawlGroupID[] = L"GroupID";
|
|
extern const WCHAR c_szPropCrawlActualSize[] = L"ActualSizeKB";
|
|
extern const WCHAR c_szPropEnableShortcutGleam[] = L"EnableShortcutGleam";
|
|
extern const WCHAR c_szPropCDFStartCookie[] = L"CDFStartCookie";
|
|
extern const WCHAR c_szPropChannelFlags[] = L"ChannelFlags";
|
|
extern const WCHAR c_szPropAuthMethod[] = L"AuthMethod";
|
|
extern const WCHAR c_szPropAuthDomain[] = L"AuthDomain";
|
|
extern const WCHAR c_szPropChannel[] = L"Channel";
|
|
extern const WCHAR c_szPropDesktopComponent[] = L"DesktopComponent";
|
|
|
|
// Agent Control
|
|
extern const WCHAR c_szPropControlType[] = L"ControlType";
|
|
// Progress Report
|
|
extern const WCHAR c_szPropProgress[] = L"Progress";
|
|
extern const WCHAR c_szPropProgressMax[] = L"ProgressMax";
|
|
extern const WCHAR c_szPropCurrentURL[] = L"CurrentURL";
|
|
// End Report
|
|
extern const WCHAR c_szPropStatusCode[] = L"StatusCode";
|
|
extern const WCHAR c_szPropStatusString[] = L"StatusString";
|
|
extern const WCHAR c_szPropCompletionTime[] = L"CompletionTime";
|
|
extern const WCHAR c_szPropEmailURL[] = L"EmailURL";
|
|
|
|
// Tray Agent Properties
|
|
extern const WCHAR c_szPropGuidsArr[] = L"Guids Array";
|
|
|
|
// Update Agent Properties
|
|
extern const WCHAR c_szTimeStamp[] = L"Update TS";
|
|
|
|
// Tracking Properties
|
|
extern const WCHAR c_szTrackingCookie[] = L"LogGroupID";
|
|
extern const WCHAR c_szTrackingPostURL[] = L"PostURL";
|
|
extern const WCHAR c_szPostingRetry[] = L"PostFailureRetry";
|
|
extern const WCHAR c_szPostHeader[] = L"PostHeader";
|
|
|
|
// Delivery Agent Properties
|
|
extern const WCHAR c_szStartCookie[] = L"StartCookie";
|
|
|
|
// Initial cookie in AGENT_INIT
|
|
extern const WCHAR c_szInitCookie[] = L"InitCookie";
|
|
|
|
// Helper function protos
|
|
int MyOleStrToStrN(LPSTR psz, int cchMultiByte, LPCOLESTR pwsz);
|
|
int MyStrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCSTR psz);
|
|
HRESULT ReadBSTR(ISubscriptionItem *pItem, LPCWSTR szName, BSTR *bstrRet);
|
|
HRESULT ReadOLESTR(ISubscriptionItem *pItem, LPCWSTR szName, LPWSTR *ppszRet);
|
|
HRESULT ReadAnsiSTR(ISubscriptionItem *pItem, LPCWSTR szName, LPSTR *ppszRet);
|
|
HRESULT ReadBool(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT_BOOL *pBoolRet);
|
|
HRESULT ReadSCODE(ISubscriptionItem *pItem, LPCWSTR szName, SCODE *pscRet);
|
|
HRESULT WriteEMPTY(ISubscriptionItem *pItem, LPCWSTR szName);
|
|
HRESULT WriteSCODE(ISubscriptionItem *pItem, LPCWSTR szName, SCODE scVal);
|
|
HRESULT ReadDWORD(ISubscriptionItem *pItem, LPCWSTR szName, DWORD *pdwRet);
|
|
HRESULT ReadLONGLONG(ISubscriptionItem *pItem, LPCWSTR szName, LONGLONG *pllRet);
|
|
HRESULT ReadGUID(ISubscriptionItem *pItem, LPCWSTR szName, GUID *pGuid);
|
|
HRESULT WriteGUID(ISubscriptionItem *pItem, LPCWSTR szName, GUID *pGuid);
|
|
HRESULT WriteLONGLONG(ISubscriptionItem *pItem, LPCWSTR szName, LONGLONG llVal);
|
|
HRESULT WriteDWORD(ISubscriptionItem *pItem, LPCWSTR szName, DWORD dwVal);
|
|
HRESULT ReadDATE(ISubscriptionItem *pItem, LPCWSTR szName, DATE *dtVal);
|
|
HRESULT WriteDATE(ISubscriptionItem *pItem, LPCWSTR szName, DATE *dtVal);
|
|
HRESULT ReadVariant(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT *pvarRet);
|
|
HRESULT WriteVariant(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT *pvarVal);
|
|
HRESULT WriteOLESTR(ISubscriptionItem *pItem, LPCWSTR szName, LPCWSTR szVal);
|
|
HRESULT WriteAnsiSTR(ISubscriptionItem *pItem, LPCWSTR szName, LPCSTR szVal);
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CLASSSES
|
|
///////////////////////////////////////////////////////////////////////
|
|
#if 0
|
|
class CConApp;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class CRunDeliveryAgentSink
|
|
{
|
|
private:
|
|
int m_iActive;
|
|
|
|
public:
|
|
CRunDeliveryAgentSink()
|
|
{
|
|
m_iActive = 0;
|
|
}
|
|
|
|
virtual HRESULT OnAgentBegin()
|
|
{
|
|
m_iActive++;
|
|
return S_OK;
|
|
}
|
|
|
|
// OnAgentProgress not currently called
|
|
virtual HRESULT OnAgentProgress()
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// OnAgentEnd called when agent is complete. fSynchronous means that StartAgent call
|
|
// has not yet returned; hrResult will be returned from StartAgent
|
|
virtual HRESULT OnAgentEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult,
|
|
BOOL fSynchronous)
|
|
{
|
|
m_iActive--;
|
|
return S_OK;
|
|
}
|
|
|
|
virtual int AgentActive()
|
|
{
|
|
return m_iActive;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CRunDeliveryAgent object
|
|
// Will run a delivery agent and host it for you
|
|
// Create, call Init, then call StartAgent
|
|
// Use static function SafeRelease to safely release this class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class CConApp;
|
|
|
|
class CRunDeliveryAgent : public ISubscriptionAgentEvents
|
|
{
|
|
protected:
|
|
virtual ~CRunDeliveryAgent();
|
|
|
|
/// CRunDeliveryAgentSink *m_pParent;
|
|
CConApp* m_pParent;
|
|
|
|
ULONG m_cRef;
|
|
|
|
ISubscriptionItem *m_pItem;
|
|
ISubscriptionAgentControl *m_pAgent;
|
|
|
|
HRESULT m_hrResult;
|
|
BOOL m_fInStartAgent;
|
|
|
|
CLSID m_clsidDest;
|
|
|
|
void CleanUp();
|
|
|
|
public:
|
|
CRunDeliveryAgent();
|
|
|
|
HRESULT Init(CConApp *pParent, ISubscriptionItem *pItem, REFCLSID rclsidDest);
|
|
|
|
inline static void SafeRelease(CRunDeliveryAgent * &pThis)
|
|
{
|
|
if (pThis)
|
|
{
|
|
pThis->m_pParent=NULL; pThis->Release(); pThis=NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT CreateNewItem(ISubscriptionItem **ppItem, REFCLSID rclsidAgent);
|
|
|
|
// StartAgent will return E_PENDING if agent is running. Otherwise it will return
|
|
// synchronous result code from agent.
|
|
HRESULT StartAgent();
|
|
|
|
HRESULT AgentPause(DWORD dwFlags);
|
|
HRESULT AgentResume(DWORD dwFlags);
|
|
HRESULT AgentAbort(DWORD dwFlags);
|
|
|
|
// IUnknown members
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppunk);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
// ISubscriptionAgentEvents members
|
|
STDMETHODIMP UpdateBegin(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie);
|
|
STDMETHODIMP UpdateProgress(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
long lSizeDownloaded, long lProgressCurrent, long lProgressMax,
|
|
HRESULT hrStatus, LPCWSTR wszStatus);
|
|
STDMETHODIMP UpdateEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
long lSizeDownloaded,
|
|
HRESULT hrResult, LPCWSTR wszResult);
|
|
STDMETHODIMP ReportError(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
HRESULT hrError, LPCWSTR wszError);
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
class CConApp
|
|
{
|
|
private:
|
|
int m_argc;
|
|
char **m_argv;
|
|
char *m_pszURL;
|
|
char *m_pRunStr;
|
|
char *m_pTestName;
|
|
char m_CmdLine[1024];
|
|
int m_iActive;
|
|
DWORD m_dwTime; // Download time
|
|
DWORD m_dwFlags;
|
|
DWORD m_dwLevels;
|
|
DWORD m_dwChannel;
|
|
DWORD m_dwChannelFlags;
|
|
BOOL m_bVerbose;
|
|
BOOL m_bPreLoad;
|
|
BOOL m_bChannelAgent;
|
|
|
|
public:
|
|
CConApp(int argc, char **argv);
|
|
~CConApp();
|
|
HRESULT Init();
|
|
HRESULT Download();
|
|
BOOL PrintResults();
|
|
BOOL ParseCommandLine();
|
|
void Display_Usage();
|
|
BOOL Verbose();
|
|
HRESULT MessageLoop();
|
|
|
|
// Delivery agent events
|
|
virtual HRESULT OnAgentBegin();
|
|
virtual HRESULT OnAgentProgress();
|
|
virtual HRESULT OnAgentEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult,
|
|
BOOL fSynchronous);
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// HELPER FUNCTIONS
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
//---------------------------------------------------------------------
|
|
int MyOleStrToStrN(LPSTR psz, int cchMultiByte, LPCOLESTR pwsz)
|
|
{
|
|
int i;
|
|
i=WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz,
|
|
cchMultiByte, NULL, NULL);
|
|
if (!i)
|
|
{
|
|
DBGOUT("MyOleStrToStrN string too long; truncated");
|
|
psz[cchMultiByte-1]=0;
|
|
}
|
|
#ifdef DEBUG
|
|
else
|
|
ZeroMemory(psz+i, sizeof(TCHAR)*(cchMultiByte-i));
|
|
#endif
|
|
|
|
return i;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
int MyStrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCSTR psz)
|
|
{
|
|
int i;
|
|
i=MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, cchWideChar);
|
|
if (!i)
|
|
{
|
|
DBGOUT("MyStrToOleStrN string too long; truncated");
|
|
pwsz[cchWideChar-1]=0;
|
|
}
|
|
#ifdef DEBUG
|
|
else
|
|
ZeroMemory(pwsz+i, sizeof(OLECHAR)*(cchWideChar-i));
|
|
#endif
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// Can return S_OK with NULL bstr
|
|
HRESULT ReadBSTR(ISubscriptionItem *pItem, LPCWSTR szName, BSTR *bstrRet)
|
|
{
|
|
ASSERT(pItem && bstrRet);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
|
|
(Val.vt==VT_BSTR))
|
|
{
|
|
*bstrRet = Val.bstrVal;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&Val); // free any return value of wrong type
|
|
*bstrRet = NULL;
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Cannot return S_OK with emptry string
|
|
HRESULT ReadOLESTR(ISubscriptionItem *pItem, LPCWSTR szName, LPWSTR *ppszRet)
|
|
{
|
|
HRESULT hr;
|
|
BSTR bstrRet = NULL;
|
|
*ppszRet = NULL;
|
|
hr = ReadBSTR(pItem, szName, &bstrRet);
|
|
if (SUCCEEDED(hr) && bstrRet && bstrRet[0])
|
|
{
|
|
int len = (lstrlenW(bstrRet) + 1) * sizeof(WCHAR);
|
|
*ppszRet = (LPWSTR) CoTaskMemAlloc(len);
|
|
if (*ppszRet)
|
|
{
|
|
CopyMemory(*ppszRet, bstrRet, len);
|
|
}
|
|
}
|
|
|
|
SAFEFREEBSTR(bstrRet);
|
|
if (*ppszRet)
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadAnsiSTR(ISubscriptionItem *pItem, LPCWSTR szName, LPSTR *ppszRet)
|
|
{
|
|
HRESULT hr;
|
|
BSTR bstrRet = NULL;
|
|
*ppszRet = NULL;
|
|
hr = ReadBSTR(pItem, szName, &bstrRet);
|
|
if (SUCCEEDED(hr) && bstrRet && bstrRet[0])
|
|
{
|
|
// Don't forget to allocate a long string for DBCS.
|
|
int len = (lstrlenW(bstrRet) + 1) * sizeof(CHAR) * 2;
|
|
*ppszRet = (LPSTR) LocalAlloc(NULL, len);
|
|
if (*ppszRet)
|
|
{
|
|
MyOleStrToStrN(*ppszRet, len, bstrRet);
|
|
}
|
|
}
|
|
|
|
SAFEFREEBSTR(bstrRet);
|
|
if (*ppszRet)
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadBool(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT_BOOL *pBoolRet)
|
|
{
|
|
ASSERT(pItem && pBoolRet);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
|
|
// accept VT_I4 or VT_BOOL
|
|
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
|
|
(Val.vt==VT_BOOL || Val.vt==VT_I4))
|
|
{
|
|
if (Val.vt==VT_I4)
|
|
{
|
|
if (Val.lVal)
|
|
*pBoolRet = VARIANT_TRUE;
|
|
else
|
|
*pBoolRet = VARIANT_FALSE;
|
|
}
|
|
else
|
|
*pBoolRet = Val.boolVal;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&Val); // free any return value of wrong type
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadSCODE(ISubscriptionItem *pItem, LPCWSTR szName, SCODE *pscRet)
|
|
{
|
|
ASSERT(pItem && pscRet);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) && Val.vt == VT_ERROR)
|
|
{
|
|
*pscRet = Val.scode;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&Val);
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteEMPTY(ISubscriptionItem *pItem, LPCWSTR szName)
|
|
{
|
|
ASSERT(pItem);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
return pItem->WriteProperties(1, &szName, &Val);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteSCODE(ISubscriptionItem *pItem, LPCWSTR szName, SCODE scVal)
|
|
{
|
|
ASSERT(pItem);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_ERROR;
|
|
Val.scode = scVal;
|
|
|
|
return pItem->WriteProperties(1, &szName, &Val);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadDWORD(ISubscriptionItem *pItem, LPCWSTR szName, DWORD *pdwRet)
|
|
{
|
|
ASSERT(pItem && pdwRet);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
|
|
(Val.vt==VT_I4 || Val.vt==VT_I2))
|
|
{
|
|
if (Val.vt==VT_I4)
|
|
*pdwRet = (DWORD) Val.lVal;
|
|
else
|
|
*pdwRet = (DWORD) Val.iVal;
|
|
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&Val); // free any return value of wrong type
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadLONGLONG(ISubscriptionItem *pItem, LPCWSTR szName, LONGLONG *pllRet)
|
|
{
|
|
ASSERT(pItem && pllRet);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
|
|
(Val.vt==VT_CY))
|
|
{
|
|
*pllRet = *((LONGLONG *) &(Val.cyVal));
|
|
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&Val); // free any return value of wrong type
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadGUID(ISubscriptionItem *pItem, LPCWSTR szName, GUID *pGuid)
|
|
{
|
|
ASSERT(pItem && pGuid);
|
|
|
|
BSTR bstrGUID = NULL;
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(ReadBSTR(pItem, szName, &bstrGUID)) &&
|
|
SUCCEEDED(CLSIDFromString(bstrGUID, pGuid)))
|
|
{
|
|
hr = NOERROR;
|
|
}
|
|
SAFEFREEBSTR(bstrGUID);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteGUID(ISubscriptionItem *pItem, LPCWSTR szName, GUID *pGuid)
|
|
{
|
|
ASSERT(pItem && pGuid);
|
|
|
|
WCHAR wszCookie[GUIDSTR_MAX];
|
|
|
|
#ifdef DEBUG
|
|
int len =
|
|
#endif
|
|
StringFromGUID2(*pGuid, wszCookie, sizeof(wszCookie));
|
|
ASSERT(GUIDSTR_MAX == len);
|
|
return WriteOLESTR(pItem, szName, wszCookie);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteLONGLONG(ISubscriptionItem *pItem, LPCWSTR szName, LONGLONG llVal)
|
|
{
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_CY;
|
|
Val.cyVal = *((CY *) &llVal);
|
|
|
|
return pItem->WriteProperties(1, &szName, &Val);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteDWORD(ISubscriptionItem *pItem, LPCWSTR szName, DWORD dwVal)
|
|
{
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_I4;
|
|
Val.lVal = dwVal;
|
|
|
|
return pItem->WriteProperties(1, &szName, &Val);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadDATE(ISubscriptionItem *pItem, LPCWSTR szName, DATE *dtVal)
|
|
{
|
|
ASSERT(pItem && dtVal);
|
|
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_EMPTY;
|
|
|
|
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) && (Val.vt==VT_DATE))
|
|
{
|
|
*dtVal = Val.date;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&Val); // free any return value of wrong type
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteDATE(ISubscriptionItem *pItem, LPCWSTR szName, DATE *dtVal)
|
|
{
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_DATE;
|
|
Val.date= *dtVal;
|
|
|
|
return pItem->WriteProperties(1, &szName, &Val);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT ReadVariant(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT *pvarRet)
|
|
{
|
|
ASSERT(pvarRet->vt == VT_EMPTY);
|
|
return pItem->ReadProperties(1, &szName, pvarRet);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteVariant(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT *pvarVal)
|
|
{
|
|
return pItem->WriteProperties(1, &szName, pvarVal);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteOLESTR(ISubscriptionItem *pItem, LPCWSTR szName, LPCWSTR szVal)
|
|
{
|
|
VARIANT Val;
|
|
|
|
Val.vt = VT_BSTR;
|
|
Val.bstrVal = SysAllocString(szVal);
|
|
|
|
HRESULT hr = pItem->WriteProperties(1, &szName, &Val);
|
|
|
|
SysFreeString(Val.bstrVal);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT WriteAnsiSTR(ISubscriptionItem *pItem, LPCWSTR szName, LPCSTR szVal)
|
|
{
|
|
VARIANT Val;
|
|
BSTR bstrVal;
|
|
int iLen;
|
|
HRESULT hr;
|
|
|
|
iLen = lstrlen(szVal);
|
|
bstrVal = SysAllocStringLen(NULL, iLen);
|
|
if (bstrVal)
|
|
{
|
|
MyStrToOleStrN(bstrVal, iLen + 1, szVal);
|
|
|
|
Val.vt = VT_BSTR;
|
|
Val.bstrVal = bstrVal;
|
|
|
|
hr = pItem->WriteProperties(1, &szName, &Val);
|
|
|
|
SysFreeString(bstrVal);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//==============================================================================
|
|
// CRunDeliveryAgent provides generic support for synchronous operation of a
|
|
// delivery agent
|
|
// It is aggregatable so that you can add more interfaces to the callback
|
|
//
|
|
// Taken from webcheck\cdfagent.cpp
|
|
//==============================================================================
|
|
CRunDeliveryAgent::CRunDeliveryAgent()
|
|
{
|
|
m_cRef = 1;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CRunDeliveryAgent::Init(CConApp* pParent,
|
|
ISubscriptionItem *pItem,
|
|
REFCLSID rclsidDest)
|
|
{
|
|
ASSERT(pParent && pItem);
|
|
|
|
if (m_pParent || m_pItem)
|
|
return E_FAIL; // already initialized. can't reuse an instance.
|
|
|
|
if (!pParent || !pItem)
|
|
return E_FAIL;
|
|
|
|
m_pParent = pParent;
|
|
m_clsidDest = rclsidDest;
|
|
|
|
m_pItem = pItem;
|
|
pItem->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
CRunDeliveryAgent::~CRunDeliveryAgent()
|
|
{
|
|
CleanUp();
|
|
}
|
|
|
|
//
|
|
// IUnknown members
|
|
//
|
|
//---------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CRunDeliveryAgent::AddRef(void)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CRunDeliveryAgent::Release(void)
|
|
{
|
|
if( 0L != --m_cRef )
|
|
return m_cRef;
|
|
|
|
delete this;
|
|
return 0L;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
STDMETHODIMP CRunDeliveryAgent::QueryInterface(REFIID riid, void ** ppv)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
// Validate requested interface
|
|
if ((IID_IUnknown == riid) ||
|
|
(IID_ISubscriptionAgentEvents == riid))
|
|
{
|
|
*ppv=(ISubscriptionAgentEvents *)this;
|
|
}
|
|
else
|
|
return E_NOINTERFACE;
|
|
|
|
// Addref through the interface
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ISubscriptionAgentEvents members
|
|
//
|
|
//---------------------------------------------------------------------
|
|
STDMETHODIMP CRunDeliveryAgent::UpdateBegin(const SUBSCRIPTIONCOOKIE *)
|
|
{
|
|
if (m_pParent)
|
|
m_pParent->OnAgentBegin();
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
STDMETHODIMP CRunDeliveryAgent::UpdateProgress(
|
|
const SUBSCRIPTIONCOOKIE *,
|
|
long lSizeDownloaded,
|
|
long lProgressCurrent,
|
|
long lProgressMax,
|
|
HRESULT hrStatus,
|
|
LPCWSTR wszStatus)
|
|
{
|
|
if (m_pParent)
|
|
m_pParent->OnAgentProgress();
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#define INET_S_AGENT_BASIC_SUCCESS _HRESULT_TYPEDEF_(0x000C0F8FL) // From webcheck/delagent.h
|
|
|
|
STDMETHODIMP CRunDeliveryAgent::UpdateEnd(const SUBSCRIPTIONCOOKIE *pCookie,
|
|
long lSizeDownloaded,
|
|
HRESULT hrResult,
|
|
LPCWSTR wszResult)
|
|
{
|
|
ASSERT((hrResult != INET_S_AGENT_BASIC_SUCCESS) && (hrResult != E_PENDING));
|
|
|
|
m_hrResult = hrResult;
|
|
if (hrResult == INET_S_AGENT_BASIC_SUCCESS || hrResult == E_PENDING)
|
|
{
|
|
// Shouldn't happen; let's be robust anyway.
|
|
m_hrResult = S_OK;
|
|
}
|
|
|
|
if (m_pParent)
|
|
{
|
|
m_pParent->OnAgentEnd(pCookie, lSizeDownloaded, hrResult, wszResult, m_fInStartAgent);
|
|
}
|
|
|
|
CleanUp();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
STDMETHODIMP CRunDeliveryAgent::ReportError(
|
|
const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
HRESULT hrError,
|
|
LPCWSTR wszError)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CRunDeliveryAgent::StartAgent()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!m_pParent || !m_pItem || m_pAgent)
|
|
return E_FAIL;
|
|
|
|
AddRef(); // Release before we return from this function
|
|
m_fInStartAgent = TRUE;
|
|
|
|
m_hrResult = INET_S_AGENT_BASIC_SUCCESS;
|
|
|
|
if(m_pParent->Verbose())
|
|
DBGOUT("Using new interfaces to host agent");
|
|
|
|
ASSERT(!m_pAgent);
|
|
|
|
hr = CoCreateInstance(m_clsidDest, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_ISubscriptionAgentControl, (void **)&m_pAgent);
|
|
|
|
if (m_pAgent)
|
|
{
|
|
hr = m_pAgent->StartUpdate(m_pItem, (ISubscriptionAgentEvents *)this);
|
|
}
|
|
|
|
hr = m_hrResult;
|
|
|
|
m_fInStartAgent = FALSE;
|
|
Release();
|
|
|
|
if (hr != INET_S_AGENT_BASIC_SUCCESS)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return E_PENDING;
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CRunDeliveryAgent::AgentPause(DWORD dwFlags)
|
|
{
|
|
if (m_pAgent)
|
|
return m_pAgent->PauseUpdate(0);
|
|
|
|
if(m_pParent->Verbose())
|
|
DBGOUT("CRunDeliveryAgent::AgentPause with no running agent!!");
|
|
return S_FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CRunDeliveryAgent::AgentResume(DWORD dwFlags)
|
|
{
|
|
if (m_pAgent)
|
|
return m_pAgent->ResumeUpdate(0);
|
|
|
|
if(m_pParent->Verbose())
|
|
DBGOUT("CRunDeliveryAgent::AgentResume with no running agent!!");
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CRunDeliveryAgent::AgentAbort(DWORD dwFlags)
|
|
{
|
|
if (m_pAgent)
|
|
return m_pAgent->AbortUpdate(0);
|
|
|
|
if(m_pParent->Verbose())
|
|
DBGOUT("CRunDeliveryAgent::AgentAbort with no running agent!!");
|
|
return S_FALSE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
void CRunDeliveryAgent::CleanUp()
|
|
{
|
|
SAFERELEASE(m_pItem);
|
|
SAFERELEASE(m_pAgent);
|
|
m_pParent = NULL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CRunDeliveryAgent::CreateNewItem(ISubscriptionItem **ppItem, REFCLSID rclsidAgent)
|
|
{
|
|
ISubscriptionMgrPriv *pSubsMgrPriv=NULL;
|
|
SUBSCRIPTIONITEMINFO info;
|
|
|
|
*ppItem = NULL;
|
|
|
|
HRESULT hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_ISubscriptionMgrPriv, (void**)&pSubsMgrPriv);
|
|
|
|
if (pSubsMgrPriv)
|
|
{
|
|
SUBSCRIPTIONCOOKIE cookie;
|
|
|
|
info.cbSize = sizeof(info);
|
|
info.dwFlags = SI_TEMPORARY;
|
|
info.dwPriority = 0;
|
|
info.ScheduleGroup = GUID_NULL;
|
|
info.clsidAgent = rclsidAgent;
|
|
|
|
pSubsMgrPriv->CreateSubscriptionItem(&info, &cookie, ppItem);
|
|
|
|
pSubsMgrPriv->Release();
|
|
}
|
|
else
|
|
{
|
|
printf("CoCreateInstance IID_ISubscriptionMgrPriv failed. hr=0x%x\r\n", hr);
|
|
}
|
|
|
|
return (*ppItem) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////
|
|
//---------------------------------------------------------------------
|
|
CConApp::CConApp(int argc, char **argv)
|
|
{
|
|
m_argc = argc;
|
|
m_argv = argv;
|
|
m_dwTime = 0;
|
|
m_pszURL = NULL;
|
|
m_bVerbose = FALSE;
|
|
m_bPreLoad = FALSE;
|
|
m_bChannelAgent = FALSE;
|
|
m_dwFlags = 3;
|
|
m_dwLevels = 0;
|
|
m_dwChannel = 1;
|
|
m_dwChannelFlags = CHANNEL_AGENT_PRECACHE_ALL;
|
|
m_pRunStr = NULL;
|
|
m_pTestName = NULL;
|
|
m_iActive = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
CConApp::~CConApp()
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CConApp::Init()
|
|
{
|
|
HRESULT hr = CoInitialize(NULL);
|
|
ON_FAILURE_RETURN(hr);
|
|
|
|
if(!ParseCommandLine())
|
|
return(E_FAIL);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CConApp::Download()
|
|
{
|
|
ISubscriptionItem *pSubscriptItem = NULL;
|
|
IImgCtx *pImgCtx = NULL;
|
|
IClassFactory *pImageCF = NULL;
|
|
|
|
if(m_bVerbose)
|
|
{
|
|
printf("URL=%s\r\n", m_pszURL);
|
|
if(m_bPreLoad)
|
|
printf("Preloading Mshtml\r\n");
|
|
if(m_bChannelAgent)
|
|
printf("ChannelAgent: Channel=%d Flags=0x%x\r\n", m_dwChannel, m_dwChannelFlags);
|
|
else
|
|
printf("WebCrawlerAgent: Levels=%d Flags=0x%x\r\n", m_dwFlags, m_dwLevels);
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
CLSID clsid;
|
|
|
|
if (m_bChannelAgent)
|
|
clsid = CLSID_ChannelAgent;
|
|
else
|
|
clsid = CLSID_WebCrawlerAgent;
|
|
|
|
CRunDeliveryAgent *prda = new CRunDeliveryAgent;
|
|
|
|
hr = prda->CreateNewItem(&pSubscriptItem, clsid);
|
|
if (FAILED(hr) || !pSubscriptItem)
|
|
{
|
|
printf("prda->CreateNewItem failed.\r\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!prda || FAILED(prda->Init((CConApp *)this, pSubscriptItem, clsid)))
|
|
{
|
|
if (prda)
|
|
prda->Release();
|
|
else
|
|
printf("new CRunDeliveryAgent failed.\r\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Preload mshtml
|
|
if (m_bPreLoad)
|
|
{
|
|
if (FAILED(hr = CoGetClassObject(CLSID_IImgCtx, CLSCTX_SERVER, NULL, IID_IClassFactory, (void **)&pImageCF)))
|
|
{
|
|
printf("CoGetClassObject(CLSID_IImgCtx...) failed hr=%x\r\n", hr);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (FAILED(hr = pImageCF->CreateInstance(NULL, IID_IImgCtx, (void **)&pImgCtx)))
|
|
{
|
|
printf("CreateInstance(IID_IImgCtx...) failed hr=%x\r\n", hr);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
// Set properties
|
|
if (m_bChannelAgent)
|
|
{
|
|
WriteDWORD(pSubscriptItem, c_szPropChannel, m_dwChannel);
|
|
WriteDWORD(pSubscriptItem, c_szPropChannelFlags, m_dwChannelFlags);
|
|
}
|
|
else
|
|
{
|
|
WriteDWORD(pSubscriptItem, c_szPropCrawlFlags, m_dwFlags);
|
|
WriteDWORD(pSubscriptItem, c_szPropCrawlLevels, m_dwLevels);
|
|
}
|
|
|
|
// Set url property and start the download
|
|
WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
|
|
MyStrToOleStrN(wszURL, INTERNET_MAX_URL_LENGTH, m_pszURL);
|
|
WriteOLESTR(pSubscriptItem, c_szPropURL, wszURL);
|
|
|
|
m_dwTime = GetTickCount(); // Start time
|
|
|
|
hr = prda->StartAgent();
|
|
if (hr == E_PENDING)
|
|
{
|
|
hr = S_OK;
|
|
|
|
if (Verbose())
|
|
DBGOUT("CRunDeliveryAgent StartAgent succeeded");
|
|
MessageLoop();
|
|
}
|
|
|
|
m_dwTime = GetTickCount() - m_dwTime; // End time
|
|
|
|
// Clean up
|
|
if (pSubscriptItem)
|
|
{
|
|
pSubscriptItem->Release();
|
|
pSubscriptItem = NULL;
|
|
}
|
|
|
|
if (pImgCtx)
|
|
{
|
|
pImgCtx->Release();
|
|
pImgCtx = NULL;
|
|
}
|
|
|
|
if (pImageCF)
|
|
{
|
|
pImageCF->Release();
|
|
pImageCF = NULL;
|
|
}
|
|
|
|
if (prda)
|
|
{
|
|
prda->Release();
|
|
prda = NULL;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
return E_FAIL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CConApp::MessageLoop()
|
|
{
|
|
MSG msg;
|
|
BOOL dw;
|
|
|
|
// Yield and wait for "UpdateEnd" notification
|
|
while (m_iActive > 0 && (dw = ::GetMessage(&msg, NULL, 0, 0)))
|
|
{
|
|
::TranslateMessage(&msg);
|
|
::DispatchMessage(&msg);
|
|
}
|
|
|
|
if(dw == 0)
|
|
printf("GetMessage = 0, GLE=%d\r\n", GetLastError());
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
BOOL CConApp::PrintResults()
|
|
{
|
|
printf("%s, %s, %ld, %ld, %ld %s\r\n",
|
|
m_pTestName ?m_pTestName :(m_bChannelAgent) ?"Webcheck ChannelAgent" :"Webcheck WebCrawlAgent",
|
|
m_pRunStr ?m_pRunStr :"1",
|
|
m_dwTime,
|
|
0, // bytes read - future use, matches other tests
|
|
0, // kb/sec - future use
|
|
m_CmdLine
|
|
);
|
|
return(TRUE);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
BOOL CConApp::ParseCommandLine()
|
|
{
|
|
BOOL bRC = TRUE;
|
|
int argc = m_argc;
|
|
char **argv = m_argv;
|
|
DWORD dwLen = 0;
|
|
|
|
*m_CmdLine = '\0';
|
|
|
|
argv++; argc--;
|
|
while( argc > 0 && argv[0][0] == '-' )
|
|
{
|
|
switch (argv[0][1])
|
|
{
|
|
case 'c':
|
|
m_bChannelAgent = TRUE;
|
|
break;
|
|
case 'f':
|
|
m_dwFlags = atoi(&argv[0][2]);
|
|
break;
|
|
case 'l':
|
|
m_dwLevels = atoi(&argv[0][2]);
|
|
break;
|
|
case 'p':
|
|
m_bPreLoad = TRUE;
|
|
break;
|
|
case 'r':
|
|
m_pRunStr = &argv[0][2];
|
|
break;
|
|
case 't':
|
|
m_pTestName = &argv[0][2];
|
|
break;
|
|
case 'u':
|
|
m_pszURL = &argv[0][2];
|
|
break;
|
|
case 'v':
|
|
m_bVerbose = TRUE;
|
|
break;
|
|
default:
|
|
bRC = FALSE;
|
|
break;
|
|
}
|
|
|
|
if(bRC)
|
|
{
|
|
dwLen += lstrlen(argv[0]) + 1; // length of arg and space
|
|
if(dwLen < ((sizeof(m_CmdLine)/sizeof(m_CmdLine[0]))-1))
|
|
{
|
|
lstrcat(m_CmdLine, ",");
|
|
lstrcat(m_CmdLine, argv[0]);
|
|
}
|
|
}
|
|
|
|
argv++; argc--;
|
|
}
|
|
|
|
if(!m_pszURL || (bRC == FALSE))
|
|
{
|
|
Display_Usage();
|
|
bRC = FALSE;
|
|
}
|
|
|
|
return(bRC);
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
void CConApp::Display_Usage()
|
|
{
|
|
printf("Usage: %s -uURL [Options]\r\n\n", m_argv[0]);
|
|
printf("Options:\r\n");
|
|
printf("\t-c Run ChannelAgent instead of WebCrawl.\r\n");
|
|
printf("\t-f# Webcrawl agent flags.\r\n");
|
|
printf("\t-l# Delivery agent levels to crawl.\r\n");
|
|
printf("\t-p Preload Mshtml.\r\n");
|
|
printf("\t-v Turn on verbose output.\r\n");
|
|
printf("\t-tStr test name string (used in results output)\n");
|
|
printf("\t-rStr run# string (used in results output)\n");
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
inline BOOL CConApp::Verbose()
|
|
{
|
|
return(m_bVerbose);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
HRESULT CConApp::OnAgentBegin()
|
|
{
|
|
m_iActive++;
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// OnAgentProgress not currently called
|
|
HRESULT CConApp::OnAgentProgress()
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// OnAgentEnd called when agent is complete. fSynchronous means that StartAgent call
|
|
// has not yet returned; hrResult will be returned from StartAgent
|
|
HRESULT CConApp::OnAgentEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
|
|
long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult,
|
|
BOOL fSynchronous)
|
|
{
|
|
m_iActive--;
|
|
return S_OK;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////
|
|
int __cdecl main(int argc, char **argv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CConApp App(argc, argv);
|
|
hr = App.Init();
|
|
if(!FAILED(hr))
|
|
{
|
|
hr = App.Download();
|
|
App.PrintResults();
|
|
}
|
|
|
|
return((int)hr);
|
|
}
|
|
|