当前位置: 首页 > 编程语言 > C#

在C#-C++之间编组复杂结构共享

时间:2023-04-10 15:48:44 C#

在C#/C++之间编组复杂结构我正在尝试从C++填充结构数组并将结果传回C#。我认为也许创建一个包含结构数组的结构可能是前进的方向,因为我遇到的大多数示例都使用结构(但传递原始类型)。我已经尝试了以下但到目前为止没有运气。在下面的url找到了一个例子:http://limbioliong.wordpress.com/2011/08/20/passing-a-pointer-to-a-structure-from-c-to-c-part-2/?relatedposts_exclude=542我在C#中有以下内容正在使用系统;使用System.Collections.Generic;使用System.Linq;使用系统文本;使用System.Runtime.InteropServices;namespaceCSharpDLLCall{classProgram{[StructLayout(LayoutKind.Sequential,Pack=8)]publicstructStruct1{[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]publicdouble[]d1;[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]publicdouble[]d2;}[StructLayout(LayoutKind.Sequential)]publicstructTestStructOuter{publicintlength;嵌入公共IntPtr;}staticvoidMain(string[]args){Programprogram=newProgram();program.demoArrayOfStructs();}publicvoiddemoArrayOfStructs(){TestStructOuterouter=newTestStructOuter();testStructOuter.embedded=newStruct1[10];外部.length=10;outer.embedded=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1))*10);Marshal.StructureToPtr(外部,外部。嵌入式,假);testAPI2(参考外部);外部=(TestStructOuter)(Marshal.PtrToStructure(outer.embedded,typeof(TestStructOuter)));Marshal.FreeHGlobal(外部嵌入);}[DllImport(@"C:CPP_ProjectsDLLDLLSampleReleaseDLLSample.dll")]staticexternvoidtestAPI2(IntPtrpTestStructOuter);在头文件中的C++我有#ifdefDLLSAMPLE_EXPORTS#defineDLLSAMPLE_API__declspec(dllexport)#else#defineDLLSAMPLE_API__declspec(dllimport)#endif#includeusingnamespacestd;#pragmapack(1)structstruct1{doubled1[];双d2[];};结构TestStructOuter{结构1*嵌入式;};extern"C"{DLLSAMPLE_APIvoid__stdcalltestAPI2(TestStructOuter*pTestStructOuter);我在cpp中有:#include"stdafx.h"#include"DLLSample.h"__declspec(dllexport)void__stdcalltestAPI2(TestStructOuter*pTestStructOuter){//不确定这是必要的//for(inti=0;iembedded=newstruct1;//}for(inti=0;i<10;++i){结构1s1;for(intidx=0;idxembedded[0]=s1;}}这似乎不起作用我收到错误:参数不正确(HRESULTexception:0x80070057(E_INVALIDARG))这可能意味着它无法识别结构数组.我有什么想法可以做到这一点吗?谢谢。好的,我有一个工作示例。我将其发布为另一个答案,因为它是一种非常不同的方法。所以,在C++方面,我有这个头文件:structStruct1{intd1[10];intd2[10];};extern"C"__declspec(dllexport)void__stdcallTestApi2(int*pLength,Struct1**pStructures);以下代码:__declspec(dllexport)void__stdcallTestApi2(int*pLength,Struct1**pStructures){intlen=10;*pLength=len;*pStructures=(Struct1*)LocalAlloc(0,len*sizeof(Struct1));Struct1*pCur=*pStructures;for(inti=0;id1[idx]=i+idx;pCur->d2[idx]=i+idx;}pCur++;}}现在,重要的一点是LocalAlloc。这实际上是我所有的地方问题是因为我分配内存不正确。LocalAlloc是对Marshal.AllocHGlobal的.NET调用,这非常方便,因为这意味着我们可以使用调用方中的内存并根据需要处置它...现在,此方法允许您返回任意长度的结构数组。例如,可以使用相同的方法。返回一个结构数组的结构,你就更深入了。关键是LocalAlloc——您可以使用Marshal类轻松访问的内存,而不是Discarded内存。您必须返回数组长度的原因是因为无法知道您“返回”了多少数据。这是非托管代码中的一个常见“问题”,如果您曾经做过任何P/Invoking,您就会了解它。现在,C#方面。我正在尝试以一种很好的方式执行此操作,但问题是结构数组根本不可blittable,这意味着您不能简单地使用MarshalAs(UnmanagedType.LPArray,...)。因此,我们必须采用IntPtr方法。定义如下所示:[StructLayout(LayoutKind.Sequential)]publicclassStruct1{[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]publicint[]d1;[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]publicint[]d2;}[DllImport(@"Win32Project.dll",CallingConvention=CallingConvention.StdCall)]staticexternvoidTestApi2(outintlength,outIntPtrstructs);基本上,我们得到一个指向“数组”长度的指针,以及指向数组第一个元素的指针。这就是我们读取数据所需的全部内容。代码如下:intlength;IntPtrpStructs;TestApi2(输出长度,输出pStructs);//准备C#端数组,将数据复制到Struct1[]structs=newStruct1[length];IntPtrcurrent=pStructs;for(inti=0;i如果你想实际返回一个结构数组,唯一改变的是方法参数进入“包装器”结构。方便的是.NET可以处理自动编组包装器,不太方便的是它不能处理内部数组,所以你必须使用长度+IntPtr再次手动管理它。首先,不要使用未知长度的数组。你杀死了托管代码和非托管代码之间数组的任何可能使用-你无法告诉所需的大小(Marshal.SizeOf是无用的),你必须手动传递数组长度等。如果它不是固定长度的数组,请使用IntPtr:[StructLayout(LayoutKind.Sequential,Pack=8)]publicstructStruct1{[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]publicdouble[]d1;[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]publicdouble[]d2;}[StructLayout(LayoutKind.Sequential)]publicstructTestStructOuter{publicintlength;嵌入公共IntPtr;}(如果您的嵌入式数组是固定长度的,请随意忽略它,但包括ByValArray、SizeConst位。您还必须将ArraySubType=System.Runtime.InteropServices.UnmanagedType.Struct添加到属性中)。您可能已经注意到,TestStructOuter在这种情况下几乎没有用,它只会增加复杂性(请注意,与本地语言相比,编组是最昂贵的操作之一,因此如果您调用它,这可能是个好主意保持简单)。现在,您只为外部结构分配内存。即使在您的代码中,Marshal.SizeOf也不知道结构应该有多大;对于IntPtr更是如此(或者,更准确地说,您只需要一个IntPtr,大约4-8个字节+长度)。大多数时候你想直接传递IntPtr而不是进行这种包装(在C++/CLI中使用相同的东西完全是另一回事,尽管这对你的情况来说是不必要的)。你的方法的签名将是这样的:现在如果你使用IntPtr方法,你想手动分配内存,你只需要正确地做,例如:TestStructOuterouter=newTestStructOuter();testStructOuter.length=1;testStructOuter.embedded=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1)));Marshal.StructureToPtr(嵌入式,testStructOuter.embedded,假);最后,您调用方法://编组自动完成testAPI2(refouter);不要忘记释放内存,最好在内存分配finally子句之后尝试绕过所有内容:Marshal.FreeHGlobal(outer.embedded);现在,这过于复杂而且不是最佳的。放入TestStructOuter是一种可能性,然后您可以将长度和指针直接传递给嵌入式数组,避免不必要的编组。另一种选择是在TestStructOuter中使用固定大小的数组(如果它需要一个数组:)),这将解决您的很多问题并消除任何手动编组的需要。换句话说,如果TestStructOuter是按照我之前提到的那样定义的:突然之间,您的整个调用和一切都像testAPI2(refouter);一样简单;整个编组是自动完成的,不需要手动分配或转换。希望这会有所帮助:)提示:LeadnC++/CLI。我一生中不得不处理两次复杂的互操作——一次是ISDN(AVMdevkits使它更容易——遗憾的是C++,我需要C#),现在是Nanex(非常实时复杂和完整的市场ata提要,sadl复杂的C++,我在这两种情况下都需要C#)我在C++/CLI中创建自己的包装器,与C++交谈并在C#中编写以显示真实的对象模型。允许我把事情做得更好,并处理我们友好的Marshaller无法有效处理的许多边缘情况。以上就是《C#学习教程:在C#/C++之间编组复杂结构》的全部内容。如果对你有用,需要了解更多C#学习教程,希望大家多加关注---本文来自网络收藏,不代表立场,如涉及侵权,请右击联系管理员删除。如需转载请注明出处: