【Win32 API】利用SendMessage实现winform与wpf之间的消息传递
原文:【Win32 API】利用SendMessage实现winform与wpf之间的消息传递
引言
有一次心血来潮,突然想研究一下进程间的通信,能够实现消息传递的方法有几种,其中win32api中的sendmessage就是当中的一种比较简单的方法。于是参考了网上各种资料,做了一个小demo。
发送方Winform
1.新建一个Winform项目,添加控件,如下
2.界面做好,接着来编写代码,首先利用DllImport来声明SendMessage函数原型,如下:
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd,int Msg, int wParam, IntPtr lParam );
3.其中,lParam参数说明如下
lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT
{
DWORD dwData; //用户定义数据
DWORD cbData; //数据大小
PVOID lpData; //指向数据的指针
} COPYDATASTRUCT;
4.所以为了方便起见,还需要定义个一个结构,如下
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
5.相应地,sendmessage函数更改为如下:
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam );
6.至此,sendmessage函数定义完成,但是还不够,我们还需要能找到接收消息的窗体的函数,所以还要声明两个函数:
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", EntryPoint = "FindWindowEx“)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);
7.接下来,我们可以开始写发送消息具体实现。
发送到form的textbox按钮的方法实现如下:
IntPtr WINDOW_HANDLER = FindWindow(null, "Win32窗体"); if (WINDOW_HANDLER != IntPtr.Zero)
{ IntPtr hwndThree = FindWindowEx(WINDOW_HANDLER, , null, "");
hwndThree =new IntPtr(GetWindow(hwndThree.ToInt32(), ));
hwndThree = new IntPtr(GetWindow(hwndThree.ToInt32(), )); //获取按钮的句柄 找3次才找到目标textbox SendMessage(hwndThree, WM_SETTEXT, , this.sendtext.Text);
}
发送到Winform按钮的方法实现如下:
IntPtr WINDOW_HANDLER = FindWindow(null, "Win32窗体");
if (WINDOW_HANDLER != IntPtr.Zero)
{
string text = this.sendtext.Text;
byte[] sarr = System.Text.Encoding.Default.GetBytes(text);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr);
cds.lpData = text;
cds.cbData = len + ;
SendMessage(WINDOW_HANDLER, WM_COPYDATA, , ref cds);
}
发送到WPF按钮的方法实现如下:
IntPtr WINDOW_HANDLER = FindWindow(null, "WPF窗体");
if (WINDOW_HANDLER != IntPtr.Zero)
{
string text = this.sendtext.Text;
byte[] sarr = System.Text.Encoding.Default.GetBytes(text);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr);
cds.lpData = text;
cds.cbData = len + ;
SendMessage(WINDOW_HANDLER, WM_COPYDATA, , ref cds);
}
8.至此,发送端的编码完成,其中第一个按钮的功能是将消息直接发送到winform接收方的textbox上,第二个按钮是将消息发送到winform接收方的窗体上,再由窗体的方法处理,第三个按钮是将消息发送到wpf接收方的窗体上,再由wpf的方法处理。为什么没有直接发送到wpf的textbox的方法呢,那是因为wpf里面的控件是没有句柄的,只有窗体才有句柄,然后发送消息需要接收方的句柄,所以无法实现。
接收方winform
1.新建winform项目,编写界面如下:
2.编写后台代码,定义结构COPYDATASTRUCT和重写winform的消息处理方法WndProc,代码如下:
public const int WM_COPYDATA = 0x004A; public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
} protected override void WndProc(ref System.Windows.Forms.Message m)
{
switch (m.Msg)
{
case WM_COPYDATA:
COPYDATASTRUCT MyKeyboardHookStruct = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
this.textBox2.Text = MyKeyboardHookStruct.lpData;
break;
default:
base.WndProc(ref m); // 调用基类函数处理其他消息。
break;
}
}
3.至此,winform接收端编码完成,我们只需在WndProc处理一下消息类型为WM_COPYDATA的消息即可。
接收方wpf
1.新建wpf项目,界面如下
2.编写后台代码,wpf没有消息处理方法WndProc,所以处理上复杂些。主要利用HwndSource实现接收消息,具体代码如下:
public MainWindow()
{
InitializeComponent(); this.Loaded += Window_Loaded;
} #region 定义常量消息值
public const int WM_GETTEXT = 0x0D;
public const int WM_SETTEXT = 0x0C;
public const int WM_SIZEING = 0x0214;
public const int WM_COPYDATA = 0x004A;
public const int WM_LBUTTONDBLCLK = 0x0203;
#endregion #region 定义结构体
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
#endregion private void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource hWndSource;
WindowInteropHelper wih = new WindowInteropHelper(this);
hWndSource = HwndSource.FromHwnd(wih.Handle);
//添加处理程序
hWndSource.AddHook(MainWindowProc);
}
private IntPtr MainWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{ case WM_COPYDATA:
{ COPYDATASTRUCT mystr = new COPYDATASTRUCT();
Type mytype = mystr.GetType(); COPYDATASTRUCT MyKeyboardHookStruct = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
this.textbox.Text = MyKeyboardHookStruct.lpData;
break; }
default:
{
break;
} }
return IntPtr.Zero;
}
3.wpf接收端完成。
最终界面效果
小结
本文介绍了如何用sendmessage函数在窗体间发送消息,sendmessage函数是win32api的一种,然而win32api又是一个好庞大的话题了,我现在还只是入门未遂,渐行渐学罢了.另外,消息的传递方法不只一种,例如我们还可以用wcf进行通信,有时间再研究.最后,如果您有更好的建议,请不吝指教,感激不尽!
【Win32 API】利用SendMessage实现winform与wpf之间的消息传递的更多相关文章
- 调用win32 api 函数SendMessage() 实现消息直接调用
简单的调用例子, 适合初学者学习,当然 我也是初学者. #include <windows.h> #include <stdio.h> #include <stdlib. ...
- WPF Win32 API 嵌入Form 窗体
WIn32 API: public class Win32Native { [DllImport("user32.dll", SetLastError = true, CharSe ...
- Web API应用架构在Winform混合框架中的应用(4)--利用代码生成工具快速开发整套应用
前面几篇介绍了Web API的基础信息,以及如何基于混合框架的方式在WInform界面里面整合了Web API的接入方式,虽然我们看似调用过程比较复杂,但是基于整个框架的支持和考虑,我们提供了代码生成 ...
- [C++] Win32 API 的多线程Timer管理Trick - 利用PostThreadMessage
有时候我们需要在程序里定时地完成一些任务, 比如5秒后发送, 10秒后弹窗之类的操作. 这就需要一个类似于定时器的组件. 这个组件在windows.h里被称为Timer. 设置一个Timer 第一步当 ...
- C# 调Win32 API SendMessage简单用法及wMsg常量
函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.该函数是应用程序和应用程序之间进行消息传递的主要手段之一. 函数原型:LRESU ...
- 对比MFC和Winform及WPF
MFC 生成本机代码,自然是很快.可是,消息循环,减缓了界面显示速度.winform 封装了 win32 的api,多次进行P/invoke 操作 (大部分使用p/invoke操作封装),速度慢 .w ...
- Winform、WPF、Silverlight、MFC区别与联系
WinForm 在Windows中,诸如窗体绘制等功能由GDI(图形设备接口)实现,放在操作系统内核中.Windows Forms在底层使用的是GDI+.GDI+是GDI的“面向对象包装”,使用C++ ...
- win32 API函数
cozy的博文 win32 API函数大全 (2008-03-15 16:28) 分类: 个人日记 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WN ...
- 利用SendMessage实现窗口拖动
原文:利用SendMessage实现窗口拖动 利用SendMessage实现窗口拖动 周银辉 想想以前用跟踪鼠标位 ...
随机推荐
- Android 优秀开源项目
以下是本人日常工作中收集的比较不错的Android开源项目 roottools: RootTools gives Rooted developers easy access to common roo ...
- Vue 2.0 v-for 响应式key, index及item.id参数对v-bind:key值造成差异研究
Vue 2.0 v-for 响应式key, index及item.id参数对v-bind:key值造成差异研究 在github上阅览README.md以获得最佳阅读体验,点这里 v-for响应式key ...
- LintCode题解之Search Range in Binary Search Tree
1.题目描述 2.问题分析 首先将二叉查找树使用中序遍历的方式将元素放入一个vector,然后在vector 中截取符合条件的数字. 3.代码 /** * Definition of TreeNode ...
- mysql中删除同一行会经常出现死锁?太可怕了
之前有一个同事问到我,为什么多个线程同时去做删除同一行数据的操作,老是报死锁,在线上已经出现好多次了,我问了他几个问题: 1. 是不是在一个事务中做了好几件事情? 答:不是,只做一个删除 ...
- 在SQL Server中使用CLR调用.NET类库中的方法 (转载)
在SQL Server中调用 .NET 类库的方法要分为下面几步来实现: 在.NET中新建一个类库项目,并在这个项目中添加一个类文件,并把要被SQL Server调用的方法定义为公有的,静态的方法. ...
- Hsqldb中设置主键,并让主键自增
CREATE TABLE userinfo ( Id INTEGER GENERATED BY DEFAULT AS IDENTITY, Name varchar(100) NOT NULL, Dep ...
- 转:SQL 关于apply的两种形式cross apply 和 outer apply
原文地址:http://www.cnblogs.com/Leo_wl/archive/2013/04/02/2997012.html SQL 关于apply的两种形式cross apply 和 out ...
- android打开存储卡(TF卡\SD卡)中的sqlite文件
android的SDK直接支持sqlite3的API. 打开SD卡上面的sqlite数据库,不需要SQLiteOpenHelper的继承类.只需要,SQLiteDatabase中的一些静态方法.如 ...
- 【转】HTTP学习---Web 缓存
[原文]https://www.toutiao.com/i6592743068623962632/ 1. 前端缓存概述 前端缓存主要是分为HTTP缓存和浏览器缓存.其中HTTP缓存是在HTTP请求传输 ...
- [python]如何理解uiautomator里面的 child, child_by_text, sibling,及使用场景
如何理解uiautomator里面的 child, child_by_text, sibling,我们借助android原生的uiautomatorviewer抓取的控件来进行理解 以如下图进行详细讲 ...