gpt4 book ai didi

c# - 在 C# 中传递 IntPtr 指针后,在非托管 C++ 代码中分配数组,编码(marshal)处理类型

转载 作者:太空宇宙 更新时间:2023-11-04 16:22:40 26 4
gpt4 key购买 nike

我正在尝试实现一些涉及在托管 C# 和非托管 C++ 代码之间编码数组的项目。我遇到了一个问题,我在网上找到的解决方案似乎都不起作用。对于这方面的任何评论,我将不胜感激。

我没有展示完整的代码,而是展示问题的非常简化的部分。虽然它看起来像一个大块——它很简单——只是概念性的。只是想提供尽可能多的全貌。

C++部分:

Object.h

class cObject
{
public:
//...constructor, destructor...
int Method_Known_Size(double* array, int size);
int Method_Unknown_Size(double* array);
...
void FreeArray(double* p);
}

对象.cpp

int Method_Known_Size(double* array, int size)
{
//modify array somehow..
for(int i=0; i<size; i++) array[i] = i;

}

int method_Unknown_Size(double* array)
{
int size = 9;
array = new double[size];
for(int i=0; i<size; i++) array[i] = i;
}

(跳过 Caller.h)Caller.cpp

//...callers for constructor, destructor, for releasing unmanaged memory...
extern "C" int __stdcall Run_Known_Size(cObject* pObject, double* array, int size)
{
return cObject->Method_Known_Size(array, size);
}

extern "C" int __stdcall Run_Unknown_Size(cObject* pObject, double* array)
{
return cObject->Method_Unknown_Size(array);
}

extern "C" void __stdcall Release(cObject* cObject, double* array)
{
if(cObject != NULL) cObject->FreeArray(array);
}

所以,基本上 Run_Known_Size 方法只是修改已经由 C# 分配的内存,而 Run_Unknown_Size 创建数组并修改它。

C#部分

public class DllWrapper: IDisposable
{
/* Creating an object, disposing,...
[DllImport("cObject.dll")]
CreateObject();...DisposeObject(IntPtr pObject);
...CallFreeArray(IntPtr pArray);*/

[DllImport("cObject.dll")]
private static extern int CallRun_Known_Size(IntPtr pObject,
[Out] double [] arr_allocated, int size);

[DllImport("cObject.dll")]
private static extern int CallRun_Unknown_Size(IntPtr pObject,
[Out] IntPtr arr_not_allocated);

private IntPtr m_pNativeObject;

public DllWrapper()
{
this.m_pNativeObject = CreateObject();
}

public void Dispose()
{
Dispose(true);
}

protected virtual void Dispose(bool bDisposing)
{
if (this.m_pNativeObject != IntPtr.Zero)
{
DisposeObject(this.m_pNativeObject);
this.m_pNativeObject = IntPtr.Zero;
}

if (bDisposing)
{
GC.SuppressFinalize(this);
}
}

~DllWrapper()
{
Dispose(false);
}

public void ReleaseUnmanAraray(IntPtr pArr)
{
CallFreeArray(pArr);
}

public int Run_Known_Size(double[] arr_allocated, int size)
{
return CallRun_Known_Size(this.m_pNativeObject, arr_allocated, size);
}

public int Run_Unknown_Size(IntPtr arr_not_allocated)
{
return CallRun_Known_Size(this.m_pNativeObject, arr_not_allocated);
}
}

static void Main(string[] args)
{
double[] alloc_arr = new double[] { 1, 5, 3, 3, 5, 5, 8, 9,1 };
int size = 9;


double[] Arr_for_Copy = new double[size];

IntPtr pArr = new IntPtr();

DllWrapper wrapper = new DllWrapper();

int res1 = Run_Known_Size(alloc_arr, size);
int res2 = Run_Unknown_size(pArr);

if (pArr != IntPtr.Zero) // pArr IS ZERO ALWAYS!!!!!!
{
Marshal.Copy(pArr, Arr_for_Copy, 0, size);
}
else
{
Console.WriteLine("Pointer was zero again");
}

wrapper.ReleaseUnmanAraray(pScores);
wrapper.Dispose();

Console.ReadLine();
}

对于在 C# 中分配的数组,一切都工作得很好——它们是从 C++ 修改而来的,没有错误。但是如果我不知道数组的大小,因此无法预分配数组,我找到的唯一解决方案是传递 [Out] IntPtr 并让 C++ 管理内存、分配和修改数组。然后返回的 IntPtr 可以编码到 C# 的 double[] 数组,因为我们已经知道大小(为简化起见,我只将数字 4 作为大小,但我通过 int* size 来确定大小)。

在传递 IntPtr 并基于此指针在 C++ 中创建数组后,我的所有试验都以零指针结束(没有错误)。

我见过涉及 COM 对象的解决方案,但由于可移植性问题,我不得不避免使用它。

提前致谢。

最佳答案

Method_Unknown_Size 的参数是 double* 并且您正在更改参数本身。如果你想改变调用者发送的原始值,你应该将参数定义为一个指向数组的指针,这意味着指向double的指针引用指向 double 的指针

您还应该以某种方式告诉调用者数组的大小(我想您已经做到了)。

C++:

int method_Unknown_Size(double *&array)
{
int size = 9;
array = new double[size];
for(int i=0; i<size; i++) array[i] = i;
return size;
}

void FreeArray(double *&p)
{
delete[] p;
p = NULL;
}

extern "C" int __stdcall Run_Unknown_Size(cObject *pObject, double *&array)
{
return cObject->Method_Unknown_Size(array);
}

extern "C" void __stdcall Release(cObject *cObject, double *&array)
{
if(cObject != NULL) cObject->FreeArray(array);
}

C#:

[DllImport("cObject.dll")]
private static extern int Run_Unknown_Size(IntPtr pObject,
out IntPtr arr_not_allocated);

[DllImport("cObject.dll")]
private static extern int Release(IntPtr pObject,
ref IntPtr arr_not_allocated);


// to allocate the array:
IntPtr pArr;
int res2 = Run_Unknown_size(m_pNativeObject, out pArr);

// to free the array:
Release(m_pNativeObject, ref pArr);

这绝对有效!如果没有,请告诉我!

关于c# - 在 C# 中传递 IntPtr 指针后,在非托管 C++ 代码中分配数组,编码(marshal)处理类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15217939/

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