C#+API實現指定表單啟用

來源:互聯網
上載者:User

不熟悉API使得我為了實現一個簡單的功能浪費了很長的時間,下面就把自己查閱的相關東西做個總結:

常用的處理表單的API函數如下(注意:API函數必須放在表單中...):

使用C#語言,要引用DllImport,必須要添加using System.Runtime.InteropServices命名空間

(1)獲得當前前台表單控制代碼

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();

傳回值類型是IntPtr,即為當前獲得焦點視窗的控制代碼

使用方法 :   IntPtr myPtr=GetForegroundWindow();

(2)枚舉所有螢幕上的頂層視窗,並將視窗控制代碼傳送給應用程式定義的回呼函數,利用該法可以獲得所有當前開啟的表單的控制代碼資訊 

[DllImport("user32.dll")]
public static extern  bool EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam);

其中lpEnumFunc指向一個應用程式定義的回呼函數指標;

lparam指向一個傳遞給回呼函數的應用程式的定義值;

回呼函數原型

bool CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lparam);

其中hwnd是一個頂層視窗的控制代碼

lparam是一個應用程式定義的一個值(即EnumWindows中lParam)

下面用一個例子對該方法說明
程式中要實現一個功能:可以在當前開啟的表單中找到目標表單,並在需要時將其啟用,置為前台表單
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.InteropServices;//調用DLLIMPORTnamespace EmuWindowInfor{    /// <summary>    /// 調用API的EnumWindows來枚舉視窗    /// </summary>    class Program    {
//定義控制代碼的全域變數
public int HANDLE; //定義回呼函數的委託 public delegate bool CALLBACK(int hwnd,int lparm); //用於擷取前台視窗控制代碼,設定當前視窗控制代碼 [DllImport("user32.dll")] public static extern int EnumWindows(CALLBACK x, int y); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int GetWindowText(int hWnd, StringBuilder lpText, int nCount); static void Main(string[] args) { CALLBACK myCallBack = new CALLBACK(Report); EnumWindows(myCallBack, 0); Console.ReadKey(); } //執行個體化回呼函數(可以在回呼函數中根據表單名稱找到目標表單控制代碼) public static bool Report(int hwnd,int lparm) { //分配空間 var sb = new StringBuilder(50); GetWindowText(hwnd, sb, sb.Capacity); //注意某些視窗沒有標題 if (sb.ToString() != String.Empty) Console.WriteLine(sb.ToString()); //if (sb.ToString() == "Microsoft PowerPoint - [les_03_使用_rman [相容模式]]") // Console.WriteLine(hwnd.ToString()); //回呼函數有傳回值 return true; } }}

以上代碼實現了通過表單名稱找到目標表單的控制代碼,再利用API函數SetForegroundWindow來將該表單啟用並前置

[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(int hWnd);

其中hWnd就是目標表單的控制代碼

(3)根據表單的類名和視窗的名稱獲得目標表單

[DllImport("coredll.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

其中lpClassName是要找的視窗的類

lpWindowName是要找的視窗的標題,當然在搜尋的時候不一定兩者都要知道,但至少要知道一個。根據視窗標題尋找的一般多用在多視窗的應用程式中,因為程式中的表單標題固定,方便搜尋。但要是對於系統中

的一些表單,例如記事本表單,PPT等,表單的標題是不定的,所以用視窗類別搜尋更方便。當然有關常見的視窗類別可以很方便找到,下面是一個搜尋當前開啟文字文件的視窗控制代碼的代碼

 

           IntPtr ParenthWnd = new IntPtr(0);            ParenthWnd = FindWindow(null,"Word Mobile");            //判斷這個表單是否有效            if (ParenthWnd != IntPtr.Zero)            {                MessageBox.Show("找到視窗");            }            else                MessageBox.Show("沒有找到視窗");

 

如果用VC開發平台,可以使用其中的Spy快速的找到視窗的類型,在Spy++中有一個FindWindow工具,它允許你使用滑鼠選擇視窗,然後Spy++會顯示這個視窗的類。

同時在微軟的協助文檔中也給出了對微軟常用OFFICE工具表單控制代碼尋找的方法,同樣是用FindWindow()方法,連結:http://support.microsoft.com/kb/302295/zh-cn

(4)尋找子表單的方法

[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindowEx( IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow )

其中hwndParent是要尋找子視窗的父視窗控制代碼,如果hwndParent為Null,則函數以桌面視窗為父視窗,尋找桌面視窗的所有子視窗;如果hwndParent是HWND_MESSAGE,函數僅尋找所有訊息視窗;

    hwndChildAfter :子視窗控制代碼。尋找從在Z序中的下一個子視窗開始。子視窗必須為hwndPareRt視窗的直接子視窗而非後代視窗。如果HwndChildAfter為NULL,尋找從hwndParent的第一個子視窗開始。如果hwndParent 和 hwndChildAfter同時為NULL,則函數尋找所有的頂層視窗及訊息視窗。

    lpszClass:指向一個指定了類名的空結束字串,或一個標識類名字串的成員的指標。如果該參數為一個成員,則它必須為前次調用theGlobaIAddAtom函數產生的全域成員。該成員為16位,必須位於lpClassName的低16位,高位必須為0。

    lpszWindow:指向一個指定了視窗名(視窗標題)的空結束字串。如果該參數為 NULL,則為所有視窗全匹配。傳回值:如果函數成功,傳回值為具有指定類名和視窗名的視窗控制代碼。如果函數失敗,傳回值為NULL。總之,這個函數尋找子視窗,從排在給定的子視窗後面的下一個子視窗開始。在尋找時不區分大小寫。

下面通過一個簡單的例子來說明對子視窗的尋找。相信大家都有QQ號,那麼就寫一個簡單的外掛:通過尋找QQ登陸視窗並類比按鍵實現QQ的自動登陸,以下只是介紹其中如何通過父表單尋找子表單

const int BM_CLICK = 0xF5;  IntPtr maindHwnd = FindWindow(null, "QQ使用者登入"); //獲得QQ登陸框的控制代碼  if (maindHwnd != IntPtr.Zero)  {      IntPtr childHwnd = FindWindowEx(maindHwnd, IntPtr.Zero, null, "登入");   //獲得按鈕的控制代碼      if (childHwnd != IntPtr.Zero)      {          SendMessage(childHwnd, BM_CLICK, 0, 0);     //發送點擊按鈕的訊息      }      else     {          MessageBox.Show("沒有找到子視窗");      }  }  else {      MessageBox.Show("沒有找到視窗");  

(5)找到表單後對其的簡單處理,比如開關,隱藏

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

其中ShowWindow(IntPtr hwnd, int nCmdShow);

nCmdShow的含義

0    關閉視窗

1    正常大小顯示視窗

2    已最小化的視窗

3    已最大化的視窗

(6)擷取視窗大小及位置

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;                             //最左座標
            public int Top;                             //最上座標
            public int Right;                           //最右座標
            public int Bottom;                        //最下座標
        }

樣本:

                    InPtr awin = GetForegroundWindow();    //擷取當前視窗控制代碼
                    RECT rect = new RECT();
                    GetWindowRect(awin, ref rect);
                   int width = rc.Right - rc.Left;                        //視窗的寬度
                   int height = rc.Bottom - rc.Top;                   //視窗的高度
                    int x = rc.Left;                                              
                    int y = rc.Top;

(7)常用操作:

GetClassName(
  hWnd: HWND;         {指定視窗控制代碼}
  lpClassName: PChar; {緩衝區}
  nMaxCount: Integer  {緩衝區大小}
): Integer;           {返回類名大小; 失敗返回 0}擷取指定視窗的類名 

GetNextWindow(
  hWnd: HWND; {指定的視窗控制代碼}
  uCmd: UINT  {指定的關係選項}
): HWND;      {失敗返回0; 成功返回符合的視窗控制代碼}
//uCmd 可選值:
GW_HWNDNEXT  = 2; {同層級 Z 序之下}
GW_HWNDPREV  = 3; {同層級 Z 序之上}擷取指定視窗Z上或Z下的視窗的控制代碼 

GetTopWindow(
  hWnd: HWND; {指定的視窗控制代碼}
): HWND;      {失敗返回0; 成功返回最頂層的子視窗控制代碼}擷取指定視窗的子視窗中最頂層的視窗控制代碼

GetWindow(
  hWnd: HWND; {指定的視窗控制代碼}
  uCmd: UINT  {指定的關係選項}
): HWND;      {失敗返回0; 成功返回符合的視窗控制代碼}

//uCmd 可選值:
GW_HWNDFIRST = 0; {同層級第一個}
GW_HWNDLAST  = 1; {同層級最後一個}
GW_HWNDNEXT  = 2; {同層級下一個}
GW_HWNDPREV  = 3; {同層級上一個}
GW_OWNER     = 4; {屬主視窗}
GW_CHILD     = 5; {子視窗}擷取與指定視窗具有指定關係的視窗的控制代碼 

GetWindowTextLength(
  hWnd: HWND {視窗控制代碼}
): Integer;  {返回視窗標題長度} 擷取視窗標題長度 

SetWindowText(
  hWnd: HWND;     {視窗控制代碼}
  lpString: PChar {新標題串指標}
): BOOL;設定視窗標題 

GetDesktopWindow: HWND; {無參數; 返回桌面視窗的控制代碼}

(8)還有個問題尚待解決

前面我們提到找到目標控制代碼後通過SetForeGroudWindow(int hwnd)方法可以將其啟用並設定為前台視窗,但是如果只是想將其啟用而不設定為前台的話就要用到函數SetActiveWindow()

但是使用該方法要特別注意,當在其他線程中對當前線程表單進行啟用使用該方法是沒有作用的。具體解決以後再給出,先去吃飯去......

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.