简单写一个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 < <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(msg->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->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->index, msg-><span style="color: rgba(0, 0, 0, 1)">msg);
dumpData(msg);
}</span></pre>
</div>
<p> </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<Msg.MsgData><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> </p>
<p>3. 接着将C++项目添加为C#项目的项目引用。</p>
<p><img src="https://img2024.cnblogs.com/blog/2033325/202505/2033325-20250508233254630-1320164402.png"></p>
<p> 这里存在一个问题,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)"><</span><span style="color: rgba(128, 0, 0, 1)">ItemGroup</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</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)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">CopyToOutputDirectory</span><span style="color: rgba(0, 0, 255, 1)">></span>Always<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">CopyToOutputDirectory</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">None</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">ItemGroup</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p> </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]