HTTP ダウンロード :【VC++】




ブラウザでダウンロード
それなりに込み入った処理なので、lightbox.lib をかなり使っています。
※ こちらの 標準クラス

リソースは、Visual Studio で作ったもの(lightbox.res)を
XN Resource Editor で変更して使っています。
サブタイトル
以下は引数の指定方法です

1) ホスト名
2) パス
3) ローカルパス

例) lightbox.on.coocan.jp /download/WinOfSql102.lzh "C:\TMP File\test.lzh"

※ ダウンロードした後、そのディレクトリをエクスプローラで開きます
#define _WIN32_WINNT 0x0500
#include <tchar.h>
#include "lightbox\lightbox.h"

#pragma comment( lib, "lightbox\\lightbox.lib" )
#pragma comment( lib, "shlwapi.lib" )
#pragma comment( lib, "wininet.lib" )   

#define IDD_HTTPDOWNLOAD	129
#define IDC_TARGET			1000
#define IDC_FILEPATH		1001
#define IDC_PROGRESS1		1003
#define IDC_DOWNLOADSIZE	1005
#define THREAD_END			LBOX_USER + 1

LboxDlg *Dlg = NULL;
LboxProgressBar Pbar;
LboxThread Thread;
LboxTool Tool;
LboxString LString;
LboxToken Token;
LboxString Server;
LboxString RemoteFile;
LboxString LocalFile;

DWORD content_length;
DWORD nByte = 0;

LRESULT CALLBACK DialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
DWORD WINAPI ThreadProc( LPVOID lpParameter );

// *********************************************************
// Windows アプリケーションとしてのエントリポイント
// Link.exe で /SUBSYSTEM:WINDOWS がデフォルトで
// 指定される事になります
// *********************************************************
int APIENTRY _tWinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR lpCmdLine,
	int nCmdShow
)
{
	// " で囲まれたトークン内のスペースを 0x01 に置き換える
	int i,len,flg;
	len = lstrlen( lpCmdLine );
	flg = 0;
	for( i = 0; i < len; i++ ) {
		if ( flg == 0 ) {
			if ( lpCmdLine[i] == '"'  ) {
				flg = 1;
			}
		}
		else {
			// スペースをいったん置き換える
			if ( lpCmdLine[i] == ' ' ) {
				lpCmdLine[i] = 0x01;
			}
			if ( lpCmdLine[i] == '"'  ) {
				flg = 0;
			}
		}
	}

	// 0x01 に置き換えた文字を一括で元に戻す為の文字列
	char s[4];
	char d[4];
	s[0] = 0x01;
	s[1] = 0x00;
	d[0] = ' ';
	d[1] = 0x00;

	// スペースでトークン分解
	Token.CreateToken( lpCmdLine, " " );

	// トークンを文字列オブジェクトにセットして、
	// 0x01 を スペースに戻して、" で囲まれていたら " を削除
	Server = Token.Token[0];
	Server.Replace( s, d );
	Server.RemoveEnclose( '"' );

	RemoteFile = Token.Token[1];
	RemoteFile.Replace( s, d );
	RemoteFile.RemoveEnclose( '"' );

	LocalFile = Token.Token[2];
	LocalFile.Replace( s, d );
	LocalFile.RemoveEnclose( '"' );

	// ダイアログを呼び出す
	DialogBox(
		hInstance,
		(LPCTSTR)IDD_HTTPDOWNLOAD,
		GetDesktopWindow(),
		(DLGPROC)DialogProc);

}


// *********************************************************
// ダウンロードスレッド
// *********************************************************
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{

	HINTERNET hSession;
	HINTERNET hConnect;
	HINTERNET hHttp;

	// セッション
	hSession = InternetOpen(
		"lightbox",
		INTERNET_OPEN_TYPE_DIRECT,
		NULL, NULL, 0
	);
	if ( hSession == NULL ) {
		return false;
	}

	// サーバー接続
	hConnect = InternetConnect(
		hSession,
		Server.szLboxString,
		INTERNET_INVALID_PORT_NUMBER,
		NULL,
		NULL,
		INTERNET_SERVICE_HTTP,
		0,
		NULL
	);
	if ( hConnect == NULL ) {
		InternetCloseHandle( hConnect );
		InternetCloseHandle( hSession );
		return false;
	}

	// HTTP リクエストの準備
	hHttp = HttpOpenRequest(
		hConnect,
		NULL,
		RemoteFile.szLboxString,
		"HTTP/1.1",
		NULL,
		NULL,
		INTERNET_FLAG_RELOAD | INTERNET_FLAG_KEEP_CONNECTION,
		0
	);
	if ( hHttp == NULL ) {
		return false;
	}

	// HTTP リクエスト
	if ( !( HttpSendRequest( hHttp, NULL, 0, NULL, 0 )) ) {
		InternetCloseHandle( hHttp );
		InternetCloseHandle( hConnect );
		InternetCloseHandle( hSession );
		return false;
	}

	// コンテンツの長さを取得
	DWORD dwByte;
	DWORD nLength;
	char buff[4096+16];

	nLength = 4096;
	dwByte = 0;
	HttpQueryInfo(
			hHttp,
			HTTP_QUERY_CONTENT_LENGTH,
			buff,
			&nLength,
			&dwByte
		);
	buff[nLength] = 0x00;

	// コンテンツの長さを表示し、プログレスバーを初期化
	Dlg->EditSetText( IDC_DOWNLOADSIZE, buff );
	content_length = atol( buff );
	Pbar.SetRange( 1, content_length );
	Pbar.SetStep( 1 );

	// 書き込み用のファイル
	FILE *fp;

	fp = fopen( LocalFile.szLboxString, "wb" );
	if ( fp == NULL ) {
		InternetCloseHandle( hHttp );
		InternetCloseHandle( hConnect );
		InternetCloseHandle( hSession );
		return false;
	}

	// 読み込みループ
	BOOL bLoop;
	
	bLoop = true;
	dwByte = 0;
	while( bLoop ) {
		bLoop = InternetReadFile(
			hHttp,
			buff,
			4096,
			&dwByte
		);
		if ( dwByte == 0 ) {
			break;
		}
		fwrite( buff, dwByte, 1, fp );
		nByte += dwByte;
		Pbar.SetPos( nByte );
	}

	// 終了
	fclose( fp );
	InternetCloseHandle( hHttp );
	InternetCloseHandle( hConnect );
	InternetCloseHandle( hSession );

	// ダイアログへ終了通知
	Dlg->PostMsg( THREAD_END, 0, 0 );
	return 0;

}

// *********************************************************
// メッセージ処理
// *********************************************************
LRESULT CALLBACK DialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
		case WM_INITDIALOG:
			// ダイアログオブジェクトのインスタンス化
			Dlg = new LboxDlg( hDlg );
			// スタイル変更
			Dlg->ChangeStyle( WS_SYSMENU, 0 );
			Dlg->ChangeExStyle( WS_EX_APPWINDOW, 0 );
			Dlg->ChangeIcon( 107 );
			Dlg->StatusCreate( 0 );
			Dlg->StatusSetText( "ダウンロードしています。しばらくお待ち下さい" );

			// URL を表示
			LString = "http://";
			LString += Server;
			LString += RemoteFile;
			Dlg->EditSetText( IDC_TARGET, LString );

			// ローカルパスを表示
			Dlg->EditSetText( IDC_FILEPATH, LocalFile );

			// プログレスバーの初期化
			Pbar.hWnd = GetDlgItem( hDlg, IDC_PROGRESS1 );

			// スレッド開始
			Thread.Create( hDlg, ThreadProc );

			return TRUE;

		case WM_COMMAND:
			if( LOWORD(wParam) == IDCANCEL ) 	{
				if ( Thread.hThread != NULL ) {
					Thread.Close();
				}
				EndDialog(hDlg, LOWORD(wParam));
				return TRUE;
			}
			break;

		case THREAD_END:
			Thread.Close();
			EndDialog(hDlg, IDOK);

			// エクスプローラ起動用文字列作成
			LString = "explorer.exe /e,";
			LString += LocalFile;
			LString.RemoveFileSpec();
			// 起動
			Tool.Execute( LString, NULL );
			break;

	}
	return FALSE;
}



Windows アプリケーションなので、このままでは非同期なので、
パッチ処理として用いるには、VBScript を使用して以下のようにして終了を待ちます

※ 但し、内部でエクスプローラを実行している処理は、ダウンロードが終わると即実行されます。

完全にバッチ化するには、コンソール版として移植すると良いです。

Set WshShell = CreateObject( "WScript.Shell" )
Call WshShell.Run( _
"http_download.exe lightbox.on.coocan.jp /download/WinOfSql102.lzh ""C:\TMP File\test.lzh""", _
, True )
MsgBox("OK")