7

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

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

这是 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;
    }
}

有任何想法吗?

4

2 回答 2

7

如果没有有关您的设置的更多信息,我不确定您一定会出错。我尽可能地复制了代码(在 WPF 应用程序中使用 WndProc,从我自己的 win32 应用程序发送),它对我来说很好。如果您正在运行 64 位应用程序,肯定会出现一些错误,即 Pack = 1 将导致 COPYDATASTRUCT 未对齐,并且从指针读取可能会以痛苦结束。

它只是通过整数而崩溃吗?查看传递 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;
}
于 2009-12-14T22:32:08.007 回答
3

我已经构建了几个应用程序(分别使用 VC++ 和 VC#),解决了问题的“简化”变体(即无法获取该结构),它们似乎完美地工作,所以它可能真的是什么正如tyranid所说,使用您的设置。

无论如何,这是代码(只需将其粘贴到新创建的WIN32 APPLICATION(用于 VC++)和WINDOWS FORMS APPLICATION以供 C# 运行和测试就足够了):

StackProxy.cpp

#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;
}

Form1.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);
        }
    }
}

希望这可以帮助。

PS 我对 C# 和(尤其是)互操作(主要对 C++ 编程感兴趣)知之甚少,但 [几小时前] 没有人回答我只是认为尝试这个问题将是一个很好的挑战。更不用说赏金了:)

*amn it,我迟到了:))

于 2009-12-15T00:37:19.710 回答