Win32API 進捗を確認しながらファイルのコピーを行う CopyFileEx, CopyProgressRoutine

進捗を確認しながらファイルのコピーを行うには、CopyFileEx()関数とCopyFileEx()関数の中から呼ばれるコールバック関数を用いる。

CopyFileExは以下のようなプロトタイプになっている。

BOOL CopyFileEx(
  LPCWSTR lpExistingFileName, // 既存ファイルの名前
  LPCWSTR lpNewFileName,      // 新規ファイルの名前
  LPPROGRESS_ROUTINE lpProgressRoutine, // コールバック関数
  LPVOID lpData,    // コールバック関数に渡す
  LPBOOL pbCancel,  // 操作の取り消しに使う
  DWORD dwCopyFlags // ファイルのコピー方法を指定する
);



さらに、LPPROGRESS_ROUTINE型は以下のように定義されている。この関数が、ファイルのコピー中に呼ばれることでファイルコピーの進捗を確認することができる。

DWORD CALLBACK CopyProgressRoutine(
  LARGE_INTEGER TotalFileSize,  // バイト単位の総ファイルサイズ
  LARGE_INTEGER TotalBytesTransferred,
 // 転送された総バイト数
  LARGE_INTEGER StreamSize,  // このストリームの総バイト数
  LARGE_INTEGER StreamBytesTransferred,
 // このストリームに対して転送された
                            // 総バイト数
  DWORD dwStreamNumber,     // 現在のストリーム
  DWORD dwCallbackReason,   // CopyProgressRoutine 関数が呼び出された理由
  HANDLE hSourceFile,       // コピー元ファイルのハンドル
  HANDLE hDestinationFile,  // コピー先ファイルのハンドル
  LPVOID lpData             // CopyFileEx 関数から渡される
);



CopyFileExのサンプルコードは以下の通り。

#include <windows.h>
#include <stdio.h>

//CopyFileExで使われるコールバック関数
DWORD CALLBACK CopyProgressRoutine(
		LARGE_INTEGER TotalFileSize,// バイト単位の総ファイルサイズ
		LARGE_INTEGER TotalBytesTransferred,// 転送された総バイト数
		LARGE_INTEGER StreamSize,// このストリームの総バイト数
		LARGE_INTEGER StreamBytesTransferred,// このストリームに対して転送された総バイト数
		DWORD dwStreamNumber,// 現在のストリーム
		DWORD dwCallbackReason,// CopyProgressRoutine 関数が呼び出された理由
		HANDLE hSourceFile, // コピー元ファイルのハンドル
		HANDLE hDestinationFile, // コピー先ファイルのハンドル
		LPVOID lpData)// CopyFileEx 関数から渡される
{
	puts("--------------------------------------------------");
	printf("TotalFileSize = %u[B]\n", TotalFileSize.LowPart);
	printf("TotalBytesTransferred = %u[B]\n", TotalBytesTransferred.LowPart);
	printf("StreamSize = %u[B]\n", StreamSize.LowPart);
	printf("StreamBytesTransferred = %u[B]\n", StreamBytesTransferred.LowPart);
	printf("dwStreamNumber = %u\n", dwStreamNumber);

	if (dwCallbackReason == CALLBACK_CHUNK_FINISHED) {
		printf("dwCallbackReason = CALLBACK_CHUNK_FINISHED\n");
	} else if (dwCallbackReason == CALLBACK_STREAM_SWITCH) {
		printf("dwCallbackReason = CALLBACK_STREAM_SWITCH\n");
	}

	putchar('\n');

	return 0;
}

int main(int argc, _TCHAR* argv[])
{
	BOOL bCancel = FALSE;
	CopyFileEx(
	  "src.txt",		// 既存ファイルの名前
	  "dst.txt",		// 新規ファイルの名前
	  CopyProgressRoutine,	// コールバック関数
	  NULL,			// コールバック関数に渡す
	  &bCancel,		// 操作の取り消しに使う(キャンセルする際は、bCancelをTRUEにする)
	  COPY_FILE_RESTARTABLE);// ファイルのコピー方法を指定する

	puts("Finished");

	return 0;
}



約2MBのファイルをコピーした実行結果は以下のようになった。

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 0[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 0[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_STREAM_SWITCH

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 262144[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 262144[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 524288[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 524288[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 786432[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 786432[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 1048576[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 1048576[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 1310720[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 1310720[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 1572864[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 1572864[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 1835008[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 1835008[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

--------------------------------------------------
TotalFileSize = 2003328[B]
TotalBytesTransferred = 2003328[B]
StreamSize = 2003328[B]
StreamBytesTransferred = 2003328[B]
dwStreamNumber = 1
dwCallbackReason = CALLBACK_CHUNK_FINISHED

Finished


参考
http://msdn.microsoft.com/ja-jp/library/cc429187.aspx
http://msdn.microsoft.com/ja-jp/library/cc429191.aspx