P / Invoke Return array of structures with string fields

I use p / invoke to return the "DN_OPstruct" array from my unmanaged code:

struct DN_OPstruct { const char* TargetNode_Identifier; const char* Name; int TargetNode_NamespaceIndex; ... }; EXTERN_C UA_EXPORT_WRAPPER_IMPORT int getOpToArr(const char* _rootGuid, DN_OPstruct ** array, int * arraySizeInElements){ std::list<UA_Ref_and_TargetNode> uaList; uaList = getLisT(...) *arraySizeInElements = uaList.size(); int bytesToAlloc = sizeof(DN_OPstruct) * (*arraySizeInElements); DN_OPstruct * a = static_cast<DN_OPstruct*>(CoTaskMemAlloc(bytesToAlloc)); *array = a; for (UA_Ref_and_TargetNode &i: uaList){ DN_OPstruct iterOp; iterOp = getOp(...); opList.push_back(iterOp); } return 1; } 

My managed code is as follows:

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DN_OPstruct { private IntPtr TargetNode_Identifier; private IntPtr NamePtr; public string Guid { get { return Marshal.PtrToStringAnsi(TargetNode_Identifier); } set { TargetNode_Identifier = Marshal.StringToHGlobalAnsi(value); } } public string Name { get { return Marshal.PtrToStringAnsi(NamePtr); } set { NamePtr = Marshal.StringToHGlobalAnsi(value); } } public int TargetNode_NamespaceIndex; ... }; [DllImport(@"...", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getOpToArr", ExactSpelling = true, CharSet = CharSet.Ansi)] public static extern int getOpToArr([MarshalAs(UnmanagedType.LPStr)]string myNodeGuid, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out DN_OPstruct[] array, out int arraySizeInElements); 

If I try to call a method, I will go into unmanaged code and be able to debug it successfully, and I will get an array with my DN_OPstructs. However, if I read its fields like .Name or .Guid , I get this error:

Exception the first time at 0x000007fefd921757 in (...). exe: 0xC0000005: Access location violation 0xffffffffffffffffff.

If there is a handler for this exception, the program can safely continue.

I tried adding "ArraySubType = UnmanagedType.LPStruct" to the declaration of my method; It did not help.

+5
source share
1 answer
 public static extern int getOpToArr( [MarshalAs(UnmanagedType.LPStr)] string myNodeGuid, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out DN_OPstruct[] array, out int arraySizeInElements ); 

The problem is the second parameter. Unmanaged code cannot synthesize a managed .net array. You need to declare p / invoke as follows:

 public static extern int getOpToArr( string myNodeGuid, out IntPtr arrayPtr, out int arrayLen ); 

Then you will need to use Marshal.PtrToStructure to marshal the elements of the array in a managed array.

 IntPtr arrayPtr; int arrayLen; int retval = getOpToArr(nodeGuid, out arrayPtr, out arrayLen); // check retval IntPtr ptr = arrayPtr; DN_OPstruct[] arr = new DN_OPstruct[arrayLen]; for (int i = 0; i < arrayLen; i++) { arr[i] = (DN_OPstruct)Marshal.PtrToStructure(ptr, typeof(DN_OPstruct)); ptr += Marshal.SizeOf(typeof(DN_OPstruct)); } 

I am also a little skeptical about the properties of your structure. Why do you have setters as well as getters? It does not look like data flows in that direction. And the unmanaged code you use shows the distribution using CoTaskMemAlloc , which does not match StringToHGlobalAnsi . Therefore, despite the fact that I doubt that you should write settings and, perhaps, should delete calls to StringToHGlobalAnsi , I also suspect that you are using confusion over the dispenser used.

Please note that the code in your question does not provide any evidence of how you allocated the array that is returned to the caller. So, as far as we know, a problem may arise in this part of the code.

+1
source

Source: https://habr.com/ru/post/1209093/


All Articles