MithrilWorks

[WinAPI] SHFileOperationの挙動がおかしい

 SHFileOperationを用いると、ファイルのコピー、移動、削除などができる。
Windows XP SP2までは問題なく動作したが、Windows XP SP3、Windows Vistaでは妙なエラーが出て操作ができなくなる。
function SHFileOperation(lpFileOp: TSHFileOpStruct): Integer;
引数 説明
lpFileOp TSHFileOpStruct(SHFILEOPSTRUCT)構造体。
 構造体メンバは以下のとおりである。
TSHFileOpStruct(TSHFileOpStructA)構造体
1
2
3
4
5
6
7
8
9
10
11
12
PSHFileOpStruct = PSHFileOpStructA;
TSHFileOpStructA = packed record
  Wnd: HWND;                  //親ウィンドウのハンドル
  wFunc: UINT;                //操作機能を示すフラグ
  pFrom: PAnsiChar;           //操作元ファイル名
  pTo: PAnsiChar;             //操作先ファイル名
  fFlags: FILEOP_FLAGS;       //以下に説明
  fAnyOperationsAborted: BOOL;
  hNameMappings: Pointer;
  lpszProgressTitle: PAnsiChar;
end;
TSHFileOpStruct = TSHFileOpStructA;
 wFuncには以下の定数が指定できる。
定数 説明
FO_MOVE ファイルの移動を行う。(=$0001)
FO_COPY ファイルのコピーを行う。(=$0002)
FO_DELETE ファイルの削除を行う。(=$0003)
FO_RENAME ファイルのリネームを行う。(=$0004)
 uFlagに指定できる代表的な定数は以下のとおり。
定数 説明
FOF_RENAMEONCOLLISION 衝突する場合はリネームする。(=$0008)
FOF_NOCONFIRMATION 表示されるダイアログに「はい」か「すべて」を選択。(=$0010)
FOF_ALLOWUNDO できる限りアンドゥを行う。
pFromには絶対パスを指定しなければならない。(=$0040)
FOF_FILESONLY ワイルドカード「*.*」をファイルのみに適用する。(=$0080)
FOF_NOCONFIRMMKDIR フォルダ作成時でも確認しない。(=$0200)
 ここで問題となるのは、pFromに複数ファイルを指定できる点である。
ファイルとファイルの区切り文字としてヌル文字を使用するため、指定するファイル名の最後にはヌル文字を2つつけなければならない。
(ファイル名1)#0(ファイル名2)#0...(ファイル名3)#0#0
 となる。
 当方の環境では、Windows XP SP2まではヌル文字が1文字でも問題なく動作した。SP3以降ではファイル名が文字化けし、操作に失敗した。
 Delphiでは、PChar(FileName)のようにキャストして使用するが、これではヌル文字が1文字しか入らないため、バグが起こってしまう。
以下のようにすることで、ヌル文字を付加するとよい。
サンプルコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var
  shfos: TSHFileOpStruct;
begin
  with shfos do
  begin
    wnd := Handle;
    wFunc := FO_COPY;
    pFrom := PChar(FileName + #0#0);
    pTo := PChar(Target + #0#0);
    fFlags := FOF_FILESONLY or FOF_ALLOWUNDO or FOF_NOCONFIRMATION;
    fAnyOperationsAborted := False;
    hNameMappings := nil;
    lpszProgressTitle := nil;
  end;
  SHFileOperation(shfos);
end;