Skip to content

Instantly share code, notes, and snippets.

@seraphy
Last active April 26, 2018 02:00
Show Gist options
  • Save seraphy/8ce9084fa2074bb9fbca4be2f1de364f to your computer and use it in GitHub Desktop.
Save seraphy/8ce9084fa2074bb9fbca4be2f1de364f to your computer and use it in GitHub Desktop.
InnoSetupで、SHFileOperationを使った複数フォルダ/ファイルのコピーの例。 https://stackoverflow.com/questions/45244210/inno-setup-invoke-or-replicate-native-windows-file-copy-operation
; SHFileOperationまわりの定義を外部ファイルに分離している
#include "SHFileOperationModule.iss"
[Setup]
AppId=SHFileOperationExample
AppName=SHFileOperationExample
AppVersion=1.0.0
VersionInfoVersion=1.0.0
VersionInfoDescription={#SetupSetting("AppName")} Installer
OutputBaseFilename={#SetupSetting("AppName")}_{#SetupSetting("AppVersion")}
DefaultDirName={sd}\{#SetupSetting("AppName")}
DefaultGroupName=InnoSetupScriptExample
OutputDir=.
; 以前のインストールがある場合に以前のAppDirを使うか?
UsePreviousAppDir=No
SetupLogging=yes
[Files]
[Code]
procedure StartInstall();
var
FromPath: array of string;
ToPath: string;
begin
FromPath := [
ExpandConstant('{src}\data1.dat'),
ExpandConstant('{src}\data2.dat')
];
ToPath := ExpandConstant('{app}\data\');
ShellFileOperation(FromPath, ToPath, FILEOPE_COPY);
end;
{ インストールステップごとに呼び出される }
procedure CurStepChanged(CurStep: TSetupStep);
begin
case CurStep of
ssInstall: StartInstall();
end;
end;
#ifndef _INCLUDE_SHFILEOPERAIONMODULE_
#define _INCLUDE_SHFILEOPERAIONMODULE_
[CustomMessages]
FailedToShellFileOperation=Failed to %1 folder.%nerr=%2
CancelToShellFileOperation=the %1 operation was cancelled by user.
[Code]
#IFDEF UNICODE
#DEFINE AW "W"
#ELSE
#DEFINE AW "A"
#ENDIF
// SHFileOperationを使ったファイルコピーの例
// https://stackoverflow.com/questions/45244210/inno-setup-invoke-or-replicate-native-windows-file-copy-operation
type
TSHFileOpStruct = record
hwnd: HWND;
wFunc: UINT;
pFrom: string;
pTo: string;
fFlags: Word;
fAnyOperationsAborted: BOOL;
hNameMappings: HWND;
lpszProgressTitle: string;
end;
FILEOPE_TYP = (FILEOPE_COPY, FILEOPE_MOVE);
const
FO_MOVE = $0001;
FO_COPY = $0002;
FOF_NOCONFIRMATION = $0010; // 確認等不要
FOF_NOCONFIRMMKDIR = $0200; // コピー先フォルダがない場合は暗黙でフォルダを作成する
ERR_CANCELED = 1223; // キャンセルした場合
function SHFileOperation(lpFileOp: TSHFileOpStruct): Integer;
external 'SHFileOperation{#AW}@shell32.dll stdcall';
function RetryOrRaise(msg: String): Boolean; forward;
procedure ShellFileOperation(srcs: array of string; dest: string; mode: FILEOPE_TYP);
var
FromPath: String;
ToPath: String;
idx: Integer;
FileOp: TSHFileOpStruct;
Msg: String;
strMode: String;
ret: Boolean;
retCode: Integer;
begin
case mode of
FILEOPE_COPY: begin
strMode := 'Copy';
FileOp.wFunc := FO_COPY;
end;
FILEOPE_MOVE: begin
strMode := 'Move';
FileOp.wFunc := FO_MOVE;
end;
else RaiseException('Unknown mode: ' + IntToStr(Ord(mode)));
end;
FileOp.hwnd := WizardForm.Handle;
FileOp.fFlags := FOF_NOCONFIRMATION + FOF_NOCONFIRMMKDIR;
repeat
// コピー元がフォルダまたはファイルとして実在する場合のみ
FromPath := '';
for idx := 0 to GetArrayLength(srcs) -1 do begin
if DirExists(srcs[idx]) or FileExists(srcs[idx]) then begin
FromPath := FromPath + srcs[idx] + #0; // ヌル区切り、ダブルヌル終端
end;
end;
// FromPathを表示用にセミコロン区切り文字列に変換する
Msg := FromPath;
StringChangeEx(Msg, #0, ';', True);
//MsgBox(Msg, mbInformation, MB_OK);
if FromPath = '' then begin
exit; // コピー・移動する内容が何もないので常に成功
end;
ToPath := dest + #0; // ダブルヌル終端
FileOp.pFrom := FromPath;
FileOp.pTo := ToPath;
retCode := SHFileOperation(FileOp);
ret := (retCode = 0);
if not ret then begin
if retCode = ERR_CANCELED then begin // キャンセルした場合
ret := RetryOrRaise(ExpandConstant('{cm:CancelToShellFileOperation,' +
strMode + '}') +#13 #10 + 'src=' + Msg + #13 #10 + 'dest=' + dest);
end else begin // そのほかのエラー
ret := RetryOrRaise(ExpandConstant('{cm:FailedToShellFileOperation,' +
strMode + ',' + IntToStr(retCode) + '}') +#13 #10 +
'src=' + Msg + #13 #10 + 'dest=' + dest);
end;
end;
until ret;
end;
///////////////////////////////////////////////////
// リトライ・無視・Abortのダイアログを表示し
// リトライの場合はFalse、無視の場合はTrueを返す.
// Abortの場合は例外をあげる.
function RetryOrRaise(msg: String): Boolean;
begin
Result := False;
// リトライ・無視・アボートのいずれかの選択ダイアログ
// (無人インストール時はABORT応答扱いとする.)
case SuppressibleMsgBox(msg, mbError, MB_ABORTRETRYIGNORE or MB_DEFBUTTON2, IDABORT) of
IDIGNORE: begin
// 成功してものと見なして次に進む
Result := True;
exit;
end;
IDABORT: begin
// 例外で終了する
RaiseException('Installation abort by user: ' + msg);
end;
end;
end;
[/Code]
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment