首页 > 解决方案 > 使用系统 Windows 自动化发送 WM_COPYDATA 消息

问题描述

我正在使用以下代码将消息/命令发送到另一个窗口/进程。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace AvroSwitch
{
    public class clsSwitch
    {
        [DllImport("User32.dll")]
        private static extern int RegisterWindowMessage(string lpString);

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

        //For use with WM_COPYDATA and COPYDATASTRUCT
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

        public const int WM_COPYDATA = 0x4A;

        //Used for WM_COPYDATA for string messages
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

        private static int sendWindowsStringMessage(int hWnd, int wParam, string msg)
        {
            int result = -1;

            if (hWnd > 0)
            {
                byte[] sarr = System.Text.Encoding.Unicode.GetBytes(msg);
                sarr = System.Text.Encoding.Convert(ASCIIEncoding.ASCII, UnicodeEncoding.Unicode, sarr);
                int len = sarr.Length;
                COPYDATASTRUCT cds;
                cds.dwData = (IntPtr)0;
                cds.lpData = System.Text.Encoding.Unicode.GetString(sarr);
                cds.cbData = len + 1;
                result = SendMessage(hWnd, WM_COPYDATA, wParam, ref cds);
            }

            return result;
        }

        private static int getWindowId(string className, string windowName)
        {
            return FindWindow(className, windowName);
        }

        public static int toBangla()
        {
            return sendWindowsStringMessage(getWindowId("TAvroMainForm1", null), 0, "bn");
        }

        public static int toEnglish()
        {
            return sendWindowsStringMessage(getWindowId("TAvroMainForm1", null), 0, "sys");
        }
    }
}

我正在使用 2 个函数 toBangle() 和 toEnglish(),但它们都不起作用。

但上面的代码不起作用。我认为这可以使用系统 Windows 自动机轻松实现。

更新 1:

这是来自 delphi 中第三方应用程序的代码,用于将确切的命令发送到主应用程序/窗口。

Function SendCommand(cmd: String): boolean;
Var
     copyDataStruct           : TCopyDataStruct;
     receiverHandle           : THandle;
Begin
     result := false;
     copyDataStruct.dwData := 0;        //0=string
     copyDataStruct.cbData := 1 + Length(cmd);
     copyDataStruct.lpData := PChar(cmd);

     receiverHandle := FindWindow(PChar('TAvroMainForm1'), Nil);
     If receiverHandle = 0 Then
          Exit;


     SendMessage(receiverHandle, WM_COPYDATA, 0, Integer(@copyDataStruct));
     Result := True;
End;

更新 2:

这是处理 wm 命令的主窗口/应用程序的代码:

Procedure TAvroMainForm1.WMCopyData(Var Msg: TWMCopyData);
Var
         cmd: String;
Begin
         cmd := PChar(Msg.CopyDataStruct.lpData);
         cmd := Lowercase(cmd);

         If cmd = 'bn' Then Begin
                    KeyLayout.BanglaMode;
                    // Send something back
                    Msg.result := 21;
         End;

         If cmd = 'sys' Then Begin
                    KeyLayout.SysMode;

                    // Send something back
                    Msg.result := 21;
         End;
End;

任何帮助将不胜感激..

标签: c#vb.netwinapiautomation

解决方案


尝试以下方法传递 ANSI 文本

string msg = "bn"; //or "sys"
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)0;
cds.lpData = msg;
cds.cbData = Encoding.Default.GetBytes(msg).Length;
SendMessage(hwnd, WM_COPYDATA, wParam, ref cds);

这应该可以工作,因为lpData已经编组

public struct COPYDATASTRUCT
{
    public IntPtr dwData;
    public int cbData;
    [MarshalAs(UnmanagedType.LPStr)]
    public string lpData;
}

推荐阅读