2025-11-28 00:35:46 +09:00

474 lines
13 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
/**
* This sample demonstrates how to use the GetProperty method on the new
* IBackgroundCopyFile5 interface to obtain the last set HTTP headers
* received for each file in a download job.
*
* The information in the HTTP headers could be used, fo example, to
* determine the file type or when it last changed on the server.
*/
#include "stdafx.h"
#include <windows.h>
#include <bits.h>
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof( *(x) ))
/**
* Definition of constants
*/
static const unsigned int HALF_SECOND_AS_MILLISECONDS = 500;
static const unsigned int TWO_SECOND_LOOP = 2000 / HALF_SECOND_AS_MILLISECONDS;
/**
* Simple data structure containing the remote and local names for a file.
*/
typedef struct
{
LPWSTR RemoteFile;
LPWSTR LocalFile;
} DOWNLOAD_FILE;
/**
* Array containing multiple DOWNLOAD_FILE data structures representing the files
* that will be added to the download job.
*/
DOWNLOAD_FILE FileList[] =
{
{
L"http://download.microsoft.com/download/8/5/5/8551E67C-3D6E-4EAA-891B-6B46A97F179F/Live_Meeting_2007_Getting_Started_Guide_Service.doc",
L"c:\\temp\\data\\Getting started with Microsoft Office Live Meeting.doc"
},
{
L"http://download.microsoft.com/download/3/0/9/309778fd-659e-4853-b556-a14931cc3a2a/Live_Meeting_2007_Service_Quick_Reference_Card.doc",
L"c:\\temp\\data\\Live_Meeting_2007_Service_Quick_Reference_Card.doc"
},
{
L"http://download.microsoft.com/download/D/2/2/D22D16C3-7637-41D3-99DA-10E7CEBAD290/SQL2008UpgradeTechnicalReferenceGuide.docx",
L"c:\\temp\\data\\SQL2008UpgradeTechnicalReferenceGuide.docx"
}
};
/**
* Forward declaration of functions
*/
HRESULT GetBackgroundCopyManager(_Out_ IBackgroundCopyManager **Manager);
HRESULT CreateDownloadJob(_In_ LPCWSTR Name, _In_ IBackgroundCopyManager *Manager, _Out_ IBackgroundCopyJob **Job);
HRESULT MonitorJobProgress( _In_ IBackgroundCopyJob *Job );
HRESULT DisplayFileHeaders( _In_ IBackgroundCopyJob *Job );
VOID DisplayProgress( _In_ IBackgroundCopyJob *Job );
VOID DisplayHeaders( _In_ LPWSTR Headers );
VOID DisplayError( _In_ IBackgroundCopyJob *Job );
/*
* Main program entry point
*/
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr;
IBackgroundCopyManager *Manager;
// Get the BITS Background Copy Manager
hr = GetBackgroundCopyManager(&Manager);
if( SUCCEEDED( hr ) )
{
IBackgroundCopyJob *Job;
// Create a new download job
hr = CreateDownloadJob( L"MyJob", Manager, &Job );
if( SUCCEEDED(hr) )
{
// Add the files to the job
for( int i=0; i<ARRAY_LENGTH(FileList); ++i)
{
hr = Job->AddFile(
FileList[i].RemoteFile,
FileList[i].LocalFile
);
if( FAILED(hr) )
{
printf(
"Error: Unable to add remote file '%ws' to the download job (error %08X).\n",
FileList[i].RemoteFile,
hr
);
}
else
{
printf(
"Downloading remote file '%ws' to local file '%ws'\n",
FileList[i].RemoteFile,
FileList[i].LocalFile
);
}
}
// Start the job and display its progress
hr = Job->Resume();
if( FAILED(hr) )
{
printf( "ERROR: Unable to start the BITS download job (error code %08X).\n", hr );
}
else
{
MonitorJobProgress( Job );
}
// Release the BITS IBackgroundCopyJob interface
Job->Release();
Job = NULL;
}
// Release the IBackgroundCopyManager interface
Manager->Release();
Manager = NULL;
}
return 0;
}
/**
* Gets a pointer to the BITS Background Copy Manager.
*
* If successful, it returns a success code and sets the
* referenced IBackgroundCopyFileManager interface pointer
* to a reference counted instance of the Background Copy Manager
* interface.
*/
HRESULT
GetBackgroundCopyManager(_Out_ IBackgroundCopyManager **Manager)
{
HRESULT hr;
//Specify the appropriate COM threading model for your application.
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(
__uuidof(BackgroundCopyManager),
NULL,
CLSCTX_LOCAL_SERVER,
__uuidof(IBackgroundCopyManager),
(void**) Manager
);
}
else
{
printf( "ERROR: Unable to initialize COM (error code %08X).\n", hr );
}
return hr;
}
/**
* Creates a new download job with the specified name.
*/
HRESULT
CreateDownloadJob(_In_ LPCWSTR Name, _In_ IBackgroundCopyManager *Manager, _Out_ IBackgroundCopyJob **Job)
{
HRESULT hr;
GUID guid;
hr = Manager->CreateJob(
Name,
BG_JOB_TYPE_DOWNLOAD,
&guid,
Job
);
return hr;
}
/**
* Monitors and displays the progress of the download job.
*
* A new status message is output whenever the job's status changes or,
* when transferring data, every 2 seconds displays how much data
* has been transferred.
*/
HRESULT
MonitorJobProgress( _In_ IBackgroundCopyJob *Job )
{
HRESULT hr;
LPWSTR JobName;
BG_JOB_STATE State;
int PreviousState = -1;
bool Exit = false;
int ProgressCounter = 0;
hr = Job->GetDisplayName( &JobName );
printf( "Progress report for download job '%ws'.\n", JobName );
// display the download progress
while( !Exit )
{
hr = Job->GetState( &State );
if( State != PreviousState )
{
switch( State )
{
case BG_JOB_STATE_QUEUED:
printf( "Job is in the queue and waiting to run.\n" );
break;
case BG_JOB_STATE_CONNECTING:
printf( "BITS is trying to connect to the remote server.\n" );
break;
case BG_JOB_STATE_TRANSFERRING:
printf( "BITS has started downloading data.\n" );
DisplayProgress( Job );
break;
case BG_JOB_STATE_ERROR:
printf( "ERROR: BITS has encountered a non-recoverable error (error code %08X).\n", GetLastError() );
printf( " Exiting job.\n" );
Exit = true;
break;
case BG_JOB_STATE_TRANSIENT_ERROR:
printf( "ERROR: BITS has encountered a recoverable error.\n" );
DisplayError( Job );
printf( " Continuing to retry.\n" );
break;
case BG_JOB_STATE_TRANSFERRED:
DisplayProgress( Job );
printf( "The job has been successfully completed.\n" );
printf( "Finalizing local files.\n" );
Job->Complete();
break;
case BG_JOB_STATE_ACKNOWLEDGED:
printf( "Finalization complete.\n" );
Exit = true;
break;
case BG_JOB_STATE_CANCELLED:
printf( "WARNING: The job has been cancelled.\n" );
Exit = true;
break;
default:
printf( "WARNING: Unknown BITS state %d.\n", State );
Exit = true;
}
PreviousState = State;
}
else if (State == BG_JOB_STATE_TRANSFERRING )
{
// display job progress every 2 seconds
if( ++ProgressCounter % TWO_SECOND_LOOP == 0 )
{
DisplayProgress( Job );
}
}
Sleep(HALF_SECOND_AS_MILLISECONDS);
}
printf("\n");
if( SUCCEEDED(hr) )
{
hr = DisplayFileHeaders( Job );
}
return hr;
}
/**
* For each file in the job, obtains the (final) HTTP headers received from the
* remote server that hosts the files and then displays the HTTP headers.
*/
HRESULT
DisplayFileHeaders( _In_ IBackgroundCopyJob *Job )
{
HRESULT hr;
IEnumBackgroundCopyFiles *FileEnumerator;
printf( "Individual file information.\n" );
hr = Job->EnumFiles( &FileEnumerator );
if( FAILED(hr) )
{
printf( "WARNING: Unable to obtain an IEnumBackgroundCopyFiles interface.\n");
printf( " No further information can be provided about the files in the job.\n");
}
else
{
ULONG Count;
hr = FileEnumerator->GetCount( &Count );
if( FAILED(hr) )
{
printf("WARNING: Unable to obtain a count of the number of files in the job.\n" );
printf( " No further information can be provided about the files in the job.\n");
}
else
{
for( ULONG i=0; i < Count; ++i )
{
IBackgroundCopyFile *TempFile;
hr = FileEnumerator->Next(1, &TempFile, NULL);
if( FAILED(hr) )
{
printf("WARNING: Unable to obtain an IBackgroundCopyFile interface for the next file in the job.\n" );
printf( " No further information can be provided about this file.\n");
}
else
{
IBackgroundCopyFile5 *File;
hr = TempFile->QueryInterface( __uuidof( IBackgroundCopyFile5 ), (void **) &File );
if( FAILED(hr) )
{
printf("WARNING: Unable to obtain an IBackgroundCopyFile5 interface for the file.\n" );
printf( " No further information can be provided about this file.\n");
}
else
{
LPWSTR RemoteFileName;
hr = File->GetRemoteName( &RemoteFileName );
if( FAILED(hr) )
{
printf("WARNING: Unable to obtain the remote file name for this file.\n" );
}
else
{
printf("HTTP headers for remote file '%ws'\n", RemoteFileName );
CoTaskMemFree( RemoteFileName );
RemoteFileName = NULL;
}
BITS_FILE_PROPERTY_VALUE Value;
hr = File->GetProperty(
BITS_FILE_PROPERTY_ID_HTTP_RESPONSE_HEADERS,
&Value
);
if( FAILED(hr) )
{
printf("WARNING: Unable to obtain the HTTP headers for this file.\n" );
}
else
{
if(Value.String)
{
DisplayHeaders( Value.String );
CoTaskMemFree( Value.String );
Value.String = NULL;
}
}
File->Release();
File = NULL;
}
TempFile->Release();
TempFile = NULL;
}
}
}
FileEnumerator->Release();
FileEnumerator = NULL;
}
return S_OK;
}
/**
* Displays the current progress of the job in terms of the amount of data
* and number of files transferred.
*/
VOID
DisplayProgress( _In_ IBackgroundCopyJob *Job )
{
HRESULT hr;
BG_JOB_PROGRESS Progress;
hr = Job->GetProgress( &Progress );
if( SUCCEEDED(hr) )
{
printf(
"%llu of %llu bytes transferred (%lu of %lu files).\n",
Progress.BytesTransferred, Progress.BytesTotal,
Progress.FilesTransferred, Progress.FilesTotal
);
}
else
{
printf( "ERROR: Unable to get job progress (error code %08X).\n", hr );
}
}
/**
* Parses the provided string containing HTTP headers,
* splits them apart and displays them to the user.
*/
VOID
DisplayHeaders( _In_ LPWSTR Headers )
{
printf("Headers: %ws\n", Headers );
}
VOID
DisplayError( _In_ IBackgroundCopyJob *Job )
{
HRESULT hr;
IBackgroundCopyError *Error;
LPWSTR ErrorDescription;
hr = Job->GetError( &Error );
if( FAILED(hr) )
{
printf( "WARNING: Error details are not available.\n");
}
else
{
hr = Error->GetErrorDescription( LANGIDFROMLCID(GetThreadLocale()), &ErrorDescription );
if( SUCCEEDED(hr) )
{
printf( " Error details: %ws\n", ErrorDescription );
CoTaskMemFree( ErrorDescription );
}
Error->Release();
}
}