以往我們經常是需要使用C#來調用C++的dll,這通過PInvoke就能實現。現在在實際的項目過程中,有時會遇到在C++的項目中調用某個C#的dll來完成特定的某個功能,我們都知道,Native C++是沒辦法直接調用.NET平臺的dll的。那有沒有辦法來做到這一點了?答案是肯定的。
我們以OMCS實時音視頻框架爲例,OMCS WinPC 版的SDK是C#開發的,有些使用C++ QT開發Windows應用的客戶,想調用OMCS來進行語音視頻會話或遠程桌面等功能,那該怎麼做了?
一.基本原理
雖然,Native C++是調用不了C#的dll的,但是Managed C++(C++/CLI)可以調用C#的dll,所以,可以使用C++/CLI作爲橋樑來將 Native C++ 和 C#連接起來。
(1)新建一個C++/CLI的庫(比如名稱爲OmcsWrap),添加引用並調用OMCS.dll,使用Managed C++語法調用OMCS.dll中的組件,並暴露出標準的C/C++接口。
(2)編譯C++/CLI庫得到 OmcsWrap.dll 和 OmcsWrap.lib。該庫的接口是符合C++規範的。
(3)在Native C++項目(如QT)中,鏈接 OmcsWrap.dll、OmcsWrap.lib即可。
二.C++/CLI調用C#版的OMCS示例
如果瞭解OMCS的基本用法(不瞭解的可以查看:OMCS入門Demo:語音視頻、電子白板、遠程桌面 功能展現),那麼下面的C++/CLI的調用代碼就很容易理解了。
我們新建一個C++/CLI的控制檯項目,來演示如何通過OMCS的攝像頭連接器連接到任意一個在線用戶的攝像頭,拿到攝像頭的視頻圖像Bitmap數據。
using namespace System; using namespace System::Drawing; using namespace OMCS::Passive; using namespace OMCS::Passive::Video; ref class Tester { private: DynamicCameraConnector^ dynamicCameraConnector; int frameCount = 0; public: Tester() { IMultimediaManager^ mgr = MultimediaManagerFactory::GetSingleton(); //登陸 aa09 mgr->Initialize("aa09", "", "127.0.0.1", 9900); Console::WriteLine(L"登錄OMCS服務器成功!"); } void Start() { dynamicCameraConnector = gcnew DynamicCameraConnector(); dynamicCameraConnector->NewFrameReceived += gcnew ESBasic::CbGeneric<array<unsigned char, 1>^>(this, &Tester::OnNewFrameReceived); dynamicCameraConnector->ConnectEnded += gcnew ESBasic::CbGeneric<OMCS::Passive::ConnectResult>(this, &Tester::OnConnectEnded); //連接自己的攝像頭 dynamicCameraConnector->BeginConnect(L"aa09"); } //攝像頭圖像數據 void OnNewFrameReceived(array<unsigned char, 1>^ rgb24) { Bitmap^ bm = ESBasic::Helpers::ImageHelper::ConstructRGB24Bitmap(rgb24, dynamicCameraConnector->VideoSize.Width, dynamicCameraConnector->VideoSize.Height); ++this->frameCount; Console::WriteLine(L"收到圖像幀:" + this->frameCount.ToString("00000")); } //連接攝像頭的結果 void OnConnectEnded(OMCS::Passive::ConnectResult result) { if (result == ConnectResult::Succeed) //連接成功 { Console::WriteLine(L"連接攝像頭成功!"); } else { Console::WriteLine(L"連接攝像頭失敗!原因:" + result.ToString()); } } void Stop() { if (this->dynamicCameraConnector != nullptr) { if (this->dynamicCameraConnector->Connected) { this->dynamicCameraConnector->Disconnect(); //斷開到目標攝像頭的連接 Console::WriteLine(L"斷開攝像頭連接器!"); } this->dynamicCameraConnector = nullptr; } } };
(1)這裏僅僅是將收到的攝像頭視頻圖像幀的幀數打印出來,真實的使用場景中,可以將圖像幀回調傳給QT,QT就可以在UI控件上將圖像渲染出來。這樣就可以看到視頻了。
(2)這裏是以攝像頭爲例,桌面也是完全一樣的模式,使用DynamicDesktopConnector。
(3)對於麥克風聲音,則更簡單一下,因爲其不需要UI渲染,所以直接在C++/CLI中調用MicrophoneConnector就可以了。連接目標麥克風成功,本地電腦就會自動播放其聲音。
啓動OMCS服務端(可從文末下載)後,運行本文的控制檯程序,運行效果如下截圖所示:
這裏只是簡單的示意一下C++/CLI調用OMCS的方式,至於封裝一個給Native C++來調用C++/CLI庫,這個庫要提供哪些API,則取決於具體的項目需求,這裏就不舉例了。
三. Demo 源碼下載
1. C++/CLI調用OMCS Demo:CppCli-CallOMCS-Demo.rar
2. Demo 服務端+C#客戶端:OMCS.Demos.Simplest.rar
關於OMCS實時視頻功能的demo介紹,請參見這裏。
最後提一下,還有一種 Native C++ 調用C#的dll的方式,是使用COM組件。
這種方式是在C#的dll外再封裝一層,將其接口全部轉換成COM接口,如此,標準的COM組件就可以被Native C++調用了。
COM組件這種做法已經很古老,而且相當繁瑣,所以不是迫不得已,一般不會採用這種方式。