C#+API實現指定窗體激活


不熟悉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;//調用DLLIMPORT

namespace 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()

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM