LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# 通过窗口句柄为指定窗口发送指令(user32.dll,mshtml)

admin
2023年9月14日 19:7 本文热度 701

本文中要处理两种窗体的句柄控制:

常规窗口:可以轻松获取到窗口的句柄信息,进而获取到窗口内的控件的句柄,以此类推最终获取到要定位的控件的句柄;

内嵌浏览内核:实际内容是一个网页,被包含在一个容器内。

Spy++

spy++(spyxx)是VS自带的开发工具,再VS安装目录下的tools文件夹下可以找到。它可以看到所有一已经打开的窗口的句柄。
使用方法:
Ctrl+F打开搜索窗口,鼠标拖动红框的图标,放到窗口上面,就可以获取到窗口的句柄信息:

 

点击确认可以看到详细信息:


点击同步可以自动定位到目录树上的位置:

 


在目录树上就可以看到这个窗口下的所有控件的句柄信息:

获取常规窗口的句柄并传输命令

在上面的方法中我们已经获取到了这个窗口的所有句柄信息。在这四个句柄中我们只关心开两个控件,即 确认Button 和 Edit输入框。目标确认,开始获取。我们要引用user32.dll中的本地方法,主要是下面四个:

//根据窗口类型或者窗口标题获取窗口句柄

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

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

 

//根据父窗口句柄、子窗口句柄、窗口类型、窗口标题 获取句柄

[DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]

private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

/// <summary>

/// 向指定句柄的窗口发送消息

/// </summary>

/// <param name="hWnd">窗口句柄</param>

/// <param name="Msg">消息类型</param>

/// <param name="wParam">消息1</param>

/// <param name="lParam">消息2</param>

/// <returns></returns>

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

private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);

 

//将指定句柄的窗口置顶

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

private static extern bool SetForegroundWindow(IntPtr hWnd);


上述SendMessage中的第二个参数Msg类型种类很多,我们主要使用以下两个:

const int WM_SETTEXT = 0x000C; //为指定句柄的窗口设置文本信息

const int WM_CLICK = 0x00F5; //为指定句柄的窗口发送点击事件


具体实现代码如下:

//根据窗口名称获取出啊港口句柄

IntPtr IPWnd = new IntPtr(0);

IPWnd = FindWindow(null, "运维客户端");

if (IPWnd != IntPtr.Zero)

{

    //根据找到的窗口  找到里面的输入框

    IntPtr txtWnd = new IntPtr(0);

    txtWnd = FindWindowEx(IPWnd, IntPtr.Zero, "Edit", null);

    if (txtWnd != IntPtr.Zero)

    {

        //如果找到了,就往里面输入文本信息

        SendMessage(txtWnd, WM_SETTEXT, IntPtr.Zero, "文本信息");

    }

 

    //对于存在相同类型的控件,寻找起来是相对麻烦一些的,因为他们没有独特的标志,但是有独自的index

    //如该例中的Button ,我们可以通过index获取想要的控件句柄

    //但是因为该按钮是第一个,所以默认找到的就是它,可以不做特殊处理

    //如果要按照INDEX获取 可以使用下面的 FindWindowByIndex 方法

    IntPtr buttonQRWnd = new IntPtr(0);

    buttonQRWnd = FindWindowEx(IPWnd, IntPtr.Zero, null, null);

    if (buttonQRWnd != IntPtr.Zero)

    {

        //将窗体置顶 点击事件要确保被点击的单位在最顶层,要不然点不到

        SetForegroundWindow(IPWnd);

        //在任何操作之前最好等待一下,在这里主要避免置顶操作还未完成就触发点击事件,从而导致点击失效

        Thread.Sleep(150);

        //给按钮发送点击消息

        SendMessage(buttonQRWnd, WM_CLICK, IntPtr.Zero, "");

    }

}

static IntPtr FindWindowByIndex(IntPtr hWndParent, int index)

{

    if (index == 0)

        return hWndParent;

    else

    {

        int ct = 0;

        IntPtr result = IntPtr.Zero;

        do

        {

            result = FindWindowEx(hWndParent, result, "Button", null);

            if (result != IntPtr.Zero)

                ++ct;

        }

        while (ct < index && result != IntPtr.Zero);

        return result;

    }

}


获取内嵌网页的窗体中的元素,并发送消息

获取句柄的步骤都是一样的,只不过在这种情况下我们基本上只能获取到最外层的窗体内容,里面的内容都是Html的,我们获取不到句柄,所以我们需要使用一个利器 mshtml,可以获取到指定句柄窗体内的 IHTMLDocument ,进而获取到指定元素。
通过 NuGet 安装 mshtml

基础使用代码如下:

//获取主窗口句柄

IntPtr LoginWnd = new IntPtr(0);

LoginWnd = FindWindow("OMClientPlus", null);

if (LoginWnd != IntPtr.Zero)

{

    //下面的操作都是为了找到最里面的控件的句柄

    //也就是sehlln内包含了shellView,shellView内又包含了ies ,最终ies才是承载html的容器控件

    //视情况按照Spy++中显示的控件包含关系确认最终的控件信息

    IntPtr shell = FindWindowEx(LoginWnd,IntPtr.Zero, "Shell Embedding",null);

    Thread.Sleep(50);

    IntPtr shellview = FindWindowEx(shell, IntPtr.Zero, "Shell DocObject View", null);

    Thread.Sleep(50);

    IntPtr ies = FindWindowEx(shellview, IntPtr.Zero, "Internet Explorer_Server", null);

    Thread.Sleep(50);

  

    //获取容器控件中的HtmlDoucument

    mshtml.IHTMLDocument2 id = GetHtmlDocument(ies.ToInt32());

 

    //获取到所有的Input类型的组件

    mshtml.IHTMLElementCollection inputs;

    inputs = (mshtml.IHTMLElementCollection)id.all.tags("input");

 

    //找到用户名

    mshtml.IHTMLElement accountElement = (mshtml.IHTMLElement)inputs.item("u",0);

    mshtml.IHTMLInputElement accountInputElement = (mshtml.IHTMLInputElement)accountElement;

    accountInputElement.value = account;

    Thread.Sleep(150);

 

    //找到密码

    mshtml.IHTMLElement passwordElement = (mshtml.IHTMLElement)inputs.item("p", 0);

    mshtml.IHTMLInputElement passwordInputElement = (mshtml.IHTMLInputElement)passwordElement;

    passwordInputElement.value = password;

    Thread.Sleep(150);

 

    //点击确认按钮

    mshtml.IHTMLElement login = (mshtml.IHTMLElement)inputs.item("Login", 0);

    login.click();

}

public mshtml.IHTMLDocument2 GetHtmlDocument(int hwnd)

 {

     System.Object domObject = new System.Object();

     int tempInt = 0;

     System.Guid guidIEDocument2 = new Guid();

     int WM_Html_GETOBJECT = Win32API.RegisterWindowMessage("WM_Html_GETOBJECT");//定义一个新的窗口消息

     int W = Win32API.SendMessage(hwnd, WM_Html_GETOBJECT, 0, ref tempInt);//注:第二个参数是RegisterWindowMessage函数的返回值

     int lreturn = Win32API.ObjectfromLresult(W, ref guidIEDocument2, 0, ref domObject);

     mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)domObject;

     return doc;

 }

如上就是mshtml 的简单用法,更多使用方法还需不断深入探索。


该文章在 2023/9/14 19:07:44 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved