【问题标题】:WinAPI SendMessage from .NET来自 .NET 的 WinAPI SendMessage
【发布时间】:2012-05-20 21:45:16
【问题描述】:

我有一个winapi代码示例:

struct CommunicationInfo {
    long internalMsg;
    const TCHAR * srcModuleName;
    void * info; 
  };

...

const TCHAR* szText = _T("Hello from my plugin!\n(test message)");
    CommunicationInfo ci = { 0x0401, cszMyPlugin, (void *) szText };
    ::SendMessage( hNppWnd, 0x111, (WPARAM) _T("NppExec.dll"), (LPARAM) &ci );

我想从 .net 进行相同的调用,我编写了这样的包装器:

[StructLayout(LayoutKind.Sequential)]
    public struct CommunicationInfo
    {
        public Int64 internalMsg;
        [MarshalAs(UnmanagedType.LPWStr)]
        public StringBuilder srcModuleName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public StringBuilder data;
    };

...

[DllImport("user32")]
public static extern IntPtr SendMessage(IntPtr hWnd, 
    NppMsg Msg, IntPtr wParam, 
    [MarshalAs(UnmanagedType.Struct)] CommunicationInfo communicationInfo);

...

SendMessage(hNppWnd, 0x111, 
    Marshal.StringToHGlobalUni("NppExec.dll"), 
    new CommunicationInfo 
    { 
        data = new StringBuilder("test test"),
        internalMsg = 0x0401,
        srcModuleName = new StringBuilder("ModuleName")
    });

但是这段代码不起作用。我哪里做错了?

【问题讨论】:

    标签: pinvoke sendmessage


    【解决方案1】:

    我相信,CommunicationInfo 结构中的“long”字段在 WinAPI 中是 32 位的。所以尝试在 C# 中将“internalMsg”定义为 System.Int32

    为了确定,请尝试在 C/C++ 中调用 printf("%d\n", sizeof(CommunicationInfo)) 以了解实际大小。如果在 32 位系统上是 (4 + 4 + 4),那么 C# 结构也必须是 12 字节大小。

    “char*”指针也必须是指向非托管内存的指针,所以 StringBuilder 不会这样做。

    有关编组示例,请参阅此 PInvoke error when marshalling struct with a string in it

    【讨论】:

    • Попробовал с Int32 - то же самое。 А чтобы проверить printf("%d\n", sizeof(CommunicationInfo)) нету компилятора под рукой。 в любом случае, зная реальный размер CommunicationInfo, как я смогу задать его через .net ?
    • “[MarshalAs(UnmanagedType.LPWStr)] public StringBuilder srcModuleName;”也很麻烦。尝试在 SO 中搜索如何编组字符串指针的答案。 StringBuilder 无济于事。您必须为每个字段分配非托管内存。
    • 是的,在 Windows 上,long 对于 32 位和 64 位进程在 C 和 C++ 中都是 32 位。
    • 刚刚向 OP 指出了问题。当然,long 在 Windows 上是 32 位的。寻址/int模式列表在这里unix.org/version2/whatsnew/lp64_wp.html
    【解决方案2】:

    正如 Viktor 指出的那样,C/C++ long 的大小为 32 位,因此需要与 C# int 匹配。最重要的是,没有正确处理结构的传递。此外,对StringToHGlobalUni 的调用会泄漏,因为您从未调用过FreeHGlobal

    我可能会像这样处理编组:

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct CommunicationInfo
    {
        public int internalMsg;
        public string srcModuleName;
        public string data;
    };
    ....
    [DllImport("user32")]
    public static extern IntPtr SendMessage(
        IntPtr hWnd, 
        uint Msg, 
        [MarshalAs(UnmanagedType.LPWStr)] string wParam, 
        ref CommunicationInfo communicationInfo
    );
    ....
    CommunicationInfo communicationInfo = new CommunicationInfo 
    { 
        internalMsg = 0x0401,
        srcModuleName = "ModuleName",
        data = "test test"
    };
    SendMessage(hNppWnd, 0x111, "NppExec.dll", ref communicationInfo);
    

    【讨论】:

    • hNppWnd 是与运行代码在同一进程中的窗口。无论如何,您的代码工作正常。谢谢!
    • 很好。我只是想覆盖所有的基础!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多