Comment : utiliser des serveurs COM natifs avec CRCWs
Mise à jour : novembre 2007
Contrairement aux autres langages .NET, Visual C++ propose des fonctionnalités d'interopérabilité qui permettent l'accès direct et transparent aux API non managées, notamment aux interfaces COM. Cela procure des avantages considérables en particulier pour l'interopérabilité COM.
Exemple
Comme l'exemple fourni dans la rubrique Comment : utiliser des serveurs COM natifs avec TLBIMP, l'exemple suivant utilise les interfaces COM définies dans Quartz.dll (situées dans le répertoire C:\window\System32) pour lire des fichiers AVI. Dans ce cas-ci, toutefois, l'interopérabilité C++ est utilisée plutôt qu'un assembly d'interopérabilité distinct généré avec Tlbimp.exe. Cette technique procure plusieurs avantages. Dans cet exemple, le code d'interopérabilité est généré dans l'application ; il n'existe donc aucune dépendance d'un assembly distinct. En outre, l'interface managée exposée est personnalisée pour ressembler davantage à .NET. Par exemple, la méthode RenderFile prend un System.String plutôt qu'un char*. La version managée de l'interface COM est appelée CRCW (Custom Runtime Callable Wrapper).
L'écriture de CRCW n'exige aucun assembly d'interopérabilité, mais elle requiert des fichiers d'en-tête qui définissent les interfaces COM. Pour les composants COM qui comprennent des bibliothèques de types, ces en-têtes peuvent être générés à l'aide du MIDL Compiler.
La première partie de l'exemple de code suivant définit le wrapper personnalisé exposant les membres qui seront exposés à l'application managée. La deuxième partie est une application console qui utilise le wrapper personnalisé pour lire des fichiers AVI.
Exécutez le fichier .exe résultant avec le nom d'un fichier AVI valide afin que le fichier soit restitué dans une fenêtre.
// 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();
}