Win32 API对文本框发送消息(多个文本Edit,动态 控件 ID)


最近在群里有人说用Win32 Api不能对文本框设置内容(是别人写的一个程序,设置它的文本框的值).但是搞过win32的人都会说.这个应该不难啊,大概是搞.net的人,被微软 宠坏了.基本都不要用win32 api,这里我也不讨论用这个东西好不好,反正有人有这个需求,就要去做这个东西,我就自己建了一个工程,只要得到这个窗体的句柄,然后向他发送消息就搞定了,用到FindWindow,SendMessage搞定就可以了,我们所做的最核心的内容就是要找句柄.

要在win32 api下面使用FindWindow,SendMessage,必须这2个声明

代码
[DllImport("user32.dll",EntryPoint="FindWindow",SetLastError=true)]
publicstaticexternIntPtrFindWindow(stringlpClassName,stringlpWindowName);

[DllImport(
"User32.dll",EntryPoint="SendMessage",CharSet=CharSet.Auto)]
publicstaticexternintSendTextMessage(
IntPtrhWnd,
intMsg,
intwParam,
stringlParam
);

记得这里要加上CharSet,否则发送中文可能是乱码,调用的时候

查找窗体的句柄,然后再在这个窗体下面查找这个文本框的句柄,窗口我们是根据窗体的标题文本来查找,文本控件时根据控件的类型来找.

IntPtrhwndCalc=WinAPIuser32.FindWindow(null,"Form1aa");

IntPtrhwndtext
=WinAPIuser32.FindWindowEx(hwndCalc,0,"Edit",null);

设置文本

WinAPIuser32.SendTextMessage(hwndtext,MSCODE.WM_SETTEXT,0,"mextb1860第一个文本框");

轻松搞定了.很简单.

这个时候我想,窗体上只有一个文本框,也就是说一个Edit,查找起来是很方便,可是往往,我们在实际情况中,一个窗体上有很多文本框,我们要找到其中一个文本框设置它的值,这个时候你在用WinAPIuser32.FindWindowEx(hwndCalc,0,"Edit",null);就做不到了.因为他得到的,始终是最后一个 文本框的句柄,也就是说如果页面上有

3个文本,你使用这个时候只会获取到最后一个文本框的 句柄,如果你要设置第2个文本框你是做不到的,我们有2个办法,一个是EnumChildWindows方法来遍历下面的所有文本框,对这些文本框进行赋值,第2中方法就是 根据控件ID来查找句柄,在一个程序编译完成以后,也就是发布给客户用的时候,窗体上的控件ID就是固定的了,不可改变,我这里说的控件ID不是指.net的立面一个TextBox控件的ID,而是在windows下面,显现出来的ID,这样我们就可以通过固定的ID来查找,注意ID是固定的,不会再改变,这样我们就可以用GetDlgItem的方法来通过ID号来获取句柄,这里我们先讲第2中方法,第一种方法,比较复杂,而且后面我会用第一种方法来做一个非常特殊的演示,那就是如果控件ID时动态的时候,我们也如何获取句柄

[DllImport("user32.dll",EntryPoint="GetDlgItem")]
publicstaticexternIntPtrGetDlgItem(
IntPtrhDlg,
intnIDDlgItem
);

当然得到了句柄还有什么做不到的,对这3个文本发送消息,设置文本内容

代码
IntPtrhwndtext=WinAPIuser32.GetDlgItem(hwndCalc,1247226);
WinAPIuser32.SendTextMessage(hwndtext,MSCODE.WM_SETTEXT,
0,"mextb1860第一个文本框");

hwndtext
=WinAPIuser32.GetDlgItem(hwndCalc,1181678);
WinAPIuser32.SendTextMessage(hwndtext,MSCODE.WM_SETTEXT,
0,"mextb1860第二个文本框");

hwndtext
=WinAPIuser32.GetDlgItem(hwndCalc,919180);
WinAPIuser32.SendTextMessage(hwndtext,MSCODE.WM_SETTEXT,
0,"mextb1860第三个文本框");

一切很顺利,就像我们想的一样,3个文本框的内容都改变了,太好了,不过不要太高兴了,因为我们这里的ID是固定所以都硬编码进去了,在一般情况下是没有问题,因为大部分的都是固定的,这个时候我发现.net的程序的控件ID时随时改变的,而且每次运行一次ID都不一样,这个ID是跟着句柄改变,句柄是多少ID就是多少,老火啊.这回要根据ID来获取句柄是获取是行不通了,现在的情况是 一个页面多个Edit类控件的ID是动态的,程序每次运行都不一样,不固定.

关闭程序,再重新打开,在看下ID

那么我现在用第二种办法来解决,请出EnumChildWindows方法,这个方法比较特殊,有个一个参数是一个回调函数

[DllImport("user32.dll")]
publicstaticexternintEnumChildWindows(inthWndParent,CallBacklpfn,intlParam);

CallBack是一个委托

代码
[DllImport("user32.dll")]
publicstaticexternintEnumChildWindows(inthWndParent,CallBacklpfn,intlParam);
///<summary>
///回调业务
///</summary>
publicdelegatevoidCallBusiness(IntPtrhwnd);
publicdelegateboolCallBack(IntPtrhwnd,intlParam);
///<summary>
///遍历子窗体的父窗体句柄
///</summary>
publicstaticCallBackcallBackEnumChildWindows=newCallBack(ChildWindowProcess);
///<summary>
///委托业务,需要客户端添加
///</summary>
publicstaticCallBusinessCallFuntion;
///<summary>
///遍历子窗体或控件
///</summary>
///<paramname="hWnd"></param>
///<paramname="lParam"></param>
///<returns></returns>
publicstaticboolEnumChildWindows(IntPtrhWnd,intlParam)
{
EnumChildWindows(hWnd.ToInt32(),callBackEnumChildWindows,
0);
returntrue;
}
///<summary>
///获取类名字
///</summary>
///<paramname="hwnd">需要获取类名的句柄</param>
///<paramname="lpClassName">类名(执行完成以后查看)</param>
///<paramname="nMaxCount">缓冲区</param>
///<returns></returns>
[DllImport("user32.dll",EntryPoint="GetClassName")]
publicstaticexternintGetClassName(
IntPtrhwnd,
StringBuilderlpClassName,
intnMaxCount
);
///<summary>
///遍历子控件
///</summary>
///<paramname="hwnd"></param>
///<paramname="lParam"></param>
///<returns></returns>
publicstaticboolChildWindowProcess(IntPtrhwnd,intlParam)
{
if(CallFuntion!=null)
{
CallFuntion(hwnd);
}
returntrue;
}

EnumChildWindows用来遍历所有的子控件的句柄,有一个回调函数,CallBusiness也是一个代理,是提供给客户端调用的时候来编写逻辑的.代码很简单,应该很容易理解,客户端调用的代码,因为是.net开发的程序 所以 Edit的控件类型有点不一样,不过没关系,不影响我们查找

代码
List<IntPtr>list=newList<IntPtr>();
WinAPIuser32.CallFuntion
=delegate(IntPtrenumIntPtr)
{
StringBuilders
=newStringBuilder(2000);
WinAPIuser32.GetClassName(enumIntPtr,s,
255);
if(s.ToString()=="WindowsForms10.EDIT.app.0.378734a")
{
list.Add(enumIntPtr);
}
};
WinAPIuser32.EnumChildWindows(hwndCalc,
0);
WinAPIuser32.CallFuntion
=null;
//第1个文本框
WinAPIuser32.SendTextMessage(list[2],MSCODE.WM_SETTEXT,0,"mextb1860第一个文本框");
//第2个文本框
WinAPIuser32.SendTextMessage(list[1],MSCODE.WM_SETTEXT,0,"mextb1860第二个文本框");
//第3个文本框
WinAPIuser32.SendTextMessage(list[0],MSCODE.WM_SETTEXT,0,"mextb1860第三个文本框");

代码会提供下载,不明白的可以自己仔细看看.

/Files/mextb1860/WinAPITest.rar

优质内容筛选与推荐>>
1、Spring Boot参考教程(一) SpringBoot概述及Hello World
2、控件属性大全(持续更新)
3、正则之exec、test、match异同
4、P1039 大规模间谍入侵
5、【BZOJ 2705】 [SDOI2012]Longge的问题


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn