浅述如何为程序提供二次开发功能 - 1 (原创)

        什么是二次开发?    我自己理解为:用户可以利用提供者提供的接口使用已有系统中的资源、功能为已有系统提供新的功能;而所提供的新功能可以无缝集成到已有系统中,已有系统无需重新编译。

        为系统提供二次开发功能,以前觉得是比较神秘的东西,但是自从去年仔细捉摸一番后,发现事实没有那么难,我就把曾经的经历写出来给大家看看.

        提到二次开发,我不知道大家首先想的是什么软件,我想到的是AutoCAD,比较熟悉它的VBA二次开发,不过拿起ObjectArx也玩得转.我所说的这套二次开发的思路与ObjectArx比较相像,都是用动态链接库实现;现在跟我一步一步的探索吧,不过还要多动脑筋,免得陷入我的思维定势;那样我的抛砖引玉的想法就泡汤啦,会比较失望:(,Now let's begin.
 
    1.1 动态链接库
    动态链接库的简单例子
    library mydll;
    uses
    SysUtils,
    Classes,
    Dialogs;

    procedure test(str: pchar); export; stdcall;
    begin
      ShowMessage(str);
    end;

    exports test;

    {$R *.res}

    begin
    end.
    上面是一个完整的动态链接库代码,下面是调用方法
    type
      TDllFunc = procedure(str: pchar); stdcall;
    var
      DllHandle: THandle;
      DllFunc: TDllFunc;

      ...
      DllHandle := LoadLibrary('mydll.dll');
      ...

      DllFunc := GetProcAddress(DllHandle, 'test');
      DllFunc('测试我的动态链接库');
      ...
      FreeLibrary(DllHanle);
    关于动态链接库就到这,不再赘述了

    1.2 动态链接库的统一接口
    有了动态链接库,我们的程序可以实现扩充了;但是问题又来了,我们的程序怎么知道动态链接库中的函数名字、参数等?不知道怎么调用?其实解决这个问题有一个很简单地做法---那就是统一函数名称和参数;这样,我们的程序只需要找到动态链接库文件就可以调用它们了;现在我们把编译好的动态链接库放到指定的目录,这样我们的Exe可以到这个目录中遍历所有的.dll文件,从而调用它们提工的功能函数。
    下面是我以前的代码中的一部分(加载目中的全部.dll文件,以及得到它们的功能借口)
    procedure TDllManager.GetWorkers;
    var
      SRec: TSearchRec;
      retval: Integer;
      DllFunc: TDllFunc;
    begin
                        // 在当前目录下的dev2目录中搜索*.dll文件
      retval := FindFirst('./dev2/*.dll', faAnyFile, sRec); 
      try
        while retval = 0 do
        begin
          if (SRec.Attr and faDirectory) = 0 then  // 文件
          begin
            // 加载动态连接库
            try
              TmpDllName := SRec.Name;
              TmpHandle := LoadLibrary(pchar('./input/' + TmpDllName));   // 加载动态链接库
              DllFunc := GetProcAddress(TmpHandle, DLLFuncName);          // 取得函数地址
              if assigned(DllFunc) then
                DllFunc();        // 调用函数

       ... ...

            except
              if TmpHandle <> 0 then
                FreeLibrary(TmpHandle);
            end;
          end;
          retval := FindNext(SRec);
        end;
      finally
        FindClose(SRec);
      end;
    end;
    好了,现在程序怎么自动调用动态链接库的方法有了(其实是变通了一下而已)。

    1.3 在动态链接库中调用EXE中的函数
    现在,我想为主程序添加一个新的菜单,怎么办?把MainMenu作为参数传给动态链接库,对这种做法确实可行,但是又没有考虑过,如果我的二次开发工作是在VC中进行的,怎么办?VC中可没有Delphi的TMainMenu控件。
    想想window api中的的窗口回调,我们会不会有启发呢?对,回调函数可以解决上面的问题。
    下面用代码简单说明:
    type
      procedure TCallBack = procedure(menuname: pchar); stdcall;

    // 注意这个函数一定不要是类的成员函数
    procedure AddMenu(menuname: pchar);
    begin
      // 添加菜单
      ... ...
    end;

    调用动态链接库
    type
      procedure TDllFunc(CallBacl: TCallBack); stdcall;       
    ... ...
    var
      DllFunc: TDllFunc;
      // 加载dll,取得函数地址
      ...
      DllFunc(TCallBack(AddMenu));
      ...
   
    动态链接库中这样写     
    procedure test(CallBacl: TCallBack); stdcall; export;
    begin
      CallBack('测试菜单');  // 回调函数,实现新增菜单
    end;

    这样,在动态链接库中调用EXE中函数的功能就实现了,可是如果这样做的话我们会遇到非常大的麻烦,因为我们不得不为系统各种复杂的功能定义很多回调函数和相应的动态连接库接口函数;如果真的这样做了恐怕没有人会去做系统的二次开发,因为那些接口实在太让人头痛了,解决办法将在在下一篇揭晓。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值