先行知识:Delphi/接口/DLL/COM(了解)
难度:★★☆☆☆
在开始之前先说一些题外话,这段时间一直很忙(马上就要期末考试,而且最惨的是现在正在忙着准备即将到来的英语4级考试),所以自己也不知道这篇文章够不够份量。这篇文章的内容可能不是太多,但我还是抽时间把它写了出来作为我们的Delphi Open Tools Api实例研究(二)。另外我又发现了一些很不错的关于这方面的资料和网站,一并在文后推荐给大家。
还记得上次的实例研究一吗?我们展示了一个通过设计时组件包扩展delphi的例子。这次我们仍将做一个实际意义的delphi插件,菜单仍向上次一样不变,不过这次的不是上次的向源文件插入一行代码,而是向当前工程中添加一份开发文档,并显示在delphi的代码编辑器中提供给开发者修改。(同时也保存在工程文件所在的目录下)。然而这次与上次有一个很大的不同,也是这次最重点要说的地方是:我们将把这次的插件编译成dll,而不是上次的组件包,这给创建自己更人性话的插件安装程序(而不是叫用户打开一个组件包来自己安装)提供了机会。
先来看看这次的重点,我们建立了一个动态连接库项目,并在加入的第一个单元文件内实现了我们的插件类。与上次不同的是,我们并不采用传统的组件注册过程Register,而是在单元类定义了一个类型为TwizardInitProc的全局函数,并在项目文件中以WizardEntryPoint名称导出(注意:必须使用这个名称。)
exports
InitNewMenu Name WizardEntryPoint;
下面是单元中的这个函数的原形和实现:
function InitNewMenu(const BorlandIDEServices:IBorlandIDEServices;
RegisterProc:TWizardRegisterProc;var Terminate:TWizardTerminateProc):boolean;stdcall;
//RegisterProc:TWizardRegisterProc;参数用来创建向导,实际上这个初始化函数是用来创建一个dll
//形式的传统Wizard这种时候就可以向RegisterProc参数传递一个实现了IOTAWizard的类实例,用以
//注册向导,如同这样RegisterProc(xxx.Create)。这里我们只是使用这个函数作为初始化dll的入口点
//所以并没有使用这个函数,而是直接MyNTATest:=TNTATest.Create; 另外var Terminate参数用来释放
//你在向导中使用的资源,你可以赋给它一个普通的过程类型如Terminate:=xxx; xxx为一个procedure
//这样ide在退出时,便会调用这个过程来释放资源。注意这个函数必须以stdcall指示。
var
svcs:IOTAServices;
begin
result:=BorlandIDEServices <> nil;
if result then
begin
svcs:=BorlandIDEServices as IOTAServices;
//保存BorlandIDEServices指针
ToolsAPI.BorlandIDEServices:=BorlandIDEServices;
//设置dll的host application句柄
Application.Handle:=svcs.GetParentHandle;
MyNTATest:=TNTATest.Create;
end;
end;
另外这次也使用了一个新的OTA接口,主要体现在菜单项的第一个事件内(我们完成了向当前工程中添加一份开发文档的工作):IOTAActionServices,这是个相当有用的接口,在ide运行时由BorlandIDEServices实现,可以用来完成对IDE各种功能的调用。如:CloseFile、OpenFile、OpenProject、ReloadFile、SaveFile。这些功能的作用根据它们的名称就能猜测出来。本来我还想使用IOTAProjectOptions接口来得到当前工程的相关信息和配置选项一并写在文档文件里,但并没有得到理想的结果,最多只得到了关于工程有哪些Options的字符串列表。我们有可能将在下次的文章中研究和IOTAProject相关的一系列接口。下面是产生文档部分的代码(对应于菜单项的第一个菜单事件):
procedure TNTATest.AddDocumentToPro(sender:TObject);
var
templen,i,temppos:integer;
DocumentFile:TextFile;
ModuleCount: Integer;
TempString,MoudleFilePath:String;
begin
//请求IOTAModuleServices t接口
Supports(BorlandIDEServices,IOTAModuleServices,MoudleService);
ModuleCount:=MoudleService.ModuleCount;
if ModuleCount<>0 then //没有任何文件打开
begin
CurentMoudle:=MoudleService.CurrentModule;
//获得当前的文件名,我们可以用它得到项目路径
TempString:=CurentMoudle.FileName;
//下面的部分用来分析字符串并取出项目的路径//
i:=pos('\',TempString);templen:=length(TempString);temppos:=i;
while i<>0 do
begin
TempString:=RightStr(TempString,templen-i);
i:=pos('\',TempString);templen:=length(TempString);temppos:=temppos+i;
end;
MoudleFilePath:=leftstr(CurentMoudle.FileName,temppos);
////////////////////////////////////////////
if Supports(BorlandIDEServices,IOTAActionServices,ActionServices) then
begin
AssignFile(DocumentFile,MoudleFilePath+'DocumentFile.txt');
Rewrite(DocumentFile);
try
writeln(DocumentFile,'项目名称:');
writeln(DocumentFile,'项目主程序名:');
writeln(DocumentFile,'项目版本号:');
writeln(DocumentFile,'项目描述:');
writeln(DocumentFile,'项目组成员:');
writeln(DocumentFile,'文档建立时间:'+DateTimeToStr(now));
finally
CloseFile(DocumentFile);
end;
//注意,我们用到了IOTAActionServices的OpenFile方法来打开刚才保存的文档
ActionServices.OpenFile(MoudleFilePath+'DocumentFile.txt');
end;
end
else
messagebox(IDEHandle,'There isn''''t Active Project.','DocCreator',MB_ICONWARNING);
end;
其余的代码(如向IDE添加菜单等和上次的类似),在这里我们就省略不写出来了,你可以参看上一篇文章(连接: http://www.csdn.net/develop/read_article.asp?id=21725 ),也可以给我来信得到代码(地址和上一次的一样)。最后当我们完成代码编写时,我们就可以将它编译成dll文件。现在来看看我们怎么来安装我们的插件:首先退出delphi,打开注册表,在HKEY_CURRENT_USER/Software/Borland/Delphi/7.0/Experts键下新建立一个字符串类型的值,名称为我们的插件的名称,值为我们编译得到的dll的路径。现在重新启动delphi,怎么样,插件开始工作了吧。有了这个办法后相信我们可以很容易的为我们的插件创建安装程序和反安装程序(无非就是简单的操作注册表而已,当你再次推出delphi,并在注册表中删除刚才建立的值,重启delphi会发现插件已经卸载了),使其变的对用户更友好,也可以更加方便我们的发布。最后再做一点说明:关于调试dll插件的说明,我建议不要在编码过程中返太多的错误(指运行时的),你会发现你会为调式插件而不得不一次次的启动、关闭delphi,这是一件相当烦人的事情(把我害惨了),我建议你可以先把插件作为上一次的组件包形式进行测试和调式,这样不用重启delphi,当调式成功后再改为dll形式的。另外这次的插件依然以delphi7为基础,在低版本的delphi中可能会有错误。最后说明的是,这个插件可能会使delphi在退出的时候产生一个AV错误,我暂时还没有解决这个问题(希望高人指教),虽然我使用了string类型,但我也的确引用了sharemem单元。我也尝试在Terminate参数中向其赋一个退出释放资源的函数,但问题依旧。
在文章的最后我向大家推荐一些我最近发现的一些关于OTA的相当不错的网站和资料:
http://www.gexperts.org/opentools/ 在这里你将会得到一份OTA的FAQ,相当不错。
http://www.tempest-sw.com/opentools/ 一些老版本的OTA资料
http://home.quicknet.nl/qn/prive/rapp/delphi/delphi.html OTA部分接口的相关资料和例子
http://www.frasersoft.net/program/ delphi的OTA帮助补丁(非官方),但相当不全
最后祝大家新年愉快。J
本文地址:http://com.8s8s.com/it/it5200.htm