如果用纯 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”,如图一所示,
图一 子窗口最大化时的主窗口标题
当两个窗口处于常态时,其画面如图二所示:
图二 子窗口在常态时两个窗口的标题