如果用纯 c 代码编写,那么必须自己负责用 defframeproc 和 defmdichildproc 创建窗口;在 mfc 中则使用 cmdiframewnd/cmdichildwnd;.net 框架平台里则设置 form.ismdicontainer 和 form.mdiparent,不管用哪种方式,其核心都是 user kernel,尤其是 defframeproc,当 mdi 子窗口最大化时,它会联接父子窗口的标题文本来产生主窗口标题串。理解了这一点,下面我来示范如何改写mdi。这个例子的原始版本来自 msdn 库中用c#写的 scribble mdi(用 “scribble sample”搜索一下即可找到)。基本思路是首先在 scribble 例子的 mainwindow 中改写 wm_gettext 消息处理例程,必须添加两个数据成员:normaltext 和 maximizedtext,用它们来保存常态和最大化状态的标题 : // in scribble.cs, mainwindow class
private string normaltext = "scribble2"; private string maximizedtext = "window is now maximized"; 如果想让其它类存取这两个成员,那么可以通过属性机制代替数据成员,如:
private string normaltext;
public string normaltext { get { return normaltext; } set { normaltext = value; } } 因为在例子程序中 mainwindow 是唯一一个存取该字符串的类,所以没有必要使用属性机制。有了这两个新的数据成员,你要做的只是 改写 wm_gettext 处理例程,返回子窗口最大化状态以及常态时的标题文本。那么如何改写 wm_gettext 处理例程呢?
windows.forms 提供了一些 处理 wm_xxx 消息的虚拟函数,如 onresize/wm_size等,但是恰恰缺少与 wm_gettext 相关东东(ongettext/wm_gettext)。不要担心,没有虚函数,我们总是可以改写包罗万象的 wndproc 处理例程。为此必须知道所处理的消息id,也就是 wm_gettext 的消息 id = 0x000d,有人会问,你是怎么知道这个消息的 id 是 0x000d 啊,很简单,一种方法是运行 spy 获取,另一种方法是直接查找windows sdk 中的 winuser.h 头文件。一旦你能深入到 wndproc 这一层次编写代码,那么你基本上能用 c 语言写程序了,因为 win32 api 和其它语言之间所有东东通过 wparams 和 lparams 参数传递的,包括字符串在内。对于 wm_gettext 来说,message.lparam 是指向 char* 的指针,message.wparam 是该指针长度。也就是说你必须完成将文本串拷贝到调用者的缓冲里。好在这并不是太难,下面是程序代码:
public class mainwindow : system.windows.forms.form
{ private string normaltext = "scribble2"; private string maximizedtext = "window is now maximized"; // handle wm_gettext: return maximized or // normal text, depending on // state of active mdi child window. protected override void wndproc(ref message m) { const int wm_gettext = 0x000d; if (m.msg==wm_gettext) { form active = this.activemdichild; string s = active!=null && active.windowstate==formwindowstate.maximized ? maximizedtext : normaltext; char[] c = s.tochararray(); intptr buf = m.lparam; int len = c.length; marshal.copy(c, 0, buf, math.min((int)m.wparam, len)); m.result = (intptr)len; return; } base.wndproc(ref m); } ...... // rest of mainwindow unchanged from scribble sample } 经过上述的改动,现在运行程序,当mdi子窗口最大化时,主窗口标题显示的文本是“window is now maximized”,如图一所示,
图一 子窗口最大化时的主窗口标题 当两个窗口处于常态时,其画面如图二所示:
图二 子窗口在常态时两个窗口的标题 |