三小隻 發表於 2025-5-8 23:43:00

简单写一个C函数供C#代码调用

<p>在C#中调用C++动态库导出的函数时,有时候需要封送一些复杂的数据结构,这时候不确定自己封送的数据的内存布局对不对,就想要弄个简单的C++项目模拟一下被调用的接口,检查一下C#的数据封送是否正确。</p>
<p>因为对C++项目基本上没任何了解,捣鼓了半天才搞定,所以这里简单记录一下过程,以加深记忆。</p>
<p>1. 首先用C++的动态链接库模板创建一个项目。然后在dllmain.cpp中定义一个名为PostMsg的C导出函数,该函数接收MsgData结构体并打印,代码如下:</p>
<div class="cnblogs_code">
<pre>typedef <span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> MsgData
{
    </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> index;
    </span><span style="color: rgba(0, 0, 255, 1)">char</span> msg[<span style="color: rgba(128, 0, 128, 1)">32</span><span style="color: rgba(0, 0, 0, 1)">];
    BYTE data[</span><span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">];
} MsgData;

</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> dumpData(<span style="color: rgba(0, 0, 255, 1)">const</span> MsgData*<span style="color: rgba(0, 0, 0, 1)"> msg)
{
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (size_t i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(msg-&gt;data); i++<span style="color: rgba(0, 0, 0, 1)">)
    {
      printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%02x </span><span style="color: rgba(128, 0, 0, 1)">"</span>, *(msg-&gt;data +<span style="color: rgba(0, 0, 0, 1)"> i));
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> ((i + <span style="color: rgba(128, 0, 128, 1)">1</span>) % <span style="color: rgba(128, 0, 128, 1)">8</span> == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
      {
            printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n</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)">extern</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
__declspec(dllexport) </span><span style="color: rgba(0, 0, 255, 1)">void</span> PostMsg(MsgData*<span style="color: rgba(0, 0, 0, 1)"> msg)
{
    printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">index=%d\nmsg=\"%s\"\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, msg-&gt;index, msg-&gt;<span style="color: rgba(0, 0, 0, 1)">msg);
    dumpData(msg);
}</span></pre>
</div>
<p>&nbsp;</p>
<p>2. 然后创建一个C#的控制台程序来调用它。这里通过DllImport特性来导入C++项目的PostMsg函数,同样也定义了对应的MsgData结构体,代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> msg = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Msg.MsgData()
{
    Index </span>= <span style="color: rgba(128, 0, 128, 1)">2025</span><span style="color: rgba(0, 0, 0, 1)">,
    Msg </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">custom msg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
    Data </span>= [<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">4</span>,<span style="color: rgba(128, 0, 128, 1)">5</span>,<span style="color: rgba(128, 0, 128, 1)">6</span>,<span style="color: rgba(128, 0, 128, 1)">7</span>,<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">]
};
</span><span style="color: rgba(0, 0, 255, 1)">var</span> ptr = Marshal.AllocHGlobal(Marshal.SizeOf&lt;Msg.MsgData&gt;<span style="color: rgba(0, 0, 0, 1)">());
Marshal.StructureToPtr(msg, ptr, </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
Msg.PostMsg(ptr);


</span><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Msg
{
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">extern</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> PostMsg(IntPtr msg);

   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> MsgData
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> Index;
      
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> Msg;
      
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[] Data;
    }
}</span></pre>
</div>
<p>&nbsp;</p>
<p>3. 接着将C++项目添加为C#项目的项目引用。</p>
<p><img src="https://img2024.cnblogs.com/blog/2033325/202505/2033325-20250508233254630-1320164402.png"></p>
<p>&nbsp;这里存在一个问题,C#项目不支持添加C++的项目引用,所以这里标了黄色感叹号,虽然构建C#项目的时候会先构建C++项目,但不会自动把C++项目的输出拷贝到C#项目的输出目录。</p>
<p>网上有很多方法能够解决把C++输出拷贝到C#输出目录的问题,我这里采用添加项目文件的方式,在C#的项目文件里添加以下内容:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">ItemGroup</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">None </span><span style="color: rgba(255, 0, 0, 1)">Include</span><span style="color: rgba(0, 0, 255, 1)">="../x64/$(Configuration)/*.dll;../x64/$(Configuration)/*.pdb"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">CopyToOutputDirectory</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>Always<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">CopyToOutputDirectory</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>      
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">None</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">ItemGroup</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>&nbsp;</p>
<p>4. 最后看一下结果:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">index=2025
msg="custom msg"
01 02 03 04 05 06 07 08</span></pre>
</div>
<p>结果正常,这样就可以简单验证一下自己往C函数里封送的数据是不是正确了</p><br><br>
来源:https://www.cnblogs.com/yangtb/p/18867332
頁: [1]
查看完整版本: 简单写一个C函数供C#代码调用