C# 根据进程ID获取进程主窗口句柄

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 根据进程ID获取进程主窗口句柄相关的知识,希望对你有一定的参考价值。

我的进程是个隐藏窗口的进程,所以用Process.MainWindowHandle 无法获取到值,总是0。后来我在网上搜到了大家对于此类问题的处理方法,就是用枚举,API的EnumThreadWindows

虽然我能获取到句柄了,但是获取到的不是正确的句柄。这里的NRCServer进程是个exe程序,他的WindowState设置为Minimized,ShowInTaskbar 设置为 false 于是窗口被隐藏。所以我没能获取到它的MainWindowHandle,只有进程Id。并且在NRCServer进程启动的时候,弹出对话框显示了主窗口句柄,但是根据调用API函数获取到的句柄,不是显示的这个。

逐语句调试,发现,在EnumWindowsProc中,其实能获取到至少三个同Id号但是不同句柄的窗口。虽然这三个句柄都不是我的进程的,但是让我疑惑的是,怎么会有三个同Id的?另外,究竟该如何获取到正确的那个句柄?!
谢谢各位大虾,帮忙解答一下!

以下是一些获取窗口句柄的winapi,希望对你有点作用
/// <summary>
/// 查找一个窗口,返回此窗口的句柄
/// </summary>
/// <param name="lpClassName">要查找的窗口的类名,如果设为null,表示适配所有类</param>
/// <param name="lpWindowName">要查找的窗口的标题文本</param>
/// <returns>返回窗口的句柄,如果没找到,返回0</returns>
[DllImport("user32.DLL", EntryPoint="FindWindowW", SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long FindWindow(string lpClassName,string lpWindowName);

/// <summary>
/// 在窗口列表中寻找与指定条件相符的第一个子窗口
/// </summary>
/// <param name="hwndParent">在其中查找子的父窗口。如设为零,表示使用桌面窗口(通常说的顶级窗口都被认为是桌面的子窗口,所以也会对它们进行查找)</param>
/// <param name="hwndChildAfter">子窗口句柄。查找从在Z序中的下一个子窗口开始。子窗口必须为hwndPareRt窗口的直接子窗口而非后代窗口。如果HwndChildAfter为NULL,查找从hwndParent的第一个子窗口开始。如果hwndParent 和 hwndChildAfter同时为NULL,则函数查找所有的顶层窗口及消息窗口。</param>
/// <param name="lpszClass">要查找的窗口的类名,如果设为null,表示适配所有类</param>
/// <param name="lpszWindow">要查找的窗口的标题文本</param>
/// <returns>找到的窗口的句柄。如未找到相符窗口,则返回零</returns>
[DllImport("user32.DLL", EntryPoint="FindWindowExW", SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long FindWindowEx(long hwndParent,long hwndChildAfter,string lpszClass,string lpszWindow);

/// <summary>
/// 将指定的窗口带至窗口列表顶部。倘若它部分或全部隐藏于其他窗口下面,则将隐藏的部分完全显示出来。该函数也对弹出式窗口、顶级窗口以及MDI子窗口产生作用
/// </summary>
/// <param name="hwnd">欲带至顶部的那个窗口的句柄</param>
/// <returns>非零表示成功,零表示失败</returns>
[DllImport("user32.DLL", EntryPoint="BringWindowToTopW", SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long BringWindowToTop(long hwnd);

/// <summary>
/// 获得拥有输入焦点的窗口的句柄
/// </summary>
/// <returns>拥有焦点的那个窗口的句柄。如没有窗口拥有输入焦点,则返回零</returns>
[DllImport("user32.DLL", EntryPoint="GetFocus",SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long GetFocus();

/// <summary>
/// 搜索内部窗口列表,寻找隶属于指定窗口的头一个窗口的句柄
/// </summary>
/// <param name="hwnd">想在其中搜寻顶级子的窗口。零表示寻找位于桌面的顶级窗口</param>
/// <returns>Z序列中的顶级窗口也是内部窗口列表的第一个窗口</returns>
[DllImport("user32.DLL", EntryPoint="GetTopWindow",SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long GetTopWindow(long hwnd );

/// <summary>
/// 获得整个窗口的范围矩形,窗口的边框、标题栏、滚动条及菜单等都在这个矩形内
/// </summary>
/// <param name="hwnd">想获得范围矩形的那个窗口的句柄</param>
/// <param name="lpRect">屏幕坐标中随同窗口装载的矩形</param>
/// <returns>非零表示成功,零表示失败</returns>
[DllImport("user32.DLL", EntryPoint="GetWindowRect",SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long GetWindowRect(long hwnd,RECTAPI lpRect);

/// <summary>
/// 返回包含了指定点的窗口的句柄。忽略屏蔽、隐藏以及透明窗口
/// </summary>
/// <param name="xPoint">x点值</param>
/// <param name="yPoint">y点值</param>
/// <returns>包含了指定点的窗口的句柄。如指定的点处没有窗口存在,则返回零</returns>
[DllImport("user32.DLL", EntryPoint="WindowFromPoint",SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.StdCall)]
public static extern long WindowFromPoint(long xPoint,long yPoint);
参考技术A 给窗体设置一个Text,比如this.Text=“隐藏窗口”;然后用API直接找名字,一下就能找到了。 参考技术B 不太清楚你是要获取别的进程的句柄还是你自己程序的句柄
你自己程序的话可以用Application访问所有Windows窗口,然后Windows窗口上面有Handle就可以获取了追问

是我自己的程序。handle我的确可以获取,可是我需要的是主窗口句柄:MainWindowHandle

追答

你的这个主窗口是什么意思?Application有个MainWindow属性

追问

一个进程......

追答

就是说你要获取另一个进程的主窗口?貌似.net有安全机制,没办法让你直接访问到另外进程的句柄
你是否能看到你的目标进程的window结构,用spy++看看,说不定是找的过程有问题

追问

这是我在Spy++上找到的,但是看不懂(>_<)

 

追答

有title的,你可以看看它的结构,前面)009那个就是句柄,你找找看哪个是你所谓的主窗口

追问

找到了:

 

是句柄为00141222的那个

 

追答

如果你知道地址的话,可以直接使用IntPtr构建一个句柄出来

追问

地址我之前试过获取,可以得到。怎么用IniPtr构建啊?

追答

直接转换就可以了

追问

不知道你说的是不是这个进程的主模块内存地址?是的话,这个Process类获取到的这个值就是IntPtr类型啊。但是与窗口句柄不等。

追答

不是,模块的句柄和你的主窗体的句柄是不同的

追问

哦,这样啊,那我应该获取哪个地址?

本回答被提问者采纳

以上是关于C# 根据进程ID获取进程主窗口句柄的主要内容,如果未能解决你的问题,请参考以下文章

C#获取当前窗体句柄及该窗体里的信息

如何从进程 ID 获取主窗口句柄?

如何从进程 ID 获取主窗口句柄?

.NET (C#):只有进程句柄或 PID 时获取子窗口?

c# 怎样获得想要的线程ID

获取进程所有窗口的句柄