(二)一个工作任务引起的乱战——C++程序编译为dll,让C#调用
C++程序编译为C#可调用的dll的过程:
1.新建一个Win32 Console Application 项目,项目名为:DLLDemo,下一步选择Application type为DLL;
2.在Source Files文件夹的DLLDemo.cpp文件中加入代码:
extern "C" _declspec(dllexport) int Add(int a,int b){ return a+b; }
这个函数将在C#中调用。
3.build项目。
会在D:\\visualStudio\\Projects\\DLLDemo\\Debug看到DLLDemo.dll文件,该文件就是要被C#调用的dll。
C#调用C++dll的方法:
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace InteropDemo { class Program { [DllImport("D:\\visualStudio\\Projects\\DLLDemo\\Debug\\DLLDemo.dll", EntryPoint = "Add", CallingConvention = CallingConvention.Cdecl)] public static extern int Add(int a, int b); //DllImport请参照MSDN static void Main(string[] args) { Console.WriteLine(Add(1, 2)); Console.Read(); } } }
【运行结果】:
3
注意:CallingConvention = CallingConvention.Cdecl参数很重要,如果没有错,会抛异常。
这是Windows下c++程序编译成dll供c#调用的方法,可惜还是不能解决工作任务,因为那个api是Linux下的源码。于是,我只能自己写代码,包装请求参数,发消息。下面的文字是我处理工作任务的过程,可以跳过不看,因为没有处理成功,对你们可能没有太大的帮助。
现在介绍下服务接入文档,其请求包要求如下:
上图请求包中参数m_sContent的格式如下:
如果自己包装请求,这里存在两个问题不知道怎么解决:
首先,两图中结构体每个成员的需要限定长度;
其次,在请求包中m_sContent本来是规定为string类型的,又做了另一个规定为结构体,这中间存在一个转换问题,理解不透。
在处理这个问题的过程中,我采用了三种方法:
首先定义的结构体为:
//请求包结构体定义 public struct ReqPackage { public string m_cVersion;//协议的版本号 public uint m_dwNeedRst;//是否需要返回 public uint m_dwCmd;//请求的服务类型 public uint m_dwContentLen;//内容有效长度 public string m_sContent;//内容为请求命令或者返回的相关信息 public uint m_dwPkgSeq;//upd包序列号,tcp下为0 }; //消息内容结构体定义 public struct MsgReq { public uint m_iFuid;// 用户ID public int m_iMask;//发送屏蔽码* public int m_iMsgLen;//消息的有效长度 public string m_sMsgContent;//消息 }
1.将两个结构体转化为byte[]然后处理长度。处理过程有误,没有成功;后来发现这段代码也有错误,不能这样处理。
//将请求包各参数按长度组合好 public byte[] ReqPackageTo(ReqPackage reqPackage) { byte[] structudp = StructToBytes(reqPackage); List<byte> bufferIn = new List<byte>(); var parametersVer = new byte[4]; parametersVer = BitConverter.GetBytes(structudp[0]); bufferIn.AddRange(parametersVer); for (int i = 1; i < structudp.Length; i++) { if (i != 4) { var parameters = new byte[4]; parameters = BitConverter.GetBytes(structudp[i]); bufferIn.AddRange(parameters); } else//消息内容实际长度以m_dwContentLen为准,最大长度为846字节 { uint sizeCon = reqPackage.m_dwContentLen; var parametersCon = new byte[sizeCon]; parametersCon = System.Text.Encoding.Default.GetBytes(reqPackage.m_sContent); bufferIn.AddRange(parametersCon); } } return bufferIn.ToArray(); } //将消息内容各参数按长度组合好 public byte[] MsgReqTo(MsgReq msgReq) { byte[] structMsg = StructToBytes(msgReq); List<byte> bufferIn = new List<byte>(); for (int i = 1; i < structMsg.Length; i++) { if (i != 3) { var parameters = new byte[4]; parameters = BitConverter.GetBytes(structMsg[i]); bufferIn.AddRange(parameters); } else//消息内容实际长度以m_iMsgLen为准,最大长度为846字节 { int sizeCon = msgReq.m_iMsgLen; var parametersCon = new byte[sizeCon]; parametersCon = parametersCon = System.Text.Encoding.Default.GetBytes(msgReq.m_sMsgContent); bufferIn.AddRange(parametersCon); } } return bufferIn.ToArray(); }
2.将m_sContent结构体的各个成员单独处理,均先转换为byte[],限定长度,然后转换成一个byte[],再转换成string(为的是赋值给请求包中m_sContent)。然后将请求包中的各个成员单独处理,均先转换为byte[],限定长度,然后转换成一个byte[]。没有成功;
//将请求包各参数按长度组合好 public byte[] reqPackBytes(ReqPackage reqp) { List<byte> bufferIn = new List<byte>(); var m_cVersion = new byte[1]; m_cVersion = System.Text.Encoding.Default.GetBytes(reqp.m_cVersion); var m_dwCmd = new byte[4]; m_dwCmd = System.BitConverter.GetBytes(reqp.m_dwCmd); var m_dwNeedRst = new byte[4]; m_dwNeedRst = System.BitConverter.GetBytes(reqp.m_dwNeedRst); //var m_dwPkgSeq = new byte[4]; //m_dwPkgSeq=System.BitConverter.GetBytes(reqp.m_dwPkgSeq); var m_dwContentLen = new byte[4]; m_dwContentLen = System.BitConverter.GetBytes(reqp.m_dwContentLen); byte[] m_sContent = System.Text.Encoding.Default.GetBytes(reqp.m_sContent); bufferIn.AddRange(m_cVersion); bufferIn.AddRange(m_dwCmd); bufferIn.AddRange(m_dwNeedRst); bufferIn.AddRange(m_dwContentLen); bufferIn.AddRange(m_sContent); // bufferIn.AddRange(m_dwPkgSeq); return bufferIn.ToArray(); } //将消息内容各参数按长度组合好 public byte[] msConBytes(MsgReq msgR) { List<byte> bufferIn = new List<byte>(); var m_iFuid = new byte[4]; m_iFuid = System.BitConverter.GetBytes(msgR.m_iFuid); var m_iMask = new byte[4]; m_iMask = System.BitConverter.GetBytes(msgR.m_iMask); var m_iMsgLen = new byte[4]; m_iMsgLen = System.BitConverter.GetBytes(msgR.m_iMsgLen); byte[] m_sMsgContent = System.Text.Encoding.Default.GetBytes(msgR.m_sMsgContent); bufferIn.AddRange(m_iFuid); bufferIn.AddRange(m_iMask); bufferIn.AddRange(m_iMsgLen); bufferIn.AddRange(m_sMsgContent); return bufferIn.ToArray(); }
3.比较笨的一种方法,手动拼字节。没有成功。
StringBuilder msgBodyBuffer = new StringBuilder(846);//m_sContent String msgBody = msgBodyBuffer.ToString(); byte[] msgBodyBytes = System.Text.Encoding.Default.GetBytes(msgBody); byte[] msg = new byte[859]; msg[0] = 0x02; // 协议版本 msg[1] = 0; msg[2] = 0; msg[3] = 0; msg[4] = (byte)1; // 是否响应 msg[5] = 0; msg[6] = 0; msg[7] = 0; msg[8] = 0; msg[9] = 0; msg[10] = 0; msg[11] = 0; // 请求的服务类型 msg[12] = (byte)(0x325 & 0xFF); // 请求命令的有效长度, 为什么是0x2D? msg[13] = (byte)((0x325 >> 8) & 0xFF); msg[14] = 0; msg[15] = 0; uint uid = 0; String uidStr = Fuid; if (uidStr != null && uidStr.Length > 0) uid = uint.Parse(uidStr); msg[17] = (byte)(uid & 0xFF); msg[18] = (byte)((uid >> 8) & 0xFF); msg[19] = (byte)((uid >> 16) & 0xFF); msg[20] = (byte)((uid >> 24) & 0xFF); msg[21] = 0; msg[22] = 0; msg[23] = 0; msg[24] = (byte)1; // 发送屏蔽码 int length = msgBodyBytes.Length; if (length > 834) length = 834; msg[25] = 0; msg[26] = 0; msg[27] = (byte)(length & 0xFF); // 消息的有效长度 msg[28] = (byte)((length >> 8) & 0xFF); Array.Copy(msgBodyBytes, 0, msg, 28, length);
整了不少时间还没整出来,备受打击。希望能找到解决方法。
下一文将介绍udp通信。