简体   繁体   English

调用外部C ++方法时无法识别字节数组

[英]Byte array is not recognised when calling external C++ method

There is C++ api: 有C ++ API:

typedef struct
{
    BYTE    bCommandCode;
    BYTE    bParameterCode;

    struct
    {
        DWORD   dwSize;
        LPBYTE  lpbBody;
    }
    Data;
}
COMMAND;

And a function: 和一个功能:

DLL_API DWORD WINAPI ExecuteCommand( LPCSTR, CONST COMMAND, CONST DWORD, LPREPLY);

And my C# equivalent code: 和我的C#等效代码:

public struct Data
{
    public int dwSize;
    public byte[] lpbBody;
}

public struct Command
{
    public byte bCommandCode;
    public byte bParameterCode;

    public Data Data;
}

[DllImport(@"api.dll", CallingConvention = CallingConvention.Winapi)]
public static extern int ExecuteCommand(string port, Command command, int timeout, ref Reply reply);

Reply struct is not necessary here. 这里不需要回复结构。

I call ExecuteCommand: 我叫ExecuteCommand:

Command command = new Command();
command.bCommandCode = 0x10;
command.bParameterCode = 0x10;

byte[] bData = { 0xff, 0xff };
command.Data.dwSize = bData.Length;
command.Data.lpbBody = bData;

Reply reply = new Reply();
var result = ExecuteCommand("COM1", command, 5000, ref reply);

When I see logs from C++ dll I see that by byte[] bData is not correctly recognised at all. 当我看到来自C ++ dll的日志时,我看到通过byte [] bData根本无法正确识别。 What I am doing wrong? 我做错了什么? Maybe this definition is not correct: public byte[] lpbBody? 也许这个定义是不正确的:public byte [] lpbBody? How can I pass array as LPBYTE in the struct to the C++ method? 如何在struct中将数组作为LPBYTE传递给C ++方法?

When you allocate a managed object, (such as the byte array you are having issues with) it is mapped to a certain address in the managed heap, which, in turn, is mapped to a certain unmanaged memory address. 分配托管对象(例如遇到问题的字节数组)时,它会映射到托管堆中的某个地址,而该地址又会映射到某个非托管内存地址。 The mapping between managed and unmanaged addresses can change when the GC operates, since it de-fragments the unmanaged memory space assigned to it by moving unmanaged memory chunks around. 当GC运行时,托管地址和非托管地址之间的映射可以更改,因为它通过移动非托管内存块来分散分配给它的非托管内存空间的碎片。

When you invoke an unmanaged API with a byte[] as a reference, the marshaling process basically passes the unmanaged address of the byte array object to the native API. 当您使用byte []作为参考调用非托管API时,封送处理基本上将字节数组对象的非托管地址传递给本机API。 Thus, it is quite possible that the memory address of the byte array no longer points to what you expect it to when you attempt to use it, due to the aforementioned de-fragmentation. 因此,由于前面提到的碎片整理,字节数组的内存地址很可能不再指向您期望使用的字节数组。

I sincerely believe this is what you're experiencing. 我真诚地相信这就是您正在经历的事情。
Luckily, this issue can be easily resolved: 幸运的是,此问题可以轻松解决:

GCHandle pinned = GCHandle.Alloc(bData, GCHandleType.Pinned);
IntPtr arrPtr = pinned.AddrOfPinnedObject();

The first line tells the GC to not fiddle with the Managed -> Unmanaged mapping for this object. 第一行告诉GC不要为此对象管理Managed-> Unmanaged映射。 The second speaks for itself. 第二个不言而喻。 All you have to do now is change the 'Data' struct at the C# side to hold an IntPtr instead of byte[] 您现在要做的就是在C#端更改'Data'结构以保留IntPtr而不是byte []
(no need to change the C++ side). (无需更改C ++端)。

public struct Data
{
    public int dwSize;
    public IntPtr lpbBody;
}

Be sure to call the GCHandle.Free() method when done with the GCHandle object. 使用GCHandle对象完成操作后,请确保调用GCHandle.Free()方法。

I do hope you are marking your marshaled types with the MarshalAsAttribute class and you simply omitted them in the example. 我确实希望您使用MarshalAsAttribute类标记已封送处理的类型,并且在示例中只是将其省略。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM