【AutoIt】進捗表示と上書き確認機能を備えたファイルコピーツール

Autoit で大きなファイルをコピーする際、「進捗が分からず不安」「間違って上書きしてしまいそうで怖い」と感じたことはありませんか?

この記事では、その両方の問題を解決する、実用的なファイルコピーツールを紹介します。

Windows API を利用した圧倒的な速度と、プログレスバーによる進捗表示、そして安全な上書き確認機能を備えた、決定版とも言えるスクリプトです。

※ヘルプファイルのサンプルコードを元に作成しています。

目次

完成したスクリプトの全コード

#include <APIFilesConstants.au3>
#include <Misc.au3>
#include <WinAPIError.au3>
#include <WinAPIFiles.au3>
#include <MsgBoxConstants.au3>

; ### メイン処理 ###

Local $hProgressProc = DllCallbackRegister('_ProgressProc', 'int', 'int64;int64;int64;int64;dword;dword;handle;handle;ptr')

Local $sSourceFile = FileOpenDialog("コピー元のファイルを選択してください", @MyDocumentsDir, "すべてのファイル (*.*)")
If @error Then
    DllCallbackFree($hProgressProc)
    Exit
EndIf

Local $sSourceName = StringMid($sSourceFile, StringInStr($sSourceFile, "\", 0, -1) + 1)
Local $sDestFile = FileSaveDialog("コピー先のファイルパスと名前を指定してください", @MyDocumentsDir, "すべてのファイル (*.*)", 0, $sSourceName)
If @error Then
    DllCallbackFree($hProgressProc)
    Exit
EndIf

; ### 上書き確認処理 ###
If FileExists($sDestFile) Then
    Local $iResponse = MsgBox($MB_YESNO + $MB_ICONQUESTION, "上書き確認", "同じ名前のファイルが既に存在します。" & @CRLF & "上書きしますか?")
    If $iResponse = $IDNO Then
        DllCallbackFree($hProgressProc)
        Exit
    EndIf
EndIf

ProgressOn('ファイルコピー', 'ファイルをコピーしています...', '0%')
If Not _WinAPI_CopyFileEx($sSourceFile, $sDestFile, $COPY_FILE_RESTARTABLE, DllCallbackGetPtr($hProgressProc)) Then
    _WinAPI_ShowLastError('ファイルのコピー中にエラーが発生しました: ' & $sSourceFile)
EndIf

ProgressOff()
DllCallbackFree($hProgressProc)
MsgBox(0, "完了", "処理が完了しました。")


; ### コピーの進捗報告を受け取るコールバック関数 ###
Func _ProgressProc($iTotalFileSize, $iTotalBytesTransferred, $iStreamSize, $iStreamBytesTransferred, $iStreamNumber, $iCallbackReason, $hSourceFile, $hDestinationFile, $pData)
    #forceref $iStreamSize, $iStreamBytesTransferred, $iStreamNumber, $iCallbackReason, $hSourceFile, $hDestinationFile, $pData

    Local $iPercent = Round($iTotalBytesTransferred / $iTotalFileSize * 100)

    If $iPercent = 100 Then
        ProgressSet($iPercent, '', '完了')
    Else
        ProgressSet($iPercent, $iPercent & '%')
    EndIf

    If _IsPressed('1B') Then
        Return $PROGRESS_CANCEL
    Else
        Return $PROGRESS_CONTINUE
    EndIf
EndFunc   ;==>_ProgressProc

コードの詳しい解説

ファイルの選択

このスクリプトは、実行するとまずユーザーにファイルの選択を促します。

  • コピー元の選択: FileOpenDialogを使い、コピーしたいファイルをユーザーに選択させます。
  • コピー先の選択: FileSaveDialogを使い、コピー先の場所とファイル名を決定させます。ここでは、StringMid関数などを使ってコピー元のファイル名をあらかじめ入力欄にセットしておくことで、ユーザーの利便性を高めています。

上書きの確認処理

ここが、安全性を高めるための重要な部分です。

  1. 存在チェック: FileExists関数を使い、ユーザーが指定したコピー先のパスに、既にファイルが存在するかどうかを確認します。
  2. 確認ダイアログ: もしファイルが存在した場合、MsgBox関数を使って「上書きしますか?」と尋ねる「はい/いいえ」のダイアログボックスを表示します。
  3. 処理の分岐:
    • ユーザーが「いいえ」 ($IDNO) をクリックした場合、Exitでスクリプトはコピー処理を行わずに安全に終了します。
    • ユーザーが「はい」 ($IDYES) をクリックした場合、このIfブロックを抜け、後続のコピー処理が実行されます。

Windows API によるコピー実行

ユーザーが上書きを許可した場合、あるいはコピー先にファイルが存在しなかった場合に、この処理が実行されます。

  • _WinAPI_CopyFileEx: これは、Windows OS に「このファイルをコピーしてください」と作業を依頼するための関数です。実際のデータ移動は、最も効率的な方法で OS が実行します。
  • コールバック: DllCallbackRegisterで登録した_ProgressProc関数を、OS がコピー中に呼び出して進捗を報告してくれます。これにより、OS ネイティブの速度と、進捗表示を両立しています。
  • 進捗表示: ProgressOnで表示したウィンドウの中身を、コールバック関数の中でProgressSetを使って更新しています。
  • 中止機能: コールバック関数の中で_IsPressed('1B')をチェックすることで、ユーザーが Esc キーを押したらコピーを中断する機能も実装しています。

コールバック関数の詳しい解説

コールバックとは何か

コールバックとは、直訳すると「後で呼び返す」という意味です。プログラミングにおいては、「ある処理(A)が終わった後や、その途中で、指定した別の処理(B)を自動的に実行してもらう」という仕組みを指します。

今回のスクリプトに例えると、

  • 処理A: _WinAPI_CopyFileExによる、OS が行うファイルコピー作業
  • 処理B: _ProgressProcという進捗報告(プログレスバー更新)

つまり、「OS にファイルコピーをお願いする際に、『作業の途中で、定期的に_ProgressProc関数を呼び出して進捗を報告してください』と、連絡先を渡しておく」というのがコールバックの考え方です。

なぜコールバックが必要か

_WinAPI_CopyFileExは、一度実行するとコピーが完了するまで制御が戻ってきません。

もしコールバックがなければ、私たちはコピーが終わるまで何もできず、進捗を知る術がありません。

コールバックがあることで、重い処理を OS に任せつつ、その途中経過をリアルタイムで受け取ることが可能になります。

実際のコードでの流れ

1. 「連絡先」の作成

Local $hProgressProc = DllCallbackRegister('_ProgressProc', 'int', 'int64;int64;...')

DllCallbackRegisterは、AutoIt で作成した_ProgressProc関数を、Windows API(C言語の世界)が理解できる形式の「連絡先」に変換し、登録する作業です。

戻り値として、その連絡先のハンドル(識別番号)が$hProgressProcに格納されます。

2. 「連絡先」を渡して作業を依頼

_WinAPI_CopyFileEx(..., DllCallbackGetPtr($hProgressProc))

_WinAPI_CopyFileExを呼び出す際、DllCallbackGetPtrで連絡先のアドレスを取得し、引数として渡します。

これにより、OS は「コピー作業中に、このアドレスにある関数を呼び出せばいいのだな」と認識します。

3. OS からの「呼び返し」と情報提供

Func _ProgressProc($iTotalFileSize, $iTotalBytesTransferred, ...)

コピー作業が始まると、OS は内部でデータの一部をコピーするたびに、登録された_ProgressProc関数を呼び出します。

その際、引数として$iTotalFileSize(全体のファイルサイズ)や$iTotalBytesTransferred(今までにコピーした量)といった、非常に詳細なライブ情報を渡してくれます。

スクリプトは、この渡された情報を使ってパーセンテージを計算し、ProgressSetでプログレスバーを更新しているのです。

このコールバックという仕組みこそが、OS の高速な処理能力と、AutoIt の柔軟な GUI機能を両立させる鍵となっています。

【AutoIt】#forceref と #AutoIt3Wrapper_AU3Check_Parameters について

  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次