我使用p / invoke从我的非托管代码返回一个" DN_OPstruct"的数组:
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;
}
我的托管代码如下所示:
[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);
如果我试图调用该方法,我将跳入非托管代码并可以通过成功调试它,我得到一个带有我的DN_OPstructs的数组。但是,如果我读出 .Name或.Guid 这样的字段,我会收到此错误:
(...)0x000007fefd921757的第一次机会异常.exe:0xC0000005: 访问冲突读取位置0xffffffffffffffffff。
如果存在此异常的处理程序,则程序可能是安全的 继续进行。
我尝试添加&#34; ArraySubType = UnmanagedType.LPStruct&#34;我的方法声明;它没有帮助。
答案 0 :(得分:1)
public static extern int getOpToArr(
[MarshalAs(UnmanagedType.LPStr)]
string myNodeGuid,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
out DN_OPstruct[] array,
out int arraySizeInElements
);
问题是第二个参数。非托管代码无法合成托管的.net数组。你需要像这样声明p / invoke:
public static extern int getOpToArr(
string myNodeGuid,
out IntPtr arrayPtr,
out int arrayLen
);
然后,您需要使用Marshal.PtrToStructure
将数组元素封送到托管数组。
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));
}
我也对你的结构中的属性持怀疑态度。为什么你有吸气剂和吸气剂?它看起来不像数据在那个方向上流动。您使用的非托管代码会显示CoTaskMemAlloc
的分配,而StringToHGlobalAnsi
与StringToHGlobalAnsi
不匹配。因此,即使我怀疑你应该编写设置,所以也许应该删除对{{1}}的调用,我也怀疑你正在使用的分配器存在混淆。
请注意,问题中的代码没有提供有关如何分配返回给调用者的数组的证据。因此,据我们所知,这部分代码可能存在问题。