问题
Note: The final working solution is after the edit!
I hope someone can help me with a problem I've been trying to solve for the last few days.
I am trying to pass a struct from a unmanaged C++ DLL to a C# script. This is what I have so far:
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);
The problem is that this works, but the value printed is completely off (sometimes it prints around 400, sometimes max int value).
I'm guessing that there's something wrong with how I marshalled the struct in C#. Any ideas?
Edit:
This is the working solution using ref:
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 );
回答1:
You're returning a pointer to a local variable which has already been destroyed before .NET can read it. That's a bad idea in pure C++ and a bad idea with p/invoke.
Instead, have C# pass a pointer to a structure (just use the ref
keyword) and the C++ code just fill it in.
回答2:
The MarkerInfo variable is local and goes out of scope when the function returns. Don't return pointers to local variables, the objects they point to won't exist anymore.
回答3:
Going to give this a whirl... thx for the post...
// 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);
// */
来源:https://stackoverflow.com/questions/18519729/passing-struct-from-unmanaged-c-to-c-sharp