如果用純 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”,如圖一所示,
圖一 子視窗最大化時的主視窗標題
當兩個視窗處於常態時,其畫面如圖二所示:
圖二 子視窗在常態時兩個視窗的標題