방법: CRCW와 함께 네이티브 COM 서버 사용
업데이트: 2007년 11월
다른 .NET 언어와 달리 Visual C++에서는 COM 인터페이스를 비롯한 관리되지 않는 API에 직접 매끄럽게 액세스하는 데 필요한 interop 기능을 제공합니다. 특히 COM interop의 경우 이 기능을 사용하면 많은 이점을 얻을 수 있습니다.
예제
방법: TLBIMP와 함께 네이티브 COM 서버 사용에 나와 있는 예제와 마찬가지로 이 예제에서는 C:\window\System32 디렉터리에 있는 Quartz.dll에서 정의한 COM 인터페이스를 사용하여 AVI 파일을 재생합니다. 그러나 이 예제의 경우에는 Tlbimp.exe를 사용하여 생성된 별도의 interop 어셈블리 대신 C++ interop를 사용합니다. 이 방법을 사용하면 여러 가지 이점을 얻을 수 있습니다. 이 경우 interop 코드가 응용 프로그램으로 빌드되므로 별도의 어셈블리에 의존할 필요가 없습니다. 또한 노출되어 관리되는 인터페이스를 .NET에 더욱 적합하도록 사용자 지정할 수 있습니다. 예를 들어, RenderFile 메서드에서 char* 대신 System.String을 사용합니다. 관리되는 버전의 COM 인터페이스를 CRCW(사용자 지정 런타임 호출 가능 래퍼)라고 합니다.
CRCW를 작성하는 데 interop 어셈블리는 필요하지 않지만 COM 인터페이스를 정의하는 헤더 파일은 필요합니다. 형식 라이브러리가 포함된 COM 구성 요소의 경우 이러한 헤더는 MIDL Compiler를 사용하여 생성할 수 있습니다.
다음 코드 예제의 첫 번째 부분에서는 관리되는 응용 프로그램에 노출할 멤버를 노출하는 사용자 지정 래퍼를 정의합니다. 두 번째 부분은 사용자 지정 래퍼를 사용하여 AVI 파일을 재생하는 콘솔 응용 프로그램입니다.
유효한 AVI 파일의 이름을 사용하여 결과 .exe 파일을 실행하면 파일이 창에 렌더링됩니다.
// use_native_COM_servers_with_CRCWs.cpp
// compile with: /clr
// processor: x86
#include <comdef.h>
#import "quartz.tlb" no_namespace
using namespace System;
using namespace System::Runtime::InteropServices;
//_COM_SMARTPTR_TYPEDEF(IMediaControl, IID_IMediaControl);
ref struct Player : public IDisposable {
Player() : fm((new IMediaControlPtr())) {
fm->CreateInstance(__uuidof(FilgraphManager), 0, CLSCTX_INPROC_SERVER);
if ((*fm) == 0)
throw gcnew Exception("Could not create COM object");
}
~Player() {
this->!Player();
}
!Player() {
(*fm).Release();
delete fm;
}
void RenderFile(String^ file) {
IntPtr ip = Marshal::StringToBSTR(file);
BSTR b = static_cast<BSTR>(ip.ToPointer());
(*fm)->RenderFile(b);
Marshal::FreeBSTR(ip);
}
void Run() {
(*fm)->Run();
}
private:
IMediaControlPtr* fm;
};
void DisplayUsage() {
Console::WriteLine("AVIPlayer2: Plays AVI files.");
Console::WriteLine("Usage: AVIPlayer2.EXE <filename>");
}
int main() {
array<String^>^ args = Environment::GetCommandLineArgs();
if (args->Length != 2) {
DisplayUsage();
return 0;
}
String^ filename = args[1];
if (filename->Equals("/?")) {
DisplayUsage();
return 0;
}
Player^ player = gcnew Player;
player->RenderFile(filename);
player->Run();
Console::WriteLine("press any key");
Console::ReadLine();
}