主程序的调用使用动态调用,这个调的方法在没有使用MDIChild的时候是可以调用中DLL中的窗体相关的设置如下:主程序中的FormStyle设置为fsMDIForm,DLL中的Form的FormStyle属性设置为:fsMDIChild
DLL的函数接口如下:var
  DllProc: Pointer;
  DLLApp : TApplication;procedure APROC(vParaentApp : TApplication; AppHld : THandle; MainForm : TForm; imgList : TImageList; AdoConn : TADOConnection; AUser : string);stdcall;
begin
  //Application.Handle := AppHld;
  DLLApp := Application;
  Application := vParaentApp;
  MyAdo := AdoConn;
  SetParent(AppHld,Application.Handle);
  if not Assigned(frmMenuedit) then
    frmMenuedit := TfrmMenuedit.Create(Application);  //***每次执行到这里的时候就出错了.
  //frmMenuedit.Parent := MainForm;
  vImg := imgList;
  vLoginUser := AUser;  frmMenuedit.Show;
  //frmMenuedit.Free;
  FreeAndNil(frmMenuedit);
  Application.Handle := 0;
  
end;
procedure DLLUnloadProc(Reason : Integer); register;
begin
  if Reason = DLL_PROCESS_DETACH then Application := DLLApp;//恢复
end;exports
  APROC;
begin
  DLLApp := Application; //保存 DLL 中初始的 Application 对象
  DLLProc := @DLLUnloadProc;     //保证 DLL 卸载时恢复原来的 Application
end.

解决方案 »

  1.   

    我看你用到了adoconnetion, 有没有做CoInitialize(nil)?另,请把错误信息贴出来~~
      

  2.   

    给你一段代码看看,是主窗体调用DLL窗体的例子。{一 Dll的制作一般分为以下几步:  
    1 在一个DLL工程里写一个过程或函数  
    2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。  
    二 参数传递  
    1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。  
    2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].一句话,与windows c++兼容。  
    3 用stdcall声明后缀。  
    4 最好大小写敏感。  
    5 无须用far调用后缀,那只是为了与windows 16位程序兼容。  
     
    三 DLL的初始化和退出清理[如果需要初始化和退出清理]  
    1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:  
    procedure DllEnterPoint(dwReason: DWORD);far;stdcall;  
    dwReason参数有四种类型:  
    DLL_PROCESS_ATTACH:进程进入时  
    DLL_PROCESS_DETACH进程退出时  
    DLL_THREAD_ATTACH 线程进入时  
    DLL_THREAD_DETACH 线程退出时  
    在初始化部分写:  
    DLLProc := @DLLEnterPoint;  
    DllEnterPoint(DLL_PROCESS_ATTACH);  
    2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil);  
    3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。  
     
    四 全局变量的使用  
    在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据传递,除非你用内存映像文件。  
     
    五 调用静态载入  
    1 客户端函数声名:  
    1)大小写敏感。  
    2)与DLL中的声明一样。  
    如: showform(form:Tform);Far;external'yproject_dll.dll';  
    3)调用时传过去的参数类型最好也与windows c++一样。  
    4)调用时DLL必须在windows搜索路径中,顺序是:当前目录;Path路径;windows;widows\system;windows\ssystem32;  
     
    六 调用动态载入  
    1 建立一种过程类型[如果你对过程类型的变量只是一个指针的本质清楚的话,你就知道是怎么回事了]。如:}  
    type  
    mypointer=procedure(form:Tform);Far;external;   
    var  
      Hinst:Thandle;   
      showform:mypointer;   
    begin  
      Hinst:=loadlibrary('yproject_dll');//Load一个Dll,按文件名找。   
      showform:=getprocaddress(Hinst,'showform');   
    //按函数名找,大小写敏感。如果你知道自动化对象的本质就清楚了。   
      showform(application.mainform);//找到函数入口指针就调用。   
      Freelibrary(Hinst);   
    end;   
    {  
    七 在DLL建立一个TForM  
    1 把你的Form Uses到Dll中,你的Form用到的关联的单元也要Uses进来[这是最麻烦的一点,因为你的Form或许Uses了许多特殊的单元或函数]  
    2 传递一个Application参数,用它建立Form.  
     
    八 在DLL中建立一个TMDIChildForM  
    1 Dll中的MDIForm.FormStyle不用为fmMDIChild.  
    2 在CreateForm后写以下两句:}  
    function ShowForm(mainForm:TForm):integer;stdcall   
    var  
      Form1: TForm1;   
      ptr:PLongInt;   
    begin  
      ptr:=@(Application.MainForm);   
    {先把dll的MainForm句柄保存起来,也无须释放,只不过是替换一下}  
      ptr^:=LongInt(mainForm);   
    {用主调程序的mainForm替换DLL的MainForm。MainForm是特殊的WINDOW,它专门管理Application中的Forms资源.为什么不直接Application.MainForm := mainForm,  
    因为Application.MainForm是只读属性}  
      Form1:=TForm1.Create(mainForm);//用参数建立   
    end;   
    //备注:参数是主调程序的Application.MainForm   
    {  
    九 示例:  
    DLL源代码:}  
    library Project2;   
      
    uses  
    SysUtils,   
    Classes,   
    Dialogs,   
    Forms,   
    Unit2 in 'Unit2.pas' {Form2};   
      
    {$R *.RES}  
    var  
    ccc: Pchar;   
      
    procedure OpenForm(mainForm:TForm);stdcall;   
    var  
    Form1: TForm1;   
    ptr:PLongInt;   
    begin  
      ptr:=@(Application.MainForm);   
      ptr^:=LongInt(mainForm);   
      Form1:=TForm1.Create(mainForm);   
    end;   
      
    procedure InputCCC(Text: Pchar);stdcall;   
    begin  
      ccc := Text;   
    end;   
      
    procedure ShowCCC;stdcall;   
    begin  
      ShowMessage(String(ccc));   
    end;   
      
    exports  
      OpenForm;   
      InputCCC,   
      ShowCCC;   
    begin  
    end.   
      
    调用方源代码:   
    unit Unit1;   
      
    interface  
      
    uses  
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,   
    StdCtrls;   
      
    type  
    TForm1 = class(TForm)   
    Button1: TButton;   
    Button2: TButton;   
    Edit1: TEdit;   
    procedure Button1Click(Sender: TObject);   
    procedure Button2Click(Sender: TObject);   
    private  
    { Private declarations }  
    public  
    { Public declarations }  
    end;   
      
    var  
    Form1: TForm1;   
      
    implementation  
      
    {$R *.DFM}  
    procedure OpenForm(mainForm:TForm);stdcall;External'project2.dll';   
    procedure ShowCCC;stdcall;External'project2.dll';   
    procedure InputCCC(Text: Pchar);stdcall;External'project2.dll';   
      
    procedure TForm1.Button1Click(Sender: TObject);   
    var  
      Text: Pchar;   
    begin  
      Text := Pchar(Edit1.Text);   
    // OpenForm(Application.MainForm);//为了调MDICHILD   
      InputCCC(Text);//为了实验DLL中的全局变量是否在各个应用程序间共享   
    end;   
      
    procedure TForm1.Button2Click(Sender: TObject);   
    begin  
      ShowCCC;   
    //这里表明WINDOWS 32位应用程序DLL中的全局变量也是在应用程序地址空间中,   
    //16位应用程序或许不同,没有做实验。   
    end;  
      

  3.   

    小鱼给的真全啊!frmMenuedit := TfrmMenuedit.Create(Application);  //***每次执行到这里的时候就出错了.
    如果换成非fsMDIChild 就能成功吗?
      

  4.   

    执行到那句的错误信息如下:---------------------------
    Debugger Exception Notification
    ---------------------------
    Project Water_MIS.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'. Process stopped. Use Step or Run to continue.
    ---------------------------
    OK   Help   
    ---------------------------
      

  5.   


    刚才试下了,发现没有设置成fsMDIChild也是一样出现上面的那个错误,我设置的值为:fsNormal
      

  6.   

    SetParent(AppHld,Application.Handle);
    此句改为Windows.setparent(AppHld,Application.Handle);
      

  7.   

    把俺的代码给你看看,仅供参考:
    library PubMoudle;uses
      SysUtils,Classes,Forms,
      wPubWnd in 'wPubWnd.pas' {frmPubWnd},
      wEdtBase in 'wEdtBase.pas' {frmEdtBase};var DllApp: TApplication;procedure MyDllHandle(iReason: Integer);
    begin
      if iReason = 0 then
        Application := DllApp;
      if iReason = 1 then
        DllApp := Application;
    end;exports PubWndShow;begin
      DllProc := @MyDllHandle;
    end.
    ===========================================================
    unit wPubWnd;uses
      Windows, Messages, SysUtils, Variants,…… ……type
      TfrmPubWnd = class(TForm)
        CoolBar1: TCoolBar;
        ADOQuery1: TADOQuery1;
        …… ……
      private
        procedure ViewWndFace(sTableName: string);
        { Private declarations }
      public
        { Public declarations }
      end;procedure PubWndShow(App: TApplication;ADOC: TADOConnection;sTmp,sCurUser: string); stdcall;implementation{$R *.dfm}procedure PubWndShow(App: TApplication;ADOC: TADOConnection;sTmp,sCurUser: string);
    begin
    //  Screen := Scr;
      Application := App;
      with TfrmPubWnd.Create(nil) do
      begin
          if Pos(':',sTmp) > 0 then
          begin
            Caption := Copy(sTmp,1,Pos(':',sTmp) - 1);
            sTmp := Copy(sTmp,Pos(':',sTmp) + 1,Length(sTmp) - Pos(':',sTmp));
          end;
          ADOQuery1.Connection := ADOC;
          ViewWndFace(sTmp);
      end;
    end;…… ……procedure TfrmPubWnd.ToolButton8Click(Sender: TObject);
    begin
      Close;
    end;procedure TfrmPubWnd.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caFree;
    end;end.
      

  8.   

    转自《悟透Delphi》第三章 WIN32的时空观 第四节 数据和代码在哪里
      
    模块的静态数据区一般都是你定义的全局变量、常量等所在的地方。这些数据元素的访问地址都是相对于模块而言的。也就是说,这些数据元素标识方法和结构关系都是相对于该模块的程序的。模块外的其他模块程序是不能直接标识和解释本模块中定义的这些数据元素的,除非将这些数据元素的地址从模块内传递给其他模块的程序。例如,我们看看下面的两个模块程序:program ExeModule;function TheVariable: Pointer; external 'DllModule.DLL';begin// aVariable := 56789; //无法直接标识和访问另一模块中的数据元素。Integer(TheVariable^) := 56789; //只能通过从另一模块获取地址间接访问其数据元素。end.这个程序编译后将生成ExeModule.EXE模块文件。当然它启动时需要DllModule.DLL。library DllModule;varaVariable : Integer;function TheVariable: Pointer;beginresult:=@aVariable;end;exports TheVariable;beginaVariable := 12345;end.第二个程序由于指明它是library程序,所以编译后将生成DllModule.DLL模块文件。虽然在DllModule模块中定义了一个全局变量aVariable,但ExeModule模块的程序却无法直接标识和找到该变量。只能通过调用DllModule模块的TheVariable函数获取aVariable的地址指针之后,间接访问aVariable变量。有朋友说,如果将aVariable放到一个独立的PASCAL单元文件中,然后在两个模块的主程序中都uses这个单元,不就可以互相访问了吗?我们就来看看下面这些程序文件。这是VarUnit.pas单元文件:unit VarUnit;interfacevaraVariable : Integer;implementationend.这是ExeModule.dpr文件,它将生成ExeModule.EXE文件:program ExeModule;usesVarUnit;beginaVariable := 56789;end.这是DllModule.dpr文件,它将生成DllModule.DLL文件:library DllModule;usesVarUnit;beginaVariable := 12345;end.这两个模块都引用了VarUnit单元。假如这两个模块都在同一个进程空间中,那么,在ExeModule模块中访问的aVariable变量和在DllModule中访问的aVariable变量真的是同一个变量吗?答案是否定的!原来,ExeModule中访问的aVariable变量是在其自身模块的静态数据区域内,而DllModule中访问的aVariable变量也是自己所有的。尽管模块引用了相同单元中的变量,但这些变量在不同的模块中都会有一个独立的副本。在随后对运行包编译模式的讨论中,我们还将讨论到共用单元变量的问题。因此,我们要记住:在非运行包编译模式下,DELPHI中的各种全局变量和对象,如Application、Screen、Session、Printer等等,在每一个EXE和DLL模块中都有一个自己的副本,而不是同一个东西。