转自:http://www.cnblogs.com/trieagle/p/3811375.html

C#调用API向外部程序发送数据

最近有可能要做一个项目。在项目中有这么一个功能,在A程序中调用B程序,同时在A程序中进行登陆后,要将A程序的登录名和密码自动填充到B程序的登陆对话框中,这样B程序就不需要再输入一次用户名和密码了,简化操作人员的操作。刚好最近闲着没事,就在怎么想怎么去实现。经过两天的折腾,基本上完成了上述功能的实现。下面就把实现方法、过程与大家进行分享。

一、原理

要实现上述功能,需要调用Win API来实现。Win32 API即为Microsoft 32位平台的应用程序编程接口(Application Programming Interface)。所有在Win32平台上运行的应用程序都可以调用这些函数。

那么在本程序的实现过程中,需要用到以下三个API函数(函数说明均从网上找的,方便大家查看),以及自己编写的一个FindWindowByIndex函数。

1、static extern int SendMessage1(IntPtr hwnd, uint wMsg, int wParam, int lParam);

顾名思义,SendMessage函数的功能是“发送消息”,即将一条消息发送到指定对象(操作系统、窗口或控件等)上,以产生特定的动作(如滚屏、修改对象外观等)。

其中四个自变量的含义和说明如下:

hWnd:对象的句柄。希望将消息传送给哪个对象,就把该对象的句柄作为实参传送。

wMsg:被发送的消息。根据具体需求和不同的对象,将不同的消息作为实参传送,以产生预期的动作。

wParam、lParam:附加的消息信息。这两个是可选的参数,用来提供关于wMsg消息更多的信息,不同的wMsg可能使用这两个参数中的0、1或2个,如果不需要哪个附加参数,则将实参赋为NULL(在VB中赋为0)。

2、public static extern IntPtr FindWindow(string className, string windowName);

FindWindow函数返回与指定字符创相匹配的窗口类名或窗口名的最顶层窗口的窗口句柄。这个函数不会查找子窗口。

lpClassName:指向一个以null结尾的、用来指定类名的字符串或一个可以确定类名字符串的原子。如果这个参数是一个原子,那么它必须是一个在调用此函数前已经通过GlobalAddAtom函数创建好的全局原子。这个原子(一个16bit的值),必须被放置在lpClassName的低位字节中,lpClassName的高位字节置零。

lpWindowName:指向一个以null结尾的、用来指定窗口名(即窗口标题)的字符串。如果此参数为NULL,则匹配所有窗口名。

返回值:如果函数执行成功,则返回值是拥有指定窗口类名或窗口名的窗口的句柄。如果函数执行失败,则返回值为 NULL 。可以通过调用GetLastError函数获得更加详细的错误信息。

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

在窗口列表中寻找与指定条件相符的第一个子窗口 。该函数获得一个窗口的句柄,该窗口的类名和窗口名与给定的字符串相匹配。这个函数查找子窗口,从排在给定的子窗口后面的下一个子窗口开始。在查找时不区分大小写。

hwndParent:要查找的子窗口所在的父窗口的句柄(如果设置了hwndParent,则表示从这个hwndParent指向的父窗口中搜索子窗口)。如果hwndParent为 0 ,则函数以桌面窗口为父窗口,查找桌面窗口的所有子窗口。Windows NT5.0 and later:如果hwndParent是HWND_MESSAGE,函数仅查找所有消息窗口。

hwndChildAfter :子窗口句柄。查找从在Z序中的下一个子窗口开始。子窗口必须为hwndParent窗口的直接子窗口而非后代窗口。如果HwndChildAfter为NULL,查找从hwndParent的第一个子窗口开始。如果hwndParent 和 hwndChildAfter同时为NULL,则函数查找所有的顶层窗口及消息窗口。

lpszClass:指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobaIAddAtom函数产生的全局成员。该成员为16位,必须位于lpClassName的低16位,高位必须为0。

pszWindow:指向一个指定了窗口名(窗口标题)的空结束字符串。如果该参数为 NULL,则为所有窗口全匹配。

返回值:Long,找到的窗口的句柄。如未找到相符窗口,则返回零。会设置GetLastError如果函数成功,返回值为具有指定类名和窗口名的窗口句柄。如果函数失败,返回值为NULL。

4、static IntPtr FindWindowByIndex(IntPtr hwndParent, int index)

该函数通过隐含的索引来查找相应的控件。

该函数源代码如下:

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, null, null);

if (result != IntPtr.Zero)

++ct;

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

return result;

}

}

二、API调用方法(注:本段文字从网上摘录)

1、使用相应的命名空间using System.Runtime.InteropServices;

2、使用DllImportAttribute特性来引入api函数,注意声明的是空方法,即方法体为空。

[DllImport("user32.dll")]

public static extern ReturnType FunctionName(type arg1,type arg2,...);

//调用时与调用其他方法并无区别

可以使用字段进一步说明特性,用逗号隔开,如: [ DllImport( "kernel32", EntryPoint="GetVersionEx" )]

DllImportAttribute特性的公共字段如下:

1、CallingConvention 指示向非托管实现传递方法参数时所用的 CallingConvention 值。CallingConvention.Cdecl : 调用方清理堆栈。它使您能够调用具有 varargs 的函数。CallingConvention.StdCall : 被调用方清理堆栈。它是从托管代码调用非托管函数的默认约定。

2、CharSet 控制调用函数的名称版本及指示如何向方法封送 String 参数。

此字段被设置为 CharSet 值之一。如果 CharSet 字段设置为 Unicode,则所有字符串参数在传递到非托管实现之前都转换成 Unicode 字符。这还导致向 DLL EntryPoint 的名称中追加字母“W”。如果此字段设置为 Ansi,则字符串将转换成 ANSI 字符串,同时向 DLL EntryPoint 的名称中追加字母“A”。大多数 Win32 API 使用这种追加“W”或“A”的约定。如果 CharSet 设置为 Auto,则这种转换就是与平台有关的(在 Windows NT 上为 Unicode,在 Windows 98 上为 Ansi)。CharSet 的默认值为 Ansi。CharSet 字段也用于确定将从指定的 DLL 导入哪个版本的函数。CharSet.Ansi 和 CharSet.Unicode 的名称匹配规则大不相同。对于 Ansi 来说,如果将 EntryPoint 设置为“MyMethod”且它存在的话,则返回“MyMethod”。如果 DLL 中没有“MyMethod”,但存在“MyMethodA”,则返回“MyMethodA”。对于 Unicode 来说则正好相反。如果将 EntryPoint 设置为“MyMethod”且它存在的话,则返回“MyMethodW”。如果 DLL 中不存在“MyMethodW”,但存在“MyMethod”,则返回“MyMethod”。如果使用的是 Auto,则匹配规则与平台有关(在 Windows NT 上为 Unicode,在 Windows 98 上为 Ansi)。如果 ExactSpelling 设置为 true,则只有当 DLL 中存在“MyMethod”时才返回“MyMethod”。

3、EntryPoint 指示要调用的 DLL 入口点的名称或序号。

如果你的方法名不想与api函数同名的话,一定要指定此参数,例如:

[DllImport("user32.dll",CharSet="CharSet.Auto",EntryPoint="MessageBox")]
 public static extern int MsgBox(IntPtr hWnd,string txt,string caption, int type);

4、ExactSpelling 指示是否应修改非托管 DLL 中的入口点的名称,以与 CharSet 字段中指定的 CharSet 值相对应。如果为 true,则当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Ansi 值时,向方法名称中追加字母 A,当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Unicode 值时,向方法的名称中追加字母 W。此字段的默认值是 false。

5、PreserveSig 指示托管方法签名不应转换成返回 HRESULT、并且可能有一个对应于返回值的附加 [out, retval] 参数的非托管签名。

6、SetLastError 指示被调用方在从属性化方法返回之前将调用 Win32 API SetLastError。 true 指示调用方将调用 SetLastError,默认为 false。运行时封送拆收器将调用 GetLastError 并缓存返回的值,以防其被其他 API 调用重写。用户可通过调用 GetLastWin32Error 来检索错误代码。

三、程序实现过程

程序A:两个文本框与一个启动按钮。两个文本框用来输入用户名和密码,启动按钮用来启动程序B。

程序B:两个文本框,用来接受程序A所发送过来的字符串。

1、A程序代码清单如下:

using System.Runtime.InteropServices;

using System.Threading;

private static System.Diagnostics.Process p;

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]

static extern int SendMessage1(IntPtr hwnd, uint wMsg, int wParam, int lParam);

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]

public static extern IntPtr FindWindow(string className, string windowName);

[DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]

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

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, null, null);

if (result != IntPtr.Zero)

++ct;

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

return result;

}

}

2、启动按钮事件代码

private void button4_Click(object sender, EventArgs e)

{

if (p == null)

{

p = new System.Diagnostics.Process();

p.StartInfo.FileName =”B程序Path”;

p.Start();

//必须让线程挂起一定时间,否则字符串不能自动发送过去。

Thread.Sleep(500);

IntPtr ParenthWnd = new IntPtr(0);

IntPtr pp = new IntPtr(0);

IntPtr mwh = IntPtr.Zero;

//通过窗口标题来获取窗口

ParenthWnd = FindWindow(null, "******");

//通过索引来获取B程序的文本编辑框,通过索引先获取该控件的ID,然后将该ID转换为16进制,与Spy++查看到ID进行对比,从而确定控件的索引。

IntPtr butt = FindWindowByIndex(ParenthWnd, 5);

uint WM_CHAR = 0x0102;

// SendMessage1每次发送一个字符串,所以通过循环发送完整用户名

foreach (char c in this.textBox1.Text)

{

SendMessage1(butt, WM_CHAR, c, 0);

}

//获取密码输入框

IntPtr butt1 = FindWindowByIndex(ParenthWnd, 3);

//发送密码

foreach (char c in this.textBox2.Text)

{

SendMessage1(butt1, WM_CHAR, c, 0);

}

}

else

{

if (p.HasExited) //是否正在运行{

p.Start();

}

}

3、程序运行结果

点击启动后,在第二个程序中(前面的),直接获取到第一个程序所发送的用户名和密码。

转载于:https://www.cnblogs.com/Joetao/articles/5788381.html

C#调用API向外部程序发送数据(转载)相关推荐

  1. 实现api返回json数据并在调用api时处理json数据

    json数据如下 "name": [{"age": 25,"height": 160,"weight": 100,&qu ...

  2. python调用api接口获取天气数据_python 接口实战--天气API

    1.接口地址: 网页请求: 将结果拷贝到bjson中,格式化为json的格式. 在python中实现天气测试,代码实现. import requests    导入requests库 from url ...

  3. 蹒跚学步之调用安卓摄像头并发送数据

    今天学习一下安卓,想调一下摄像头,拍张照片,转为Base64编码,再输入一些文本,然后发送给后台,类似: { "text":"xxx", "pics& ...

  4. tushare调用API获取金融相关数据

    首页:https://tushare.pro/ 整体的思路是: 首先获得token,可以参考官网教程 代码中传入token,调用接口 步骤 1. 获得token 首先进入网站:https://tush ...

  5. 树莓派+python flask 调用天气api接口实现天气数据web

    *注:树莓派我用的是在Win10上面的虚拟机镜像 * 文章目录 前言 一.flask是什么? 二.使用步骤 1.引入库 2.写一个简单的flask 3.实验准备 4.实验开始 5.结尾调试 总结 前言 ...

  6. [译] Linux 网络栈监控和调优:发送数据(2017)

    转载自:http://arthurchiao.art/blog/tuning-stack-tx-zh/ 点击阅读原文 Published at 2018-12-17 | Last Update 202 ...

  7. linux内核网络协议栈--监控和调优:发送数据(三十)

    译者序 本文翻译自 2017 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Sending Data.如果能看懂英文,建议阅读原 ...

  8. linux网络接口数据重新封包,Linux网络之设备接口层:发送数据包流程dev_queue_xmit...

    写在前面 本文主要是分析kernel-3.8的源代码,主要集中在Network的netdevice层面,来贯穿interface传输数据包的流程,kernel 博大精深,这也仅仅是一点个人愚见,作为一 ...

  9. java调用kafka接口发送数据_Java调用Kafka生产者,消费者Api及相关配置说明

    本次的记录内容包括: 1.Java调用生产者APi流程 2.Kafka生产者Api的使用及说明 3.Kafka消费者Api的使用及说明 4.Kafka消费者自动提交Offset和手动提交Offset ...

最新文章

  1. 0基础学习数据分析必须掌握的技能有哪些?
  2. java 浮点数精度_Java中浮点数精度问题
  3. Spring配置文件约束头
  4. 筛选末位数字为1或5_看看广州示范性高中排行榜,怎么填报志愿?如何运用末位考生分数...
  5. mysql 聚簇索引和非聚簇索引_MySQL 聚簇索引 二级索引 辅助索引(上两期中奖名单)...
  6. pandas基础-Python3
  7. 基于python和酷Q的QQ机器人开发实践(1)
  8. 西威SIEI电梯变频器维修图纸
  9. matlab2010安装详细图解案例
  10. JavaWeb开发——注册登录的表单验证
  11. MySQL逻辑架构及工作流程
  12. uwe5622 uwe5621ds 紫光展锐 wifi 移植的几个关键点:
  13. 玩个游戏好难 Win10我的世界(Minecraft)下载
  14. ppwjs之bootstrap文字排版:kbd元素(键盘格式元素)
  15. 腾讯云.xb 数据库备份恢复
  16. Linux curl 命令模拟 POST/GET 请求
  17. mysql drop fulltext_MySQL使用全文索引(fulltext index)
  18. 编程修养-C语言篇(下)(转)
  19. 考研复试英文自我介绍模板(学长已上岸)
  20. 【GlobalMapper精品教程】021:利用控制点校正栅格图像

热门文章

  1. Flex很可能会消失
  2. 【资料】wpcap.dll/Packet.dll库中相应函数
  3. LightBus新浪微博客户端开源下载
  4. Visio绘制功能分解图
  5. 4.3.9 ICMP协议
  6. verilog 里面,always,assign和always@(*)区别
  7. python argparse举例说明
  8. 这样是不是就可以预测语音长度和内容了
  9. Java基础学习总结(8)——super关键字
  10. 又一款4800像素手机曝光:vivo V15 Pro