【问题标题】:Passing struct from unmanaged C++ to C#将结构从非托管 C++ 传递到 C#
【发布时间】:2013-09-02 09:43:46
【问题描述】:

注意:最终的工作解决方案是在编辑之后!

我希望有人可以帮助我解决我过去几天一直试图解决的问题。

我正在尝试将结构从非托管 C++ DLL 传递到 C# 脚本。这是我目前所拥有的:

C++

EXPORT_API uchar *detectMarkers(...) {
    struct markerStruct {
            int id;
    } MarkerInfo;

    uchar *bytePtr = (uchar*) &MarkerInfo;

    ...

    MarkerInfo.id = 3;
    return bytePtr;
}

C#

[DllImport ("UnmanagedDll")] 
    public static extern byte[] detectMarkers(...);

...

[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 1)]
public struct markerStruct
{
    [MarshalAs(UnmanagedType.U4)]
    [FieldOffset(0)]
    public int Id;
}

...

markerStruct ByteArrayToNewStuff(byte[] bytes){
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    markerStruct stuff = (markerStruct)Marshal.PtrToStructure(
        handle.AddrOfPinnedObject(), typeof(markerStruct));
    handle.Free();
    return stuff;
}

...

print(ByteArrayToNewStuff (detectMarkers(d, W, H, d.Length) ).Id);

问题是这可行,但打印的值完全关闭(有时打印大约 400,有时打印最大 int 值)。

我猜我在 C# 中编组结构的方式有问题。有什么想法吗?

编辑:

这是使用参考的工作解决方案:

C++

struct markerStruct {
    int id;
};

...

EXPORT_API void detectMarkers( ... , markerStruct *MarkerInfo) {
    MarkerInfo->id = 3;
    return;
}

C#

[DllImport ("ArucoUnity")] 
    public static extern void detectMarkers( ... ,
        [MarshalAs(UnmanagedType.Struct)] ref MarkerStruct markerStruct);

...

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct MarkerStruct
{
    public int Id;
}

...

detectMarkers (d, W, H, d.Length, ref markerInfo);      
print( markerInfo.Id );

【问题讨论】:

    标签: c# c++ unmanaged


    【解决方案1】:

    您正在返回一个指向局部变量的指针,该变量在 .NET 可以读取之前已被销毁。这在纯 C++ 中是个坏主意,而在 p/invoke 中是个坏主意。

    相反,让 C# 传递一个指向结构的指针(只需使用 ref 关键字),然后 C++ 代码只需填写它。

    【讨论】:

    • 我尝试使用 ref,但我仍然没有设法得到正确的值...你能看看我编辑的问题吗?
    • @kolarek:就像我在回答中所说的那样,当您使用 refout 关键字时,C# 实际上会传递一个指针。所以在 C++ 端使用void detectMarkers( /*...*/ markerStruct* MarkerInfo),然后使用MarkerInfo->id = 3;。另外,去掉 p/invoke 签名中的 In 属性,这意味着不会从 C++ 中取回数据,这显然与您想要的相反。
    • 非常感谢,我已经启动并运行了!
    • @kolarek:很高兴听到这个消息。如果此答案解决了您的问题,请单击其左侧的空心复选标记,让未来的访问者知道这是正确的解决方案。此外,很高兴看到您将工作代码添加到您的问题中。
    【解决方案2】:

    MarkerInfo 变量是本地变量,在函数返回时超出范围。 不要返回指向局部变量的指针,它们指向的对象将不再存在。

    【讨论】:

    • 谢谢!你对我应该怎么做有什么建议吗?
    【解决方案3】:

    打算试一试...感谢帖子...

    // new struct and generic return for items to 
    struct  _itemStruct
    {
        unsigned int id; // 0 by default, so all lists should start at 1, 0 means unassigned
        wchar_t *Name;
    };
    
    // for DLL lib precede void with the following... 
    // EXPORT_API 
    void getItems(std::vector<_itemStruct *> *items)
    {
        // set item list values here
    
    
        //unsigned char *bytePtr = (unsigned char*)&items; // manual pointer return
    
        return;
    };
    
    /* // In theory c# code will be...
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct _itemStruct
    {
        public unsigned int Id;
        public string Name;
    }
    
    [DllImport ("ListOfItems")] // for ListOfItems.DLL
    public static extern void getItems(
    [MarshalAs(UnmanagedType.Struct)] ref List<_itemStruct> items);
    // */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 2021-12-29
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      • 2021-08-19
      相关资源
      最近更新 更多