进程间通信最简单的方式就是发送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?

  1. #include <windows.h>   
  2. #include <time.h>   
  3. #include <conio.h>   
  4. #include <stdio.h>   
  5. int main()  
  6. {  
  7.     const char szDlgTitle[] = "RecvMessage";  
  8.   
     
  9.     HWND hSendWindow = GetConsoleWindow ();  
  10.     if (hSendWindow == NULL)  
  11.         return -1;  
  12.     HWND hRecvWindow = FindWindow(NULL, szDlgTitle);  
  13.     if (hRecvWindow == NULL)  
  14.         return -1;  
  15.   
     
  16.     char szSendBuf[100];  
  17.     time_t  timenow;  
  18.     COPYDATASTRUCT CopyData;  
  19.   
     
  20.     for (int i = 0; i < 10; i++)  
  21.     {  
  22.         time(&timenow);  
  23.         sprintf(szSendBuf, "%s", ctime(&timenow));//注意,ctime()返回的字符串后面带了'\n'   
  24.         CopyData.dwData = i;  
  25.         CopyData.cbData = strlen(szSendBuf);  
  26.         szSendBuf[CopyData.cbData - 1] = '\0';  
  27.         CopyData.lpData = szSendBuf;  
  28.   
     
  29.         SendMessage(hRecvWindow, WM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);  
  30.         printf("%s\n", szSendBuf);  
  31.         Sleep(1000);  
  32.     }  
  33.     return 0;  
  34. }  

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

  1. #include "stdafx.h"   
  2. #include "resource.h"   
  3. #include <stdio.h>   
  4. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);  
  5. int APIENTRY WinMain(HINSTANCE hInstance,  
  6.                      HINSTANCE hPrevInstance,  
  7.                      LPSTR     lpCmdLine,  
  8.                      int       nCmdShow)  
  9. {  
  10.     // TODO: Place code here.   
  11.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);  
  12.     return 0;  
  13. }  
  14. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  15. {  
  16.     const char szDlgTitle[] = "RecvMessage";  
  17.     static HWND s_hEditShowRecv;  
  18.   
     
  19.     switch (message)  
  20.     {  
  21.     case WM_INITDIALOG:  
  22.         SetWindowText(hDlg, szDlgTitle);  
  23.         s_hEditShowRecv = GetDlgItem(hDlg, IDC_EDIT_RECVMESSAGE);  
  24.         return TRUE;  
  25.   
     
  26.     case WM_COMMAND:  
  27.         switch (LOWORD(wParam))  
  28.         {  
  29.         case IDOK:  
  30.         case IDCANCEL:  
  31.             EndDialog(hDlg, LOWORD(wParam));  
  32.             return TRUE;  
  33.         }  
  34.         break;  
  35.   
     
  36.     case WM_COPYDATA:  
  37.         {  
  38.             COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;  
  39.             char szBuffer[300];  
  40.   
     
  41.             memset(szBuffer, 0, sizeof(szBuffer));  
  42.             sprintf(szBuffer, "dwData:%d cbData:%d\r\nlpData:0x%08x = %s\r\n\r\n",   
  43.                 pCopyData->dwData, pCopyData->cbData,   
  44.                 (PVOID)pCopyData->lpData, (char*)pCopyData->lpData);  
  45.             //在编辑框中追加数据   
  46.             SendMessage(s_hEditShowRecv, EM_SETSEL, (WPARAM)-1, (LPARAM)-1); // (0, -1)表示全选, (-1,任意)表示全不选   
  47.             SendMessage(s_hEditShowRecv, EM_REPLACESEL, FALSE, (LPARAM)szBuffer);  
  48.             SendMessage(s_hEditShowRecv, EM_SCROLLCARET, 0, 0);  
  49.         }  
  50.         return TRUE;  
  51.     }  
  52.     return FALSE;  
  53. }  

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

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using System.Threading;  
  5. using System.Runtime.InteropServices;  //[DllImport("user32.dll")]中DllImport的命名空间   
  6.   
     
  7. namespace UseWMCOPYDATA  
  8. {  
  9.     class Program  
  10.     {  
  11.         static void Main(string[] args)  
  12.         {  
  13.             string strDlgTitle = "RecvMessage";   
  14.   
     
  15.             //接收端的窗口句柄   
  16.             IntPtr hwndRecvWindow = ImportFromDLL.FindWindow(null, strDlgTitle);  
  17.             if (hwndRecvWindow == IntPtr.Zero)  
  18.             {  
  19.                 Console.WriteLine("请先启动接收消息程序");  
  20.                 return;  
  21.             }  
  22.   
     
  23.             //自己的窗口句柄   
  24.             IntPtr hwndSendWindow = ImportFromDLL.GetConsoleWindow();  
  25.             if (hwndSendWindow == IntPtr.Zero)  
  26.             {  
  27.                 Console.WriteLine("获取自己的窗口句柄失败,请重试");  
  28.                 return;  
  29.             }  
  30.   
     
  31.             for (int i = 0; i < 10; i++)  
  32.             {  
  33.                 string strText = DateTime.Now.ToString();  
  34.                 //填充COPYDATA结构   
  35.                 ImportFromDLL.COPYDATASTRUCT copydata = new ImportFromDLL.COPYDATASTRUCT();  
  36.                 copydata.cbData = Encoding.Default.GetBytes(strText).Length; //长度 注意不要用strText.Length;   
  37.                 copydata.lpData = strText;                                   //内容   
  38.   
     
  39.                 ImportFromDLL.SendMessage(hwndRecvWindow, ImportFromDLL.WM_COPYDATA, hwndSendWindow, ref copydata);  
  40.   
     
  41.                 Console.WriteLine(strText);  
  42.                 Thread.Sleep(1000);  
  43.             }  
  44.   
     
  45.         }  
  46.     }  
  47.   
     
  48.     public class ImportFromDLL  
  49.     {  
  50.         public const int WM_COPYDATA = 0x004A;  
  51.   
     
  52.         //启用非托管代码   
  53.         [StructLayout(LayoutKind.Sequential)]   
  54.         public struct COPYDATASTRUCT   
  55.         {  
  56.             public int dwData;    //not used   
  57.             public int cbData;    //长度   
  58.             [MarshalAs(UnmanagedType.LPStr)]  
  59.             public string lpData;   
  60.         }  
  61.   
     
  62.         [DllImport("User32.dll")]  
  63.         public static extern int SendMessage(  
  64.             IntPtr hWnd,     // handle to destination window    
  65.             int Msg,         // message   
  66.             IntPtr wParam,    // first message parameter    
  67.             ref COPYDATASTRUCT pcd // second message parameter    
  68.         );  
  69.   
     
  70.         [DllImport("User32.dll", EntryPoint = "FindWindow")]  
  71.         public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);  
  72.   
     
  73.         [DllImport("Kernel32.dll", EntryPoint = "GetConsoleWindow")]  
  74.         public static extern IntPtr GetConsoleWindow();  
  75.   
     
  76.     }  
  77. }  

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#实现(转)的更多相关文章

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

    原文地址:http://blog.csdn.net/morewindows/article/details/6804157 进程间通信最简单的方式就是发送WM_COPYDATA消息.本文提供C++及C ...

  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. 致诸位新程序员:来自Chuck Jazdzewski慈父般的忠告

    记住这几句话,学无止境.(Never stop learning.)沟通至关重要.(Communication is critical.)履行承诺,胜过交付.(Under promise, over ...

  2. arcgis api for javascript 出现 undefinedModule错误

    一般都是script代码里面语法错误,如. .;:之类的

  3. rhel-server-7.2-x86_64无法联网(VMware环境)

    vim /etc/sysconfig/network-script vim ifcfg-eno16777736 (编辑网卡名) 将ONBOOT=NO更改为YES (启动network服务时是否启用该网 ...

  4. highcharts 结合phantomjs纯后台生成图片系列二之php

    上篇文章中介绍了phantomjs的使用场景,方法.本篇文章详细介绍使用php,highcharts 结合phantomjs纯后台生成图片. 一.准备: 下载phantomjs解析插件,从 highc ...

  5. OpenCV码源笔记——RandomTrees (二)(Forest)

    源码细节: ● 训练函数 bool CvRTrees::train( const CvMat* _train_data, int _tflag,                        cons ...

  6. LA 6187 - Never Wait for Weights 并查集的带权路径压缩

    只有一个地方需要注意: 设节点a的根为u,b的跟为v,则:a = u + d[a];  b = v + d[b]; 已知:b-a=w.所以v - u = d[a] - d[b] + w; 在合并两个集 ...

  7. Python3 学习第四弹:编码问题(转载)

    关于python的编码问题一直以来不得解,终于在今天从这篇博文中明白了. 原文地址: http://nedbatchelder.com/text/unipain.html 译文地址:http://py ...

  8. UVALive 3486/zoj 2615 Cells(栈模拟dfs)

    这道题在LA是挂掉了,不过还好,zoj上也有这道题. 题意:好大一颗树,询问父子关系..考虑最坏的情况,30w层,2000w个点,询问100w次,貌似连dfs一遍都会TLE. 安心啦,这肯定是一道正常 ...

  9. Math.trunc

  10. mysql违背了唯一约束

    执行一批数据,违背唯一约束时会中断,导致后面的数据写不进去. mysql有提供ignore关键字,使用insert ignore into .... 这样,当违背了唯一约束的时候~就会直接跳过,不会报 ...