程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> C# 窗體常用API函數 應用程序窗體查找

C# 窗體常用API函數 應用程序窗體查找

編輯:C#基礎知識

常用的處理窗體的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);

如果coredll.dll,出現找不到,可以使用user32.dll代替

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

其中lpClassName是要找的窗口的類

lpWindowName是要找的窗口的標題,當然在搜索的時候不一定兩者都要知道,但至少要知道一個。根據窗口標題查找的一般多用在多窗口的應用程序中,因為程序中的窗體標題固定,方便搜索。但要是對於系統中的一些窗體,例如記事本窗體,PPT等,窗體的標題是不定的,所以用窗口類搜索更方便。當然有關常見的窗口類可以很方便找到,下面是一個搜索當前打開文本文檔的窗口句柄的代碼

IntPtr ParenthWnd = new IntPtr(0);
ParenthWnd = FindWindow(null,"窗口標題");
//或者用ParenthWnd = FindWindow("窗口類名",null);
//判斷這個窗體是否有效
if (ParenthWnd != IntPtr.Zero)
{
   MessageBox.Show("找到窗口");
}
else
{
   MessageBox.Show("沒有找到窗口");
}

可以使用工具AccExplorer32.exe來查找窗口所屬的類和窗體的標題。

如果用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; {無參數; 返回桌面窗口的句柄}

前面我們提到找到目標句柄後通過SetForeGroudWindow(int hwnd)方法可以將其激活並設置為前台窗口,但是如果只是想將其激活而不設置為前台的話就要用到函數SetActiveWindow()

但是使用該方法要特別注意,當在其他線程中對當前線程窗體進行激活使用該方法是沒有作用的。

想在找到目標窗體的前提下,讓目標窗體和其它窗體同時出現在桌面上,同時要保證只有目標窗體是處於激活狀態,也就是說只有目標窗體可以接受到模擬按鍵消息。終於找到了,可以通過SetForwardWindow(int handle)方法將目標窗體激活並處於最前窗體。同時利用另外一個API函數SetWindowPos來設置其他窗體,使其可以同處桌面。下面就簡單介紹下這個方法:

static extern bool SetWindowPos(
  HWND hWnd, //窗口句柄
  HWND hWndInsertAfter, //排列順序的句柄
  int X, //水平坐標
  int Y, //垂直坐標
  int cx, //寬
  int cy, //高
  UINT uFlags //窗口定位標識
  );

其中

返回值:

BOOL,如果返回值非零表示成功,返回零表示失敗。錯誤信息請參看GetLastError函數。

參數表:

參數 類型及說明 
hwnd HWND,欲定位的窗口句柄 
hWndInsertAfter HWND,置於hwnd前面的窗口句柄。這個參數必須是窗口的句柄或是下面的值之一:  HWND_BOTTOM 將窗口置於其它所有窗口的底部 
HWND_NOTOPMOST 將窗口置於其它所有窗口的頂部,並位於任何最頂部窗口的後面。如果這個窗口非頂部窗口,這個標記對該窗口並不產生影響 
HWND_TOP 將窗口置於它所有窗口的頂部 
HWND_TOPMOST 將窗口置於其它所有窗口的頂部,並位於任何最頂部窗口的前面。即使這個窗口不是活動窗口,也維持最頂部狀態

x:
int,指定窗口新的X坐標

Y:

int,指定窗口新的Y坐標

cx:

int,指定窗口新的寬度

cy:

int,指定窗口新的高度

wFlags:

UINT,指定窗口狀態和位置的標記。這個參數使用下面值的組合: SWP_DRAWFRAME 圍繞窗口畫一個框 
SWP_FRAMECHANGED 發送一條WM_NCCALCSIZE消息進入窗口,即使窗口的大小沒有發生改變。如果不指定這個參數,消息WM_NCCALCSIZE只有在窗口大小發生改變時才發送 
SWP_HIDEWINDOW 隱藏窗口 
SWP_NOACTIVATE 不激活窗口 
SWP_NOCOPYBITS 屏蔽客戶區域 
SWP_NOMOVE 保持當前位置(X和Y參數將被忽略) 
SWP_NOOWNERZORDER 不改變所有窗口的位置和排列順序 
SWP_NOREDRAW 窗口不自動重畫 
SWP_NOREPOSITION 與SWP_NOOWNERZORDER標記相同 
SWP_NOSENDCHANGING 防止這個窗口接受WM_WINDOWPOSCHANGING消息 
SWP_NOSIZE 保持當前大小(cx和cy會被忽略) 
SWP_NOZORDER 保持窗口在列表的當前位置(hWndInsertAfter將被忽略) 
SWP_SHOWWINDOW 顯示窗口 
備注:

如果設置了SWP_SHOWWINDOW或SWP_HIDEWINDOW標記,這個窗口不發生移動或改變大小。窗口成為最頂級窗口後,它的所有子窗口也會進入最頂級。一旦將其設為非最頂級,則它的所有子窗口也會轉為非最頂級。

程序中引用如下:

[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags
);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
static readonly IntPtr HWND_TOP = new IntPtr(0);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOZORDER = 0x0004;
const UInt32 SWP_NOREDRAW = 0x0008;
const UInt32 SWP_NOACTIVATE = 0x0010;
const UInt32 SWP_FRAMECHANGED = 0x0020;
const UInt32 SWP_SHOWWINDOW = 0x0040;
const UInt32 SWP_HIDEWINDOW = 0x0080;
const UInt32 SWP_NOCOPYBITS = 0x0100;
const UInt32 SWP_NOOWNERZORDER = 0x0200;
const UInt32 SWP_NOSENDCHANGING = 0x0400;
const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved