代码之家  ›  专栏  ›  技术社区  ›  Matthew Olenik

使用WMLCopyDATA从C++向WPF发送结构

  •  7
  • Matthew Olenik  · 技术社区  · 15 年前

    我有一个本地C++应用程序,暂时只需要将它的命令行字符串和当前鼠标指针坐标发送到WPF应用程序。消息发送和接收都很好,但我无法转换 IntPtr C中的实例到结构。

    当我尝试这样做时,应用程序将毫无例外地崩溃,或者跳过转换它的代码行并接收循环中的下一条消息。这可能意味着有一个本机异常发生,但我不知道为什么。

    这是C++程序。目前,我忽略了命令行字符串,并使用假光标坐标来确保工作正常。

    #include "stdafx.h"
    #include "StackProxy.h"
    #include "string"
    
    typedef std::basic_string<WCHAR, std::char_traits<WCHAR>> wstring;
    
    struct StackRecord
    {
        //wchar_t CommandLine[128];
        //LPTSTR CommandLine;
        //wstring CommandLine;
        __int32 CursorX;
        __int32 CursorY;
    };
    
    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    {
        COPYDATASTRUCT data;
        ZeroMemory(&data, sizeof(COPYDATASTRUCT));
    
        StackRecord* record = new StackRecord();
    
        wstring cmdLine(lpCmdLine);
        //record.CommandLine = cmdLine;
        record->CursorX = 5;
        record->CursorY = 16;
        data.dwData = 12;
        data.cbData = sizeof(StackRecord);
        data.lpData = record;
    
        HWND target = FindWindow(NULL, _T("Window1"));
    
        if(target != NULL)
        {
            SendMessage(target, WM_COPYDATA, (WPARAM)(HWND) target, (LPARAM)(LPVOID) &data);
        }
        return 0;
    }
    

    这里是WPF应用程序接收消息的部分。if语句中的第二行将被跳过,如果整个过程不只是崩溃的话。

        public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == Interop.WM_COPYDATA)
            {
                var data = (Interop.CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(Interop.CopyDataStruct));
                var record = (Interop.StackRecord)Marshal.PtrToStructure(data.lpData, typeof(Interop.StackRecord));
                MessageBox.Show(String.Format("X: {0}, Y: {1}", record.CursorX, record.CursorY));
            }
            return IntPtr.Zero;
        }
    

    这里是结构的C定义。我不断玩弄编组属性,却一无所获。

    internal static class Interop
    {
        public static readonly int WM_COPYDATA = 0x4A;
    
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct CopyDataStruct
        {
            public IntPtr dwData;
            public int cbData;
            public IntPtr lpData;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        public struct StackRecord
        {
            //[MarshalAs(UnmanagedType.ByValTStr)]
            //public String CommandLine;
            public Int32 CursorX;
            public Int32 CursorY;
        }
    }
    

    有什么想法吗?

    2 回复  |  直到 15 年前
        1
  •  7
  •   tyranid    15 年前

    如果没有关于设置的更多信息,我不确定您的错误是什么。我尽可能地复制代码(在WPF应用程序中使用wndproc,从我自己的win32应用程序发送),它对我来说很好。如果运行64位应用程序,则会出现一些错误,即pack=1将导致copydatastruct错位,从指针读取可能会导致痛苦。

    它是崩溃通过只是ints?查看通过lpwstr或wstring传递的注释代码将导致严重的问题,尽管在取消对发送的数据的标记之前,这不应该变得明显。

    值得一提的是,这是我的代码片段,对我来说很有用,包括让命令行通过。

    /* C++ code */
    struct StackRecord
    {
        wchar_t cmdline[128];
        int CursorX;
        int CursorY;
    };
    
    void SendCopyData(HWND hFind)
    {
        COPYDATASTRUCT cp;
        StackRecord record;
    
        record.CursorX = 1;
        record.CursorY = -1;
    
        _tcscpy(record.cmdline, L"Hello World!");
        cp.cbData = sizeof(record);
        cp.lpData = &record;
        cp.dwData = 12;
        SendMessage(hFind, WM_COPYDATA, NULL, (LPARAM)&cp);
    }
    
    /* C# code */
    public static readonly int WM_COPYDATA = 0x4A;
    
    [StructLayout(LayoutKind.Sequential)]
    public struct CopyDataStruct
    {
        public IntPtr dwData;
        public int cbData;
        public IntPtr lpData;
    }
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct StackRecord
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
        public string CommandLine;
        public Int32 CursorX;
        public Int32 CursorY;
    }
    
    protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_COPYDATA)
        {
            StackRecord record = new StackRecord();
            try
            {
                CopyDataStruct cp = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));
                if (cp.cbData == Marshal.SizeOf(record))
                {
                    record = (StackRecord)Marshal.PtrToStructure(cp.lpData, typeof(StackRecord));
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }
            handled = true;
        }
        else
        {
            handled = false;
        }
        return IntPtr.Zero;
    }
    
        2
  •  3
  •   Community datashaman    7 年前

    我已经构建了两个应用程序(分别使用vc++和vc),解决了问题的“分解”变体(即无法获得该结构),它们看起来工作得很完美,因此它可能确实与您的设置有关,如 tyranid 说。

    总之,这是代码(它必须足够粘贴到新创建的 Win32应用程序 (对于VC++)和 Windows窗体应用程序 对于C运行和测试):

    斯塔克普罗西普

    #include "stdafx.h"
    #include "StackProxy.h"
    #include <string>
    
    
    struct StackRecord {
        __int32 CursorX;
        __int32 CursorY;
    };
    
    
    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
        StackRecord record;
    
        record.CursorX = 5;
        record.CursorY = 16;
    
        COPYDATASTRUCT data;
    
        data.dwData = 12;
        data.cbData = sizeof(StackRecord);
        data.lpData = &record;
    
        HWND target = FindWindow(NULL, _T("Window1"));
    
        if(target != NULL)
            SendMessage(target, WM_COPYDATA, (WPARAM)(HWND) target, (LPARAM)(LPVOID) &data);
    
        return 0;
    }
    

    格式1.CS

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public struct COPYDATASTRUCT
            {
                public System.Int32 dwData;
                public System.Int32 cbData;
                public System.IntPtr lpData;
            }
    
            int WM_COPYDATA = 0x4A;
    
            [StructLayout(LayoutKind.Sequential)]
            public struct StackRecord
            {
                public Int32 CursorX;
                public Int32 CursorY;
            }
    
            public Form1()
            {
                InitializeComponent();
                Text = "Window1";
            }
    
            protected override void WndProc(ref Message msg)
            {
                if (msg.Msg == WM_COPYDATA) {
                    COPYDATASTRUCT cp = (COPYDATASTRUCT)Marshal.PtrToStructure(msg.LParam, typeof(COPYDATASTRUCT));
                    StackRecord record = (StackRecord)Marshal.PtrToStructure(cp.lpData, typeof(StackRecord));
                    MessageBox.Show(String.Format("X: {0}, Y: {1}, Data: {2}", record.CursorX, record.CursorY, cp.dwData));
                } 
                base.WndProc(ref msg);
            }
        }
    }
    

    希望这有帮助。

    P.S.我对C语言和(尤其是)互操作(对C++编程感兴趣)没有太多的了解,但是在几小时前没有人回答,只是觉得尝试这个问题是一个很好的挑战。更不用说赏金了。)

    *嗯,我迟到了。)