我是将test.pas(FORM)封装在abc.dll里  myDll in 'myDll.pas' {Form1};procedure newForm;stdcall;export;
var
  frm1:TForm1;
begin
    frm1:=TForm1.Create(nil);
    frm1.Show;
end;然后用主程序 123.pas 调用"newForm"过程。。test.pas Form能正常显示出来。但按上面的按钮功能。就出现“Access violation at address 004E105F in module 'abc.dll'.Read of address 00000460”错误提示
如果将abc.dll改成这样写却能正常使用我搞不懂这样写有什么区别。。
  myDll in 'myDll.pas' {Form1};procedure newForm;stdcall;export;
begin
    Form1:=TForm1.Create(nil);
    Form1.Show;
end;
我想实现的功能:是主程序 123.pas 有8个按钮。。每点击一个按钮就调用 newForm 动态生成一个 test.pas Form ...
所以想用第一种方法定义窗口来加以区分:
var
  frm1,frm2,frm3,frm4,frm5,frm6,frm7,frm8:TForm1;如果按第二种方法的虽然也能正常动态创建8个 test.pas Form 但没办法区分开来。我想显示/隐藏哪个窗口都无法判断
麻烦大家给个方法可以不按我上面所说的。。能实现相同功能就行了 

解决方案 »

  1.   

    function NewForm: THandle;
    begin
      with TTestForm.Create(nil) do
      begin
        Show;
        Result := Handle;
      end;
    end;var hnd1: THandle;
    hnd1 := NewForm;
    ShowWindow(hnd1,SW_HIDE);  //隐藏
    showWindow(hnd1,SW_SHOW);  //显示
      

  2.   

    newfang 你好按你的方法:
    dll:
      myDll in 'myDll.pas' {Form1};function newForm:THandle;stdcall;export;
    begin
        with TForm1.Create(nil) do
        begin
          Show;
          Result:=Handle;
        end;
    end;主程序调用:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      hnd1:Cardinal;
    begin
        hnd1:=newForm;
    end;
    窗口也是可以正常创建成功。。但点里面的按钮还是出现。
    “Access violation at address 004E105F in module 'abc.dll'.Read of address 00000460”错误提示 
      

  3.   

    分数少的可怜啊。
    你的问题中 form1 变量定义在哪里?
    你 dll 中的 8 个按钮中,是否直接使用了 form1 变量?
      

  4.   

    全部分数了。。真是不好意思form1我没定义过
    myDll in 'myDll.pas' {Form1}; 这条指令后。。就有个form1自动指向mydll.pas...。。也可以看成mydll.Form1
    8个按钮是主程序调用dll 的 newForm...
      

  5.   

    全部分数了。。真是不好意思 form1我没定义过 
    myDll in 'myDll.pas' {Form1}; 这条指令后。。就有个form1自动指向mydll.pas...。。也可以看成mydll.Form1 
    8个按钮是主程序调用dll 的 newForm...
      

  6.   

    发现问题所在。。被封装在dll里mydll.pas 里定义了
    var
      Form1: TForm1;而别的线程如mydllunit2.pas 要使用 Form的控件时,都要这样写 Form1.edtYjID.Text从而造成上面的错误。。这个该如何改? 
      

  7.   

    把Result:=Handle; 改成Result:=WindowHandle; 试试~~
      

  8.   

    TForm1的create中写上
     Form1:=self;
      

  9.   

    procedure TForm1.FormCreate(Sender: TObject);
    type TMyPro = function: THandle;
    var p: TMyPro;
    begin
      isShow := False;
      hnd := LoadLibrary('testDll.Dll');
      if hnd > 0 then
      begin
        @p := GetProcAddress(hnd,'Form1Show');
        if Assigned(@p) then hndWnd := p;
        isShow := True;
      end;
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      if hnd > 0 then FreeLibrary(hnd);
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      if hndWnd > 0 then
      begin
        if isShow then
          ShowWindow(hndWnd,SW_HIDE)
        else
          ShowWindow(hndWnd,SW_SHOWNORMAL);
      end;
      isShow := not isShow;
    end;其中:
      private
        isShow: Boolean;
        hndWnd,hnd: THandle;
        { Private declarations }
    =====================================================================
    function Form1Show: THandle;implementation{$R *.dfm}function Form1Show: THandle;
    begin
      with TForm1.Create(Application) do
      begin
        Result := WindowHandle;
        show;
      end;
    end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caFree;
    end;其中:exports Form1Show;
      

  10.   

    在dll中封装窗口类控件(包括按钮等),由于dll和exe使用的是两套application而导致dll中没有消息循环,所以在dll中的窗口类控件都不能很好地响应消息,这会导致你dll中的窗体产生很多不可预测的问题。
    所以,不建议你将窗口类控件封装到dll中,应该另开一个bpl,将这些窗口类控件封装到bpl中,然后exe和dll都带包编译,dll中只封装对这些窗口类控件的操作,exe仅仅负责调度。
    其实,不单单是窗口类控件,由于dll和exe使用的是两套类机制(虽然都是一样的,但的确是两套),所以如果将dll中的类通过函数引出来供exe用,都会存在问题,因为在exe中,无法正确定位这些类的类信息。
    所以,建议你将类封装在包中,dll中仅仅封装功能(也就是把不同的类组装在一起完成某一任务),exe仅仅负责对不同任务的调度。你上面的问题,不是不能解决,而是解决起来太麻烦,而且维护成本也太高。所以,你还是换个思路吧。
      

  11.   

    最简单个例子,dll窗体中一个TButton,和exe某窗体中的一个TButton,这两个窗体中的按钮同样都是TButton,但是却不是一个类型的东西,你如果将dll中的按钮通过 as 转换成exe中的按钮,就会报错,
    原因就是他们使用了两套类机制,这两个按钮的RTTI信息的地址是不一样的