山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他CopyFileExを使用した状況表示付きファイルコピー(32/64bit)
概要
CopyFileEx APIを使用し、1個のファイルをコピーします。コピー中にダイアログボックスを表示し残り時間、転送速度等の状況表示および中止、一時停止ができます。
コピー元のフォルダー名、コピー先のフォルダー名、ファイル名は、ソースコードの変数で定義しています。
本プログラムではD:\1.wmaをD:\temp\1.wmaにコピーします。D:\tempフォルダーはあらかじめ作成しておいてください。
テスト環境
コンパイラ
Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE実行環境
Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)Windows 7 Enterprise Service Pack 1 64bit
動作例
プログラムソースの概要
copyfileex2.cpp
_tWinMain
進行状況を表示するモードレスダイアログボックスを表示します。その後、CopyFileExを呼び出してコピーを開始します。コピー中のダイアログへのメッセージは、CopyFileExの引数で指定した、関数の中で処理しています。コピーが終了またはキャンセルされた場合は、CopyFileExから戻るので、ダイアログボックスへのメッセージを_tWinMain内のメッセージループで処理します。ダイアログボックスでPostQuitMessagが呼び出されるとメッセージループを抜けてプログラムを終了します。
DlgProc1
WM_INITDIALOGメッセージ
ダイアログボックスの初期化時に呼び出されます。コピー元フォルダー、コピー先フォルダー、ファイル名の表示、プログレスバーの範囲の設定を行います。
転送速度を計算するために、プロセッサ時間を取得しcpy->startに保存します。
WM_COMMANDメッセージ
IDC_CPY_CHG
CopyProgressRoutine関数から呼び出されます。引数lParamよりコピーしたバイト数及びファイルのサイズを取得します。現在のプロセッサ時間から開始時のプロセッサ時間を減じ、転送速度を計算します。
これらの情報をダイアログボックスに表示します。
IDOK
コピー終了後にOKボタンをクリックした場合に呼び出されます。ダイアログボックスを閉じ、PostQuitMessagを呼び出しプログラムを終了させます。
IDC_CPY_PAUSE_BUTTON
コピーを開始しているときは、ボタンに一時停止を表示しており、クリックすると呼び出されます。ボタンに再開を表示させ::pause_f=TRUEに設定します。コピーを中断しているときは、ボタンに再開を表示しており、クリックすると呼び出されます。ボタンに一時停止を表示させ::pause_f=FALSEに設定します。
IDCANCEL
キャンセルボタンをクリックすると呼び出されます。::cansel_f=TRUEに設定し、コピーをキャンセルさせます。
CopyProgressRoutine
CopyFileExから呼び出されます。コピーしたバイト数及びファイルのサイズを取得し、SendMessageによりDlgProc1関数にWM_COMMANDメッセージを発行しダイアログボックスに状況を表示させます。一時停止及びキャンセルボタンからのメッセージを有効にするためにメッセージループをサポートしています。
一時停止中でない場合は、PeekMessageによりメッセージの有無を確認し有効なメッセージがある場合は処理します。
一時停止中の場合は、再開ボタン及びキャンセルボタンのメッセージを処理するためにGetMessageによりメッセージが発生するまで待機します。メッセージが発生すればそれを処理します。一時停止中の場合は、一時停止が解除されない限りGetMessageからの処理を繰り返します。
。
ソースコード
copyfileex2.cpp
// ファイルコピーサンプル
// モードレスダイアログボックスにより状況表示を行う
// キャンセル及び一時停止機能付き
#include <windows.h>
#include <shlwapi.h>
#include <commctrl.h>
#include <time.h>
#include <stdio.h>
#include <tchar.h>
#include "resource.h"
#pragma comment(lib,"shlwapi.lib")
INT_PTR CALLBACK DlgProc1(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); // ダイアログボックスプロシージャー
DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData );
HWND hDlg=0;
BOOL cancel_f=FALSE; // キャンセルを選択するとTRUE
BOOL pause_f=FALSE; // 一時停止を選択するとTRUE
HINSTANCE hInst;
TCHAR* src=_TEXT("D:"); // コピー元フォルダー
TCHAR* dtc=_TEXT("D:\\temp"); // コピー先フォルダー
TCHAR* fname=_TEXT("1.wma"); // コピーするファイル名
struct CpyData{
LARGE_INTEGER TotalFileSize; // コピーされたバイト数
LARGE_INTEGER TotalBytesTransferred; // ファイルサイズ
TCHAR* src;
TCHAR* dtc;
TCHAR* fname;
clock_t start;
};
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInst, TCHAR* lpszCmdLine, int nCmdShow){
MSG msg;
CpyData cpy;
TCHAR srcname[MAX_PATH]; // コピー元ファイル名
TCHAR dtcname[MAX_PATH]; // コピー先ファイル名
::hInst=hInstance;
_stprintf_s(srcname,sizeof(srcname)/sizeof(TCHAR),_TEXT("%s\\%s"),src,fname);
_stprintf_s(dtcname,sizeof(dtcname)/sizeof(TCHAR),_TEXT("%s\\%s"),dtc,fname);
cpy.src=::src;
cpy.dtc=::dtc;
cpy.fname=::fname;
// コピーの進行状況を示すモードレスダイアログボックスを表示する
::hDlg=CreateDialogParam(::hInst,_TEXT("CPY_DLG"),0,DlgProc1,(LPARAM)&cpy);
CopyFileEx(srcname,dtcname,CopyProgressRoutine,&cpy,&cancel_f,0);
EnableWindow(GetDlgItem(hDlg,IDOK),TRUE);
EnableWindow(GetDlgItem(hDlg,IDCANCEL),FALSE);
EnableWindow(GetDlgItem(hDlg,IDC_CPY_PAUSE_BUTTON),FALSE);
// コピー終了後またはコピーがキャンセルされた後のダイアログボックスのメッセージループ
while(::hDlg){
while(GetMessage(&msg , 0 , 0 , 0 )){
if(IsDialogMessage(::hDlg , &msg)==0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return 0;
}
// CopyFileEx関数から呼び出される。進行状況が知らされる
DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData ){
MSG msg;
CpyData* cpy=(CpyData*)lpData;
cpy->TotalFileSize=TotalFileSize; // コピーしたバイト数
cpy->TotalBytesTransferred=TotalBytesTransferred; // ファイルのサイズ数
// CopyFileEx実行中のダイアログボックスのメッセージ処理
do{
if(::pause_f==FALSE){ // 一時停止中でないためメッセージがある場合のみ処理する
if(PeekMessage(&msg , ::hDlg , 0 , 0 , PM_REMOVE)){
if (::hDlg && IsDialogMessage(::hDlg , &msg)==0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}else{ // 一時停止中なのでメッセージが発生するまで待機して処理する
GetMessage(&msg , ::hDlg , 0 , 0 );
if (::hDlg && IsDialogMessage(::hDlg , &msg)==0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}while( ::pause_f==TRUE); // 一時停止中に再開ボタンを検出するためにメッセージが発生(::pause_f==FALSE)となるまでループする
if(::hDlg)
SendMessage(::hDlg,WM_COMMAND,IDC_CPY_CHG,(LPARAM)cpy); // 進行状況をダイアログボックスに送信する
// Sleep(1000); //デバック用に進行状況をゆっくり表示する場合に使用
return PROGRESS_CONTINUE;
}
// ダイアログボックスプロシージャー
INT_PTR CALLBACK DlgProc1(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
CpyData* cpy;
switch (msg) {
case WM_INITDIALOG:{
EnableWindow(GetDlgItem(hDlg,IDOK),FALSE);
cpy=(CpyData*)lParam;
SetWindowText(GetDlgItem(hDlg,IDC_CPY_SRCDIR_LABEL),cpy->src);
SetWindowText(GetDlgItem(hDlg,IDC_CPY_NAME_LABEL),cpy->fname);
SetWindowText(GetDlgItem(hDlg,IDC_CPY_DTCDIR_LABEL),cpy->dtc);
SendMessage(GetDlgItem(hDlg,IDC_CPY_PROGBAR), PBM_SETRANGE, (WPARAM)0, MAKELPARAM(0, 100));
cpy->start=clock();
return TRUE;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_CPY_CHG:{ // コピーの進行状況の表示
TCHAR buf[256];
cpy=(CpyData*)lParam;
clock_t end=clock();
double t=double(end - cpy->start)*1000.0/CLOCKS_PER_SEC;
double speed=double(cpy->TotalBytesTransferred.QuadPart)/(t/1000);
if(0<cpy->TotalBytesTransferred.QuadPart){ // コピーされたデーターがある場合
if(cpy->TotalBytesTransferred.QuadPart==cpy->TotalFileSize.QuadPart){
SetWindowText(GetDlgItem(::hDlg,IDC_CPY_TIME_LABEL),_TEXT("コピーが終了しました"));
EnableWindow(GetDlgItem(hDlg,IDOK),TRUE);
}else{
double t2;
t2=(cpy->TotalFileSize.QuadPart - cpy->TotalBytesTransferred.QuadPart)/speed;
_stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("約%.1f秒"),t2);
SetWindowText(GetDlgItem(::hDlg,IDC_CPY_TIME_LABEL),buf); // 残り時間
}
}else
SetWindowText(GetDlgItem(::hDlg,IDC_CPY_TIME_LABEL),_TEXT("コピーを開始しました"));
_stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%lluKB/%lluKB"),(cpy->TotalFileSize.QuadPart-cpy->TotalBytesTransferred.QuadPart)/1024 , cpy->TotalFileSize.QuadPart/1024);
SetWindowText(GetDlgItem(::hDlg,IDC_CPY_COUNT_LABEL),buf);
int pos=(int)(cpy->TotalBytesTransferred.QuadPart*100/cpy->TotalFileSize.QuadPart);
SendMessage(GetDlgItem(::hDlg,IDC_CPY_PROGBAR) , PBM_SETPOS , pos,0); // プログレスバー位置設定
_stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%.1fKB/秒"),speed/1024);
SetWindowText(GetDlgItem(::hDlg,IDC_CPY_SPEED_LABEL),buf); // 転送速度
return TRUE;
}
case IDOK:{ // ダイアログボックスを閉じる
::hDlg=0;
DestroyWindow(hDlg);
PostQuitMessage(0);
return TRUE;
}
case IDC_CPY_PAUSE_BUTTON:{ // 一時停止または再開が押された場合
if(::pause_f == FALSE){
::pause_f=TRUE;
SetWindowText(GetDlgItem(hDlg,IDC_CPY_PAUSE_BUTTON) , _TEXT("再開"));
}else{
::pause_f=FALSE;
SetWindowText(GetDlgItem(hDlg,IDC_CPY_PAUSE_BUTTON) , _TEXT("一時停止"));
}
return TRUE;
}
case IDCANCEL: // キャンセルが押された場合
::cancel_f=TRUE;
::pause_f=FALSE;
return FALSE;
default:
return FALSE;
}
default:
return FALSE;
}
return FALSE;
}
resoucr.h
#define IDC_CPY_SRCDIR_LABEL 100
#define IDC_CPY_NAME_LABEL 101
#define IDC_CPY_DTCDIR_LABEL 102
#define IDC_CPY_TIME_LABEL 103
#define IDC_CPY_COUNT_LABEL 104
#define IDC_CPY_SPEED_LABEL 105
#define IDC_CPY_PAUSE_BUTTON 107
#define IDC_CPY_PROGBAR 108
#define IDC_CPY_CHG 2010
resource.rc
#include <windows.h>
#include "resource.h"
//----------------------------------
// ダイアログ (IDD_)
//----------------------------------
CPY_DLG DIALOG DISCARDABLE 0, 0, 413, 160
STYLE WS_POPUP | WS_CAPTION | DS_SETFONT | WS_VISIBLE
CAPTION "コピー中"
FONT 9, "MS Pゴシック"
{
CONTROL "名前", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 14, 15, 192, 12
CONTROL "", IDC_CPY_NAME_LABEL, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 80, 15, 319, 12
CONTROL "元のフォルダー", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 14, 29, 192, 12
CONTROL "", IDC_CPY_SRCDIR_LABEL, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 80, 29, 319, 12
CONTROL "対象", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 14, 43, 192, 12
CONTROL "", IDC_CPY_DTCDIR_LABEL, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 80, 43, 319, 12
CONTROL "残りの時間", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 14, 57, 192, 12
CONTROL "", IDC_CPY_TIME_LABEL, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 80, 57, 319, 12
CONTROL "残りの項目", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 14, 71, 192, 12
CONTROL "", IDC_CPY_COUNT_LABEL, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 80, 71, 319, 12
CONTROL "スピード", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 14, 85, 192, 12
CONTROL "", IDC_CPY_SPEED_LABEL, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 80, 85, 319, 12
CONTROL "ProgressBar", IDC_CPY_PROGBAR, "MSCTLS_PROGRESS32", WS_CHILD | WS_VISIBLE | WS_BORDER, 14, 106, 385, 12
CONTROL "OK(&O)", IDOK, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 235, 132, 50, 14
CONTROL "一時停止(&P)", IDC_CPY_PAUSE_BUTTON, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 292, 132, 50, 14
CONTROL "キャンセル(&C)", IDCANCEL, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 349, 132, 50, 14
}
Copyright (C) 2012 山本ワールド All Rights Reserved.