进程通信之一 使用WM_COPYDATA C++及C#实现(转)
进程间通信最简单的方式就是发送WM_COPYDATA消息。本文提供C++及C#程序相互通信的二种实现方式。这样消息的接收端可以用C++实现,发送端可以用C++或C#实现。
发送WM_COPYDATA消息:
SendMessage(接收窗口句柄, WM_COPYDATA, (WPARAM)发送窗口句柄, (LPARAM)&CopyData);
其中的CopyData为COPYDATASTRUCT结构类型,该结构定义如下:
typedef struct tagCOPYDATASTRUCT {
DWORD dwData; // Specifies data to be passed to the receiving application.
DWORD cbData; //Specifies the size, in bytes, of the data pointed to by the lpData member.
PVOID lpData; // Pointer to data to be passed to the receiving application. can be NULL.
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
注意:该消息只能由SendMessage()来发送,而不能使用PostMessage()。因为系统必须管理用以传递数据的缓冲区的生命期,如果使用了PostMessage(),数据缓冲区会在接收方(线程)有机会处理该数据之前,就被系统清除和回收。此外如果lpData指向一个带有指针或某一拥有虚函数的对象时,也要小心处理。
如果传入的句柄不是一个有效的窗口或当接收方进程意外终止时,SendMessage()会立即返回,因此发送方在这种情况下不会陷入一个无穷的等待状态中。
(接收方已经处理)。
接收WM_COPYDATA消息:
只要用COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;就可以了。接收方应认为这些数据是只读的。
由于发送方在接收方处理WM_COPYDATA消息完毕前都是处于等待中,所以接收方应当尽快处理WM_COPYDATA消息。
以一个简单的例子来说明如何使用WM_COPYDATA消息,有二个程序,一个用来发送表示当前时间信息的字符串,另一个接收数据后显示到编辑框中。例子中有几点要注意:
.如何得到当前控制台窗口句柄?VS2008下可以直接使用HWND GetConsoleWindow(void);函数。
.使用char *ctime(const time_t *timer);将一个time_t类型转化成一个字符串时,函数会在字符串末尾加下'\n',因为发送前要将这个'\n'去掉。
发送消息的程序代码(VS2008下编译通过):
[cpp]
view plaincopyprint?
- #include <windows.h>
- #include <time.h>
- #include <conio.h>
- #include <stdio.h>
- int main()
- {
- const char szDlgTitle[] = "RecvMessage";
- HWND hSendWindow = GetConsoleWindow ();
- if (hSendWindow == NULL)
- return -1;
- HWND hRecvWindow = FindWindow(NULL, szDlgTitle);
- if (hRecvWindow == NULL)
- return -1;
- char szSendBuf[100];
- time_t timenow;
- COPYDATASTRUCT CopyData;
- for (int i = 0; i < 10; i++)
- {
- time(&timenow);
- sprintf(szSendBuf, "%s", ctime(&timenow));//注意,ctime()返回的字符串后面带了'\n'
- CopyData.dwData = i;
- CopyData.cbData = strlen(szSendBuf);
- szSendBuf[CopyData.cbData - 1] = '\0';
- CopyData.lpData = szSendBuf;
- SendMessage(hRecvWindow, WM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);
- printf("%s\n", szSendBuf);
- Sleep(1000);
- }
- return 0;
- }
#include <windows.h>
#include <time.h>
#include <conio.h>
#include <stdio.h>
int main()
{
const char szDlgTitle[] = "RecvMessage";
HWND hSendWindow = GetConsoleWindow ();
if (hSendWindow == NULL)
return -1;
HWND hRecvWindow = FindWindow(NULL, szDlgTitle);
if (hRecvWindow == NULL)
return -1;
char szSendBuf[100];
time_t timenow;
COPYDATASTRUCT CopyData;
for (int i = 0; i < 10; i++)
{
time(&timenow);
sprintf(szSendBuf, "%s", ctime(&timenow));//注意,ctime()返回的字符串后面带了'\n'
CopyData.dwData = i;
CopyData.cbData = strlen(szSendBuf);
szSendBuf[CopyData.cbData - 1] = '\0';
CopyData.lpData = szSendBuf;
SendMessage(hRecvWindow, WM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);
printf("%s\n", szSendBuf);
Sleep(1000);
}
return 0;
}
接收消息程序代码(VC6.0下编译通过):
程序中的IDC_EDIT_RECVMESSAGE为编辑框的ID。
[cpp]
view plaincopyprint?
- #include "stdafx.h"
- #include "resource.h"
- #include <stdio.h>
- BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
- int APIENTRY WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
- {
- // TODO: Place code here.
- DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
- return 0;
- }
- BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
- {
- const char szDlgTitle[] = "RecvMessage";
- static HWND s_hEditShowRecv;
- switch (message)
- {
- case WM_INITDIALOG:
- SetWindowText(hDlg, szDlgTitle);
- s_hEditShowRecv = GetDlgItem(hDlg, IDC_EDIT_RECVMESSAGE);
- return TRUE;
- case WM_COMMAND:
- switch (LOWORD(wParam))
- {
- case IDOK:
- case IDCANCEL:
- EndDialog(hDlg, LOWORD(wParam));
- return TRUE;
- }
- break;
- case WM_COPYDATA:
- {
- COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;
- char szBuffer[300];
- memset(szBuffer, 0, sizeof(szBuffer));
- sprintf(szBuffer, "dwData:%d cbData:%d\r\nlpData:0x%08x = %s\r\n\r\n",
- pCopyData->dwData, pCopyData->cbData,
- (PVOID)pCopyData->lpData, (char*)pCopyData->lpData);
- //在编辑框中追加数据
- SendMessage(s_hEditShowRecv, EM_SETSEL, (WPARAM)-1, (LPARAM)-1); // (0, -1)表示全选, (-1,任意)表示全不选
- SendMessage(s_hEditShowRecv, EM_REPLACESEL, FALSE, (LPARAM)szBuffer);
- SendMessage(s_hEditShowRecv, EM_SCROLLCARET, 0, 0);
- }
- return TRUE;
- }
- return FALSE;
- }
#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
return 0;
}
BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
const char szDlgTitle[] = "RecvMessage";
static HWND s_hEditShowRecv;
switch (message)
{
case WM_INITDIALOG:
SetWindowText(hDlg, szDlgTitle);
s_hEditShowRecv = GetDlgItem(hDlg, IDC_EDIT_RECVMESSAGE);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
case WM_COPYDATA:
{
COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;
char szBuffer[300];
memset(szBuffer, 0, sizeof(szBuffer));
sprintf(szBuffer, "dwData:%d cbData:%d\r\nlpData:0x%08x = %s\r\n\r\n",
pCopyData->dwData, pCopyData->cbData,
(PVOID)pCopyData->lpData, (char*)pCopyData->lpData);
//在编辑框中追加数据
SendMessage(s_hEditShowRecv, EM_SETSEL, (WPARAM)-1, (LPARAM)-1); // (0, -1)表示全选, (-1,任意)表示全不选
SendMessage(s_hEditShowRecv, EM_REPLACESEL, FALSE, (LPARAM)szBuffer);
SendMessage(s_hEditShowRecv, EM_SCROLLCARET, 0, 0);
}
return TRUE;
}
return FALSE;
}
运行结果如下 (先启动接收消息程序再运行发送消息程序):
有的时候,发送消息程序用C#实现起来更加方便,因此在这也提供了用C#实现的例子发送消息程序供大家参考:
[csharp]
view plaincopyprint?
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- using System.Runtime.InteropServices; //[DllImport("user32.dll")]中DllImport的命名空间
- namespace UseWMCOPYDATA
- {
- class Program
- {
- static void Main(string[] args)
- {
- string strDlgTitle = "RecvMessage";
- //接收端的窗口句柄
- IntPtr hwndRecvWindow = ImportFromDLL.FindWindow(null, strDlgTitle);
- if (hwndRecvWindow == IntPtr.Zero)
- {
- Console.WriteLine("请先启动接收消息程序");
- return;
- }
- //自己的窗口句柄
- IntPtr hwndSendWindow = ImportFromDLL.GetConsoleWindow();
- if (hwndSendWindow == IntPtr.Zero)
- {
- Console.WriteLine("获取自己的窗口句柄失败,请重试");
- return;
- }
- for (int i = 0; i < 10; i++)
- {
- string strText = DateTime.Now.ToString();
- //填充COPYDATA结构
- ImportFromDLL.COPYDATASTRUCT copydata = new ImportFromDLL.COPYDATASTRUCT();
- copydata.cbData = Encoding.Default.GetBytes(strText).Length; //长度 注意不要用strText.Length;
- copydata.lpData = strText; //内容
- ImportFromDLL.SendMessage(hwndRecvWindow, ImportFromDLL.WM_COPYDATA, hwndSendWindow, ref copydata);
- Console.WriteLine(strText);
- Thread.Sleep(1000);
- }
- }
- }
- public class ImportFromDLL
- {
- public const int WM_COPYDATA = 0x004A;
- //启用非托管代码
- [StructLayout(LayoutKind.Sequential)]
- public struct COPYDATASTRUCT
- {
- public int dwData; //not used
- public int cbData; //长度
- [MarshalAs(UnmanagedType.LPStr)]
- public string lpData;
- }
- [DllImport("User32.dll")]
- public static extern int SendMessage(
- IntPtr hWnd, // handle to destination window
- int Msg, // message
- IntPtr wParam, // first message parameter
- ref COPYDATASTRUCT pcd // second message parameter
- );
- [DllImport("User32.dll", EntryPoint = "FindWindow")]
- public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
- [DllImport("Kernel32.dll", EntryPoint = "GetConsoleWindow")]
- public static extern IntPtr GetConsoleWindow();
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices; //[DllImport("user32.dll")]中DllImport的命名空间
namespace UseWMCOPYDATA
{
class Program
{
static void Main(string[] args)
{
string strDlgTitle = "RecvMessage";
//接收端的窗口句柄
IntPtr hwndRecvWindow = ImportFromDLL.FindWindow(null, strDlgTitle);
if (hwndRecvWindow == IntPtr.Zero)
{
Console.WriteLine("请先启动接收消息程序");
return;
}
//自己的窗口句柄
IntPtr hwndSendWindow = ImportFromDLL.GetConsoleWindow();
if (hwndSendWindow == IntPtr.Zero)
{
Console.WriteLine("获取自己的窗口句柄失败,请重试");
return;
}
for (int i = 0; i < 10; i++)
{
string strText = DateTime.Now.ToString();
//填充COPYDATA结构
ImportFromDLL.COPYDATASTRUCT copydata = new ImportFromDLL.COPYDATASTRUCT();
copydata.cbData = Encoding.Default.GetBytes(strText).Length; //长度 注意不要用strText.Length;
copydata.lpData = strText; //内容
ImportFromDLL.SendMessage(hwndRecvWindow, ImportFromDLL.WM_COPYDATA, hwndSendWindow, ref copydata);
Console.WriteLine(strText);
Thread.Sleep(1000);
}
}
}
public class ImportFromDLL
{
public const int WM_COPYDATA = 0x004A;
//启用非托管代码
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public int dwData; //not used
public int cbData; //长度
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
[DllImport("User32.dll")]
public static extern int SendMessage(
IntPtr hWnd, // handle to destination window
int Msg, // message
IntPtr wParam, // first message parameter
ref COPYDATASTRUCT pcd // second message parameter
);
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("Kernel32.dll", EntryPoint = "GetConsoleWindow")]
public static extern IntPtr GetConsoleWindow();
}
}
运行结果如下 (先启动接收消息程序再运行发送消息程序):
下一篇《进程通信之二
管道技术第一篇
输入输出的重定向》示范了程序输入输出的重定向,以及如何用管道来完成进程之间的通信。
原文地址:http://blog.csdn.net/morewindows/article/details/6804157
进程通信之一 使用WM_COPYDATA C++及C#实现(转)的更多相关文章
- 进程通信之一 使用WM_COPYDATA C++及C#实现 z
原文地址:http://blog.csdn.net/morewindows/article/details/6804157 进程间通信最简单的方式就是发送WM_COPYDATA消息.本文提供C++及C ...
- WinForm实现跨进程通信的方法
public class WinMessageHelper { private struct COPYDATASTRUCT { public IntPtr dwData; public int cbD ...
- [转]WINDOW进程通信的几种方式
windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...
- 进程通信-SendMessage使用方法
进程通信-SendMessage的使用方法 用过SendMessage进行进程通信的同学都知道,这个函数一般都搭配FindWindow使用.通过FindWindow查找进程句柄,然后使用SendMes ...
- Windows提高_1.4进程通信
进程通信 使用 WM_COPYDATA 客户端(发送端) // 1. 找到窗口程序 HWND hWnd = FindWindow(NULL, L"Window1"); // 2 ...
- unity3d进程通信利用WM_COPYDATE和HOOK
hello,近期用unity做了进程通信,应该是和c++的PC端实现通信,才開始一头雾水,后来实现了才知道好繁杂......先感谢对我提供帮助的百度,谷歌以及游戏圈的大大们. 在进程通信中非常多方法, ...
- 进程以及进程通信(IPC)类型
这里用我有限的知识来解释同时参考了一些其他博主的子类,希望能给与一部分入门的朋友一个清晰的理解,有问题之处还请指出 首先简单谈一下什么是进程? 答:进程是装入内存运行的程序段,是许多的系统对象拥有权的 ...
- Windows线程+进程通信
一 Windows线程进程 1)定义 按照MS的定义, Windows中的进程简单地说就是一个内存中的可执行程序, 提供程序运行的各种资源. 进程拥有虚拟的地址空间, 可执行代码, 数据, 对象句柄集 ...
- 几种Windows进程通信
32位Windows采用虚拟内存技术使每个进程虚拟4G内存,在逻辑上实现了对进程之间数据代码的分离与保护.那么相应的进程之间的通信也就有必要整理掌握一下. Windows进程间通讯的方法有很多:管道. ...
随机推荐
- Windows系统上如何使用SSH
Windows系统上如何使用SSH 传统的网络服务程序如FTP.Telnet等,在网络上一般使用明文传送数据.用户账号和口令信息,容易受到中间人的攻击.用户利用SSH协议后能有效防止DNS及IP欺骗, ...
- epmap服务
epmap是 tcp 135和udp135端口135端口的“epmap - DCE endpoint resolution”记录可以通过连接到135端口和做适当的查询列举出来. 135端口大多数情况下 ...
- Android Andbase应用开发框架
[运行说明]运行AndbaseDemo需要将文件中的Andbase库Add进demo中.1.andbase中包含了大量的开发常用手段.如网络下载,多线程与线程池的管理,数据库ORM,图片缓存管理,图片 ...
- UINavigationController学习笔记
http://site.douban.com/129642/widget/notes/5513129/note/187701199/ 1-view controllers的关系:Each custom ...
- Android用户界面布局(layouts)
Android用户界面布局(layouts) 备注:view理解为视图 一个布局定义了用户界面的可视结构,比如activity的UI或是APP widget的UI,我们可以用下面两种方式来声明布局: ...
- 【设计模式】—— 单例模式Singleton
前言:[模式总览]——————————by xingoo 模式意图 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有公开的调用方法. 模式结构 ...
- tuxedo入门
为文件增加用户执行权限: 官网下载tuxedo111120_64_Linux_01_x86.bin su //进入root操作,防止权限不够 创建文件夹,用来做tuxedo文件的安装路径 cd /op ...
- 解析Android开发优化之:从代码角度进行优化的技巧
下面我们就从几个方面来了解Android开发过程中的代码优化,需要的朋友参考下 通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻辑,但是性能不一定是最优化的.一般来说 ...
- 4010: [HNOI2015]菜肴制作
拓扑排序+堆. 转自popoqqq神犇. 反向建图跑拓扑排序然后逆序输出. 为什么不能正的来呢,因为不知道选当前菜要先制作哪种菜. 逆序过来跑拓扑的话,也能保证满足限制条件编号小的在前面. 题外话:我 ...
- ASP.NET在IE10,IE11中Form表单身份验证失效问题解决方法
已经研究出解决方案. 在web.config中的forms中增加cookieless="UseCookies"属性即可. <authentication mode=&qu ...