假如说有EXE和DLL,动态调用,EXE直接调用DLL的exports接口,没有问题。如果DLL要向EXE返回信息呢?
除了回调,有其他比较好的办法吗?
另外,不知道DELPHI 2010/XE里的RTTI能不能实现.net里直接对DLL进行反射的功能呢?

解决方案 »

  1.   

    1.DLL在什么时刻需要返回给EXE,是DLL执行完?还是执行过程随时需要返回
    2.DLL需要返回什么样的信息,EXE需要根据这些信息执行什么动作,还要不要传递给DLL
      

  2.   

    EXE 与DLL 通信可以用句柄来通信的DLL 向主程序发送消息
    var
      wp, lp: longint;
    begin
      wp := GlobalAddAtom(pchar(wParam));
      lp := 0;
      if lparam <> '' then lp := GlobalAddAtom(pchar(lParam));
      if  pr_Systems.MainHandle > 0 then
      begin
        PostMessage(pr_Systems.MainHandle, WM_mainmessage, wp, lp);
      end;
    end//主程序接收消息
    procedure WM_messageMain(var Message: TMessage); message WM_Mainmessage;
    var
      sl, index: integer;
      formhandle: THandle;
      strcommand, strcommandtext, strcommandsend, strcommandtextsend: string;
      commandarr: Array[0..1023] of char; // 消息命令
      commandtextarr: array[0..1023] of char;  // 消息内容
      windhand: THandle;
      wp: longint;
    begin
      strcommand := '';
      strcommandtext := '';
      if Message.WParam <> 0 then //消息命令
      begin
        sl := GlobalGetAtomName(Message.WParam, @commandarr, sizeof(commandarr));
        GlobalDeleteAtom(Message.WParam);
        if sl > 0 then
        begin
          commandarr[sl] := #0;
          strcommand := commandarr;
          strcommand := lowercase(strcommand);
        end;
      end;
      if Message.LParam <> 0 then//消息内容体
      begin
        sl := GlobalGetAtomName(Message.LParam, @commandtextarr, sizeof(commandtextarr));
        GlobalDeleteAtom(Message.LParam);
        if sl > 0 then
        begin
          commandtextarr[sl] := #0;
          strcommandtext := commandtextarr;
          strcommandtext := trim(strcommandtext);
        end;
      end;
      if strcommand = '' then exit;
      if self.FIsrecordMessage then //记录消息
      begin
        self.FMsgMainList.Append(strcommand + '=' + strcommandtext);
        if FMsgMainList.Count > MaxStringListCount then
        begin
          ttjpubfun.WriteToLog(FMsgMainList,
             TtjAppRegInfo.GetApplicationAppLogPath + 'mdiform_message_' +
                 FormatDateTime('YYYYMMDD', Now()) + '.txt');
          FMsgMainList.Clear;
        end;
      end;
      if strcommand = 'login' then //DLL登录
      begin // formhandle = <billidend>xxxx<billiden>
        formhandle := strtointdef(ttjpubfun.ExtractName(strcommandtext, '0'), 0);
        if formhandle > 0 then
        begin
          index := self.FMDIFormList.IndexOfName(inttostr(formhandle));
          if index >= 0 then FMDIFormList.Delete(index);
          FMDIFormList.Append(strcommandtext);
        end;
      end
      else if strcommand = 'logout' then //DLL退出
      begin // strcommandtext =  logout form handle  exmple  1
        formhandle := strtointdef(strcommandtext, 0);
        index := self.FMDIFormList.IndexOfName(inttostr(formhandle));
        if index >= 0 then FMDIFormList.Delete(index);
      end
      else if strcommand = 'checksubmit' then //DLL审核提交
      begin //<billiden>xxx<billiden><keyvalues>xxxxx</keyvalues>
        self.Postmessagetomsgclient('checksubmit', strcommandtext, True);
      end
      else if strcommand = 'checkpass' then //DLL审核同意
      begin
        self.PostmessageTomsgclient(strcommand, strcommandtext, true);
      end
      else if strcommand = 'checkunpass' then //DLL审核不同意
      begin
        self.PostmessageTomsgclient(strcommand, strcommandtext, True);
      end
      else if strcommand = 'checkback' then
      begin
        self.PostmessageTomsgclient(strcommand, strcommandtext, True);
      end
      else if strcommand = 'checkcancel' then
      begin
        self.PostmessageTomsgclient(strcommand, strcommandtext, True);
      end
      else if strcommand = 'checkinfo' then
      begin
        self.PostmessageTomsgclient(strcommand, strcommandtext, True);
      end
      else if strcommand = 'help' then //DLL请求打开帮助文件
      begin
        self.openhelp(strcommandtext);
      end;
    end;//帮助文件负责解释是哪个窗体,哪个控件,好定位到相应的帮助文件
    procedure THelpFile.openhelpchm(const value: string);
    var
      dllname, formname, controlname, sTopic: string;
      helpcontext, index: integer;
      query: HH_FTS_Query;
      popup: HH_POPUP;
      hh: HWND;
    begin
      dllname := TAnalysestr.ReadString(value, 'dllname', '');
      formname := TAnalysestr.ReadString(value, 'formname', '');
      controlname := TAnalysestr.ReadString(value, 'controlname', '');
      helpcontext :=  strtointdef(TAnalysestr.ReadString(value, 'helpcontext', '0'), 0);
      sTopic := '';  if (dllname <> '') or  (formname <> '') or (controlname <> '') then
      begin
        if Fadodataset_help.Locate('dllname;formname;controlname', vararrayof([dllname, formname, controlname]), []) then
          sTopic := Fadodataset_help.FieldByname('htmfilename').AsString
        else if Fadodataset_help.Locate('dllname;formname', vararrayof([dllname, formname]), []) then
          sTopic := Fadodataset_help.FieldByname('htmfilename').AsString
        else if Fadodataset_help.Locate('dllname', dllname, []) then
          sTopic := Fadodataset_help.FieldByname('htmfilename').AsString;
      end;  if TAnalysestr.ReadString(value, 'query', '') <> '' then
      begin
        with query do
        begin
          cbStruct := sizeof(HH_FTS_Query);
          fUniCodeStrings := false;
          iProximity := HH_FTS_DEFAULT_PROXIMITY;
          fStemmedSearch := True;
          fExecute := True;
          fTitleOnly := False;
          pszWindow := nil;
          pszSearchQuery := pchar(TAnalysestr.ReadString(value, 'query', ''));
        end;
        strfullquery := TAnalysestr.ReadString(value, 'query', '');
        
        HtmlHelpA(0, pchar(Fhelpfilename), HH_DISPLAY_SEARCH,  PDWORD(@query));    hh := FindWindow('HH Parent', pchar('hrms help'));
        if hh <= 0 then hh := FindWindow('HH Parent', pchar('help'));
        if hh > 0 then
        begin
          EnumChildWindows(hh, @EnumWindowsProc, 0);
        end;
      end
      else if helpcontext > 0 then
      begin
        with popup do
        begin
          cbStruct := sizeof(HH_POPUP);
          hinst:= 0;
          idString := helpcontext;
          pszText:=nil;
          //pt:= pt;
          GetCursorPos(pt);
          clrForeground:=COLORREF(-1);
          clrBackground:=COLORREF(-1);
          rcMargins.Left := 0;
          rcMargins.Top := 0;
          rcMargins.Right := 25;
          rcMargins.Bottom := 25;
          pszFont:=LPCTSTR('BOLD');
        end;
        HtmlHelpA(0, pchar(Fhelpfilename), HH_DISPLAY_TEXT_POPUP, PDWORD(@popup));
      end
      else if sTopic <> '' then
        HtmlHelpA(0, pchar(Fhelpfilename), HH_DISPLAY_TOPIC, PDWORD(pchar(sTopic)))
      else if sTopic = '' then
        HtmlHelpA(0, pchar(Fhelpfilename), HH_DISPLAY_TOC, PDWORD(pchar(sTopic))) 
    end;
      

  3.   

    DELPHI的EXE和DLL都各自有一个Application对象,这个对于很多处理都需要小心,不建议直接把窗体封装到DLL中,但是可以把一些逻辑处理封装到DLL中。
      

  4.   

    一般只用回调传返回信息
    对于各自独立的功能模块,可封装在DLL中,传入application.handle和数据库连接_Connection
    以减少主exe的大小。对于与主程序交互比较多的一般不做成dll
      

  5.   

    dll可以封装对象的,李维的书里面讲过。利用interface,exe可以直接调用dll里导出的对象,访问对象的属性,事件,就没有什么通信的问题了~
      

  6.   

    要么就发消息。给dll把主窗体句柄传进去。dll给它发消息~