2009-12-11 90 views
7

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

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

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

任何想法?

+0

我也试过在一个WinForms窗口覆盖的WndProc,行为是一样的。 – 2009-12-13 23:26:06

回答

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; 
} 
+0

“即Pack = 1将导致COPYDATASTRUCT变得不对齐,并且从指针读取可能以痛苦结束。” 啊,现在很明显。我习惯于从Pack = 1的文件中读取结构。 C++应用程序是32位的,但是我有一个64位系统,.NET代码被打印到64位代码。删除包= 1修复了它。谢谢。 “看着你的评论代码传递一个LPWSTR或wstring会导致严重的问题” 我认为这可能是。我也尝试传递一个固定的wchar_t字符串,因为你没有成功,但这是由于上述问题。 – 2009-12-14 23:50:05

3

我已经建立了几个(用VC++和VC#,分别)的应用,解决这个问题的“水煮向下”变种(即无法得到该结构),他们似乎flawelessly工作,所以它可能真的是你的设置,因为tyranid说。

总之,这里的代码(它必须是不够的,只是将其粘贴到新创建的的Win32应用程序(对于VC++)和Windows窗体应用程序为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); 
     } 
    } 
} 

希望这会有所帮助。

P.S.我对C#和(特别是)interop(主要是C++编程感兴趣)没有太多的了解,但几个小时前没有人回答这个问题,只是认为尝试这个问题会是一个很好的挑战。且不说赏金:)

* AMN吧,我来晚了:))

+0

啊,谢谢! – 2009-12-15 02:15:07