都9102年了,还要用弄Win32 API--记某IC卡读卡器使用Win32 API模拟操作开发心得

举报
motozilog 发表于 2019/03/12 17:18:43 2019/03/12
【摘要】 都云时代了,前段时间做一个IC卡读卡器的辅助工具。其中用到了Win32 API和C# WebBrowser的爬虫,记录并分享一下。

都云时代了,前段时间,因为公司突然来了一大批IC卡读卡器要制作,而且只有1个星期时间进行制作,某部门的苦苦哀求下答应帮他们做一个IC卡读卡器的辅助工具。

这个读卡器原厂的附带的制作工具,操作步骤居然有12()!并且既有WinXPexe(只能WinXP,不支持Win7……),又有Web端。其实难点在于WinXPexe端,要模拟菜单点击、键盘输入、鼠标点击。而Web端嘛,再不行就直接用python bs4嘛(不过最后也用C#成功弄了爬虫)。记录一下整个开发调试过程。

image.png

首先理解一个概念:句柄

句柄是Windows用来标志应用程序中建立的或是使用的唯一整数(相当于唯一的ID)Windows大量使用了句柄来标识对象,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。应用程序能够通过句柄访问相应的对象的信息,但是句柄不是指针,程序不能利用句柄来直接阅读文件中的信息。

 

获取句柄通常采用2Win32 API函数:

FindWindow(

  lpClassName,        {窗口的类名}

  lpWindowName: PChar {窗口的标题}

): HWND;              {返回窗口的句柄; 失败返回 0}

 

//FindWindowEx FindWindow 多出两个句柄参数:

FindWindowEx(

  Parent: HWND;     {要查找子窗口的父窗口句柄}

  Child: HWND;      {子窗口句柄}

  ClassName: PChar; {}

  WindowName: PChar {}

): HWND;

{

如果 Parent 0, 则函数以桌面窗口为父窗口, 查找桌面窗口的所有子窗口;

如果  HWND_MESSAGE, 函数仅查找所有消息窗口;

子窗口必须是 Parent 窗口的直接子窗口;

如果 Child 0, 查找从 Parent 的第一个子窗口开始;

如果 Parent Child 同时是 0, 则函数查找所有的顶层窗口及消息窗口.

}

 

1.查找主窗口的句柄:

IntPtr mainHandle = FindWindow(null, "UKeyManage");
if (mainHandle != IntPtr.Zero)
{
下续对菜单进行点击操作
}

 

2.对菜单进行点击操作

image.png

IntPtr menu = GetMenu(mainHandle);
Console.WriteLine("menu" + menu);

int subMenuCount = 0;
for (int s = 0; s < 65535; s++)
{
    IntPtr subMenu = GetSubMenu(menu, s);
    if (subMenu != IntPtr.Zero)
    {
        subMenuCount++;
		//用户证书在第2个菜单(证书管理)下
        if (subMenuCount < 2) { continue; }
        Console.WriteLine("subMenu" + subMenu);

        int itemCount = 0;
        for (int i = 0; i < 65535; i++)
        {
            IntPtr item = GetMenuItemID(subMenu, i);
            if (item != IntPtr.Zero && (int)item != -1)
            {
                itemCount++;
				//证书管理下面的第2个就是导出用户证书
                if (itemCount == 2)
                {
                    //导出用户证书
                    Console.WriteLine("item" + item);
					//发送点击菜单命令
                    PostMessage(mainHandle, WM_COMMAND, item, 0);
                    break;
                }
            }
        }
        break;
    }
}

3.模拟键盘输入操作

image.png

//弹出来的对话框先取窗口句柄
IntPtr initWinHandle = FindWindow(null, "UsrPinDlg");
Console.WriteLine("UsrPinDlg" + initWinHandle);

//先设置最前端
SetForegroundWindow(initWinHandle);

Thread.Sleep(500);
SendKeys.SendWait("********");//密码
Thread.Sleep(500);

//查找Button的句柄
IntPtr initOkHandle = FindWindowEx(initWinHandle, 0, "Button", null);
Console.WriteLine("b:" + initOkHandle);

//点击Button
SendMessage(initOkHandle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);


4.获取ListBox的信息

image.png

//回到主界面,查看ListBox的消息
IntPtr mainHandle2 = FindWindow(null, "UKeyManage");
Console.WriteLine("mainHandle2" + mainHandle2);

IntPtr listBoxHandle = FindWindowEx(mainHandle2, 0, "ListBox", null);
Console.WriteLine("listBoxHandle" + listBoxHandle);

IntPtr lbHandle = SendMessage(listBoxHandle, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
Console.WriteLine("lbHandle" + lbHandle);
List<string> lbContent = new List<string>();
StringBuilder sb = new StringBuilder();

//逐行获取
for (int lb = 0; lb < (int)lbHandle; lb++)
{
    StringBuilder sblb = new StringBuilder();
    IntPtr getText = SendMessage(listBoxHandle, LB_GETTEXT, lb, sblb);
    sb.Append(sblb);
}

Console.WriteLine("lbText:" + sb.ToString());
if (sb.ToString().Contains("成功"))
{
    return true;
}
else
{
    return false;
}


其它菜单操作类似,在此不进行阐述。

 

接下来是Web

1.浏览到主页

webBrowser1.Navigate("https://xxxxxxxxx/xxxx");

2.通过HtmlElementCollection解释并模拟点击

image.png

//查找,在input下的j_id_id23:j_id_id381
HtmlElementCollection link = this.webBrowser1.Document.GetElementsByTagName("input").GetElementsByName("j_id_id23:j_id_id381");

for (int i = 0; i < link.Count; i++)
{
    Console.WriteLine(i + link[i].Name);
	//点击
    link[i].InvokeMember("click");
    break;
}

技术难点都搞定了,就弄出第1版成品。

由于第1版只有2天的开发时间,其实后续可以利用DevCon对设备进行禁用/启用,这样可以一次性插好几个读卡器,然后自动实现批量(将全部禁用,做那一个时就开那个)。

Win32API初尝到此结束。其实AI的实际产品经常要与硬件打交道(像摄像头、语音输入之类),作为一位主管不仅仅是懂得算法、调参,还得懂得整个产品涉及的技术进行把控,关键时刻自己要出手。



                                               


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。