方法 : CRCW でネイティブ COM サーバーを使用する
更新 : 2007 年 11 月
他の .NET 言語とは異なり、Visual C++ には COM インターフェイスなどのアンマネージ API を直接、しかもシームレスにアクセスできるようにする相互運用機能が用意されています。特に COM 相互運用でこの機能を使用すると、大きな利点があります。
使用例
「方法 : TLBIMP でネイティブ COM サーバーを使用する」で示した例と同様、次の例では、Quartz.dll (C:\window\System32 ディレクトリにある) で定義される COM インターフェイスを使用して、AVI ファイルを再生します。ただし、この例では、Tlbimp.exe によって生成される個々の相互運用機能アセンブリではなく C++ Interop を使用します。この手法にはいくつか利点があります。この場合、相互運用コードがアプリケーションに組み込まれるため、個々のアセンブリへの依存関係がありません。また、公開されたマネージ インターフェイスをカスタマイズすることで、より .NET に近くなっています。たとえば、RenderFile メソッドは、char* ではなく System.String を受け取ります。COM インターフェイスのマネージ バージョンを、カスタム ランタイム呼び出し可能ラッパー (CRCW) と呼びます。
CRCW を記述するには、相互運用機能アセンブリは必要ありませんが、COM インターフェイスを定義するヘッダー ファイルが必要です。タイプ ライブラリを含む COM コンポーネントの場合、MIDL Compiler を使用してこれらのヘッダーを生成できます。
次のコード例の先頭部分に、カスタム ラッパーが定義されています。カスタム ラッパーは、マネージ アプリケーションに公開されるメンバを公開します。2 番目の部分は、カスタム ラッパーを使用して 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();
}