Program Language/C#

[C#] OCX에 포인터 데이터 넘기기

야곰야곰+책벌레 2022. 10. 26. 18:12
728x90
반응형

C#에는 기본적으로 포인터를 지원하지 않는다. 포인터를 사용하기 위해서 unsafe를 이용하던데, 기본적으로 사용하지 말라고 한 것을 굳이 사용해야 싶어서 구글링 해서 여기저기 검색해 보았다. 가장 간단한 방법으로 C++에서도 사용하던 것인데 포인터의 주소를 넘기는 것이다. 포인터의 주소는 32bit에서는 long으로 64bit에서는 __int64 혹은 long long으로 넘겨주곤 했다. C#은 모두 long long이다. 그렇기 때문에 OCX의 메서드를 만들 때에도 LONGLONG으로 만들어야 한다.

 

void CtopgraphCtrl::AddArrayDataPtr(LPCTSTR name, LONG length, LONGLONG xPtr, LONGLONG yPtr, LONGLONG zPtr)

포인터의 길이를 나타내는 length와 각 데이터의 주소를 담을 LONGLONG 변수를 선언했다. 이는 단순하게 포인터로 변경할 수 있다.

	double *x = (double *)xPtr;
	double *y = (double *)yPtr;
	double *z = (double *)zPtr;

double 포인터를 넘길 예정임으로 이런 식으로 변경할 수 있다.

C#에서는 long이 LONGLONG이기 때문에 아래와 같이 선언한다.

void AddArrayData([MarshalAs(UnmanagedType.LPWStr)] string name, int length, long x, long y, long z);

이제 이것을 사용해야 하는데, 이때 사용해야 하는 부분을 검색을 통해 알아 두었다. (C# 자체가 익숙치 않다)

우선 배열 형식의 선언을 한 뒤, 데이터를 담는다.

_GraphMarshal ocx = graphView.GetOcx() as _GraphMarshal;

int dataSize = 100000;

double[] x = new double[dataSize];
double[] y = new double[dataSize];
double[] z = new double[dataSize];

for (int i = 0; i < dataSize; i++)
{
    x[i] = i;
    y[i] = 100 * Math.Sin(i * 3.14 / 180);
    z[i] = 0;
}

IntPtr를 이용하여 주소를 받아갈 수 있도록 해야 한다. AllocHZGLobal과 FreeHGlobal을 이용하면 된다.

이 형식은 IntPtr 포인터를 지원하는 언어와 포인터를 지원하지 않는 언어 간의 데이터를 참조하는 일반적인 수단으로 사용할 수 있습니다.

IntPtr을 이용하여 메모리의 주소를 넘겨줄 수 있다.

IntPtr xPtr = Marshal.AllocHGlobal(sizeof(double) * x.Length);
Marshal.Copy(x, 0, xPtr, x.Length);
IntPtr yPtr = Marshal.AllocHGlobal(sizeof(double) * y.Length);
Marshal.Copy(y, 0, yPtr, y.Length);
IntPtr zPtr = Marshal.AllocHGlobal(sizeof(double) * z.Length);
Marshal.Copy(z, 0, zPtr, z.Length);

ocx.AddArrayData("sine", dataSize, (long)xPtr, (long)yPtr, (long)zPtr);

Marshal.FreeHGlobal(xPtr);
Marshal.FreeHGlobal(yPtr);
Marshal.FreeHGlobal(zPtr);

 

728x90
반응형