Gewusst wie: Verwenden von systemeigenen COM-Servern mit CRCWs
Aktualisiert: November 2007
Im Gegensatz zu anderen .NET-Sprachen bietet Visual C++ Interop-Funktionen, durch die nicht verwaltete APIs, einschließlich COM-Schnittstellen, direkt und nahtlos verwendet werden können. Dies bietet insbesondere für COM-Interop leistungsfähige Vorteile.
Beispiel
Wie bei dem Beispiel in Gewusst wie: Verwenden von systemeigenen COM-Servern mit TLBIMP, werden auch in diesem Beispiel COM-Schnittstellen in Quartz.dll (die sich im Verzeichnis C:\window\System32 befindet) definiert, um AVI-Dateien wiederzugeben. In diesem Fall wird jedoch C++-Interop anstelle einer separaten, mit Tlbimp.exe generierten Interop-Assembly verwendet. Diese Technik bietet zahlreiche Vorteile. Der Interop-Code wird hier in die Anwendung integriert, sodass keine Abhängigkeit zu einer separaten Assembly besteht. Außerdem wird die verfügbare verwaltete Schnittstelle angepasst, um sie .NET-ähnlicher zu machen. Beispielsweise wird bei der RenderFile-Methode ein System.String anstelle eines char* verwendet. Die verwaltete Version der COM-Schnittstelle wird als benutzerdefinierter Runtime Callable Wrapper (CRCW) bezeichnet.
Das Schreiben von CRCWs erfordert keine Interop-Assembly, jedoch Headerdateien zur Definition der COM-Schnittstellen. Bei COM-Komponenten, die Typbibliotheken einschließen, können diese Header mit dem MIDL Compiler generiert werden.
Der erste Teil des folgenden Codebeispiels definiert den benutzerdefinierten Wrapper, der die Member verfügbar macht, die für die verwaltete Anwendung verfügbar gemacht werden. Der zweite Teil ist eine Konsolenanwendung, die den benutzerdefinierten Wrapper verwendet, um AVI-Dateien wiederzugeben.
Wenn Sie die resultierende EXE-Datei mit dem Namen einer gültigen AVI-Datei ausführen, wird diese in einem Fenster angezeigt.
// 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();
}