1. c# -> activex 메소드 호출
2. activex -> c# 이벤트 호출
두 가지 경우가 있다. activex가 c#과 연동하기 위해서는 activex 에서 적절한 메소드를 만든다음 커맨드창에서
aximp /source MyActiveX.ocx
해서 만들어진 인터페이스용 cs 소스파일과 dll 을 사용한다.
이때 메소드의 매개변수를 c++의 BYTE* 와같이 포인터로해도 c#에서는 포인터를 매개변수로 사용할 수 없으므로 만들어진 cs 파일에는 ref byte 타입으로 변경되어 포인터값을 전달할 수 없다.
2의 경우도 마찬가지로 aximp 커맨드를 통해 생성되는 인터페이스용 cs 파일에는 포인터 타입이 들어가지않는다.
activex가 아닌 dll 인 경우 c# 함수 프로토타입 선언에서 byte[] 타입으로 매개변수를 지정해서 쓰면되지만 activex(ocx)는 aximp 로 생성된 소스를 사용해야하므로 난감한 상황이 발생한다.
결론적으로 포인터는 결국 32(혹은 64)비트 정수값일 뿐이며 사용하기에 따라 BYTE*, LONG* 등으로 캐스팅해서 사용할 뿐이다. (결국 해석의 차이)
따라서 매개변수를 굳이 포인터 타입으로 할 이유가 없다. activex 쪽에서 LONGLONG 타입(64비트 프로세스인 경우 대비해서 LONG보다 LONGLONG 권장)으로 매개변수를 지정한다음 포인터값(주소)을 넘겨주거나 넘겨받으면 그만이다.
1. 포인터 매개변수 전달 예 - activex
void MyActiveXCtrl::SetIntArrayData(LONGLONG pData)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your dispatch handler code here
int *data = (int *)pData;
...
}
aximp /source MyActiveX.ocx => cs 파일 생성
1. 포인터 매개변수 전달 예 - c#
int[] data = new int[10];
for (int i = 0; i < data.Length; i++) data[i] = i;
IntPtr ptr = Marshal.AllocHGlobal(sizeof(int) * data.Length);
Marshal.Copy(data, 0, ptr, data.Length);
myAxCtrl.SetIntArrayData((long)ptr); => c# long은 vc++ LONGLONG 이므로
Marshal.FreeHGlobal(ptr);
2. 포인터 매개변수 전달 예 - activex
void MyActiveXCtrl::OnDataEvent(LONG size, LONGLONG pData)
{
FireEvent(eventidOnDataEvent, ...., pData);
}
2. 포인터 매개변수 전달 예 - c#
myAxCtrl.OnDataEvent += axAxCtrl_OnDataEvent;
private void axAxCtrl_OnDataEvent(_AXMyActiveXCtrlEvents_OnDataEvent e)
{
byte[] btaImage = new byte[e.size];
unsafe
{
byte* p = (byte*)e.pData;
Marshal.Copy((IntPtr)p, btaImage, 0, e.size);
}
// now you can use btaImage data
...
}1번의 경우 c# -> activex 로 포인터를 전달하는데 원하는 데이터(여기서는 int 배열)를 IntPtr 변수에 복사한다음 포인터값을 전달한다. 이때 포인터를 받는 c++에서는 LONGLONG 타입을 int* 로 타입캐스팅해서 사용하면된다.
2번의 경우 activex -> c# 으로 포인터를 전달하는데 포인터 size를 지정한다음 LONGLONG 타입(64비트) 정수에 포인터 주소값을 넣어서 c# 쪽으로 전달한다.
c#에서는 전달받은 long 타입(64비트) 데이터를 byte* 으로 캐스팅한다음 c#에서 쉽게 사용하도록 byte 배열에 복사한다.