zoukankan      html  css  js  c++  java
  • C#中调用unmanaged DLL

    using System;

    using System.Collections.Generic;

    using System.ComponentModel;

    using System.Data;

    using System.Drawing;

    using System.Linq;

    using System.Text;

    using System.Windows.Forms;

    using System.Diagnostics; // for Process

    using System.Runtime.InteropServices; // for DllImport

     

    namespace ZSICReaderDemo

    {

    public partial class Form1 : Form

    {

    public Form1()

    {

    InitializeComponent();

    }

     

    [DllImport("ZSICReader.DLL")]

    public static extern bool LinkReader();

     

    [DllImport("ZSICReader.DLL")]

    public static extern bool StopReader();

     

    [StructLayout(LayoutKind.Sequential)] // 调用C++DLL必须使用 LayoutKind.Sequential

    // 接口体需要讲参数类型进行转换

    public struct CONSUMERINFO

    {

    public uint ulNum; // 用户编号

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strCardNum; // 卡序号

    public uint ulCardNo; // 卡内码

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strName; // 姓名

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strSex; // 性别

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strDepartment; // 部门名称

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strSort; // 人员类别

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strAddr; // 地址

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strCertificate; // 证件号

    public double dbCardfee; // 卡押金

    public double dbLeftMoney; // 余额

    public double dbSubsidyMoney; //补助金额

     

    public uint lDepartment; // 部门编号

    public uint lSort; // 人员类别编号

     

    public bool bGS; // 挂失状态

    public bool bDestroy; // 注销状态

    public uint ulPsw; // 大额消费密码

     

    public uint lTimes; // 卡使用次数

     

    public double dbTJSKLeftMoney; // 脱机水控余额

    public uint lTJSKCardTimes; // 脱机水控卡次数

     

    public uint lJiFen; // 积分值

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string strContact; // 联系方式

    }

     

    [DllImport("ZSICReader.DLL", CharSet = CharSet.Ansi, SetLastError = false)]

    public static extern bool ReadCardInfo(ref CONSUMERINFO ConsumerInfo);

     

    // 由于DLL中使用了打开了系统串口,所以必须手动调用FreeLibrary释放资源,否则主程序退出DLL时DLL_PROCESS_DETACH会出错

    [DllImport("Kernel32")]

    public static extern int FreeLibrary(IntPtr hModule);

     

    private void button1_Click(object sender, EventArgs e)

    {

    try

    {

    if (LinkReader())

    {

    MessageBox.Show("连接读卡器成功!");

     

    }

    else

    {

    MessageBox.Show("连接读卡器失败!");

     

    }

    }

    catch (System.Exception ex)

    {

     

    }

     

    }

     

    private void button2_Click(object sender, EventArgs e)

    {

    try

    {

    if (StopReader())

    {

    MessageBox.Show("停止读卡器成功!");

    }

    else

    {

    MessageBox.Show("停止读卡器失败!");

    }

    }

    catch (System.Exception ex)

    {

     

    }

    }

     

    private void button3_Click(object sender, EventArgs e)

    {

    try

    {

    CONSUMERINFO ConsumerInfo = new CONSUMERINFO();

     

    if (ReadCardInfo(ref ConsumerInfo))

    {

    MessageBox.Show("读取卡信息成功");

    MessageBox.Show("卡序号:" + ConsumerInfo.ulCardNo.ToString());

    MessageBox.Show("用户编号:" + ConsumerInfo.ulNum.ToString());

    MessageBox.Show("姓名:" + ConsumerInfo.strName);

    MessageBox.Show("性别:" + ConsumerInfo.strSex);

    MessageBox.Show("卡余额:" + ConsumerInfo.dbLeftMoney.ToString());

     

    }

    else

    {

    MessageBox.Show("读取卡信息失败");

    }

    }

    catch (System.Exception ex)

    {

     

    }

    }

     

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)

    {

    try

    { // 在关闭窗口时释放引用的链接库

    foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)

    {

    if (mod.ModuleName == "ZSICReader.DLL")

    {

    FreeLibrary(mod.BaseAddress);

    }

    }

    }

    catch (System.Exception ex)

    {

     

    }

    }

    }

    }

     

    注意:在C#项目中调试unmanaged dll时需要在项目设置里启用允许调试非托管代码。
    关于如何手工卸载DLL详见这里Unload a DLL loaded using DllImport。摘要如下:

    原始C的接口定义是这样的:

    typedef struct _CONSUMERINFO

    {

    ULONG ulNum;

    char strCardNum[100];

    ULONG ulCardNo;

    char strName[100];

    char strSex[100];

    char strDepartment[100];

    char strSort[100];

    char strAddr[100];

    char strCertificate[100];

    double dbCardfee;

    double dbLeftMoney;

    double dbSubsidyMoney;

     

    long lDepartment;

    long lSort;

     

    bool bGS;

    bool bDestroy;

    ULONG ulPsw;

     

    long lTimes;

     

    double dbTJSKLeftMoney;

    long lTJSKCardTimes;

     

    long lJiFen;

    char strContact[100];

    } CONSUMERINFO;

     

    BOOL WINAPI LinkReader();

    BOOL WINAPI StopReader();

    BOOL WINAPI ReadCardInfo(CONSUMERINFO *ConsumerInfo);

     

    对比之前的C#代码,可以知道如何将C++结构转换为C#可以调用的结构了。

    为了方便查看C#与C++结构的转换,引用http://www.cnblogs.com/lizi/archive/2012/02/22/2363181.html
    做了个表格:

    C++类型

    C#类型

    基本类型

     

    Handle

    IntPtr

    Hwnd

    IntPtr

    int*

    ref int

    int&

    ref int

    void*

    IntPtr

    unsigned char*

    ref byte

    BOOL

    Bool

    DWORD

    int  uint

    char**

    作为输入参数转为char[],通过Encoding类对这个string[]进行编码后得到的一个char[]

    作为输出参数转为byte[],通过Encoding类对这个byte[]进行解码,得到字符串

    C++ Dll接口:

    void CplusplusToCsharp(in char** AgentID, out char** AgentIP);

    C#中的声明:

    [DllImport("Example.dll")]

    public static extern void CplusplusToCsharp(char[] AgentID, byte[] AgentIP);

    C#中的调用:

    Encoding encode = Encoding.Default;

    byte[] tAgentID;

    byte[] tAgentIP;

    string[] AgentIP;

    tAgentID = new byte[100];

    tAgentIP = new byte[100];

    CplusplusToCsharp(encode.GetChars(tAgentID), tAgentIP);

    AgentIP[i] = encode.GetString(tAgentIP,i*Length,Length);

    枚举类型

     

    BOOL MessageBeep(UINT uType // 声音类型); 其中的声音类型为枚举类型中的某一值。

    用户需要自己定义一个枚举类型:

    public enum BeepType

    {

      SimpleBeep = -1,

      IconAsterisk = 0x00000040,

      IconExclamation = 0x00000030,

      IconHand = 0x00000010,

      IconQuestion = 0x00000020,

      Ok = 0x00000000,

    }

    C#中导入该函数:

    [DllImport("user32.dll")]

    public static extern bool MessageBeep(BeepType beepType);

    C#中调用该函数:

    MessageBeep(BeepType.IconQuestion);

    结构体

     

    使用结构指针作为参数的函数:

    BOOL GetSystemPowerStatus(

     LPSYSTEM_POWER_STATUS lpSystemPowerStatus

    );

    Win32中该结构体的定义:

    typedef struct _SYSTEM_POWER_STATUS {

    BYTE  ACLineStatus;

    BYTE  BatteryFlag;

    BYTE  BatteryLifePercent;

    BYTE  Reserved1;

    DWORD BatteryLifeTime;

    DWORD BatteryFullLifeTime;

    } SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;

    使用结构指针作为参数的函数:

    BOOL GetSystemPowerStatus(

     LPSYSTEM_POWER_STATUS lpSystemPowerStatus

    );

    Win32中该结构体的定义:

    typedef struct _SYSTEM_POWER_STATUS {

    BYTE  ACLineStatus;

    BYTE  BatteryFlag;

    BYTE  BatteryLifePercent;

    BYTE  Reserved1;

    DWORD BatteryLifeTime;

    DWORD BatteryFullLifeTime;

    } SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;

    字符串

     

    对于字符串的处理分为以下几种情况:

    1 字符串常量指针的处理(LPCTSTR),也适应于字符串常量的处理,.net中的string类型是不可变的类型。

    2 字符串缓冲区的处理(char*),即对于变长字符串的处理,.netStringBuilder可用作缓冲区

    Win32

    BOOL GetFile(LPCTSTR lpRootPathName);

    函数声明:

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    static extern bool GetFile (

     [MarshalAs(UnmanagedType.LPTStr)]

     string rootPathName);

    函数调用:

    string pathname;

    GetFile(pathname);

    备注:

    DllImport中的CharSet是为了说明自动地调用该函数相关的Ansi版本或者Unicode版本

       

    变长字符串处理:

    C#

    函数声明:

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    public static extern int GetShortPathName(

      [MarshalAs(UnmanagedType.LPTStr)]

      string path,

      [MarshalAs(UnmanagedType.LPTStr)]

      StringBuilder shortPath,

      int shortPathLength);

    函数调用:

    StringBuilder shortPath = new StringBuilder(80);

    int result = GetShortPathName(

    @"d: est.jpg", shortPath, shortPath.Capacity);

    string s = shortPath.ToString();

    结构体

     

    具有内嵌字符数组的结构:

    Win32

    typedef struct _TIME_ZONE_INFORMATION {

      LONG    Bias;

      WCHAR   StandardName[ 32 ];

      SYSTEMTIME StandardDate;

      LONG    StandardBias;

      WCHAR   DaylightName[ 32 ];

      SYSTEMTIME DaylightDate;

      LONG    DaylightBias;

    } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

    struct TimeZoneInformation

    {

      public int bias;

      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

      public string standardName;

      SystemTime standardDate;

      public int standardBias;

      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

      public string daylightName;

      SystemTime daylightDate;

      public int daylightBias;

    }

    回调函数

     

    BOOL EnumDesktops(

     HWINSTA hwinsta,       // 窗口实例的句柄

     DESKTOPENUMPROC lpEnumFunc, // 回调函数

     LPARAM lParam        // 用于回调函数的值

    );

    回调函数DESKTOPENUMPROC的声明:

    BOOL CALLBACK EnumDesktopProc(

     LPTSTR lpszDesktop, // 桌面名称

     LPARAM lParam    // 用户定义的值

    );

    将回调函数的声明转化为委托:

    delegate bool EnumDesktopProc(

     [MarshalAs(UnmanagedType.LPTStr)]

      string desktopName,

      int lParam);

    该函数在C#中的声明:

    [DllImport("user32.dll", CharSet = CharSet.Auto)]

    static extern bool EnumDesktops(

      IntPtr windowStation,

      EnumDesktopProc callback,

      int lParam);

  • 相关阅读:
    CentOS linux系统将UTC时间修改为CST时间
    .py与.pyc文件区别
    Linux安装python3.6
    ddt源码修改:HtmlTestRunner报告依据接口名显示用例名字
    FinalShell Mac OS版,Linux版安装及教程
    jmeter 参数化学习之CSV Data Set Config随机读取一行参数
    linux把文件压缩成.tar.gz的命令
    Mac下Sublime Text3配置Python开发环境
    Web Api通过文件流下载文件到本地实例
    WebAPI返回时间数据不带T
  • 原文地址:https://www.cnblogs.com/cartler/p/3304393.html
Copyright © 2011-2022 走看看