TotalCommander的wfx插件Demo
TotalCommander作者为wfx插件开发写的Demo是用C++语言写的,帮助文件是英文的,为了方便以后用Delphi开发插件,就翻译为Delphi版的,开发过程用中文记录下载,希望也能帮助其他人。 (“TotalCommander”以下简称“TC”,“wfx插件”以下简称“插件”)
第一节 TC作者对插件的介绍
1、开发一个最小的只读类型的wfx插件必须要实现以下function:
function FsInit(PluginNr: integer; pProgressProc: tProgressProc; pLogProc: tLogProc; pRequestProc: tRequestProc): integer; stdcall; 初始化插件,得到回调函数。
function FsFindFirst(path: pchar; var FindData: tWIN32FINDDATA): thandle; stdcall; 返回文件夹中的第一个文件。
function FsFindNext(Hdl: thandle; var FindData: tWIN32FINDDATA): bool; stdcall; 返回文件夹中的下一个文件。
function FsFindClose(Hdl: thandle): integer; stdcall; 关闭搜索句柄。(工作方式有点像在查找文件。)
2、更多的功能需要完成下面的function: 注意:下面的function是可选的,如果没有实现就不要声明,也不要声明一个空函数。TC会载入声明的函数并调用这些函数。
procedure FsGetDefRootName(DefRootName: pchar; maxlen: integer); stdcall; 在网上邻居上显示这个函数返回的名称。如果不声明这个函数,TC会显示插件的不带后缀文件名。
function FsGetFile(RemoteName, LocalName: pchar; CopyFlags: integer; RemoteInfo: pRemoteInfo): integer; stdcall; 从插件中下载一个文件。
function FsPutFile(LocalName, RemoteName: pchar; CopyFlags: integer): integer; stdcall; 上传一个文件到插件中。
function FsRenMovFile(OldName, NewName: pchar; Move, OverWrite: bool; RemoteInfo: pRemoteInfo): integer; stdcall; 在插件中复制、重命名或移动一个文件。
function FsDeleteFile(RemoteName: pchar): bool; stdcall; 在插件中删除一个文件。
function FsRemoveDir(RemoteName: pchar): bool; stdcall; 在插件中删除一个文件夹。
function FsMkDir(RemoteDir: pchar): bool; stdcall; 在插件中创建一个文件夹。
function FsExecuteFile(MainWin: thandle; RemoteName, Verb: pchar): integer; stdcall; 在插件中执行一个命令、打开一个文件或显示属性。
function FsSetAttr(RemoteName: pchar; NewAttr: integer): bool; stdcall; 在插件中修改一个文件或文件夹属性。
function FsSetTime(RemoteName: pchar; CreationTime, LastAccessTime, LastWriteTime: PFileTime): bool; stdcall; 在插件中修改文件时间。
function FsDisconnect(DisconnectRoot: pchar): bool; stdcall; 用户按下断开按钮触发此函数。
function FsExtracTCustomIcon(RemoteName: pchar; ExtractFlags: integer; var TheIcon: hicon): integer; stdcall; 返回图标显示在文件列表中。
procedure FsStatusInfo(RemoteDir: pchar; InfoStartEnd, InfoOperation: integer); stdcall; 通知TC插件的工作状态。
function FsGetPreviewBitmap(RemoteName: pchar; width, height: integer; var ReturnedBitmap: hbitmap): integer; stdcall; 返回一个bitmap显示在thumbnail view。
function FsLinksToLocalFiles: bool; stdcall; 创建一个a temp panel plugin。
function FsGetLocalName(RemoteName: pchar; maxlen: integer): bool; stdcall; 见FsLinksToLocalFiles。
FsContent*(一个系列) procedure FsContentGetDetectString(DetectString: pchar; maxlen: integer); stdcall; function FsContentGetSupportedField(FieldIndex: integer; FieldName: pchar; Units: pchar; maxlen: integer): integer; stdcall; function FsContentGetValue(FileName: pchar; FieldIndex, UnitIndex: integer; FieldValue: pbyte; maxlen, flags: integer): integer; stdcall; function FsContentGetValueW(FileName: pwidechar; FieldIndex, UnitIndex: integer; FieldValue: pbyte; maxlen, flags: integer): integer; stdcall; procedure FsContentSetDefaultParams(dps: pContentDefaultParamStruct); stdcall; procedure FsContentStopGetValue(FileName: pchar); stdcall; procedure FsContentStopGetValueW(FileName: pwidechar); stdcall; function FsContentGetDefaultSortOrder(FieldIndex: integer): integer; stdcall; function FsContentGetSupportedFieldFlags(FieldIndex: integer): integer; stdcall; function FsContentSetValue(FileName: pchar; FieldIndex, UnitIndex, FieldType: integer; FieldValue: pbyte; flags: integer): integer; stdcall; function FsContentSetValueW(FileName: pwidechar; FieldIndex, UnitIndex, FieldType: integer; FieldValue: pbyte; flags: integer): integer; stdcall; function FsContentGetDefaultView(ViewContents, ViewHeaders, ViewWidths, ViewOptions: pchar; maxlen: integer): bool; stdcall; function FsContentGetDefaultViewW(ViewContents, ViewHeaders, ViewWidths, ViewOptions: pwidechar; maxlen: integer): bool; stdcall; 内容插件接口。(可能用于ctrl+q功能)
function FsGetBackgroundFlags: integer; stdcall; 独立线程在后台上传和下载文件。
procedure FsSeTCrypTCallback(CryptProc: TCryptProc; CryptoNr, Flags: integer); stdcall; 载入插件时会调用这个函数,在使用保存在TC中的密码时需要用到这个函数。
procedure FsSetDefaultParams(dps: pFsDefaultParamStruct); stdcall; 紧跟着FsInit()函数后调用,在TC5.51版本以上才有用。存储信息到TC的ini文件中。
3、插件可以利用的回调函数: TProgressProc = function(PluginNr: integer; SourceName, TargetName: pchar; PercentDone: integer): integer; stdcall; 获得复制操作的进度。 TLogProc = procedure(PluginNr, MsgType: integer; LogString: pchar); stdcall; 在log file中增加信息,并显示FTP toolbar。 TRequestProc = function(PluginNr, RequestType: integer; CustomTitle, CustomText, ReturnedText: pchar; maxlen: integer): bool; stdcall; 让用户输入信息,用户名、密码等。以上三个函数在FsInit函数中获得地址。 TCryptProc = function(PluginNr, CryptoNumber: integer; mode: integer; ConnectionName, Password: pchar; maxlen: integer): integer; stdcall; 用于存储密码到TC中。在FsSeTCrypTCallback函数中获得地址。
4、插件工作方式: 插件安装到TC后,插件被TC载入,FsGetDefRootName函数被调用,这时并不调用FsInit函数,插件返回信息被储存在wincmd.ini,然后插件被卸下。 用户进入网上邻居,TC显示所有wincmd.ini中的插件信息,插件并不会被TC载入。 用户试图进入插件目录,TC才载入插件。 TC获取上述函数的地址,如果必须存在的函数(开始那四个函数)有一个不存在,则载入失败。如果其他函数不存在,则载入也会成功,但是用户无法使用相关功能。 之后TC会调用FsInit函数,并通知插件其编号及回调函数地址。 用户进入插件目录时TC刷新文件列表。copying/moving/deleting操作涉及子目录时,TC也会刷新文件列表。这些功能靠FsFindFirst()... FsFindNext()... FsFindClose() 三个函数实现。 TC建立的路径样子为:\drive1\c:\some\subdir。第一个"\"表示根目录。 操作插件中的目录时,TC先刷新目录中的文件列表,储存在内部列表,之后复制文件,最后重复处理子目录。
5、注意: 多个文件操作时,可能同时存在其他操作并发,所以在FsFindFirst() 返回的句柄,在FsFindClose()中可能已经变动。(及时处理句柄。) 一些函数可能会自动调用其他关联函数,例如移动文件夹函数会调用删除文件夹函数。 在查找文件过程中需要注意以下两个特殊情况:1)复制时没有选择文件;2)使用F3浏览文件。 FsStatusInfo实现后,每次插件执行一个操作前后都会抛出信息,除了FsInit,FsDisconnect函数。 有些函数有两个版本,结尾有W字母的,用于Unicode系统,例如NT-based系统(Windows NT, 2000, XP, Vista, 7等)。Windows 9x/ME,TC会调用结尾不带W字母的ANSI版本。开发者必须两个版本都实现,或者分别实现两个版本的插件,在Unicode系统中(Win NT, 2000, XP, Vista, 7),TC会尝试载入.uwfx版的同名插件。
第二节 制作Demo的过程 我用的XE7做的这个Demo,用Delphi7也应该可以,需要注意XE7本身支持Unicode,Delphi7需要通过TNT组件库才能支持Unicode。 开发前需要准备头文件fsplugin.pas,这个文件声明了开发插件需要用到的声明,可以TC作者写的帮助中找到。 创建一个dll工程,保存。 新建一个unit单元,保存。引用winapi.windows,System.SysUtils,fsplugin单元。实现最基本的六个函数:FsInit, FsFindFirst, FsFindFirstW, FsFindNext, FsFindNextW, FsFindClose。 转到dll工程源码,输出上面的六个函数。 全部保存,编译dll。 把输出的dll改名为.wfx。 把改名后的插件添加到TC中(TC菜单:设置\选项->插件\文件系统插件\设置)。 在TC中转到网上邻居,看到插件名称,进入插件,这时如果发生异常,则抛出一个异常信息。 我只是实现了最少必要函数,TC作者提供的Demo写了更多的函数,而且实现方式也有些区别,例如:我用全局变量替代了指针的传递;共用函数的方法也有些不同。 如果想在网上邻居内显示插件自有图标,可以在工程目录下增加一个.res文件,其中包括一个图标就可以,这个图标最好包括16*16、24*24、32*32三种格式,否则通过拉伸显示的图标有点难看。这个文件可以复制其他application程序工程的.res文件。 Demo包括的文件: TcFsPluginDemo.dpr,插件工程文件。 fsplugin.pas,插件接口声明。 fsDemo.pas,插件函数实现单元。 fsPlugin.chm,TC作者写的插件开发帮助。 安装后的样子.JPG,插件小照。 readme.txt,本文。
第三节 结语 TC使用了四种插件: 压缩包扩展插件(wcx),压缩、解压缩、浏览压缩包。 查看器扩展插件(wlx),浏览文件内容。 文件系统扩展插件(wfx),操作非磁盘系统列表或树形表,例如:任务表,注册表,数据库,Ftp服务器等。 内容插件(wdx),可浏览更多文件信息,用于自定义列、缩略图显示或相关查找。 四种插件开发有所不同,这个Demo只适用于wfx插件。 TC是一个极其高效的文件管理软件,但在整理文件时候要不停的在不同目标文件夹之间切换,Ctrl+D和标签功能所能收藏的文件夹仍然有限,所以我一直想做一个收藏文件的插件,如果能有个Delphi版本的Demo参考,开发起来会很方便。但是TC网站上提供的带源码的插件大多数是c\c++语言写的,而且代码量比较大,不适合理解插件的工作原理。网上这方面可以参考的内容也比较少,因此我详细记录了Demo的制作过程,并在Demo的源码中做了些注释,便于自己以后作为TC插件开发模板使用,也希望能帮助其他Delphi的用户开发TC插件。 20150903 |