관리되는 C# 코드와 관리되지 않는 C++ 코드 간의 배열 마샬링과 관련된 일부 프로젝트를 구현하려고합니다. 나는 문제를 겪고 있으며 웹에서 찾은 해결책 중 어느 것도 작동하지 않는 것 같습니다. 나는이 점에 대해 어떤 의견이라도 크게 감사 할 것입니다.C#에서 IntPtr 포인터를 마샬링 형식으로 전달한 후 관리되지 않는 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);
}
Object.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# 1 메모리에 의해 할당되고, 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 * 크기를 전달했습니다).
IntPtr을 전달하고이 포인터를 기반으로 C++로 배열을 만든 후에도 모든 시도가 오류없이 끝납니다.
COM 개체와 관련된 솔루션을 보았지만 이식성 문제로 인해이 문제를 피하십시오.
미리 감사드립니다.
빠른 답장을 보내 주셔서 감사합니다. 내 작업 기계에이 코드가 있으므로 내일 확실히 확인해 보겠습니다. 이중 포인터를 시도했지만 약간 다른 방식으로. 이것이 효과가 있기를 바랍니다. 그냥 빠른 질문 : C#에서 당신은 속성을 넣어 [아웃] '. 무슨 뜻이에요? –
당신을 진심으로 환영합니다. 나는 여기서 [Out]이 필요 없다고 생각하지만, 나는 그것을 확실하게 넣는다. 이것은 마샬 러에게 변수에 대한 변경 사항을 다시 알려주지 만 객체 및 배열의 내용에 대해서만 작동합니다. 객체 * 자체가 변경되면'[Out]'이 도움이되지 않습니다! 여기에'out' 매개 변수 수정자가 사용되는 곳이 있습니다. 패스를 * reference * (또는 * pointer *)와 같은 매개 변수로 지정합니다. 자세한 내용은 [여기] (http://msdn.microsoft.com/en-us/library/ee332485.aspx)를 참조하십시오. –
매우 흥미 롭습니다. 이것은 관리/비 관리 코드와 관련된 첫 번째 프로젝트이며 웹이나 교과서에서 쉽게 찾을 수없는 몇 가지 사항에 눈을 떴습니다. 다시 한 번 감사드립니다! –