分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

进程间通信最简单的方式就是发送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 -1char 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;  }  breakcase 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;}

运行结果如下 (先启动接收消息程序再运行发送消息程序):

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

 

 

有的时候,发送消息程序用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#实现

 

 下一篇《进程通信之二 管道技术第一篇 输入输出的重定向》示范了程序输入输出的重定向,以及如何用管道来完成进程之间的通信。

 

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/6804157

 

 

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

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

相关文章: