第十一人 發表於 2022-6-6 09:44:00

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>-&gt;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>-&gt;NewFrameReceived += <span style="color: rgba(0, 0, 255, 1)">gcnew</span> ESBasic::<span style="color: rgba(0, 128, 128, 1)">CbGeneric</span>&lt;array&lt;unsigned <span style="color: rgba(0, 0, 255, 1)">char</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>&gt;^&gt;(<span style="color: rgba(0, 0, 255, 1)">this</span>, &amp;<span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 128, 1)">Tester</span>::OnNewFrameReceived);
      dynamicCameraConnector</span>-&gt;ConnectEnded += <span style="color: rgba(0, 0, 255, 1)">gcnew</span> ESBasic::<span style="color: rgba(0, 128, 128, 1)">CbGeneric</span>&lt;OMCS::Passive::ConnectResult&gt;(<span style="color: rgba(0, 0, 255, 1)">this</span>, &amp;<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-&gt;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>&lt;<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>&gt;^<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-&gt;VideoSize.Width, dynamicCameraConnector-&gt;<span style="color: rgba(0, 0, 0, 1)">VideoSize.Height);

      </span>++<span style="color: rgba(0, 0, 255, 1)">this</span>-&gt;<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>-&gt;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>-&gt;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>-&gt;dynamicCameraConnector-&gt;<span style="color: rgba(0, 0, 0, 1)">Connected)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">this</span>-&gt;dynamicCameraConnector-&gt;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>-&gt;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>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;启动OMCS服务端(可从文末下载)后,运行本文的控制台程序,运行效果如下截图所示:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<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]
查看完整版本: C++调用C#的动态库dll