我在DLL里Create一个Form,
Function ShowForm(URL:PChar):integer;stdcall;
var
  MyForm:TForm1;
begin
  Unit1.URL:=String(URL);  //我在这里定义的Form1
  MyForm:=TForm1.Create(nil);
  MyForm.Show;
  //MyForm.Free;  //如果Dll里写这句话,那么调用的时候不出错,但是我就是想不free,因为我要用这个Form呀!但是不写的话,调用的程序在关闭的时候出内存错误!为什么呢?
  ShowBSForm:=1;
end;
exports
ShowForm;
大家帮忙解释一下,我在PB里和Delphi里调用都有这个问题

解决方案 »

  1.   

    MyForm:=TForm1.Create(nil);
      MyForm.ShowModal;
    MyForm.Free;
      

  2.   

    楼上的说的我知道,我现在想要的就是在一个按钮里弹出来一个窗体,然后就不管它了,最后由用户来关它,还有,我最后是想在PB里调用的,所以不能在dll里Free掉
      

  3.   

    Function ShowForm(AHandle : THandle;URL:PChar):integer;stdcall;
    var
      MyForm:TForm1;
    begin
      Application.Handle := AHandle;
      Unit1.URL:=String(URL);  //我在这里定义的Form1
      MyForm:=TForm1.Create(nil);
      MyForm.Show;
      //MyForm.Free;  //如果Dll里写这句话,那么调用的时候不出错,但是我就是想不free,因为我要用这个Form呀!但是不写的话,调用的程序在关闭的时候出内存错误!为什么呢?
      ShowBSForm:=1;
    end;
    exports
    ShowForm;
      

  4.   

    Application.Handle := AHandle;中的AHandle是什么?
    还有,就是最后我要做成Dll,用Application.Handle := AHandle行吗?
      

  5.   

    MyForm.showmodal;
    MyForm.Release;你放心的用 
    因为 调用你的dll时  主程序被挂起的
      

  6.   

    可以,Handle 是一个句柄,如果像你那样赋值的话,那么 DLL 作的动作就会被当作是主程序做的动作。
      

  7.   

    AHandle是调用方传递的句柄
    调用方式如下:
    ShowForm(Application.handle,'HLZW')
      

  8.   

    MyForm:=TForm1.Create(SELF);
      MyForm.ShowModal;
      CMyForm.Free;
      

  9.   

    sxtdxvb(大傻瓜)我试了你说的办法,果然不出错误了,但是
    我现在想做的是:不想让主程序被挂起,怎么办呢?
    还有,你告诉我的办法我有点想不明白,release难道不释放对象吗?如果不释放的话它都做了些什么呢?如果释放的话那窗体为什么不消失呢?
    我写成Show,然后release为什么窗体就消失了呢?请告知。
      

  10.   

    //在dll单元中这样写。var
    OldExitProc:Pointer;
    Form1: TForm1;Function ShowForm(URL:PChar):integer;stdcall;
    var
      MyForm:TForm1;
    begin
      Unit1.URL:=String(URL);  //我在这里定义的Form1
      MyForm:=TForm1.Create(nil);
      MyForm.Show;
      //MyForm.Free;  //如果Dll里写这句话,那么调用的时候不出错,但是我就是想不free,因为我要用这个Form呀!但是不写的话,调用的程序在关闭的时候出内存错误!为什么呢?
      ShowForm:=1;
    end;
    procedure MyExitProc;
    var
         gfa:ATOM;
    begin
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              Form1.Free;
              GlobalDeleteAtom(gfa);
         end;
         ExitProc:=OldExitProc;
    end;
    exports
          ShowForm;
    begin
         GlobalAddAtom('MyFormCreate');
         OldExitProc:=ExitProc;
         ExitProc:=@MyExitProc;
    end.
    //在Form1的onClose这样写。
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    var
         gfa:ATOM;
    begin
         Action:=caFree;
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              GlobalDeleteAtom(gfa);
         end;
    end;
      

  11.   

    楼上的朋友,不好意思,看不明白你写的什么意思,有几个问题想问你,
    按你的意思是把procedure MyExitProc给导出为ShowForm吗?我不太明白。
    ExitProc有定义吗?
      

  12.   

    ExitProc是DLL类库在卸载时要执行的一个过程指针,我的意思是在卸载DLL时判断窗体是否卸载,如果没卸就卸之。容易理解吧?
      

  13.   

    那么
    exports
      ShowForm;
    到底是针对哪个函数呢?
      

  14.   

    //我知道了,你肯定疑惑的是这部分
    exports
          ShowForm;
    //导出结束
    begin//动态连接库初始开始
         GlobalAddAtom('MyFormCreate');
         OldExitProc:=ExitProc;
         ExitProc:=@MyExitProc;
    end.//动态连接库初始结束//这样该明白了吧?兄台好好看看Library文件结构就明白了。
      

  15.   

    //在dll单元中这样写。var
    OldExitProc:Pointer;
    Form1: TForm1;
    //--------------------------------------------------------
    Function ShowForm(URL:PChar):integer;stdcall;
    var
      MyForm:TForm1;
    begin
      Unit1.URL:=String(URL);  //我在这里定义的Form1
      MyForm:=TForm1.Create(nil);
      MyForm.Show;
      //MyForm.Free;  //如果Dll里写这句话,那么调用的时候不出错,但是我就是想不free,因为我要用这个Form呀!但是不写的话,调用的程序在关闭的时候出内存错误!为什么呢?
      ShowForm:=1;
    end;
    //--------------------------------------------------------
    procedure MyExitProc;
    var
         gfa:ATOM;
    begin
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              Form1.Free;
              GlobalDeleteAtom(gfa);
         end;
         ExitProc:=OldExitProc;
    end;
    //--------------------------------------------------------
    exports
          ShowForm;
    //--------------------------------------------------------
    begin
         GlobalAddAtom('MyFormCreate');
         OldExitProc:=ExitProc;
         ExitProc:=@MyExitProc;
    end.
    //--------------------------------------------------------
    //这样够清晰了吧。
      

  16.   

    MyForm和form1是不是重复了?
    我应该把MyForm定义成局部的还是全局的呢?
      

  17.   

    把主程序句柄传给DLL,用主程序句柄创建窗体就行了。
      

  18.   

    cjfzy(他山之石,可以攻玉。) 我不知道怎么把主程序的句柄传给DLL,尤其是在PB里调用,能告诉我怎么做吗?告诉我怎么在Delphi里传也行,谢谢了。
      

  19.   

    //对不起,照帖了你帖子的内容,如下正确的测试过的代码。
    //在dll单元中这样写。var
    OldExitProc:Pointer;
    MyForm:TForm1;
    //--------------------------------------------------------
    Function ShowForm(URL:PChar):integer;stdcall;
    begin
      Unit1.URL:=String(URL);  //我在这里定义的Form1
      MyForm:=TForm1.Create(nil);
      MyForm.Show;
      ShowForm:=1;
    end;
    //--------------------------------------------------------
    procedure MyExitProc;
    var
         gfa:ATOM;
    begin
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              MyForm.Free;
              GlobalDeleteAtom(gfa);
         end;
         ExitProc:=OldExitProc;
    end;
    //--------------------------------------------------------
    exports
          ShowForm;
    //--------------------------------------------------------
    begin
         GlobalAddAtom('MyFormCreate');
         OldExitProc:=ExitProc;
         ExitProc:=@MyExitProc;
    end.
    //--------------------------------------------------------
    //在Form1的onClose这样写。
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    var
         gfa:ATOM;
    begin
         Action:=caFree;
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              GlobalDeleteAtom(gfa);
         end;
    end;
      

  20.   

    哈哈,我知道不对,改过来了,测试好用了!谢谢你!
    还有个问题,
    begin
         GlobalAddAtom('MyFormCreate');
         OldExitProc:=ExitProc; //这句话每次调用函数的时候都先执行吧?
         ExitProc:=@MyExitProc;
    end.
    开始的时候ExitProc是什么呢?
    ExitProc:=@MyExitProc,我看了一下,MyExitProc里把ExitProc:=OldExitProc;好象是个圈呀?不明白了,请指教!
      

  21.   

    我把代码改了改,也没有问题。我把OldExitProc:=ExitProc; 去掉了。
    MyExitProc里的ExitProc:=OldExitProc;去掉了。
    把OldExitProc的声明也去掉了。您看行吗?
      

  22.   

    最好将application.handle传给动态链接库,然后窗体创建为Create(application.handle)
    应该就不会有问题了
      

  23.   

    我仔细看了一下,create的时候需要传的是一个TComponent类型的对象,但是我是PB下调用,顶多传进去一个longint的handle,我需要怎么办呢?现在很晚了,我想明天或许我会再开贴,把我的问题好好的描述一下,大家帮忙呀。
      

  24.   

    楼主大哥你说的:
    -------------------------------------------------------------------
    我把代码改了改,也没有问题。我把OldExitProc:=ExitProc; 去掉了。
    MyExitProc里的ExitProc:=OldExitProc;去掉了。
    把OldExitProc的声明也去掉了。您看行吗?
    -------------------------------------------------------------------
    拜托你不要那样做,我加这些代码的原因是因为当动态连接库卸载时如果MyForm没有
    关闭并卸载就会在DLL卸载时卸载MyForm,如果你把这些去掉我做的一切工作都是白费,
    你想,进程都被杀死了(DLL卸载了),而在它的空间内开辟的窗口资源(MyForm)还有可能
    没有关闭并释放,这是多么不安全的做法,不出错实在是侥幸。求您不要那样做!!!
      

  25.   

    //对不起,照帖了你帖子的内容,如下正确的测试过的代码。
    //在dll单元中这样写。var
    OldExitProc:Pointer;
    MyForm:TForm1;
    //--------------------------------------------------------
    Function ShowForm(URL:PChar):integer;stdcall;
    begin
      GlobalAddAtom('MyFormCreate');
      Unit1.URL:=String(URL);  //我在这里定义的Form1
      MyForm:=TForm1.Create(nil);
      MyForm.Show;
      ShowForm:=1;
    end;
    //--------------------------------------------------------
    procedure MyExitProc;
    var
         gfa:ATOM;
    begin
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              MyForm.Free;
              GlobalDeleteAtom(gfa);
         end;
         ExitProc:=OldExitProc;
    end;
    //--------------------------------------------------------
    exports
          ShowForm;
    //--------------------------------------------------------
    begin
         OldExitProc:=ExitProc;
         ExitProc:=@MyExitProc;
    end.
    //--------------------------------------------------------
    //在Form1的onClose这样写。
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    var
         gfa:ATOM;
    begin
         Action:=caFree;
         gfa:=GlobalFindAtom('MyFormCreate');
         if (gfa<>0) then
         begin
              GlobalDeleteAtom(gfa);
         end;
    end;我已经试过,原封不动的运行我的上面这段代码是不可能出错的,不必传Application.Handle.
      

  26.   

    请注意看好:GlobalAddAtom('MyFormCreate');的位置变化。
      

  27.   

    我想不用这么做吧
     MyForm:=TForm1.Create(Application);
      MyForm.Show;TForm1的Owner改为Application
    然后再TForm1的OnClose中写
    Action := caFree;
    就可,因为在dll卸载时,会自动卸掉Application对象
    还有传一个Handle给Application对象,要不在任务栏会出现两个程序的东西
    PB我不知道传啥
      

  28.   

    好用了!谢谢wizardqi(男巫),谢谢!
    GlobalAddAtom('MyFormCreate');还用在加载DLL的begin,end之间写吗?
    象我说的,
    开始的时候ExitProc是什么呢?
    ExitProc:=@MyExitProc,我看了一下,MyExitProc里把ExitProc:=OldExitProc;好象是个圈呀?不明白了,请指教!
      

  29.   

    唉,真郁闷!
    现在子窗口关闭以后关闭主窗口是没有问题了,但是我想要的是开子窗口以后象开一个应用程序一样,不受制于任何程序了,用户关闭了就行了,现在把子窗口打开以后,关闭主程序会出错,是不是我问的问题用DLL根本就实现不了?
    还有,最后是要给PB用的,到底能实现不?唉!
      

  30.   

    DELPHI5开发人员指南上面有讲的
      

  31.   

    wizardqi(男巫) ,我想了一下,这么做,只把最原始的代码加一句(在Form1的Close事件里)
    Action:=caFree;
    就行了。原理应该是一样的吧。
      

  32.   

    to wx1452(),如过这个动态连接库在别的语言中调用试问哪来的Application对象?
    to 楼主 老兄我那样做是双保险,正如我说的
    --------------------------------------------------------------------------
    进程都被杀死了(DLL卸载了),而在它的空间内开辟的窗口资源(MyForm)还有可能
    没有关闭并释放,这是多么不安全的做法,不出错实在是侥幸。
    --------------------------------------------------------------------------
    窗体释放时会告诉发出广播(GlobalDeleteAtom(gfa)语句的功能)。
    在动态连接库卸载时会检测窗体是否释放,如果窗体释放了(接到广播),就直接退出,调用系统默认的卸载过程。如果窗体没有释放,就释放后退出。
      

  33.   

    wizardqi(男巫),首先谢谢您的帮助,我都不好意思了。
    我想问您最后一个问题,到底能不能实现象我说的,开窗口以后,主程序正常的退出,而开开的窗口正常的工作?
      

  34.   

    wizardqi(男巫):因为用delphi作的dll创建了窗体,就肯定要uses Forms吧
    uses Forms就会有一个Application全局对象这你知道吧,
    而uses了Forms,Forms就肯定uses了Controls吧
    而在
    Controls的initialization
    initialization
      NewStyleControls := Lo(GetVersion) >= 4;
      InitControls;
      ...InitControls里创建了Application对象
    在Forms的finalization段
      if Application <> nil then DoneApplication;
      ...procedure DoneApplication;
    begin
      with Application do
      begin
        if Handle <> 0 then ShowOwnedPopups(Handle, False);
        ShowHint := False;
        Destroying;
        DestroyComponents;
      end;
    end;
    也就是说不管dll是否被谁调用,dll本身如果创建了窗体,那Dll本身都
    有一个Application对象
    如果dll是被delphi程序调用,并且是Build With runtime package,并且主程序也是
    Build With runtime package,那么dll就和主程序共享一个Application
    反之则是两个独立的Application对象,这也是为什么一般要给dll
    传个主程序的Applicaiton.Handle的原因
    而如果pb调用我就不知道如何传了你问题想得有些复杂了
      

  35.   

    jmf2000(蜜蜂) :
    因为你的dll的窗体是存在于你的pb程序这个进程的地址空间的
    当pb程序关掉,窗体所在的地址空间都没了,怎么能不出错呢
    你如果实现那样的效果,何不如做成单独的delphi程序
    然后你的pb程序同delphi程序使用一些比如内存映像的东西
    进行通讯
      

  36.   

    to wx14520 你说的我也知道,愁的正是调用方不一定有Application对象。
      

  37.   

    最后我是这么写的
    往DLL里传了一个handle,然后在DLL里Application.handle=传进去的handle,
    create的时候要么是(nil),要么是(application)都行,问题就全解决了。