Ole*_*ikh 0 c# c++ unmanaged managed marshalling
我正在尝试实现一些涉及托管C#和非托管C ++代码之间的封送处理数组的项目。我遇到了一个问题,我在网上找到的所有解决方案似乎都无效。我对此表示感谢。
我没有提供完整的代码,而是显示了问题的非常简化的部分。尽管它看起来很大,但非常简单-只是概念上的。只是想提供尽可能多的全貌。
C ++部分:
对象
class cObject
{
public:
//...constructor, destructor...
int Method_Known_Size(double* array, int size);
int Method_Unknown_Size(double* array);
...
void FreeArray(double* p);
}
Run Code Online (Sandbox Code Playgroud)
对象.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;
}
Run Code Online (Sandbox Code Playgroud)
(跳过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 Code Online (Sandbox Code Playgroud)
因此,基本上,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();
}
Run Code Online (Sandbox Code Playgroud)
使用C#分配的数组,一切都可以正常工作-它们是从C ++修改而来的,没有错误。但是如果我不知道数组的大小,因此无法预分配数组,我发现的唯一解决方案是传递[Out] IntPtr并让C ++管理内存,分配和修改数组。然后可以将返回的IntPtr编组到C#的double []数组中,因为我们已经知道大小了(为简单起见,我只将数字4作为大小,但是我通过int * size来确定大小)。
在传递IntPtr并基于此指针在C ++中创建数组之后,我所有的试验都以零指针(无错误)结束。
我已经看到了涉及COM对象的解决方案,但是由于可移植性问题,我不得不避免使用该解决方案。
提前致谢。
Method_Unknown_Sizeis 的参数,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);
}
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
这绝对有效!告诉我是否没有!