进程通信之一 使用WM_COPYDATA C++及C#实现 z

原文地址:http://blog.csdn.net/morewindows/article/details/6804157

进程间通信最简单的方式就是发送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()会立即返回,因此发送方在这种情况下不会陷入一个无穷的等待状态中。

返回值问题,MSDN上说如果接收方处理了,返回TRUE,否则返回FALSE,但是本人在实验时,都是返回0(接收方已经处理)。

接收WM_COPYDATA消息:

只要用COPYDATASTRUCT *pCopyData =
(COPYDATASTRUCT*)lParam;就可以了。接收方应认为这些数据是只读的。

由于发送方在接收方处理WM_COPYDATA消息完毕前都是处于等待中,所以接收方应当尽快处理WM_COPYDATA消息。

以一个简单的例子来说明如何使用WM_COPYDATA消息,有二个程序,一个用来发送表示当前时间信息的字符串,另一个接收数据后显示到编辑框中。例子中有几点要注意:

1.如何得到当前控制台窗口句柄?VS2008下可以直接使用HWND
GetConsoleWindow(void);函数。

2.使用char *ctime(const time_t
*timer);将一个time_t类型转化成一个字符串时,函数会在字符串末尾加下‘\n‘,因为发送前要将这个‘\n‘去掉。

发送消息的程序代码(VS2008下编译通过):


#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。


#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#实现的例子发送消息程序供大家参考:


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();

}
}

进程通信之一 使用WM_COPYDATA C++及C#实现 z

时间: 05-17

进程通信之一 使用WM_COPYDATA C++及C#实现 z的相关文章

WM_COPYDATA实现进程通信

在用Shuttle ESB完成C++程序和C#程序消息推送时,需要完成C++进程和ESB进程的通信问题. 进程间的通信方式有很多,比如使用内存映射文件.通过共享内存DLL共享内存.使用SendMessage向另一进程发送WM_COPYDATA消息.比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法. 下面讲解如何通过WM_COPYDATA进行进行通信及通信原理. 1.建立SendMessage方法需要引用的数据结构: namespace Entity { public

unity3d进程通信利用WM_COPYDATE和HOOK

hello,近期用unity做了进程通信,应该是和c++的PC端实现通信,才開始一头雾水,后来实现了才知道好繁杂......先感谢对我提供帮助的百度,谷歌以及游戏圈的大大们. 在进程通信中非常多方法,可是wm_copydate绝对要比别的什么内存共享好了很多. unity大部分用c#语言,c#本身Forms这个dll里面也提供了对windows消息的接收可是在unity中无法非常好地使用System.Windows.Forms,所以在以下我的代码我用unity发送进程消息的是 user32.dl

几种Windows进程通信

32位Windows采用虚拟内存技术使每个进程虚拟4G内存,在逻辑上实现了对进程之间数据代码的分离与保护.那么相应的进程之间的通信也就有必要整理掌握一下. Windows进程间通讯的方法有很多:管道.邮件槽.剪切板.共享内存.消息.套接字.RPC.DDE等. 但是他们大部分拥有一个共同的本质:利用Windows操作系统高2GB内核共享空间进行数据传递的桥梁,所以他们都是内核对象! 所以他们大部分都要遵循:A创建对象-->A写入数据-->B打开A创建的对象-->B读入数据的规则 下面着重通

进程通信-SendMessage使用方法

进程通信-SendMessage的使用方法 用过SendMessage进行进程通信的同学都知道,这个函数一般都搭配FindWindow使用.通过FindWindow查找进程句柄,然后使用SendMessage 向这个句柄发送信息.这接口使用起来比较简单,但是当初也是费了好大的劲,只为用作记录. 第一步:设计用户界面 用户界面需要有一下几个元素,设置本地的窗口名称,目标的窗口名称,发送数据,以及接受数据. 第二步:引用接口 //Win32 API函数 [DllImport("User32.dll&

Winform and WPF 第二遍双击快捷方式或应用程序打开原来的应用程序而不新建一个实例[进程通信 1]

private void Window_Loaded(object sender, RoutedEventArgs e)         {             Process[] pro = Process.GetProcesses();             int n = pro.Where(p => p.ProcessName.Equals("进程名称")).Count();             if (n > 1)             {      

C++技术问题总结-第2篇 进程通信

进程通信的方法 进程通信基本方法有如下几种. 1.消息传递机制. 2.共享内存. 3.管道和邮槽. 4.剪贴板. 5.Socket通信. 1.消息传递机制 使用WM_COPYDATA实现进程间的传递数据. 函数原型 LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam) 参数 hWnd:其窗口程序将接收消息的窗口的句柄.如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非

WinForm实现跨进程通信的方法

public class WinMessageHelper { private struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; } //使用COPYDATA进行跨进程通信 public const int WM_COPYDATA = 0x004A; [DllImport("User32.dll",

第七课 进程通信

unix_c_07.txt================第七课 进程通信================一.基本概念------------1. 何为进程间通信~~~~~~~~~~~~~~~~~进程间通信(Interprocess Communication, IPC)是指两个,或多个进程之间进行数据交换的过程.2. 进程间通信分类~~~~~~~~~~~~~~~~~1) 简单进程间通信:命令行参数.环境变量.信号.文件.2) 传统进程间通信:管道(fifo/pipe).3) XSI进程间通信:

进程通信——匿名管道

有的时候在程序的开发过程中,两个进程之间会有数据的交互.信号的机制能够实现进程通信.它通过 “中断--响应” 的异步模式来工作.但作为通信来讲,信号还是远远不够的.因为它不能够携带任何其他的信息.只利用信号机制来实现进程通信显得捉襟见肘,并且信号的优势并不此.所以必须开发新的进程间通信的方法.本文所学习的 "匿名管道" 便是其中的一种最简单的方法. 基本概念 在讲管道的基本概念之前,首先提一个问题.如果让你来设计进程通信的方式,你会怎么做?最简单的方式莫过于两个进程打开同一个文件,这样