我现在作了一个系统,系统的框架是这样的:
主程序只负责界面显示、用户操作和服务器通信,运行时需要根据配置文件载入不同的业务模块。
业务模块负责业务逻辑的处理,通过与主程序的显示接口,显示数据。
业务模块需要向主窗体发送消息。与服务器的通讯过程:
  业务模块(module)有一属性为 Connection  该属性挂接主程序的连接控件Connection
  Module  发送请求数据(调用Connection的发送函数据)----〉Connection(主程序) ----〉发送服务器 ----〉处理返回结果 ----〉Connection(主程序)  ---〉根据返回数据查找发送对象  ----〉返回给Module ----> Module(处理数据)
动态链接库文件library BillMeasure;uses
  ShareMem,
  SysUtils,
  Forms,
  TalentMeasure,
  UBillMeasure,
  Windows,
  TalentFunction,
  Classes;{$R *.res}var
   DllApplication: TApplication;function CreateMeasure(ParentApplication: TApplication):TTalentMeasure; export; stdcall;
var Measure: TTalentBillMeasure;  //用户管理
begin
   Application:=ParentApplication;
   Measure:=TTalentBillMeasure.Create(ParentApplication);  //生成窗体
   Result:=Measure;
end;procedure DLLUnloadProc(Reason: Integer); register;
begin
  if Reason = DLL_PROCESS_DETACH then  Application:=DllApplication;
end;
exports
   CreateMeasure;begin
   DllApplication:=Application;
   DLLProc := @DLLUnloadProc;
end.
在主程序中调用如下:TFunctMeasure = function( ParentApplication : TApplication ) : TTalentMeasure; stdcall;  //生成模块函数
  TMeasureModule =Record         //业务类型
     Code,
     Name,
     FileName,
     Version:string;
     ICNo:integer;
     Enable:boolean;
     DllHandle:Cardinal;
     Measure:TTalentMeasure;
  end;
procedure TFrmMainWindow.LoadDll;                           //读入动态链接库,建立模块对象
var ii, jj: Integer;
  ProcAddr: FarProc;
  FunctMeasure: TFunctMeasure;                              //生成模块
  ErrorMsg: string;
  MeasureModule: TMeasureModule ;
begin    with MeasureModule do
    begin
      DllHandle := LoadLibrary(pchar(FileName));
      if DllHandle < HINSTANCE_ERROR then
      begin
        ErrorMsg := GetDLLError(DllHandle);
        OperationLog('调用' + Name + '的动态链接库' + FileName + '出错:' + ErrorMsg);
        ShowMessage(ErrorMsg);
        Exit;
      end
      else
      begin
        //调用接口函数
        ProcAddr := GetProcAddress(DllHandle, 'CreateMeasure');
        if ProcAddr <> nil then
        begin
          FunctMeasure := ProcAddr;
          Measure := FunctMeasure(Application);             //创建计量模块对象
          Measure.WinHandle:=Handle;
          Measure.DataSet := TTalentDataset.Create(Application); //创建数据解析控件
          Measure.DataSet.Name:='DataSet'+Code;
          Measure.DataSet.Connection := TalentConnection;   //链接数据链接控件
          Measure.DataSet.OutTime := 30000;                 //请求等待时间
    end;
  end;
end;
以上是进行调用模块的主要过程。
调用一切正常,但是在运行时,经常会出现读内存地址错误的情况,而且会出现向主程序发送消息时会出现系统停顿。是不是通过动态链接库生成的对象,这种写法不对?
是不是在主程序在于动态链接库创建的对象进行通信时造成的错误。各位高手指教。

解决方案 »

  1.   

    在dll中如果封装了vcl对象,会出现主控程序与dll中通讯、dll中窗体焦点转移等难题。问题关键是dll与exe中各有Application对象,虽然在调用dll时用主控程序中的application替代dll中的application可解决部分问题,但仍然有许多无法克服的困难,这是delphi的缺陷。
    解决的办法有两个:一个调用dll时,同时将application、Screen两个对象同时传递给dll,编译dll时采用动态编译的方法,发布程序时需要同时发布vcl.bpl和rtl.bpl。
    另一个方法是采用bpl代替dll,这样整个程序中只有一个application,而且bpl是面向对象的,则所有问题均迎刀而解。
      

  2.   

    正如sxqwhxq(步青云) 所说,要传递对象,最好做成BPL,
    还有传递APPLICATION时,最好传递句柄APPLICATION.HANDLE
      

  3.   

    dll可以传出对象,但主程序只能调用dll传出对象中的虚方法
    换尔言之,你要包装一下dll中对象的相关方法,
    给主程序发消息用PostMessage