zoukankan      html  css  js  c++  java
  • dll 问题 (转)

    最近在公司写一个外壳程序,调用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窗体的Resize
    EXE主窗体改变尺寸时,窗体中的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;

    interface

    uses
      Windows, Messages, SysUtils,Forms;

    implementation

    var
      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,那个该死的应用程序图标又没了,焦虑中....
  • 相关阅读:
    Web API 强势入门指南
    毫秒必争,前端网页性能最佳实践
    Windbg Extension NetExt 使用指南 【3】 ---- 挖掘你想要的数据 Managed Heap
    Windbg Extension NetExt 使用指南 【2】 ---- NetExt 的基本命令介绍
    Windbg Extension NetExt 使用指南 【1】 ---- NetExt 介绍
    WCF : 修复 Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service 问题
    透过WinDBG的视角看String
    Microsoft Azure Web Sites应用与实践【4】—— Microsoft Azure网站的“后门”
    企业IT管理员IE11升级指南【17】—— F12 开发者工具
    WCF : 如何将NetTcpBinding寄宿在IIS7上
  • 原文地址:https://www.cnblogs.com/edrp/p/2437992.html
Copyright © 2011-2022 走看看