在C#中调用C++动态库导出的函数时,有时候需要封送一些复杂的数据结构,这时候不确定自己封送的数据的内存布局对不对,就想要弄个简单的C++项目模拟一下被调用的接口,检查一下C#的数据封送是否正确。
因为对C++项目基本上没任何了解,捣鼓了半天才搞定,所以这里简单记录一下过程,以加深记忆。
1. 首先用C++的动态链接库模板创建一个项目。然后在dllmain.cpp中定义一个名为PostMsg的C导出函数,该函数接收MsgData结构体并打印,代码如下:- typedef struct MsgData
- {
- int index;
- char msg[32];
- BYTE data[8];
- } MsgData;
- static void dumpData(const MsgData* msg)
- {
- for (size_t i = 0; i < sizeof(msg->data); i++)
- {
- printf("%02x ", *(msg->data + i));
- if ((i + 1) % 8 == 0)
- {
- printf("\n");
- }
- }
- }
- extern "C"
- __declspec(dllexport) void PostMsg(MsgData* msg)
- {
- printf("index=%d\nmsg="%s"\n", msg->index, msg->msg);
- dumpData(msg);
- }
复制代码
2. 然后创建一个C#的控制台程序来调用它。这里通过DllImport特性来导入C++项目的PostMsg函数,同样也定义了对应的MsgData结构体,代码如下:- var msg = new Msg.MsgData()
- {
- Index = 2025,
- Msg = "custom msg",
- Data = [1,2,3,4,5,6,7,8]
- };
- var ptr = Marshal.AllocHGlobal(Marshal.SizeOf<Msg.MsgData>());
- Marshal.StructureToPtr(msg, ptr, false);
- Msg.PostMsg(ptr);
- internal class Msg
- {
- [DllImport("TestDll.dll", EntryPoint = "PostMsg")]
- public static extern void PostMsg(IntPtr msg);
- [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
- public struct MsgData
- {
- public int Index;
- [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 32)]
- public string Msg;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] Data;
- }
- }
复制代码
3. 接着将C++项目添加为C#项目的项目引用。
这里存在一个问题,C#项目不支持添加C++的项目引用,所以这里标了黄色感叹号,虽然构建C#项目的时候会先构建C++项目,但不会自动把C++项目的输出拷贝到C#项目的输出目录。
网上有很多方法能够解决把C++输出拷贝到C#输出目录的问题,我这里采用添加项目文件的方式,在C#的项目文件里添加以下内容:- <ItemGroup>
- <None Include="../x64/$(Configuration)/*.dll;../x64/$(Configuration)/*.pdb">
- <CopyToOutputDirectory>Always</CopyToOutputDirectory>
- </None>
- </ItemGroup>
复制代码
4. 最后看一下结果:- index=2025
- msg="custom msg"
- 01 02 03 04 05 06 07 08
复制代码 结果正常,这样就可以简单验证一下自己往C函数里封送的数据是不是正确了
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |