• 进程通信之一 使用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类型转化成一个字符串时,函数会在字符串末尾加下' ',因为发送前要将这个' '去掉。

    发送消息的程序代码(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()返回的字符串后面带了'
    '
            CopyData.dwData = i;
            CopyData.cbData = strlen(szSendBuf);
            szSendBuf[CopyData.cbData - 1] = '';
            CopyData.lpData = szSendBuf;
    
            SendMessage(hRecvWindow, WM_COPYDATA, (WPARAM)hSendWindow, (LPARAM)&CopyData);
            printf("%s
    ", 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
    lpData:0x%08x = %s
    
    ", 
                    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();
    
        }
    }
  • 相关阅读:
    【Spring】注解的循环依赖问题
    【网络】计算机网络自顶向下读书笔记
    【JUC】并发编程的艺术笔记
    【JUC】多线程手撕代码面试题
    【操作系统】王道操作系统全盘汇总
    【Spring】IoC源码分析以及实现
    【Spring】用例子来初次理解IoC
    拼音工具类
    chr(10)与chr(13)的区别
    List 集合转String 逗号拼接
  • 原文地址:https://www.cnblogs.com/zeroone/p/3734680.html
Copyright © 2020-2023  润新知