原文地址: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 -;
HWND hRecvWindow = FindWindow(NULL, szDlgTitle);
if (hRecvWindow == NULL)
return -; char szSendBuf[];
time_t timenow;
COPYDATASTRUCT CopyData; for (int i = ; i < ; i++)
{
time(&timenow);
sprintf(szSendBuf, "%s", ctime(&timenow));//注意,ctime()返回的字符串后面带了'\n'
CopyData.dwData = i;
CopyData.cbData = strlen(szSendBuf);
szSendBuf[CopyData.cbData - ] = '\0';
CopyData.lpData = szSendBuf; SendMessage(hRecvWindow, WM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);
printf("%s\n", szSendBuf);
Sleep();
}
return ;
}

接收消息程序代码(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 ;
}
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[]; memset(szBuffer, , 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)-, (LPARAM)-); // (0, -1)表示全选, (-1,任意)表示全不选
SendMessage(s_hEditShowRecv, EM_REPLACESEL, FALSE, (LPARAM)szBuffer);
SendMessage(s_hEditShowRecv, EM_SCROLLCARET, , );
}
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 = ; i < ; 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();
} }
} 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的更多相关文章

  1. 进程通信之一 使用WM_COPYDATA C++及C#实现(转)

    进程间通信最简单的方式就是发送WM_COPYDATA消息.本文提供C++及C#程序相互通信的二种实现方式.这样消息的接收端可以用C++实现,发送端可以用C++或C#实现.     发送WM_COPYD ...

  2. WinForm实现跨进程通信的方法

    public class WinMessageHelper { private struct COPYDATASTRUCT { public IntPtr dwData; public int cbD ...

  3. [转]WINDOW进程通信的几种方式

    windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...

  4. 进程通信-SendMessage使用方法

    进程通信-SendMessage的使用方法 用过SendMessage进行进程通信的同学都知道,这个函数一般都搭配FindWindow使用.通过FindWindow查找进程句柄,然后使用SendMes ...

  5. Windows提高_1.4进程通信

    进程通信 使用 WM_COPYDATA 客户端(发送端) // 1. 找到窗口程序 HWND hWnd = FindWindow(NULL, L"Window1"); ​ // 2 ...

  6. unity3d进程通信利用WM_COPYDATE和HOOK

    hello,近期用unity做了进程通信,应该是和c++的PC端实现通信,才開始一头雾水,后来实现了才知道好繁杂......先感谢对我提供帮助的百度,谷歌以及游戏圈的大大们. 在进程通信中非常多方法, ...

  7. 进程以及进程通信(IPC)类型

    这里用我有限的知识来解释同时参考了一些其他博主的子类,希望能给与一部分入门的朋友一个清晰的理解,有问题之处还请指出 首先简单谈一下什么是进程? 答:进程是装入内存运行的程序段,是许多的系统对象拥有权的 ...

  8. Windows线程+进程通信

    一 Windows线程进程 1)定义 按照MS的定义, Windows中的进程简单地说就是一个内存中的可执行程序, 提供程序运行的各种资源. 进程拥有虚拟的地址空间, 可执行代码, 数据, 对象句柄集 ...

  9. 几种Windows进程通信

    32位Windows采用虚拟内存技术使每个进程虚拟4G内存,在逻辑上实现了对进程之间数据代码的分离与保护.那么相应的进程之间的通信也就有必要整理掌握一下. Windows进程间通讯的方法有很多:管道. ...

随机推荐

  1. SQL 跨服务器数据库增、删、改、查(一)

    --开启本服务器中操作其他服务器的功能 reconfigure --输出消息 reconfigure --输出消息 --增 INSERT INTO OPENROWSET('SQLOLEDB','jx3 ...

  2. 关于 .net 开发 Office Word 的一些问题小结

    1.在"组件服务"的DCom配置中找到Microsoft Office Word =>属性=>标识选项卡,然后选择交互式用户:::=>"安全" ...

  3. (转载)Cocos2dx-OpenGL ES2.0教程:你的第一个立方体(5)

    在上篇文章中,我们介绍了VBO索引的使用,使用VBO索引可以有效地减少顶点个数,优化内存,提高程序效率. 本教程将带领大家一起走进3D–绘制一个立方体.其实画立方体本质上和画三角形没什么区别,所有的模 ...

  4. 经管资源库项目总结----在线预览office文件的实现与总结

    依旧是这个经管的项目.在线预览作为资源和文档管理系统的一个很酷的并且是如此重要的功能,是必须要实现的.然后百度一下office在线预览,看起来so eazy啊,各种博客各种demo,一下子就做出效果来 ...

  5. 莫名其妙的主机名 VM_32_234_centos

    在腾讯服务器上部署的时候出现的莫名其妙的错误, 我在配置文件上都写 master, node1, 但是运行mapredure的时候的时候老是出现 Job job_1409546978133_0001 ...

  6. Akka Stream文档翻译:Quick Start Guide: Reactive Tweets

    Quick Start Guide: Reactive Tweets 快速入门指南: Reactive Tweets (reactive tweets 大概可以理解为“响应式推文”,在此可以测试下GF ...

  7. Avro RPC 之 Protocol 定义和代码生成

    摘自http://avro.apache.org/docs/current/spec.html#Protocol+Declaration,1.7.6版 Protocol Declaration Avr ...

  8. Android支付接入(五):机锋网

    原地址:http://blog.csdn.net/simdanfeg/article/details/9012083 前边已经陆续跟大家走了一遍运营商和支付宝付费接入,今天跟大家一起看看机锋网的支付接 ...

  9. spark storage之SparkEnv

    此文旨在对spark storage模块进行分析,整理自己所看所得,等以后再整理. ok,首先看看SparkContext中sparkEnv相关代码: private[spark] def creat ...

  10. Fiddler 日志

    Fiddler 日志(Logging) 在开发扩展插件及编写FiddlerScript时对调试程序非常有用. 1.输出日志 在FiddlerScript脚本中,你可以这样输出输出日志: Fiddler ...