c# 设置窗体句柄

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# 设置窗体句柄相关的知识,希望对你有一定的参考价值。

假设有两个程序,启动后分别形成进程一,进程二。
能否在获取到进程二的主窗体句柄后,
将进程二的主窗体句柄设置为进程一主窗体句柄的子句柄。
从而达到将进程二主界面嵌入进程一主界面中的效果。

在c#里面我都没有查找到设置窗体句柄的api,是不是c#本身没有提供这样的啊?
是不是一定需要调用win32的api呢?

C#中有求窗体的句柄方法
Form.Handle
你所说的
将进程二主界面嵌入进程一主界面中
有难度,设置句柄不可能的,完全俩进程

效果可以通过进程间通讯实现
说来复杂了
参考技术A 路过,只知道MDI可以包含窗体.. 参考技术B 要不要导入命名空间,我也不怎么懂句柄 参考技术C C#没有试过,用win32也不麻烦啊。

C#调用win32 api 操作其它窗口

 


实现以下功能:

  1. 找到窗体
  2. 找到控件(也叫子窗体
  3. 获取内容
  4. 获取位置
  5. 设置
    • 位置
    • 内容
  6. 鼠标点击

示范

1. 找窗体

以操作系统自带的计算器为例

string clWindow = "CalcFrame"; //整个窗口的类名

string tlWindow = "计算器"; //窗口标题

IntPtr ParenthWnd = FindWindow(clWindow, tlWindow);

这样就得到了窗口的句柄 ParenthWnd ,如果 ParenthWnd==IntPtr.Zero 说明没有找到窗体;

[DllImport("User32.dll", EntryPoint = "FindWindow")]

public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

参数 lpClassName,lpWindowName 可以只填写一个,但另一个需要填写: null 而不是 :"" (即 string.Empty)。

如果同时开了几个同样的窗口,比如启动了2个 计算器, 那返回的句柄是哪个的呢 ? 答案是:最顶层的那个。

1、如果计算器2界面,在计算器1界面的前面,那么会返回计算器2的句柄。 2、如果两个计算器界面是并排的,即不存在重叠(包括部分重叠), 先切换计算器1,然后切换计算器

2,然后切换别的程序,会返回计算器2的句柄,反之返回计算器1的句柄。

这个问题说的可能是Windows系统界面里某个名词的概念,如顶层窗口,Z次序,活动窗口。但我不是特别明白,姑且举例说明实际情况了。

2. 找控件,获取内容,获取位置

[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, 
string lpszClass, string lpszWindow);

这个函数使用起来比较麻烦,hwndParent 指的是目标控件的直接上级的句柄,有时候你知道窗口的句柄还不行,还需要知道之间的层级关系,逐层查找才行。这里举例说明一下怎么用 :

FindWindowEx(ParenthWnd, IntPtr.Zero, "TPanel", "打印预览");

我想说的是:参数 hwndChildAfter 可以写 IntPtr.ZerolpszClasslpszWindow 可以为null 。

我一般是用枚举的方法:枚举得到这个窗口的所有句柄列表,然后筛选这个列表,从而得到想要的句柄。 上代码:

[DllImport("user32.dll", ExactSpelling = true)]
public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, int lParam);

[DllImport("user32.dll")]
public static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll")]
public static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);



public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);

public struct WindowInfo
{
    public IntPtr hWnd;//句柄
    public string szWindowName;//窗口名
    public string szClassName;//类名
    public System.Drawing.Rectangle Rect;//位置大小信息
}

List<WindowInfo> EnumChildWindowsCallback(IntPtr handle)
{
    //用于保存句柄列表
    List<WindowInfo> wndList = new List<WindowInfo>();
    win32Api.EnumChildWindows(handle, delegate (IntPtr hWnd, int lParam)
    {
        WindowInfo wnd = new WindowInfo();
        StringBuilder sb = new StringBuilder(256);
        //get hwnd 
        wnd.hWnd = hWnd;
        //get window name 
        GetWindowTextW(hWnd, sb, sb.Capacity);
        wnd.szWindowName = sb.ToString();
        //get window class 
        GetClassNameW(hWnd, sb, sb.Capacity);
        wnd.szClassName = sb.ToString();
        RECT rect = new RECT();
        if (GetWindowRect(hWnd, ref rect) == true)
            wnd.Rect = rect.ToRectangle();

        wndList.Add(wnd);
        return true;
    }, 0);

    //这里已经得到句柄列表 “wndList” ,对wndList进行筛选即可。
    return wndList;
}

以上是关于c# 设置窗体句柄的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

C# 获取窗体的句柄和获取窗体中的空间

获取当前进程(程序)主窗体句柄并设置wpf的父窗体为此句柄

获取当前进程(程序)主窗体句柄并设置wpf的父窗体为此句柄