当我们启动一个程序,用 Process process = Process.Start(path);//path是程序的绝对路径
启动时,获取的process.Handle其实是进程的句柄,并不是窗口的句柄,而有时process.MainWindowHandle却等于0
此时就需要用枚举来获取启动进程的主窗口句柄了,代码如下
/// <summary>
/// 用于枚举子窗体是的委托
/// </summary>
/// <param name="WindowHandle">窗体句柄</param>
/// <param name="num">自定义</param>
/// <returns></returns>
public
delegate
bool
EnumChildWindow(IntPtr WindowHandle,
string
num);
/// <summary>
/// 获取指定窗体的所有子窗体
/// </summary>
/// <param name="WinHandle">窗体句柄</param>
/// <param name="ec">回调委托</param>
/// <param name="name">自定义</param>
/// <returns></returns>
[DllImport(
"User32.dll"
)]
public
static
extern
int
EnumChildWindows(IntPtr WinHandle, EnumChildWindow ecw,
string
name);
/// <summary>
/// 获取指定窗体的标题
/// </summary>
/// <param name="WinHandle">窗体句柄</param>
/// <param name="Title">缓冲区取用于存储标题</param>
/// <param name="size">缓冲区大小</param>
/// <returns></returns>
[DllImport(
"User32.dll"
)]
public
static
extern
int
GetWindowText(IntPtr WinHandle, StringBuilder Title,
int
size);
/// <summary>
/// 获取窗体类型
/// </summary>
/// <param name="WinHandle">窗体句柄</param>
/// <param name="Type">类型</param>
/// <param name="size">缓冲区大小</param>
/// <returns></returns>
[DllImport(
"user32.dll"
)]
public
static
extern
int
GetClassName(IntPtr WinHandle, StringBuilder Type,
int
size);
/// <summary>
/// 根据句柄获得进程id值
/// </summary>
/// <param name="handle">句柄</param>
/// <param name="pid"></param>
/// <returns></returns>
[DllImport(
"user32"
)]
private
static
extern
int
GetWindowThreadProcessId(IntPtr handle,
out
int
pid);
IntPtr mainHwnd = IntPtr.Zero;
//登录窗口句柄
string
typeName =
string
.Empty;
//启动程序的窗口标题
/// <summary>
/// 枚举窗体
/// </summary>
/// <param name="handle"></param>
/// <param name="num"></param>
/// <returns></returns>
private
bool
EnumChild(IntPtr handle,
string
num)
{
StringBuilder title =
new
StringBuilder();
//StringBuilder type = new StringBuilder();
title.Length = 100;
//type.Length = 100;
GetWindowText(handle, title, 100);
//取标题
//GetClassName(handle, type, 100);//取类型
if
(title.ToString() == typeName)
{
mainHwnd = handle;
return
false
;
}
return
true
;
}
//代码调用
pubilc boolTest()
{
FileVersionInfo myFileVersion = FileVersionInfo.GetVersionInfo(path);
typeName = myFileVersion.ProductName;
//获取程序产品名称
int
waitTime = 0;
while
(
true
)
{
EnumChildWindow ecw =
new
EnumChildWindow(EnumChild);
EnumChildWindows(mainWindowHandle, ecw,
""
);
GetWindowRect(mainHwnd.ToInt32(),
ref
rectMain);
int
pid = 0;
GetWindowThreadProcessId(mainHwnd,
out
pid);
//rectMain.Height - rectMain.Y < 300说明是登录窗口
if
(mainHwnd != IntPtr.Zero && process.Id == pid && rectMain.Height - rectMain.Y < 300)
//276
break
;
waitTime++;
//30秒没打开程序,登录失败
if
(waitTime >= 30)
return
false
;
Thread.Sleep(1000);
}
return
true
;
}
**********************************************************
在C#中使用API回调函数的方法就以EnumChildWindows和EnumChildProc为例子: 首先要声明EnumChildProc 为一个回调函数 public delegate bool EnumChildProc(int hwnd, IntPtr lParam); delegate为C#中的回调类型,相当于C++里面的CALLBACK,这样就可以在下面声明EnumChildWindows的时候在参数中使用EnumChildProc来作为一个类型。 声明调用user32.dll中的EnumChildWindows,如下: [DllImport("user32.dll", EntryPoint = "EnumChildWindows")] public static extern bool EnumChildWindows(int hwndParent, EnumChildProc EnumFunc, IntPtr lParam); 定义一个和EnumChildProc返回值和参数一样的函数: bool EnumCP(int hwnd,IntPtr lParam) { System.Text.StringBuilder sbClassName = new StringBuilder(255); GetClassName(hwnd, sbClassName, 255); if ("Static" == sbClassName.ToString()) { return false; } return true; } 这时就可以使用EnumChildWindows(hwnd, EnumCP, IntPtr.Zero); 当EnumCP返回true的时候,EnumChildWindow继续进行枚举窗口。当EnumCP返回false的时候,EnumChildWindow停止进行枚举窗口。
|