HOW TO:在 CRCW 中使用原生 COM 伺服器

更新:2007 年 11 月

不像其他 .NET 語言,Visual C++ 提供了 Interop 功能,允許直接且順利地存取 Unmanaged API (包括 COM 介面)。特別是對於 COM Interop,這項功能提供了強大的優點。

範例

就像 HOW TO:在 TLBIMP 中使用原生 COM 伺服器中的範例,這個範例使用定義在 Quartz.dll (可在 C:\window\System32 目錄中找到) 中的 COM 介面來播放 AVI 檔。不過,在這個情況中會使用 C++ Interop 而不是使用 Tlbimp.exe 所產生的個別 Interop 組件。這項技巧有數個優點。在這個情況中,Interop 程式碼會內建至應用程式中,所以沒有個別組件的相依性。此外,公開的 Managed 介面會自訂為更接近 .NET 的風格。例如,RenderFile 方法會使用 System.String 而不是 char*。COM 介面的 Managed 版本稱為自訂之執行階段可呼叫的包裝函式 (Custom Runtime Callable Wrapper,CRCW)。

撰寫 CRCW 不需要 Interop 組件,但是會需要定義 COM 介面的標頭檔 (Header File)。對於包含型別程式庫的 COM 元件,可以使用 MIDL Compiler產生這些標頭檔。

下列程式碼範例的第一個部分會定義自訂的包裝函式,公開 (Expose) 要公開給 Managed 應用程式的成員。第二個部分是主控台應用程式,使用自訂的包裝函式來播放 AVI 檔。

使用有效的 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();
}

請參閱

參考

使用 .NET 的原生 COM 伺服器