C++调用C#的动态库dll
<p> 以往我们经常是需要使用C#来调用C++的dll,这通过PInvoke就能实现。现在在实际的项目过程中,有时会遇到在C++的项目中调用某个C#的dll来完成特定的某个功能,我们都知道,Native C++是没办法直接调用.NET平台的dll的。那有没有办法来做到这一点了?答案是肯定的。</p><p> 我们以OMCS实时音视频框架为例,OMCS WinPC 版的SDK是C#开发的,有些使用C++ QT开发Windows应用的客户,想调用OMCS来进行语音视频会话或远程桌面等功能,那该怎么做了?</p>
<h2>一.基本原理</h2>
<p> 虽然,Native C++是调用不了C#的dll的,但是Managed C++(C++/CLI)可以调用C#的dll,所以,可以使用C++/CLI作为桥梁来将 Native C++ 和 C#连接起来。</p>
<p>(1)新建一个C++/CLI的库(比如名称为OmcsWrap),添加引用并调用OMCS.dll,使用Managed C++语法调用OMCS.dll中的组件,并暴露出标准的C/C++接口。</p>
<p>(2)编译C++/CLI库得到 OmcsWrap.dll 和 OmcsWrap.lib。该库的接口是符合C++规范的。</p>
<p>(3)在Native C++项目(如QT)中,链接 OmcsWrap.dll、OmcsWrap.lib即可。</p>
<h2>二.C++/CLI调用C#版的OMCS示例</h2>
<p> 如果了解OMCS的基本用法(不了解的可以查看:OMCS入门Demo:语音视频、电子白板、远程桌面 功能展现),那么下面的C++/CLI的调用代码就很容易理解了。</p>
<p> 我们新建一个C++/CLI的控制台项目,来演示如何通过OMCS的摄像头连接器连接到任意一个在线用户的摄像头,拿到摄像头的视频图像Bitmap数据。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> System::Drawing;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> OMCS::Passive;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> OMCS::Passive::Video;
</span><span style="color: rgba(0, 0, 255, 1)">ref</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)"> Tester</span>
{
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)">:
<span style="color: rgba(0, 128, 128, 1)">DynamicCameraConnector</span></span>^<span style="color: rgba(0, 0, 0, 1)"> dynamicCameraConnector;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> frameCount = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)">:
Tester()
{
<span style="color: rgba(0, 128, 128, 1)">IMultimediaManager</span></span>^ mgr =<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)"> MultimediaManagerFactory</span>::GetSingleton();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">登陆 aa09</span>
<span style="color: rgba(0, 0, 0, 1)">mgr</span>->Initialize(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">aa09"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">127.0.0.1</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">9900</span><span style="color: rgba(0, 0, 0, 1)">);
<span style="color: rgba(0, 128, 128, 1)">Console</span>::WriteLine(L</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">登录OMCS服务器成功!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Start()
{
dynamicCameraConnector </span>=<span style="color: rgba(0, 0, 0, 1)"> gcnew <span style="color: rgba(0, 128, 128, 1)">DynamicCameraConnector</span>();
dynamicCameraConnector</span>->NewFrameReceived += <span style="color: rgba(0, 0, 255, 1)">gcnew</span> ESBasic::<span style="color: rgba(0, 128, 128, 1)">CbGeneric</span><array<unsigned <span style="color: rgba(0, 0, 255, 1)">char</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>>^>(<span style="color: rgba(0, 0, 255, 1)">this</span>, &<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)">Tester</span>::OnNewFrameReceived);
dynamicCameraConnector</span>->ConnectEnded += <span style="color: rgba(0, 0, 255, 1)">gcnew</span> ESBasic::<span style="color: rgba(0, 128, 128, 1)">CbGeneric</span><OMCS::Passive::ConnectResult>(<span style="color: rgba(0, 0, 255, 1)">this</span>, &<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)">Tester</span>::OnConnectEnded);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接自己的摄像头</span>
dynamicCameraConnector->BeginConnect(L<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">aa09"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">摄像头图像数据</span>
<span style="color: rgba(0, 0, 255, 1)">void</span> OnNewFrameReceived(<span style="color: rgba(0, 0, 255, 1)">array</span><<span style="color: rgba(0, 0, 255, 1)">unsigned</span> <span style="color: rgba(0, 0, 255, 1)">char</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>>^<span style="color: rgba(0, 0, 0, 1)"> rgb24)
{
<span style="color: rgba(0, 128, 128, 1)">Bitmap</span></span>^bm = ESBasic::Helpers::<span style="color: rgba(0, 128, 128, 1)">ImageHelper</span>::ConstructRGB24Bitmap(rgb24, dynamicCameraConnector->VideoSize.Width, dynamicCameraConnector-><span style="color: rgba(0, 0, 0, 1)">VideoSize.Height);
</span>++<span style="color: rgba(0, 0, 255, 1)">this</span>-><span style="color: rgba(0, 0, 0, 1)">frameCount;
<span style="color: rgba(0, 128, 128, 1)">Console</span>::WriteLine(L</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">收到图像帧:</span><span style="color: rgba(128, 0, 0, 1)">"</span>+ <span style="color: rgba(0, 0, 255, 1)">this</span>->frameCount.ToString(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">00000</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">));
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接摄像头的结果</span>
<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> OnConnectEnded(OMCS::Passive::<span style="color: rgba(0, 128, 128, 1)">ConnectResult</span> result)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (result == <span style="color: rgba(0, 128, 128, 1)">ConnectResult</span>::Succeed) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接成功</span>
<span style="color: rgba(0, 0, 0, 1)"> {
<span style="color: rgba(0, 128, 128, 1)">Console</span>::WriteLine(L</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">连接摄像头成功!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
<span style="color: rgba(0, 128, 128, 1)">Console</span>::WriteLine(L</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">连接摄像头失败!原因:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> result.ToString());
}
}
</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Stop()
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>->dynamicCameraConnector !=<span style="color: rgba(0, 0, 0, 1)"> nullptr)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>->dynamicCameraConnector-><span style="color: rgba(0, 0, 0, 1)">Connected)
{
</span><span style="color: rgba(0, 0, 255, 1)">this</span>->dynamicCameraConnector->Disconnect(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">断开到目标摄像头的连接</span>
<span style="color: rgba(0, 128, 128, 1)">Console</span>::WriteLine(L<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">断开摄像头连接器!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>->dynamicCameraConnector =<span style="color: rgba(0, 0, 0, 1)"> nullptr;
}
}
};</span></pre>
</div>
<p>(1)这里仅仅是将收到的摄像头视频图像帧的帧数打印出来,真实的使用场景中,可以将图像帧回调传给QT,QT就可以在UI控件上将图像渲染出来。这样就可以看到视频了。</p>
<p>(2)这里是以摄像头为例,桌面也是完全一样的模式,使用DynamicDesktopConnector。</p>
<p>(3)对于麦克风声音,则更简单一下,因为其不需要UI渲染,所以直接在C++/CLI中调用MicrophoneConnector就可以了。连接目标麦克风成功,本地电脑就会自动播放其声音。</p>
<p> 启动OMCS服务端(可从文末下载)后,运行本文的控制台程序,运行效果如下截图所示:</p>
<p> <img src="https://img2022.cnblogs.com/blog/9005/202206/9005-20220606093225011-1994665707.png" alt=""></p>
<p> 这里只是简单的示意一下C++/CLI调用OMCS的方式,至于封装一个给Native C++来调用C++/CLI库,这个库要提供哪些API,则取决于具体的项目需求,这里就不举例了。</p>
<h2>三. Demo 源码下载</h2>
<p>1. C++/CLI调用OMCS Demo:CppCli-CallOMCS-Demo.rar </p>
<p>2. Demo 服务端+C#客户端:OMCS.Demos.Simplest.rar</p>
<p> 关于OMCS实时视频功能的demo介绍,请参见这里。</p>
<p> 最后提一下,还有一种 Native C++ 调用C#的dll的方式,是使用COM组件。</p>
<p> 这种方式是在C#的dll外再封装一层,将其接口全部转换成COM接口,如此,标准的COM组件就可以被Native C++调用了。</p>
<p> COM组件这种做法已经很古老,而且相当繁琐,所以不是迫不得已,一般不会采用这种方式。</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/zhuweisky/p/16347113.html
頁:
[1]