티스토리 뷰

안녕하세요. 구스입니다.


이 글에서는 NI 드라이버에서 제공하는 C API를 통해서 Wrapper Class를 만들어보는 방법에 대해서 알아보도록 하겠습니다. NI 제품군 드라이버는 매번 업데이트가 될 때마다, C API가 추가적으로 업데이트 되어 지원이 됩니다. 


이러한 C API를 .NET 환경에서 사용하기 위해서는 Wrapper Class가 필요하게 되지요. Wrapper Class는 .NET의 Invoke 함수(P/Invoke)를 이용하여 Unmanaged 코드를 .NET 어플리케이션에서 사용할 수 있게 도와주는 역할을 합니다.


아래의 글은 P/Invoke 함수를 통해서 Wrapper Class를 어떻게 생성하고 실질적으로 코드에서 어떻게 사용되는지 여부를 보여줍니다. 본 예제는 NI SCOPE 드라이버를 통해서 만들어졌습니다. NI SCOPE가 아닌 다른 MI 드라이버 모두 아래와 같은 방식으로 사용이 가능합니다. 


1. P/Invoke 함수를 통한 C API 접근하기


C API로 지원이 되는 특정 함수를 .NET에서 접근하기 위해서는 그 함수에 대한 정보를 해당 헤더를 통해서 확인해야 합니다. 헤더 파일의 정보는 아래와 같이 구성이 될 수 있습니다. 


ViStatus _VI_FUNC niScope_ConfigureHorizontalTiming (ViSession vi, 

ViReal64 minSampleRate, ViInt32 minNumPts, ViReal64 refPosition, ViInt32 numRecords, ViBoolean enforceRealtime);


C API에서 제공하는 함수를 .NET 환경에 노출을 시키기 위해서는 정적 Wrapper Class를 생성해야 합니다. 정적 Wrapper Class의 구성은 아래와 같이 됩니다. 


internal static class ScopePInvokeMethods { }


정적 Wrapper Class 내부에 DllImport 애트리뷰트를 활용하여 함수를 접근할 수 있습니다. 위의 niScope_ConfigureHorizontalTiming를 사용하기 위해서는 위에서 정의한 Static Wrapper Class를 아래와 같이 구성해야 합니다. 


DllImport 어트리뷰트에 대한 정보는 아래와 같습니다. 





DllImport 어트리뷰트는 Managed 환경에서 Unmanaged 코드(.NET 환경이 아닌 코드)를 접근할 때 사용이 가능한 애트리뷰트로, .NET 환경에서 C로 만들어진 DLL 접근에 많이 사용이 됩니다. 


DllImport를 사용하여 만든 niScope_ConfigureHorizontalTiming 함수는 아래와 같습니다. 


internal static class ScopePInvokeMethods { 

[DllImport( "niScope_32.dll",  

EntryPoint = "niScope_ConfigureHorizontalTiming",  CallingConvention = CallingConvention.StdCall )]

public static extern int ConfigureHorizontalTiming32( 

HandleRef instrumentHandle, double minSampleRate, int minNumPoints, double refPosition, int numRecords, bool enforceRealtime );

}


C API의 niScope_ConfigureHorizontalTiming 함수 인자와 Static Wrapper Class 내부의 함수 인자는 동일하게 구성이 되어야 합니다. 

위와 같은 Wrapper Class 생성은 Measurement Studio를 통해서 좀 더 쉽게 만들 수 있습니다. 


2. P/Invoke 함수 사용하기 


위에서 생성한 함수를 사용하기 위해서는 위의 Wrapper 클래스의 Static 함수를 호출해야 합니다. 이에 대한 예는 아래와 같습니다.


// The following is within the scope of some method. double sampleRateMin = 10000000.0; double referencePosition = 50.0; int recordLengthMin = 1000; 

int numberOfRecords = 1; 

bool enforceRealtime = true;  

var sessionHandle = new HandleRef( this._scopeSession, this._scopeSession.DangerousGetInstrumentHandle( ));


ScopePInvokeMethods.ConfigureHorizontalTiming32( sessionHandle, 

sampleRateMin, recordLengthMin, referencePosition, numberOfRecords, enforceRealTime );


참고 : HandleRef는 System.Runtime.InteropServices 네임스페이스의 자료형 입니다. HandleRef는 Unmanaged 코드상의 개체를 래핑하는데 사용되는 구조체입니다. 




마지막으로 Wrapper Class 사용을 하는데 있어 참고해야 할 점을 알려드립니다. 이에 대한 내용은 MSDN에 나와있는데요. MSDN 내용을 참고해 보면 아래와 같습니다. 


플랫폼 호출을 사용하여 관리되는 개체를 호출했는데 플랫폼 호출 이후 해당 개체가 참조되지 않으면 가비지 수집기에서 관리되는 개체가 종료될 수 있습니다. 이 동작은 리소스를 해제하고, 핸들을 무효로 만들고, 플랫폼 호출이 실패하도록 합니다. 


HandleRef 로 핸들을 래핑하면 플랫폼 호출이 종료될 때까지 가비지 수집기가 관리되는 개체를 수집하지 않습니다. 


그럼 이만 줄이겠습니다.


이 글이 도움이 되셨으면, 아래의 하트를 눌러주세요.


댓글