我写了个Dll,里面导出Frame,Frame上有ListView,编译运行都没有问题,但鼠标一点ListView,就报错Control 'ListView' has no parent window这种问题怎么解决啊,难道,Dll中的Frame里不能用ListView?把ListView换成Memo就不会有这种错

解决方案 »

  1.   

    ListView需要一个有效的window handle
      

  2.   

    还是要看你具体如何操作的,如果单单放置一个listview组件而没有任何操作的话,应该不会有这种问题
      

  3.   

    可否考虑不用frame,用其他容器或窗体去实现frmae的功能
      

  4.   

    XXXX.ParentWindow   :=   AOwner.Handle;   //加上这一句   
      

  5.   

    Windows.SetParent(ChildHandle,ParentHandle);
    将ChildHandle对应的控件的父窗口设置为ParentHandle对应的控件P.S.楼主如果用DLL仅仅是为了模块化程序的话,推荐使用package(包)分割,用Dll的话,会遇到很多郁闷的问题一下是我收集的一些问题 及其解决办法,供楼主参考Cannot assign a TFont to a TFont
    主要是由于在创建Dll的Form时,将外部调用程序的Application、Screen和MainForm都传给了Dll并且将Dll中的这几个对象都替换掉了的缘故,解决的办法是只需将外部调用程序的Application.Handle及MainForm传给Dll并替换掉Dll中的这两项值就可以了,我已测试通过,可以试一试。如:   
      var       
      p:   PLongInt;   
        
      {DllApp:   TApplication   Dll中的Application   
        OutApp:   TApplication   外部调用程序的Application   
      }   
      p:=@(DllApp.MainForm);   
      DllApp.Handle   :=   OutApp.Handle;   
      p^:=LongInt(OutApp.MainForm);   The   DLL   will   not   use   the   same   classes   as   the   main   program   even   when   compiled   from   the   same   source.   Objects   will   look   the   same,   but   their   classes   will   not   compare   equal.   That's   why   assigning   a   TFont   value   from   the   DLL   to   a   TFont   property   in   the   main   program   (or   the   other   way   around)   doesn't   work:   the   Assign   procedure   is   looking   for   the   main   program's   TFont   class,   and   never   recognises   the   DLL's   TFont   object. 最近在公司写一个外壳程序,调用DLL插件把FORM嵌入到EXE中的一个PANEL中,其中遇到了不少的问题,大部分已经解决,还有几个至今没有找到解决方法,有待研究,也希望知道解决方法的富翁共享一下研究成果.  以下列出的问题及解决方法仅针对我写的程序(DLL插件把FORM嵌入到EXE中的一个PANEL中),和自己的解决方法.  从遇到的问题看出,DELPHI封装了太多的东西,有时候直接使用API会有意想不到的效果.
      经验:DLL与EXE之间的通讯应该全部使用消息. 
    第一个问题:Tab键和Enter键在DLL的FORM中无效 原始程序:
    //frmDll为DLL中的FORM,frmEXE为EXE主窗体,下同
    //下面的代码为什么直接引用Exe中的Form又引用Dll中的Form?只是为了方便阅读,实际只是传递一个句柄,下同
    //panWorkSpace为Exe中的一个TPanel,DLL中的窗体要嵌入其中
        frmDll.WindowState :=  wsMaximized;
        frmDll.BorderStyle :=  bsNone;
        windows.SetParent(frmDll.Handle,frmExe.panWorkSpace.Handle);发现Tab及Enter键在嵌入的FORM中无效,去掉
        frmDll.BorderStyle :=  bsNone;
    后正常,但我不需要标题,就用API解决
        frmDll.WindowState :=  wsMaximized;
        SetWindowLong(frmDll.Handle,GWL_STYLE,GetWindowLong(frmDll.Handle,GWL_STYLE) and not (WS_CAPTION or WS_THICKFRAME));
        windows.SetParent(frmDll.Handle,frmExe.panWorkSpace.Handle);
    其中WS_CAPTION和WS_THICKFRAME分别表示标题栏和边框,问题解决.  第二个问题:DLL窗体的ResizeEXE主窗体改变尺寸时,窗体中的Panel也会跟着变(Panel.Align设为了alClient),但其中嵌入的DLL窗体不会跟着变,解决方法:
    //exe窗口接收消息并改变子窗体大小
    //FChildWindowList为TList,子窗体的结构信息列表
    Type
      //子窗体一些信息的结构体
      PFormInfo     = ^TFormInfo;
      TFormInfo     = record
        Handle        : HWND;
        Parent        : HWND;
        Style         : HWND;
      end;  TfrmExe = class(TForm)
      private
        procedure WMSize(var Message:TWMSize);message WM_Size;
      end;procedure TfrmExe.WMSize(var Message: TWMSize);
    //ReSize消息
    var
      i   : Integer;
      rc  : TRect;
    begin
      inherited;
      if GetWindowRect(panWorkSpace.Handle,rc) then
        if Assigned(FChildWindowList) then
          for i :=  0 to FChildWindowList.Count - 1 do
            SetWindowPos(PFormInfo(FChildWindowList[i]).Handle, 0,
                0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top,
                SWP_NOACTIVATE);
    end;  第三个问题:焦点在DLL中的窗体时,切换到其它应用程序,再点击任务栏上Application对象的按钮,不能切换过来焦点在DLL中的窗体时,切换到其它应用程序,再点击任务栏上Application对象的按钮,不能切换过来,EXE主窗体不最小化,切换到其它程序,直接点嵌入的DLL窗体,DLL窗体获得焦点,发现Application对象在任务栏上的按钮是被按下去了,但是EXE窗体并没有被提到最前,还有,DLL窗体得到焦点时,EXE窗体的标题栏变为灰色,这些都是不符合使用习惯的,虽然不影响使用,但我觉得还是要解决.1.DLL窗体得到焦点时,EXE窗体的标题栏变为灰色的解决方法.
    DLL窗体
      TfrmDll=class(TForm)
      private
        procedure WMActivate(var Message : TMessage);message WM_ACTIVATE;
      end;procedure TfrmDll.WMActivate(var Message: TMessage);
    begin
      inherited;
      SendMessage(frmEXE.Handle, WM_NCACTIVATE, Integer(True), 0);
    end;2.焦点的问题解决方法
    把下面这个单元加入工程
    //==============================================================================
    // Unit Name: AppHandler
    // Author   : ysai
    // Date     : 2003-06-05
    // Purpose  : 处理焦点问题
    // History  :
    //==============================================================================unit AppHandler;interfaceuses
      Windows, Messages, SysUtils,Forms;implementationvar
      OldWProc      : TFNWndProc;function NewWndProc(
        Handle  : HWND;
        Msg     : Integer;
        wParam  : Longint;
        lParam  : Longint
        ):Longint; stdcall;
    begin
      Result  :=  0;
      case Msg of
        WM_ACTIVATEAPP  : //嵌入到主窗口的DLL中的窗口得到焦点不会把程序提前
          begin
            case wParam of
              0 : //应用程序失去焦点
                begin
                  if Assigned(Application.MainForm)
                      and (GetWindowLong(Application.Handle, GWL_EXSTYLE)
                      and WS_EX_TOOLWINDOW = 0) then
                    SendMessage(
                        Application.MainForm.Handle,
                        WM_NCACTIVATE,
                        Integer(False),
                        0);//失去焦点把标题栏变灰
                end;
              1 : //应用程序得到焦点
                begin
                  if Assigned(Application.MainForm)
                      and (GetWindowLong(Application.Handle, GWL_EXSTYLE)
                      and WS_EX_TOOLWINDOW = 0) then
                  SendMessage(
                      Application.MainForm.Handle,
                      WM_ACTIVATE,
                      WA_ACTIVE,
                      1);//注意,这里设为1,后面会用到
                end;  //case wParam
            end;
            Result := CallWindowProc(OldWProc, Handle, Msg, wParam, lParam);
          end;  //msg : WM_ACTIVATEAPP
        else
          Result := CallWindowProc(OldWProc, Handle, Msg, wParam, lParam);
      end;  //case msg
    end;initialization
      //取代应用程序的消息处理
      OldWProc    := TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC,
        Longint(@NewWndProc)));finalization
      //还原消息处理过程
      if OldWProc <> nil then
        SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(OldWProc));end.
    //单元结束//EXE程序主窗口
      TfrmEXE = class(TForm)
      private
        procedure WMActivate(var Message : TMessage);message WM_ACTIVATE;
      end;procedure TfrmExe.WMActivate(var Message: TMessage);
    //激话消息,Message.lParam=1时是OAAppHandler单元发来的,激活子窗口
    var
      hWindow : HWND;
    begin
      inherited;
      if Message.lParam = 1 then //如果是1就是AppHander发出的消息,将焦点设到活动子窗体
      begin
        hWindow :=  GetActiveChildWindowHandle;//这个函数得到活动子窗体
        //如果有子窗口而且不存在模态显示的窗体则把焦点移到子窗体上
        if (hWindow > 0) and IsWindowEnabled(Application.Handle) then
          windows.SetForegroundWindow(hWindow);
      end;
    end;  第四个问题:SpeedButton在DLL中鼠标离开不会恢复平面(ShowModal时不会出现)(未解决)SpeedButton.Flat设为真时,在DLL中鼠标离开不会恢复平面状态,而ShowModal时不会出现,不知道原因,应该是消息处理得不好,不知道有没有人解决过  又一个焦点问题:焦点在DLL窗体时,按Alt+Tab,对话框里出来的程序中竟然没有EXE程序!焦点在EXE窗体上时没问题,焦点在DLL窗体上时,用Alt+Tab不会出现EXE应用程序的图标,切换到其它任务后,也不能用Alt+Tab切换回来!这是个比较大的BUG,还未找到原因用spy++看了一下,按下Alt+Tab键,窗体收到了一个WM_CANCELMODE消息,我想,既然焦点在exe窗体上时可以看到图标,而在dll上看不到,那么我在收到这个消息时把焦点给设到exe上不就可以了?
      事实证明这点是可行的,代码如下:
      TDllForm = class(TForm)
      private
        procedure WMCancelMode(var Message : TMessage);message WM_CANCELMODE;
      end;procedure TDllForm.WMCancelMode(var Message: TMessage);
    //处理Alt+Tab键弹出的对话框中没有应用程序图标问题
    begin
      SetForegroundWindow(exeForm.Handle);  //把exe窗体设为当前有焦点的窗体
    end;  现在不论焦点在exe的窗体上还是dll的窗体上,按Alt+Tab出现的对话框中都有应用程序的图标,但不同的是,焦点在exe的窗体上时按Alt+Tab,默认激活的是下一个应用程序,而焦点在dll窗体上时按Alt+Tab,默认激活的是第一个,也就是应用程序本身,实际激活的是exe窗体.
      虽然还是不怎么习惯,但总算把它给弄出来了,以后有好的解决方法再贴上来.  Hint的问题(未解决)焦点在Dll中的窗体时,鼠标移动到控件上不会显示控件的Hint,而且Application.OnHint事件也不会发生,但是焦点在Exe窗体上时,把鼠标放在Dll窗体中的控件上却能显示Hint.原因还未找到:(  ALT+TAB解决了,但是那是键盘,鼠标操作还是有问题焦点在DLL中时,用鼠标点其它应用程序,失去焦点了,再按ALT+TAB,那个该死的应用程序图标又没了,焦虑中.... 
      

  6.   

    没用过Frame~
    不用它看看吧
      

  7.   

    我dll里面直接输出listview,parnet也设好,还是提示这个错,好像用了listview就是不行的
      

  8.   

    如果用个form,真接show出来是正常的,如果把这个form设置一个parent到panel,则又报这个错
      

  9.   

    那你就用form代替的你frame吧,你的panel是怎么创建出来的?
      

  10.   

    你可以试试带包编译
    如果dll仅仅是供Delphi写的程序使用的话,建议用package代替dll