C#通过Kernel32.dll动态调用C++生成dll相关接口(结构体转换)相关问题整理

 公司内部服务器端全部采用C++开发,自然而然暴露给客户的肯定是C++提供的API.这里不介绍为何通讯间不采用xml或和其他方式进行传输,因为这是个个别案例.

  公司C++高手一大堆,我只是个C++新手,C#也就初级的样子(做过WEB开发以及WCF业务开发,客户端开发经验少).公司内部基本没人用过C#,客户那边又采用的是C#开发,强烈要求 写C#调用案例.固然,我也就赶着鸭子上架,尝试去做了.由于C++提供的API的源码有没有,只能通过部门老大了解,这也是大公司开发的弱势,你只能各种调底层api,学习东西很受限制..哎....

  花了2天时间研究C++与C# 数据类型转换,以及相互调用,网上文章一大堆,但是实际用起来问题非常多.

  提供几个可以参考的链接:

  http://www.cnblogs.com/wdysunflower/archive/2010/09/01/1813947.html

  http://www.cnblogs.com/yiki/archive/2008/10/29/1321848.html(个人电脑,发现收藏链接不在,回头再添上)

为了或许给以后的博友提供点帮助,少绕点圈子,特此写篇博客,大家不要喷我技术高低,其中不足之处大家可以帮我提出,一起改进.(我喜欢处理问题,对概念东西不喜欢过于追究.解决问题才是硬道理)

 少文字,多代码.

 

案例如下:

 

(1)封装了 动态加载C++dll实现 \C#结构体定义 \ C++dll中api到C#转换

/********************************************************************************

 ********Athor  : justliver

 *****  DataTime: 20130928

 *******Description:文件包含委托记录类,ServerCliAPI类

 ****************   以及相关委托数据类型(函数指针)

 ********************************************************************************

 *******************************************************************/

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.InteropServices;//调外部dll 命名空间

 

namespace demo_kpmskcxpapi

{

   

  

    //委托类型列表,每一个委托对应一个C++ dll的api

    public delegate int ServerCLI_Init(ref IntPtr hHandle);//&hHandl

    public delegate int ServerCLI_Exit(IntPtr hHandle);

 

    public delegate int ServerCLI_SetConnectOption(IntPtr hHandle, tagServerConnectOption stServerConnection);

    public delegate int ServerCLI_ConnectServer(IntPtr hHandle, StringBuilder ServerName, StringBuilder String, StringBuilder Password);//[MarshalAs(LPStr)]

    public delegate int ServerCLI_DisConnect(IntPtr hHandle);

    public delegate int ServerCLI_DisConnectForce(IntPtr hHandle);

 

    public delegate int ServerCLI_BeginWrite(IntPtr hHandle);

    public delegate int ServerCLI_SetValue(IntPtr hHandle, StringBuilder KeyName, StringBuilder Vlu);

    public delegate int ServerCLI_GetValue(IntPtr hHandle, StringBuilder KeyName, StringBuilder Vlu, int Len);

    public delegate int ServerCLI_ACallProgramAndCommit(IntPtr hHandle, StringBuilder ProgramName, ref tagCallCtrl ptagCallCtrl);// ref tagCallCtrl -> tagCallCtrl *

    public delegate int ServerCLI_ACallProgram(IntPtr hHandle, StringBuilder ProgramName, ref tagCallCtrl ptagCallCtrl);

    public delegate int ServerCLI_GetReply(IntPtr hHandle, ref tagCallCtrl ptagCallCtrl);

    public delegate int ServerCLI_RsGetColByName(IntPtr hHandle, StringBuilder KeyName, StringBuilder Vlu);//对应C++   StringBuilder -> char*  必须用StringBuilder,String无法接收数据(原因为String定长而StringBuilder非定长,大家自己查下资料,这个地方非常重要)

    /// <summary>

    /// 名称:ServerCliAPI类

    ///

    /// 描述:采用动态调用方式,封装了用到的ServerCli.dll中的相关api方便调用

    /// </summary>

    public class ServerCliAPI

    {

        #region 调用Kernel32 API

        //引入Win32API 用来来动态加载用户dll

        [DllImport("Kernel32")]

        public static extern IntPtr GetProcAddress(int handle, String funcname);

        [DllImport("Kernel32")]

        public static extern int LoadLibrary(String funcname);

        [DllImport("Kernel32")]

        public static extern int FreeLibrary(int handle);

        #endregion

 

 

        #region 转换 , 并定义与ServerCli.dll 对应的 API

        public ServerCLI_Init Init;

        public ServerCLI_Exit Exit;

 

        public ServerCLI_SetConnectOption SetConn;

        public ServerCLI_ConnectServer    Connect;

        public ServerCLI_DisConnect       DisConnect;

        public ServerCLI_DisConnectForce  DisConnectForce;

 

        public ServerCLI_BeginWrite BeginWrite;

        public ServerCLI_SetValue SetValue;

        public ServerCLI_ACallProgramAndCommit ACallProgramAndCommit;

        public ServerCLI_GetReply GetReply;

        public ServerCLI_GetErrorCode GetErrorCode;

        public ServerCLI_GetErrorMsg GetErrorMsg;

        public ServerCLI_RsOpen RsOpen;

        public ServerCLI_SQLNumResultCols SQLNumResult;

        public ServerCLI_SQLFetch SQLFetch;

        public ServerCLI_RsGetColByName RsGetColByName;

        #endregion

 

        public ServerCliAPI()

        {

            try

            {

                hModule = LoadLibrary("ServerCli.dll");//加载ServerCli.dll

 

                if (hModule <= 0)

                {

                    return;

                }

 

                //初始化所有委托句柄,,即对应的ServerCli API

 

                Init = (ServerCLI_Init)GetAddress(hModule, "ServerCLI_Init", typeof(ServerCLI_Init));

                Exit = (ServerCLI_Exit)GetAddress(hModule, "ServerCLI_Exit", typeof(ServerCLI_Exit));

 

                SetConn = (ServerCLI_SetConnectOption)GetAddress(hModule, "ServerCLI_SetConnectOption", typeof(ServerCLI_SetConnectOption));

                Connect = (ServerCLI_ConnectServer)GetAddress(hModule, "ServerCLI_ConnectServer", typeof(ServerCLI_ConnectServer));

                DisConnect = (ServerCLI_DisConnect)GetAddress(hModule, "ServerCLI_DisConnect", typeof(ServerCLI_DisConnect));

                DisConnectForce = (ServerCLI_DisConnectForce)GetAddress(hModule, "ServerCLI_DisConnectForce", typeof(ServerCLI_DisConnectForce));

 

                BeginWrite = (ServerCLI_BeginWrite)GetAddress(hModule, "ServerCLI_BeginWrite", typeof(ServerCLI_BeginWrite));

                SetValue = (ServerCLI_SetValue)GetAddress(hModule, "ServerCLI_SetValue", typeof(ServerCLI_SetValue));

                ACallProgramAndCommit = (ServerCLI_ACallProgramAndCommit)GetAddress(hModule, "ServerCLI_ACallProgramAndCommit", typeof(ServerCLI_ACallProgramAndCommit));

                GetReply = (ServerCLI_GetReply)GetAddress(hModule, "ServerCLI_GetReply", typeof(ServerCLI_GetReply));

                GetErrorCode = (ServerCLI_GetErrorCode)GetAddress(hModule, "ServerCLI_GetErrorCode", typeof(ServerCLI_GetErrorCode));

                GetErrorMsg = (ServerCLI_GetErrorMsg)GetAddress(hModule, "ServerCLI_GetErrorMsg", typeof(ServerCLI_GetErrorMsg));

                RsOpen = (ServerCLI_RsOpen)GetAddress(hModule, "ServerCLI_RsOpen", typeof(ServerCLI_RsOpen));

                SQLNumResult = (ServerCLI_SQLNumResultCols)GetAddress(hModule, "ServerCLI_SQLNumResultCols", typeof(ServerCLI_SQLNumResultCols));

                SQLFetch = (ServerCLI_SQLFetch)GetAddress(hModule, "ServerCLI_SQLFetch", typeof(ServerCLI_SQLFetch));

                RsGetColByName = (ServerCLI_RsGetColByName)GetAddress(hModule, "ServerCLI_RsGetColByName", typeof(ServerCLI_RsGetColByName));

            }

            catch (System.Exception ex)

            {

                FreeLibrary(hModule);//释放

                Console.WriteLine("转换并定义与ServerCli.dll 对应的 API 出现错误.Error:{0}", ex.Message.ToString());

            }

        }

        ~ServerCliAPI()

        {

            if (hModule > 0)

            {

                FreeLibrary(hModule);//释放

            }

        }

        //获取api地址(函数指针转委托)

        private static Delegate GetAddress(int dllModule, string functionname, Type t)

        {

            if (dllModule < 0 || string.IsNullOrEmpty(functionname) || t == null)

                return null;

 

            IntPtr addr = GetProcAddress(dllModule, functionname);

 

            if (addr == IntPtr.Zero)

                return null;

            else

                return Marshal.GetDelegateForFunctionPointer(addr, t);

        }

 

        //ServerCli.dll 对应地址

        private static int hModule { get; set; }

}

/******************结构体定义**************************************/

[StructLayout(LayoutKind.Sequential, Size = 117, CharSet = CharSet.Ansi, Pack = 1)]//数据结构必须采用此种方式,保证C++结构体缓冲区大写固定(内存布局方式\缓冲区大小\字符集\对齐单位1个字节)

// 强烈建议LayoutKind.Sequential,不要用LayoutKind.Explicit

    public unsafe struct tagCallCtrl

    {

        [MarshalAs(UnmanagedType.I4)]

        public int nFlags;                        

 

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 27)]

        public char[] szId;  //用字符数组 对应C++为 char[27]              

 

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]

        public char[] szMsgId;             

 

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]

        public char[] szCorrId;             

 

        [MarshalAs(UnmanagedType.I4)]

        public int nExpiry;                       

        [MarshalAs(UnmanagedType.I4)]

        public int nPriority;                          

        [MarshalAs(UnmanagedType.I8)]

        public Int64 tTimeStamp; // 对应C++为 _int64                   

       

        public IntPtr lpfnCallback;    // void*           

    }

       

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]//数据结构必须采用此种方式,保证C++结构体缓冲区大写固定

    public struct tagServerConnectOption

    {

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]// 声明一个字符数组,大小为33    public char[] name;

        public char[] szServerName;

        public int nProtocal;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]

        public char[] szAddress;

        public int nPort;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]

        public char[] szSendQName;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]

        public char[] szReceiveQName;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]

        public char[] szReserved;

    }

}

 

 

(2)具体调用:

ServerCliAPI = new ServerCliAPI();//初始化 调用ServerCliAPI

nRet = ServerCliAPI.Init(ref hHandle);

 

如果大家遇到相关问题可以找我探讨 QQ:一零六五八六六八一八

posted on 2013-09-29 12:33  justliver  阅读(852)  评论(0编辑  收藏  举报

导航