Delphi中正常窗口的实现[2]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 cathyeagle 的 blog

为islibrary赋值的代码显然也应该放在某个单元的initialization代码段中,而且由于initialization代码段中的代码是按照包含的单元的顺序执行的,为了保证在application对象创建之前把islibrary赋值为true,在工程文件中我们必需将包含赋值代码的单元放在forms单元之前,如下(假设该单元名为unitdllexe.pas):

program template;

uses
  unitdllexe in 'unitdllexe.pas',
  forms,
  formmain in 'formmain.pas' {mainform},
  ...

unitdllexe.pas代码清单如下:

unit unitdllexe;

interface

implementation

initialization
  islibrary := true;
  //告诉applciation对象,这是一个动态链接库,不需要创建隐藏窗口。
end.

好了,编译运行一下,我们看到,由于没有创建隐藏窗口,原先任务栏上的系统菜单消失了,换成了主窗口的系统菜单,主窗口也能够与其它windows窗口正常排列平铺。但带来的问题是窗口无法最小化。怎么回事呢?还是老方法,跟踪一下。

2.3 主窗口最小化
最小化属于系统命令,最终必定是调用api函数defwindowproc来将窗口最小化,所以我们毫无困难地就找到了tcustomform中响应wm_syscommand消息的函数wmsyscommand,其中清楚地写到将最小化的消息重定向到application.wndproc去处理:

procedure tcustomform.wmsyscommand(var message: twmsyscommand);
begin
  with message do
  begin
    if (cmdtype and $fff0 = sc_minimize) and (application.mainform = self) then
      application.wndproc(tmessage(message))
  ...
  end;
end;

而在application.wndproc中,响应最小化消息时又调用了application的minimize方法,所以症结一定是在minimize过程。

procedure tapplication.wndproc(var message: tmessage);
  ...
begin
  ...
    with message do
      case msg of
        wm_syscommand:
          case wparam and $fff0 of
            sc_minimize: minimize;
            sc_restore: restore;
          else
            default;
  ...
end;

最后,找到tapplication.minimize,就一切都明白了。这里对于defwindowproc函数的调用没有产生任何效果,为什么呢?由于前面我们欺骗application对象,滤掉了createhandle的调用,没有创建application对象响应消息所需要的窗口,因此导致其句柄fhandle为0,调用当然不成功了。如果能将fhandle指向我们的应用程序主窗口就能解决问题。

procedure tapplication.minimize;
begin
  ...
      defwindowproc(fhandle, wm_syscommand, sc_minimize, 0);
      //这里fhandle值为0
  ...
end;

3 实现
borland的天才们无心插柳的设计再一次让我们找到了解决问题的办法。由前面的分析我们知道,在用vcl开发的动态链接库中并没有创建隐藏的窗口来接收windows消息(createhandle不执行),但在动态链接库中如果要显示窗口的话又需要一个父窗口。如何解决这个问题呢?vcl的设计者将保存看不见的窗口句柄的fhandle变量设计为可写,于是我们实际上可以简单地给fhandle赋一个值来为需要显示的子窗口提供一个父窗口。例如,在某个动态链接库插件中要显示窗体,我们通常会在主模块可执行文件中将application对象的句柄通过动态链接库的某个函数传入并赋值给动态链接库的application.handle,类似于:

procedure setapplicationhandle(mainappwnd: hwnd)
begin
  application.handle := mainappwnd;
end;

好了,既然aplication.handle实际上只是一个在内部用来响应消息的窗口句柄,而原本应该创建的看不见的窗口被我们去掉了,那我们只需要给出一个窗口的句柄,用来代替那个原本多余的隐藏窗口的句柄不就行了?这样的窗口去哪里找?应用程序的主窗口正是上上之选,于是有了下面的代码。

program template;

uses
  unitdllexe in 'unitdllexe.pas',
  forms,

本文关键:Delphi中正常窗口的实现
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top