gpt4 book ai didi

c# - 在 C#/C++ 之间编码复杂结构

转载 作者:行者123 更新时间:2023-11-30 19:40:47 25 4
gpt4 key购买 nike

我正在尝试从 C++ 填充结构数组并将结果传回 C#。

我认为也许创建一个包含结构数组的结构可能是前进的方向,因为我遇到的大多数示例都使用结构(但传递基本类型)。我已经尝试了以下但到目前为止没有运气。

在以下位置找到示例:http://limbioliong.wordpress.com/2011/08/20/passing-a-pointer-to-a-structure-from-c-to-c-part-2/?relatedposts_exclude=542

我在 C# 中有以下内容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CSharpDLLCall
{
class Program
{

[StructLayout(LayoutKind.Sequential,Pack=8)]
public struct Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d2;
}

[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
public int length;
public IntPtr embedded;
}

static void Main(string[] args)
{
Program program = new Program();
program.demoArrayOfStructs();
}

public void demoArrayOfStructs()
{
TestStructOuter outer = new TestStructOuter();
testStructOuter.embedded = new Struct1[10];
outer.length = 10;
outer.embedded = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1)) * 10);
Marshal.StructureToPtr(outer, outer.embedded, false);
testAPI2(ref outer);
outer = (TestStructOuter)(Marshal.PtrToStructure(outer.embedded, typeof(TestStructOuter)));
Marshal.FreeHGlobal(outer.embedded);
}

[DllImport(@"C:\CPP_Projects\DLL\DLLSample\Release\DLLSample.dll")]
static extern void testAPI2(IntPtr pTestStructOuter);
}
}

在头文件中的 C++ 中

#ifdef DLLSAMPLE_EXPORTS
#define DLLSAMPLE_API __declspec(dllexport)
#else
#define DLLSAMPLE_API __declspec(dllimport)
#endif

#include <iostream>
using namespace std;

#pragma pack(1)
struct struct1
{
double d1[];
double d2[];
};

struct TestStructOuter
{
struct1* embedded;
};

extern "C"
{
DLLSAMPLE_API void __stdcall testAPI2(TestStructOuter* pTestStructOuter);
}

在我的cpp中:

#include "stdafx.h"
#include "DLLSample.h"

__declspec(dllexport) void __stdcall testAPI2(TestStructOuter* pTestStructOuter)
{
// not sure that this is necessary
// for (int i = 0; i < 10 ; ++i)
// {
// pTestStructOuter->embedded = new struct1;
// }

for (int i = 0; i < 10 ; ++i)
{
struct1 s1;

for (int idx = 0; idx < 10; ++idx)
{
s1.d1[i] = i+0.5;
s1.d2[i] = i+0.5;
}

pTestStructOuter->embedded[0] = s1;
}
}

这似乎不起作用我得到的错误:参数不正确。(HRESULT异常:0x80070057(E_INVALIDARG))

这可能意味着它无法识别结构数组。我有什么想法可以做到这一点?谢谢。

最佳答案

好的,我有一个工作样本。我将此作为另一个答案发布,因为这是一种非常不同的方法。

所以,在 C++ 方面,我有这个头文件:

struct Struct1
{
int d1[10];
int d2[10];
};

extern "C" __declspec(dllexport) void __stdcall
TestApi2(int* pLength, Struct1 **pStructures);

以及以下代码:

__declspec(dllexport) void __stdcall 
TestApi2(int* pLength, Struct1 **pStructures)
{
int len = 10;

*pLength = len;
*pStructures = (Struct1*)LocalAlloc(0, len * sizeof(Struct1));

Struct1 *pCur = *pStructures;

for (int i = 0; i < len; i++)
{
for (int idx = 0; idx < 10; ++idx)
{
pCur->d1[idx] = i + idx;
pCur->d2[idx] = i + idx;
}

pCur ++;
}
}

现在,重要的一点是 LocalAlloc。这实际上是我遇到所有问题的地方,因为我分配了错误的内存。 LocalAlloc 是 .NET 在执行 Marshal.AllocHGlobal 时调用的方法,这非常方便,因为这意味着我们可以使用调用方的内存并根据需要处理它.

现在,此方法允许您返回任意长度的结构数组。同样的方法可以用于例如。返回一个结构数组的结构,你只是在更深入。关键是 LocalAlloc - 这是您可以使用 Marshal 类轻松访问的内存,而且是不会被丢弃的内存。

您还必须返回数组长度的原因是,否则无法知道您“返回”了多少数据。这是非托管代码中的常见“问题”,如果您曾经做过任何 P/Invoking,您就会了解这一切。

现在,C# 端。我已经努力以一种很好的方式做到这一点,但问题是结构数组根本不是 blittable,这意味着你不能简单地使用 MarshalAs(UnmanagedType.LPArray, ...)。所以,我们必须采用 IntPtr 方式。

定义如下:

[StructLayout(LayoutKind.Sequential)]
public class Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] d1;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] d2;
}

[DllImport(@"Win32Project.dll", CallingConvention = CallingConvention.StdCall)]
static extern void TestApi2(out int length, out IntPtr structs);

基本上,我们得到一个指向“数组”长度的指针,以及指向数组第一个元素的指针。这就是我们读取数据所需的全部内容。

代码如下:

int length;
IntPtr pStructs;

TestApi2(out length, out pStructs);

// Prepare the C#-side array to copy the data to
Struct1[] structs = new Struct1[length];

IntPtr current = pStructs;
for (int i = 0; i < length; i++)
{
// Create a new struct and copy the unmanaged one to it
structs[i] = new Struct1();
Marshal.PtrToStructure(current, structs[i]);

// Clean-up
Marshal.DestroyStructure(current, typeof(Struct1));

// And move to the next structure in the array
current = (IntPtr)((long)current + Marshal.SizeOf(structs[i]));
}

// And finally, dispose of the whole block of unmanaged memory.
Marshal.FreeHGlobal(pStructs);

如果你想真正返回一个结构数组的结构,唯一改变的是方法参数移动到“包装”结构中。方便的是 .NET 可以自动处理包装器的编码,不太方便的是它不能处理内部数组,所以你必须再次使用 length + IntPtr 来手动管理它。

关于c# - 在 C#/C++ 之间编码复杂结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21822882/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com