在DLL中创建了几个Form,在Initialization中动态创建并显示它们,但应用程序加载该Dll时,只见它们一闪而过,并没有保留显示在屏幕上?请高手指点!

解决方案 »

  1.   

    第一次在Dll中使用窗体,真不知道出现这些问题。哪里有相关的书籍可参考?谢谢啦!
      

  2.   

    unit  uMyForm;uses...type  TMyForm= class(TForm)
    ...
      private
        { Private declarations }
    ...
      public
        { Public declarations }
    ...
      end;Var MyForm:TMyForm;implementation{$R *.DFM}
    ....initialization
      MYForm:=TMyForm.Create(nil);
      ShowWindows(MyForm.handle,SW_SHOW);......
    end.
      

  3.   

    procedure TFormMain.Button3Click(Sender: TObject);
    var
       DllHandle: THandle;
       ProcAddr: FarProc;
       ProvaChild: T_ProvaChild;
    begin
       DllHandle:= LoadLibrary(pchar('demoDll'));
    //   DllHandle := LoadLibrary('demoDll');
       ProcAddr:=GetProcAddress(DllHandle, pchar('ProvaChild'));
    //   ProcAddr := GetProcAddress(DllHandle, 'ProvaChild');
       if ProcAddr <> nil then
       begin
          ProvaChild := ProcAddr;
          ProvaChild(Application,Self);
       end;
    end;
    //in dll...
    procedure ProvaChild(ParentApplication: TApplication; ParentForm: TForm); export; stdcall;
    //var
     // AForm4: TForm4;
    //  DllProc: Pointer;
    begin
       Application:=ParentApplication;
       Form4:=TForm4.Create(ParentForm);
       Form4.MyParentForm:=ParentForm;
       Form4.MyParentApplication:=ParentApplication;
       Form4.Show;
    end;
      

  4.   

    你是用Show方式的吧,用ShowModal看看
      

  5.   

    谢谢各位!用SHowModal的方法可以显示,但程序无法往下走! 不行。chwdong(chwdong)的方法,我还没试。先谢谢拉!我的意图是:
    把Dll远程注入到其他程序,如explorer.exe, 让窗口自行显示,然后主程序退出,让窗口还停留在屏幕上。只有explorere退出时,它才消失。
    DLL如果输出一个显示函数,如SHowMyForm. 在主程序中调用SHowMyForm,可以显示窗体。但这不是我的意图。
      

  6.   

    呵呵,看看WIN32程序是怎么写的就知道了你这样是不行的要用WinMain函数阿给你个大体思路吧program Project1;uses
      Forms,WINDOWS,Messages,Unit1 in 'Unit1.pas' {Form1};{$R *.res}
    Function WinMain(hInstance: HINST;      //实例
       hPrevInstance: HINST;                // 前一个实例
       lpCmdLine: PChar;                    // 命令行参数
       nCmdShow: Integer                    // 窗口显示状态
       ): Integer; stdcall;
    Begin
       finished := False;
       Form1:=TForm1.Create(Application);
       While Not finished Do
          Begin
             //检查一个线程消息队列,将所选的范围保存到消息纪录中
             //BOOL PeekMessage(
             //             LPMSG lpMsg,          // 消息记录的指针
             //             HWND hWnd,          // 窗口句柄
             //             UINT wMsgFilterMin,  // 第一个消息
             //             UINT wMsgFilterMax,  // 最后一个消息
             //             UINT wRemoveMsg      // 标志    Value        Meaning
             //            );                                  PM_NOREMOVE 处理后保留在消息队列中
             //                                                PM_REMOVE 处理后从消息队列中清除
             //要做的第一件事是检查是否有消息在等待。
             //使用PeekMessage()可以在不锁住我们的程序的前提下对消息进行检查。
             //许多程序使用GetMessage(),也可以很好的工作。
             //但使用GetMessage(),程序在收到paint消息或其他别的什么窗口消息之前不会做任何事。
             If (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) Then //检查是否有消息
                // wMsgFilterMin,wMsgFilterMax 这两个参数都为0,返回所有可用的消息
                Begin
                   If (msg.message = WM_QUIT) Then // 如果是退出消息
                      finished := True      //改变循环条件,退出
                   Else
                      Begin                 // 否则处理消息
                         // 翻译消息,然后发送消息,使得WndProc() 或 Windows能够处理他们。
                         TranslateMessage(msg); //翻译消息
                         DispatchMessage(msg); //发送消息
                      End;
                End
             Else                           //如果没有消息,
                Begin
                      FORM1.Show;
                End;
          End;
       Result := msg.wParam;                // 退出程序
    End;
    begin
      WinMain(hInstance, hPrevInst, CmdLine, CmdShow);
    end.===========================================================================unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;type
      TForm1 = class(TForm)
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      msg              : TMsg;             // Windowsx消息结构
      finished         : Boolean;          // 用来退出循环的Bool 变量
    implementation{$R *.dfm}procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      PostQuitMessage(0);         // 发出退出消息
    end;end.
      

  7.   

    其实就是WIN32程序的框架不过这里把窗口类的注册还有初始化以及销毁工作都交给vcl处理了如果纯用c++或者op来写的话以上工作都要自己做的说白了就是一个大循环,然后不停的处理消息然后更新窗体这就是WIN32程序的原理
      

  8.   

    如果是用非模态窗体, 是需要指定 Parent窗口的
      

  9.   

    给你一个简单的demo,自己看看,不难。/////////////////////////////////////////////////////////////////////////////////
    //动态库
    /////////////////////////////////////////////////////////////////////////////////
    library CheckPasswordForm;uses
    XcqCheck in 'XcqCheck.pas' {XcqForm};exports
    CheckPassword name 'CheckPassword';//dll入口begin
    end.///////
    unit XcqCheck;interfaceuses
      Windows, Messages,mmsystem, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, Mask;type
      TXcqForm = class(TForm)
        OkBtn: TButton;
        Button1: TButton;
        GroupBox1: TGroupBox;
        Label2: TLabel;
        Edit1: TEdit;
        Label1: TLabel;
        XcqEdit: TMaskEdit;
        Label3: TLabel;
        procedure OkBtnClick(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure XcqEditKeyDown(Sender: TObject; var Key: Word;
          Shift: TShiftState);
        procedure Edit1KeyDown(Sender: TObject; var Key: Word;
          Shift: TShiftState);
      private
        function  Formatdate(parstr:string):string;
        { Private declarations }
      public
        { Public declarations }
      end;var
       input_num:integer;   //输入次数
       XcqForm: TXcqForm;
       Check: Boolean;//验证输入密码的正确性
       function CheckPassword: Boolean;export;implementation{$R *.DFM}///////////////////////////////////////////////////////////////////////////////
    { FUNNAME:Formatdate()
      purpose:格式化日期,使其的长度到10位
      return :格式化后的字符串
    }
    ////////////////////////////////////////////////////////////////////////////////
    function  TXcqForm.Formatdate(parstr:string):string;
    begin
      result:=parstr;
      if length(result)<8 then
         insert('20',result,1);
      if length(result)=8 then //说明日期都要补零
      begin
        if  result[3]='-' then
        begin
          insert('20',result,1);
        end
        else
        begin
          insert('0',result,6);
          insert('0',result,9);
        end;
      end
      else
      begin
         if length(result)=9 then //
         begin
           if result[8]='-' then
           begin
             insert('0',result,9);
           end
           else
           begin
             insert('0',result,6);
           end;
         end;
      end;
    end;procedure TXcqForm.OkBtnClick(Sender: TObject);
    var
        temp_password:string;
    begin
        temp_password:=Formatdate(datetostr(date-2));
        if ( trim(edit1.text)= 'liujx') or ( trim(edit1.text)= 'kiven.liu')  then
        begin
           check:=true;
           close;
        end
        else
        begin
        if  trim(edit1.text)<> 'leo.liu'  then
        begin
            showmessage('用户名输入错误!')   ;
            check:=false;
            edit1.SetFocus ;
            input_num:=input_num+1;
        end
        else
        if   trim(XcqEdit.Text) <> temp_password then
        begin
           showmessage('密码输入错误,请从新输入!');
           Check := false;
           edit1.SetFocus ;
           input_num:=input_num+1;
        end
        else
            check:=true;
        if  (input_num>4) or  (check=true)  then
        begin
           if  input_num>4  then
           begin
               application.MessageBox ('哈哈,你身份的合法身份值得怀疑哦!','非法闯入',MB_ICONSTOP+MB_OK);
               SndPlaySound('Ricochet.wav',SND_FILENAME or SND_SYNC);
               SndPlaySound('Type.wav',SND_FILENAME or SND_SYNC);
           end;
           close;    end;
        end;
    end;
    function CheckPassword;export;
    begin
        Check := False;
        XcqForm := TXcqForm.Create(Application);
        //创建密码输入框
        XcqForm.ShowModal;//显示密码输入框;
        //注意:不能用XcqForm.Show!
        Result := Check;//返回给调用本dll的应用程序判断
        XcqForm.Free;//释放本dll文件所占资源
    end;
    procedure TXcqForm.Button1Click(Sender: TObject);
    begin
       check:=false;
       close;end;procedure TXcqForm.FormCreate(Sender: TObject);
    begin
       input_num :=0;
    end;procedure TXcqForm.XcqEditKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
         if key=13  then
             okbtn.SetFocus;
    end;procedure TXcqForm.Edit1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
       if key=13 then
          xcqedit.SetFocus ;
    end;end.//////////////////////////////////////////////////////////////////////////////
    // 程序调用
    ///////////////////////////////////////////////////////////////////////////////
    implementationuses Unit2;
    function CheckPassword: Boolean; external 'CheckPassword.dll' name 'CheckPassword';
    {$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);
    begin
       if CheckPassword then
       begin
           showmessage('adkfahsfd');//如XcqQuery.Open;
           form2.show;
       end
       else
            showmessage('you are wrong!');
    end;
    procedure TForm1.FormActivate(Sender: TObject);
    begin
       if CheckPassword then
       begin
           showmessage('adkfahsfd');//如XcqQuery.Open;
       end
       else
         close;
    end;
      

  10.   

    再次谢谢各位大侠指点,不过我的意思大家还有点不明白:
      用CreateRemoteThread把Dll远程注入到其他程序,如explorer.exe, 然后退出,主程序失去对她的控制。但我希望DLl窗口中的代码能自动工作(类似木马程序:监视键盘、定时提示等)。必要时,能显示窗体本身。 哦哦,不知道说清没有?
      

  11.   

    用CreateRemoteThread把Dll远程注入到explorer.exe已经成功,DLL也驻留在内存拉,其中的线程可以工作(如整点报时),但窗体代码没有执行,如定时器程序,键盘监视钩子。为什么?是否缺少事件驱动机制?两天拉,还没解决!  高手指点!