============ 程式1 WinObject.cs using System; using System.Collections; using System.Runtime.InteropServices; using System.Text; using System.Drawing; using System.Windows.Forms; namespace MyApp { // 模擬API中的rect類別,.NET中的Rectangle不能直接套用 public struct Rect { public int left; public int top; public int right; public int bottom; public int Width { get { return right - left; } } public int Height { get { return bottom - top; } } } //將Windows API中視窗相關功能封裝為物件,非Thread-Safe! public class WinObject { IntPtr hWnd; //Window Handle public WinObject(IntPtr hWnd) { this.hWnd = hWnd; } //傳回Window Handle,此為建立物件時隨機產生的唯一代號 public IntPtr Handle { get { return hWnd; } } //傳回Class Name,類別名稱 public string ClassName { get { StringBuilder sb=new StringBuilder(128); GetClassName((int) hWnd,sb,sb.Capacity); return sb.ToString(); } } //傳回Rect以取得座標、大小等相關資訊 public Rect Rectangle { get { //取得座標位置 Rect rect=new Rect(); GetWindowRect(hWnd, ref rect); return rect; } } // 將目前的視窗物件帶為前景程式, 並取得焦點 public void BringWindowToTop() { if (IsIconic(hWnd)) //最小化時, 先還原 { int SW_RESTORE = 9; ShowWindow(hWnd,SW_RESTORE); } BringWindowToTop(hWnd); } //以類別名稱與視窗標題查詢所屬次一層的視窗物件 public WinObject FindChild(string className, string windowName) { return new WinObject( FindWindowEx(hWnd, IntPtr.Zero, className, windowName)); } //以類別名稱與視窗標題查詢直屬桌面的視窗物件 public static WinObject FindWindow(string className, string windowName) { return new WinObject(FindWindowWin32(className, windowName)); } // 傳送一個訊息給這個視窗物件 public long SendMessage(uint Msg, uint wParam, uint lParam) { return SendMessage(hWnd, Msg, wParam, lParam); } // 傳送一個訊息給這個視窗物件, 第二個參數為字串(只傳入不回傳值) public long SendMessage(uint Msg, uint wParam, string lParam) { return SendMessage(hWnd, Msg, wParam, lParam); } //傳回所屬的執行緒ID public uint ThreadId { get { uint dwProcessId=0; return GetWindowThreadProcessId(hWnd, ref dwProcessId); } } //傳回所屬的程序ID public uint ProcessId { get { uint dwProcessId=0; GetWindowThreadProcessId(hWnd, ref dwProcessId); return dwProcessId; } } //由類別名稱識別是否為特定的文字輸入控制項物件 public bool IsEditControl { get { string cn=ClassName.ToUpper(); return (cn=="EDIT" || cn=="THUNDERRT5TEXTBOX" || cn=="RICHCNTL" || cn=="RICHEDIT"); } } const uint WM_GETTEXTLENGTH=0x0e; const uint WM_GETTEXT=0x0d; const uint WM_SETTEXT=0x0c; //視窗物件的標題或控制項的文字內容 public string Text { get { if (IsEditControl) //文字輸入方塊物件用WM_GETTEXTLENGTH { int l=(int) SendMessage(hWnd,WM_GETTEXTLENGTH,0,0); StringBuilder sb=new StringBuilder(l+1); l=(int) SendMessage(hWnd,WM_GETTEXT,sb.Capacity,sb); return sb.ToString(); } else { int length = GetWindowTextLength(hWnd); StringBuilder sb = new StringBuilder(length + 1); GetWindowText(hWnd, sb, sb.Capacity); return sb.ToString(); } } set { if (IsEditControl) SendMessage(hWnd,WM_SETTEXT,0,value); else SetWindowText(hWnd, value); } } //Windows API,將視窗物件帶至前景 [DllImport("user32.dll")] static extern bool BringWindowToTop(IntPtr hWnd); //Windows API,以類別名稱與視窗標題尋找特定視窗之子視窗 [DllImport("user32.dll")] static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string windowName); //Windows API,以類別名稱與視窗標題尋找直接隸屬桌面之視窗 [DllImport("user32.dll", EntryPoint="FindWindow")] static extern IntPtr FindWindowWin32(string className, string windowName); //Windows API,傳送Message給特定視窗物件 [DllImport("user32.dll")] public static extern long SendMessage(IntPtr hWnd, uint msg, uint wParam, uint lParam); //Windows API,同上,最後參數可取回字串值,應用於WM_GETTEXT(直接用StringBuilder接回字串只適用於System Message 0-WM_USER,詳見SendMessage Function的MSDN說明) [DllImport("user32.dll")] public static extern long SendMessage(IntPtr hWnd, uint msg, int wparam, StringBuilder sb); //Windows API,同上,最後參數可傳入字串值,應用於WM_SETTEXT [DllImport("user32.dll")] public static extern long SendMessage(IntPtr hWnd, uint msg, uint wparam, string text); //Windows API,取得視窗標題 [DllImport("user32.dll")] static extern int GetWindowText(IntPtr hWnd, [In][Out] StringBuilder text, int copyCount); //Windows API,設定視窗標題 [DllImport("user32.dll")] static extern bool SetWindowText(IntPtr hWnd,[MarshalAs(UnmanagedType.LPTStr)] string text); //Windows API,取得視窗標題的長度,這是透過PInvoke取回字串時的必要前置作業 [DllImport("user32.dll")] static extern int GetWindowTextLength(IntPtr hWnd); //Windows API,取得視窗物件的類別名稱 [DllImport("user32.Dll")] public static extern void GetClassName(int h, StringBuilder s, int nMaxCount); //Windows API,取得座標及尺寸資訊 [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hwnd, ref Rect rectangle); //Windows API,取得所屬執行緒或程序之ID [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint processId); //Windows API,視窗是否被最小化 [DllImport("user32.dll")] static extern bool IsIconic(IntPtr window); //Windows API,改變視窗的狀態(最大化、最小化等) [DllImport("user32.dll")] private static extern int ShowWindow(IntPtr hWnd, int nCmdShow); } } ======== ============ // 程式2 模擬中文輸入動作,送出Message的原理請參考圖2-9 public static void KeyIn(WinObject win, string words) { const byte VK_PROCESSKEY = 0xe5; const int WM_CHAR = 0x102; keybd_event(VK_PROCESSKEY, 0x1c, 0, IntPtr.Zero); byte[] b=Encoding.GetEncoding("big5").GetBytes(words); for (int i=0; i===== ============ //程式3,IE URL輸入欄位(Edit控制項物件)的從屬架構請參考圖2-4 private void button1_Click(object sender, System.EventArgs e) { WinObject ie=WinObject.FindWindow("IEFrame",null); //找到IE視窗,標題為null表示不限定 ie.BringWindowToTop(); //帶至前景並取得焦點 //找到URL輸入方格(Textbox),其實是個Edit物件 WinObject addressEdit=ie.FindChild("WorkerW","").FindChild("ReBarWindow32","").FindChild("ComboBoxEx32",null) .FindChild("ComboBox","").FindChild("Edit",null); //由座標資訊找出TextBox在螢幕上的位置 Rect rect=addressEdit.Rectangle; //Double Click TextBox以取得輸入焦點 MouseAgent.DoubleClick(rect.left+2,rect.top+2,200); //傳入目標視窗及要輸入的字串內容 KbAgent.KeyIn(addressEdit,"可以填入中文了! Good job!"); } ========