求助,C#调用C++动态链接库
小弟要测试一个C++动态链接库在C#下的调用情况 无奈对C#一窍不通 特来求助大家
- C/C++ code
#include<string.h>#include<stdio.h>typedef struct _TAG_Info{ char tagMac[64]; char tagCoordinate[32];}TAG_INFO;typedef struct _RSSI_Info{ short nRSSI; char strCoordinate[32];}RSSI_INFO;TAG_INFO result;extern"C" _declspec(dllexport) TAG_INFO _stdcall GetCoordinateByTagsRssi(char tagMac[64],short inAPCount,RSSI_INFO*pRssiInfo){ sprintf(result.tagCoordinate,"x:%f,y:%f",10.0,10.0); strcpy(result.tagMac,tagMac); return result;}//C++的动态链接库代码 省略了算法 如果调用成功 就能显示出x:10.0000,y:10.0000 在VC6.0下调用正常
下面是小弟写的C#调用代码 很多问题 都是数据类型之间的关系搞不清楚
- C# code
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Runtime.InteropServices;using System.Windows.Forms;namespace Cstest{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } [StructLayout(LayoutKind.Sequential)] public struct TAG_INFO { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string tagMac; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string tagCoordinate; }; public struct RSSI_INFO { public Int16 nRSSI; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string strCoordinate; };//对应上面两个结构体 但是char数组和string对应总觉得不太对,又不知道该用什么 [DllImport(@"E:\dll\Debug\dlltest.dll", EntryPoint = "_GetCoordinateByTagsRssi@12")] public static extern TAG_INFO GetCoordinateByTagsRssi(string tagMac, Int16 inAPCount, ref RSSI_INFO pRssiInfo); private void button1_Click(object sender, EventArgs e) { TAG_INFO jieguo; RSSI_INFO[] test = new RSSI_INFO[3]; test[0].nRSSI = 5; test[1].nRSSI = 5; test[2].nRSSI = 5; test[0].strCoordinate = "x:0,y:5"; test[1].strCoordinate = "x:5,y:0"; test[2].strCoordinate = "x:10,y:5"; string tagmac ="AAAA"; Int16 m = 3; jieguo = GetCoordinateByTagsRssi(tagmac, m, ref test[0]); } }}
编译能通过 但是一点button 就会出现“方法的类型签名与 PInvoke 不兼容。”
资料也查了不少 无奈C#懂得太少 只好麻烦各位
[解决办法]
http://www.cnblogs.com/warensoft/archive/2011/12/09/Warenosoft3D.html
[解决办法]
1、要用[StructLayout( LayoutKind.Sequential)]防止.net进行结构优化。
2、用RSSI_INFO[] pRssiInfo而不是ref RSSI_INFO pRssiInfo,保证在PInvoke的时候,所有的数组成员不会被CLR移动。
3、要用byte[] tagMac,不然就要指定封送方式:[MarshalAs(...)] string tagMac。
[解决办法]
lz需要做好c#调用c++dll时的数据类型对应。这里总结得挺好:
http://blog.csdn.net/xqf222/article/details/5877795
[解决办法]
- C# code
class Program { public const int tagMac_BytesCount = 64; public const int tagCoordinate_BytesCount = 32; public const int tagAll_BytesCount = tagMac_BytesCount + tagCoordinate_BytesCount; [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] public struct TAG_INFO { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = tagMac_BytesCount)] public String tagMac; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = tagCoordinate_BytesCount)] public String tagCoordinate; } //定义一个与非直接复制到本机结构中的类型具有相同大小的可直接复制到本机结构中的帮助器类型 //并在平台调用函数返回后转化数据 [StructLayout(LayoutKind.Explicit)] public struct MARSHAL_TAG_INFO { [FieldOffset(0)] public Byte byteStart; [FieldOffset(tagAll_BytesCount - 1)] //强制结构大小 public Byte byteEnd; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct RSSI_INFO { public Int16 nRSSI; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string strCoordinate; } public class LibWrap { [DllImport("MyDll.dll", CharSet = CharSet.Ansi)] public static extern MARSHAL_TAG_INFO GetCoordinateByTagsRssi(String tagMac, Int16 inAPCount, [In, Out] RSSI_INFO[] pRssiInfo); } static void Main(string[] args) { TAG_INFO result; MARSHAL_TAG_INFO resultTemp; RSSI_INFO[] test = new RSSI_INFO[3]; test[0].nRSSI = 5; test[1].nRSSI = 5; test[2].nRSSI = 5; test[0].strCoordinate = "x:0,y:5"; test[1].strCoordinate = "x:5,y:0"; test[2].strCoordinate = "x:10,y:5"; String tagmac = "AAAA"; Int16 m = 3; resultTemp = LibWrap.GetCoordinateByTagsRssi(tagmac, m, test); //利用非托管内存转化数据。效率不高,或有更好的方法 IntPtr pointer = Marshal.AllocCoTaskMem(tagAll_BytesCount); Marshal.StructureToPtr(resultTemp, pointer, true); result.tagMac = Marshal.PtrToStringAnsi(pointer, tagMac_BytesCount); result.tagCoordinate = Marshal.PtrToStringAnsi(pointer + tagMac_BytesCount, tagCoordinate_BytesCount); Marshal.FreeCoTaskMem(pointer); Console.WriteLine("【{0}】,【{1}】", result.tagMac.Trim((char)0), result.tagCoordinate.Trim((char)0)); Console.ReadKey(); } }