Практическое руководство. Использование встроенных серверов COM с CRCW
Обновлен: Ноябрь 2007
В отличие от других языков .NET Visual C++ предоставляет функции взаимодействия, которые позволяют прямо и эффективно получить доступ к неуправляемым функциям API, включая COM-интерфейсы. В частности, для модели COM, это дает серьезные преимущества.
Пример
Подобно примеру в Практическое руководство. Использование неуправляемых COM-серверов с помощью средства TLBIMP, в этом примере использованы COM-интерфейсы, определенные в файле Quartz.dll (в каталоге C:\window\System32) для воспроизведения AVI-файлов. Однако в этом случае взаимодействие C++ использовано вместо отдельной сборки взаимодействия, созданной с помощью файла Tlbimp.exe. У этого метода есть несколько преимуществ. В этом случае код взаимодействия встроен в приложение, таким образом, нет зависимости от отдельной сборки. Также предоставленный управляемый интерфейс настроен так, чтобы быть более подобным .NET. Например, метод RenderFile принимает System.String вместо char*. Управляемая версия COM-интерфейса вызывает пользовательскую вызываемую оболочку времени выполнения (Custom Runtime Callable Wrapper, CRCW).
Написание оболочек CRCW не требует сборки взаимодействия, но требует файлы заголовка, которые определяют COM-интерфейсы. Для COM-компонентов, которые включают библиотеки типов, эти заголовки могут быть созданы с помощью MIDL Compiler.
Первая часть следующего кода в примере определяет пользовательскую программу-оболочку, содержащую элементы, которые будут предоставлены управляемому приложению. Вторая часть является консольным приложением, которое использует пользовательскую программу-оболочку для воспроизведения AVI-файлов.
Выполните результирующий EXE-файл с именем допустимого AVI-файла и последний будет воспроизведен в окне.
// 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();
}