就任何一個程式員來說,對WINDOWS訊息機制的認知和對訊息的處理,可以說是必修的內容。我們知道,WINDOWS訊息的兩個參數wParam 、lParam有時是數實值型別,有時則是指標類型。特別是指標類型,它指向的是一個記憶體位址,那麼對它們的處理則因開發語言的不同而有所不同。
都說C#取消了指標(非安全模式例外),可我個人覺得,C#並沒有真正取消指標,只是把她裝扮得更加迷人罷了!而不需程式員通過 *p 之類去直接處理而已。
下面我就以一個常式,來看看C#中是如何處理WINDOWS訊息中指標類型的參數的。這個常式是AOGO曾經用MASM彙編來實現的,這就是限制一個表單大小的變化在一個許可的範圍內。本常式只限制寬度不超過600。
這裡主要涉及到兩個問題:
1. 如何取得指標所指向的記憶體位址中的內容?
2. 如何將指標指向新的內容?(也可能是將新內容複寫到指標所指向的記憶體位址中)
處理這兩個問題的方法哦是知道了,至於它的內部實現機制哦就不明白了 ^_^ ^_^ ^_^
有了這兩個方法,我們就可以對WINDOWS的任何訊息進行處理了。C#的厲害由此可見!!!
好啦,哦不多說啦。看源碼就啥都明白了
===================== Form1.cs =====================
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices; // 注意這個命名空間
namespace WinMsgApp
{
public class Form1 : System.Windows.Forms.Form
{
// 聲明Winodws訊息常量
private const int WM_SIZEING = 0x0214;
// 聲明RECT結構
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
// 以下是C# IDE自動產生的程式碼
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.TextBox textBox3;
private System.Windows.Forms.TextBox textBox4;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.textBox3 = new System.Windows.Forms.TextBox();
this.textBox4 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(80, 8);
this.textBox1.Name = "textBox1";
this.textBox1.TabIndex = 0;
this.textBox1.Text = "";
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(80, 32);
this.textBox2.Name = "textBox2";
this.textBox2.TabIndex = 1;
this.textBox2.Text = "";
//
// textBox3
//
this.textBox3.Location = new System.Drawing.Point(80, 56);
this.textBox3.Name = "textBox3";
this.textBox3.TabIndex = 2;
this.textBox3.Text = "";
//
// textBox4
//
this.textBox4.Location = new System.Drawing.Point(80, 80);
this.textBox4.Name = "textBox4";
this.textBox4.TabIndex = 3;
this.textBox4.Text = "";
//
// label1
//
this.label1.Location = new System.Drawing.Point(0, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(78, 23);
this.label1.TabIndex = 4;
this.label1.Text = "Left:";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label2
//
this.label2.Location = new System.Drawing.Point(0, 32);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(78, 23);
this.label2.TabIndex = 5;
this.label2.Text = "Top:";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label3
//
this.label3.Location = new System.Drawing.Point(0, 56);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(78, 23);
this.label3.TabIndex = 6;
this.label3.Text = "Right:";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label4
//
this.label4.Location = new System.Drawing.Point(0, 80);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(78, 23);
this.label4.TabIndex = 7;
this.label4.Text = "Bottom:";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(296, 117);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.label4,
this.label3,
this.label2,
this.label1,
this.textBox4,
this.textBox3,
this.textBox2,
this.textBox1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
// 自動產生的程式碼到此結束
// 以下是處理WINDOWS訊息的主要代碼
protected override void WndProc(ref System.Windows.Forms.Message m )
{
switch(m.Msg)
{
case WM_SIZEING:
// 第一種方法,簡潔明了
// RECT rc = (RECT)m.GetLParam(typeof(RECT));
// 第二種方法,易懂稍繁
RECT rc = new RECT();
// 將m.LParam指標所指向的RECT結構複製到rc
rc = (RECT)m.GetLParam(rc.GetType());
// 將結構rc各欄位的值顯示出來
textBox1.Text = rc.left.ToString();
textBox2.Text = rc.top.ToString();
textBox3.Text = rc.right.ToString();
textBox4.Text = rc.bottom.ToString();
// 限制表單寬度不超過600
if (rc.right - rc.left >600)
{
rc.right =rc.left +600;
}
// 將結構rc複製到m.LParam指標所指向的RECT結構
Marshal.StructureToPtr(rc,m.LParam,true);
break;
default:
base.WndProc(ref m); // 調用基類函數處理其他訊息。
break;
}
}
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}