SHFILEOPSTRUCT
结构体的定义如下:
typedef struct _SHFILEOPSTRUCT { // shfos
HWND hwnd; // 显示状态信息窗口的句柄,一般设为主窗体的句柄
UINT wFunc; // 要执行的操作
LPCSTR pFrom; // 源文件或目录
LPCSTR pTo; // 目标文件或目录
FILEOP_FLAGS fFlags; // 控制文件操作的标志
BOOL fAnyOperationsAborted; // 操作是否放弃
LPVOID hNameMappings; // 文件名映射对象的句柄,很少用
LPCSTR lpszProgressTitle; // 进度条标题,仅在 fFlags 标志中指定了 //FO
F_SIMPLEPROGRESS 时有效
} SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT;
typedef struct _SHFILEOPSTRUCT { // shfos
HWND hwnd; // 显示状态信息窗口的句柄,一般设为主窗体的句柄
UINT wFunc; // 要执行的操作
LPCSTR pFrom; // 源文件或目录
LPCSTR pTo; // 目标文件或目录
FILEOP_FLAGS fFlags; // 控制文件操作的标志
BOOL fAnyOperationsAborted; // 操作是否放弃
LPVOID hNameMappings; // 文件名映射对象的句柄,很少用
LPCSTR lpszProgressTitle; // 进度条标题,仅在 fFlags 标志中指定了 //FO
F_SIMPLEPROGRESS 时有效
} SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT;
Delphi
用记录
TSHFileOpStruct
对此结构做了两种封装:
ANSI
字符和宽字符版本。读者可
从 ShellAPI 单元的第 265 行看到如下代码:
_SHFILEOPSTRUCTA = packed record //ANSI 版本
Wnd: HWND;
wFunc: UINT;
pFrom: PAnsiChar;
pTo: PAnsiChar;
fFlags: FILEOP_FLAGS;
fAnyOperationsAborted: BOOL;
hNameMappings: Pointer;
lpszProgressTitle: PAnsiChar; { only used if FOF_SIMPLEPROGRESS }
end;
{$EXTERNALSYM _SHFILEOPSTRUCTW}
_SHFILEOPSTRUCTW = packed record // 宽字符版本
Wnd: HWND;
wFunc: UINT;
pFrom: PWideChar;
pTo: PWideChar;
fFlags: FILEOP_FLAGS;
fAnyOperationsAborted: BOOL;
hNameMappings: Pointer;
lpszProgressTitle: PWideChar; { only used if FOF_SIMPLEPROGRESS }
end;
{$EXTERNALSYM _SHFILEOPSTRUCT}
_SHFILEOPSTRUCT = _SHFILEOPSTRUCTA;
TSHFileOpStructA = _SHFILEOPSTRUCTA;
TSHFileOpStructW = _SHFILEOPSTRUCTW;
TSHFileOpStruct = TSHFileOpStructA;
// 默认情况下 TSHFileOpStruct 为 ANSI 版本
{$EXTERNALSYM SHFILEOPSTRUCTA}
SHFILEOPSTRUCTA = _SHFILEOPSTRUCTA;
{$EXTERNALSYM SHFILEOPSTRUCTW}
SHFILEOPSTRUCTW = _SHFILEOPSTRUCTW;
{$EXTERNALSYM SHFILEOPSTRUCT}
SHFILEOPSTRUCT = SHFILEOPSTRUCTA;
// 默认情况下 SHFILEOPSTRUCT 为 ANSI 版本
在 ShellAPI 单元的第 200 行对 wFunc 参数的取值定义了 4 种操作:
{$EXTERNALSYM FO_MOVE}
FO_MOVE = $0001; // 移动操作,从 pFrom 到 pTo
{$EXTERNALSYM FO_COPY}
FO_COPY = $0002; // 复制操作,从 pFrom 到 pTo
{$EXTERNALSYM FO_DELETE}
FO_DELETE = $0003; // 删除操作,删除 pFrom 中指定的目录或文件(忽略 //
pTo 参数)
{$EXTERNALSYM FO_RENAME}
FO_RENAME = $0004; // 重命名操作,重命名 pFrom 中指定的目录或文件。
在 ShellAPI 单元的第 210 行对 fFlags 参数定义了如下可能取值:
{$EXTERNALSYM FOF_MULTIDESTFILES}
FOF_MULTIDESTFILES = $0001; // 表明 pTo 参数是多个文件而不是一个 // 目
录
{$EXTERNALSYM FOF_CONFIRMMOUSE}
FOF_CONFIRMMOUSE = $0002; // 目前没有实现
{$EXTERNALSYM FOF_SILENT}
FOF_SILENT = $0004; // 不创建进度条 / 报告
{$EXTERNALSYM FOF_RENAMEONCOLLISION}
FOF_RENAMEONCOLLISION = $0008; // 当目标文件已存在时,将源文件改
// 名再复制或移动
{$EXTERNALSYM FOF_NOCONFIRMATION}
FOF_NOCONFIRMATION = $0010; // 操作过程中不显示确认信息,相当 // 于用
户选择了 “yes to all”
{$EXTERNALSYM FOF_WANTMAPPINGHANDLE}
FOF_WANTMAPPINGHANDLE = $0020; // 填充 hNameMappings 成员
{$EXTERNALSYM FOF_ALLOWUNDO}
FOF_ALLOWUNDO = $0040; // 允许撤销操作
{$EXTERNALSYM FOF_FILESONLY}
FOF_FILESONLY = $0080; // 只操作文件
{$EXTERNALSYM FOF_SIMPLEPROGRESS}
FOF_SIMPLEPROGRESS = $0100; // 显示进度条对话框但不显示文件名
{$EXTERNALSYM FOF_NOCONFIRMMKDIR}
FOF_NOCONFIRMMKDIR = $0200; // 新建目录时不提示确认
{$EXTERNALSYM FOF_NOERRORUI}
FOF_NOERRORUI = $0400; // 如果操作出错,不显示用户借口
设计步骤
新建一应用程序,按照图 3.1.1 所示加入 2 个 TStaticText 组件、 2 个 TEdit 组件和 5 个 TBut
ton 组件; TstaticText 和 TButton 组件的 Caption 属性设置为如图所示, TEdit 组件的 Tex
t 属性清空。
在 uses 中加入 FileCtrl,shellapi 两单元。 SelectDirectory 函数用到 FileCtrl 单元,而
SHFileOperation 函数及 TSHFileOpStruct 记录用到 shellapi 单元。
代码分析
在第一个 “…” 按钮的 OnClick 事件中加入如下代码,用于选择操作的源目录:
procedure TForm1.Button4Click(Sender: TObject);
var
Dir: string;
begin
Dir := 'D:';
if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then
// 函数执行成功
// sdAllowCreate :允许创建目录
// sdPerformCreate :执行创建目录
// sdPrompt :显示提示信息
edit1.text:= Dir;
end;
在第二个 “…” 按钮的 OnClick 事件中加入如下代码,用于选择操作的目标目录:
procedure TForm1.Button5Click(Sender: TObject);
var
Dir: string;
begin
Dir := 'D:';
if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then
// 解释同上
edit2.text:= Dir;
end;
在 “ 复制 ” 按钮的 OnClick 事件中加入如下代码,用于执行复制操作:
procedure TForm1.Button1Click(Sender: TObject);
var
OpStruc:TSHFileOpStruct;
FromBuf,ToBuf:Array[0..128] of Char;
begin
FillChar(FromBuf,Sizeof(FromBuf),0);
FillChar(ToBuf,Sizeof(ToBuf),0);
// 用 0 初始化 FromBuf 和 ToBuf 数组
StrPCopy(FromBuf,Pchar(Edit1.Text));
StrPCopy(ToBuf,Pchar(Edit2.Text));
// 分别在 FromBuf 和 ToBuf 数组中填入操作的源目录及目标目录
// 开始填充 OpStruc 记录
with OpStruc do
begin
Wnd:=Handle;
wFunc:=FO_COPY;
// 复制操作
pFrom:=@FromBuf;
pTo:=@ToBuf;
fFlags:=FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION;
fAnyOperationsAborted:=False;
hNameMappings:=nil;
lpszProgressTitle:=nil;
end;
if SHFileOperation(OpStruc)=0 then
// 函数执行成功
MessageBox(Handle,' 复制完毕。 ',' 复制信息 ',MB_OK+MB_ICONINFORMATION);
end;
在 “ 移动 ” 按钮的 OnClick 事件中加入如下代码,用于执行移动操作:
procedure TForm1.Button2Click(Sender: TObject);
var
OpStruc:TSHFileOpStruct;
FromBuf,ToBuf:Array[0..128] of Char;
begin
FillChar(FromBuf,Sizeof(FromBuf),0);
FillChar(ToBuf,Sizeof(ToBuf),0);
StrPCopy(FromBuf,Pchar(Edit1.Text));
StrPCopy(ToBuf,Pchar(Edit2.Text));
// 开始填充 OpStruc 记录
with OpStruc do
begin
Wnd:=Handle;
wFunc:=FO_MOVE;
// 移动操作
pFrom:=@FromBuf;
pTo:=@ToBuf;
fFlags:=FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION;
fAnyOperationsAborted:=False;
hNameMappings:=nil;
lpszProgressTitle:=' 正在文件 ';
end;
if SHFileOperation(OpStruc)=0 then
// 执行成功
MessageBox(Handle,' 移动完毕。 ',' 移动信息 ',MB_OK+MB_ICONINFORMATION);
end;
在 “ 删除 ” 按钮的 OnClick 事件中加入如下代码,用于执行删除操作:
procedure TForm1.Button3Click(Sender: TObject);
var
OpStruc:TSHFileOpStruct;
FromBuf:Array[0..128] of Char;
begin
FillChar(FromBuf,Sizeof(FromBuf),0);
StrPCopy(FromBuf,Pchar(Edit1.Text));
// 开始填充 OpStruc 记录
with OpStruc do
begin
Wnd:=Handle;
wFunc:=FO_DELETE;
pFrom:=@FromBuf;
pTo:=nil;
fFlags:=FOF_NOCONFIRMATION;
lpszProgressTitle:=' 正在删除 ';
end;
if SHFileOperation(OpStruc)=0 then
// 执行成功
MessageBox(Handle,' 删除完毕。 ',' 删除信息 ',MB_OK+MB_ICONINFORMATION);
end;
总结
注意:删除时( wFunc 参数设为 FO_DELETE )如果想将文件或目录放到回收站( fFlags 参
数设置为 FOF_ALLOWUNDO )则应该给出文件的绝对路径名,否则可能无法恢复。对于多个
文件的操作,文件名之间要以 #0) 字符分隔,整个字符串以两个 # 0 结束。
从 ShellAPI 单元的第 265 行看到如下代码:
_SHFILEOPSTRUCTA = packed record //ANSI 版本
Wnd: HWND;
wFunc: UINT;
pFrom: PAnsiChar;
pTo: PAnsiChar;
fFlags: FILEOP_FLAGS;
fAnyOperationsAborted: BOOL;
hNameMappings: Pointer;
lpszProgressTitle: PAnsiChar; { only used if FOF_SIMPLEPROGRESS }
end;
{$EXTERNALSYM _SHFILEOPSTRUCTW}
_SHFILEOPSTRUCTW = packed record // 宽字符版本
Wnd: HWND;
wFunc: UINT;
pFrom: PWideChar;
pTo: PWideChar;
fFlags: FILEOP_FLAGS;
fAnyOperationsAborted: BOOL;
hNameMappings: Pointer;
lpszProgressTitle: PWideChar; { only used if FOF_SIMPLEPROGRESS }
end;
{$EXTERNALSYM _SHFILEOPSTRUCT}
_SHFILEOPSTRUCT = _SHFILEOPSTRUCTA;
TSHFileOpStructA = _SHFILEOPSTRUCTA;
TSHFileOpStructW = _SHFILEOPSTRUCTW;
TSHFileOpStruct = TSHFileOpStructA;
// 默认情况下 TSHFileOpStruct 为 ANSI 版本
{$EXTERNALSYM SHFILEOPSTRUCTA}
SHFILEOPSTRUCTA = _SHFILEOPSTRUCTA;
{$EXTERNALSYM SHFILEOPSTRUCTW}
SHFILEOPSTRUCTW = _SHFILEOPSTRUCTW;
{$EXTERNALSYM SHFILEOPSTRUCT}
SHFILEOPSTRUCT = SHFILEOPSTRUCTA;
// 默认情况下 SHFILEOPSTRUCT 为 ANSI 版本
在 ShellAPI 单元的第 200 行对 wFunc 参数的取值定义了 4 种操作:
{$EXTERNALSYM FO_MOVE}
FO_MOVE = $0001; // 移动操作,从 pFrom 到 pTo
{$EXTERNALSYM FO_COPY}
FO_COPY = $0002; // 复制操作,从 pFrom 到 pTo
{$EXTERNALSYM FO_DELETE}
FO_DELETE = $0003; // 删除操作,删除 pFrom 中指定的目录或文件(忽略 //
pTo 参数)
{$EXTERNALSYM FO_RENAME}
FO_RENAME = $0004; // 重命名操作,重命名 pFrom 中指定的目录或文件。
在 ShellAPI 单元的第 210 行对 fFlags 参数定义了如下可能取值:
{$EXTERNALSYM FOF_MULTIDESTFILES}
FOF_MULTIDESTFILES = $0001; // 表明 pTo 参数是多个文件而不是一个 // 目
录
{$EXTERNALSYM FOF_CONFIRMMOUSE}
FOF_CONFIRMMOUSE = $0002; // 目前没有实现
{$EXTERNALSYM FOF_SILENT}
FOF_SILENT = $0004; // 不创建进度条 / 报告
{$EXTERNALSYM FOF_RENAMEONCOLLISION}
FOF_RENAMEONCOLLISION = $0008; // 当目标文件已存在时,将源文件改
// 名再复制或移动
{$EXTERNALSYM FOF_NOCONFIRMATION}
FOF_NOCONFIRMATION = $0010; // 操作过程中不显示确认信息,相当 // 于用
户选择了 “yes to all”
{$EXTERNALSYM FOF_WANTMAPPINGHANDLE}
FOF_WANTMAPPINGHANDLE = $0020; // 填充 hNameMappings 成员
{$EXTERNALSYM FOF_ALLOWUNDO}
FOF_ALLOWUNDO = $0040; // 允许撤销操作
{$EXTERNALSYM FOF_FILESONLY}
FOF_FILESONLY = $0080; // 只操作文件
{$EXTERNALSYM FOF_SIMPLEPROGRESS}
FOF_SIMPLEPROGRESS = $0100; // 显示进度条对话框但不显示文件名
{$EXTERNALSYM FOF_NOCONFIRMMKDIR}
FOF_NOCONFIRMMKDIR = $0200; // 新建目录时不提示确认
{$EXTERNALSYM FOF_NOERRORUI}
FOF_NOERRORUI = $0400; // 如果操作出错,不显示用户借口
设计步骤
新建一应用程序,按照图 3.1.1 所示加入 2 个 TStaticText 组件、 2 个 TEdit 组件和 5 个 TBut
ton 组件; TstaticText 和 TButton 组件的 Caption 属性设置为如图所示, TEdit 组件的 Tex
t 属性清空。
在 uses 中加入 FileCtrl,shellapi 两单元。 SelectDirectory 函数用到 FileCtrl 单元,而
SHFileOperation 函数及 TSHFileOpStruct 记录用到 shellapi 单元。
代码分析
在第一个 “…” 按钮的 OnClick 事件中加入如下代码,用于选择操作的源目录:
procedure TForm1.Button4Click(Sender: TObject);
var
Dir: string;
begin
Dir := 'D:';
if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then
// 函数执行成功
// sdAllowCreate :允许创建目录
// sdPerformCreate :执行创建目录
// sdPrompt :显示提示信息
edit1.text:= Dir;
end;
在第二个 “…” 按钮的 OnClick 事件中加入如下代码,用于选择操作的目标目录:
procedure TForm1.Button5Click(Sender: TObject);
var
Dir: string;
begin
Dir := 'D:';
if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then
// 解释同上
edit2.text:= Dir;
end;
在 “ 复制 ” 按钮的 OnClick 事件中加入如下代码,用于执行复制操作:
procedure TForm1.Button1Click(Sender: TObject);
var
OpStruc:TSHFileOpStruct;
FromBuf,ToBuf:Array[0..128] of Char;
begin
FillChar(FromBuf,Sizeof(FromBuf),0);
FillChar(ToBuf,Sizeof(ToBuf),0);
// 用 0 初始化 FromBuf 和 ToBuf 数组
StrPCopy(FromBuf,Pchar(Edit1.Text));
StrPCopy(ToBuf,Pchar(Edit2.Text));
// 分别在 FromBuf 和 ToBuf 数组中填入操作的源目录及目标目录
// 开始填充 OpStruc 记录
with OpStruc do
begin
Wnd:=Handle;
wFunc:=FO_COPY;
// 复制操作
pFrom:=@FromBuf;
pTo:=@ToBuf;
fFlags:=FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION;
fAnyOperationsAborted:=False;
hNameMappings:=nil;
lpszProgressTitle:=nil;
end;
if SHFileOperation(OpStruc)=0 then
// 函数执行成功
MessageBox(Handle,' 复制完毕。 ',' 复制信息 ',MB_OK+MB_ICONINFORMATION);
end;
在 “ 移动 ” 按钮的 OnClick 事件中加入如下代码,用于执行移动操作:
procedure TForm1.Button2Click(Sender: TObject);
var
OpStruc:TSHFileOpStruct;
FromBuf,ToBuf:Array[0..128] of Char;
begin
FillChar(FromBuf,Sizeof(FromBuf),0);
FillChar(ToBuf,Sizeof(ToBuf),0);
StrPCopy(FromBuf,Pchar(Edit1.Text));
StrPCopy(ToBuf,Pchar(Edit2.Text));
// 开始填充 OpStruc 记录
with OpStruc do
begin
Wnd:=Handle;
wFunc:=FO_MOVE;
// 移动操作
pFrom:=@FromBuf;
pTo:=@ToBuf;
fFlags:=FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION;
fAnyOperationsAborted:=False;
hNameMappings:=nil;
lpszProgressTitle:=' 正在文件 ';
end;
if SHFileOperation(OpStruc)=0 then
// 执行成功
MessageBox(Handle,' 移动完毕。 ',' 移动信息 ',MB_OK+MB_ICONINFORMATION);
end;
在 “ 删除 ” 按钮的 OnClick 事件中加入如下代码,用于执行删除操作:
procedure TForm1.Button3Click(Sender: TObject);
var
OpStruc:TSHFileOpStruct;
FromBuf:Array[0..128] of Char;
begin
FillChar(FromBuf,Sizeof(FromBuf),0);
StrPCopy(FromBuf,Pchar(Edit1.Text));
// 开始填充 OpStruc 记录
with OpStruc do
begin
Wnd:=Handle;
wFunc:=FO_DELETE;
pFrom:=@FromBuf;
pTo:=nil;
fFlags:=FOF_NOCONFIRMATION;
lpszProgressTitle:=' 正在删除 ';
end;
if SHFileOperation(OpStruc)=0 then
// 执行成功
MessageBox(Handle,' 删除完毕。 ',' 删除信息 ',MB_OK+MB_ICONINFORMATION);
end;
总结
注意:删除时( wFunc 参数设为 FO_DELETE )如果想将文件或目录放到回收站( fFlags 参
数设置为 FOF_ALLOWUNDO )则应该给出文件的绝对路径名,否则可能无法恢复。对于多个
文件的操作,文件名之间要以 #0) 字符分隔,整个字符串以两个 # 0 结束。