C# 窗体常用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);

如果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;

原文发布于微信公众号 - 我为Net狂(dotNetCrazy)

原文发表时间:2016-02-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一“技”之长

iOS多线程编程之一——NSThread线程管理

NSTread是iOS中进行多线程开发的一个类,其结构逻辑清晰,使用十分方便,但其封装度和性能不高,线程周期,加锁等需要手动处理。

953
来自专栏Python小屋

Python使用pycuda在GPU上并行处理批量判断素数

借助于扩展库pycuda,可以在Python中访问NVIDIA显卡提供的CUDA并行计算API,使用非常方便。安装pycuda时要求已正确安装合适版本的CUDA...

4393
来自专栏图形学与OpenGL

MessageBox和AfxMessageBox函数的区别(ZZ)

AfxMessageBox(“Are you sure?”,MB_YESNO|MB_ICONQUESTION); 2.与AfxMessageBox类似...

1054
来自专栏Pythonista

牛掰的python与unix

  加载subprocess模块仅仅是将可以使用的代码文件加载进来。也可以创建自己的模块或文件,拱以后重复使用,这与加载subprocess模块的方法相同。IP...

1162
来自专栏一个爱瞎折腾的程序猿

winform制作小工具的技巧

在使用winfrom制作一些工具的时候,一些基本设置都是去属性里面找来找去,一段时间就忘了,记录记录以备不时之需。

2203
来自专栏JackieZheng

探秘Tomcat——连接器和容器的优雅启动

前言: 上篇《探秘Tomcat——启动篇》粗线条的介绍了在tomcat在启动过程中如何初始化Bootstrap类,加载并执行server,从而启动整个tomc...

2428
来自专栏ASP.NETCore

使用Rx Framework实现XAML中的物体拖动

酝酿两年之后,微软发布了Reactive Extensions(Rx)库。Rx把事件驱动UI与LINQ、并发性和异步调用结合起来。

932
来自专栏博客园

讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute

转自:https://www.cnblogs.com/sheldon-lou/p/9495377.html

1172
来自专栏张善友的专栏

Autofac正式发布2.1版

Nicholas Blumhardt经过了2年多的开发,设计和试验,Autofac发布了第二版,针对1.4版本进行了重组,提供了更好的开发体验,你可以到这里下载...

20010
来自专栏MasiMaro 的技术博文

PE文件详解(四)

本文转自小甲鱼的PE文件详解系列原文传送门 到此为止,小甲鱼和大家已经学了许多关于 DOS header 和 PE header 的知识。接下来就该轮到Se...

1531

扫码关注云+社区

领取腾讯云代金券