zoukankan      html  css  js  c++  java
  • 使用.NE平台调用服务访问非托管 DLL 中的函数

    使用.NET平台调用服务访问非托管 DLL 中的函数

    概述:描述在Microsoft.Net框架下使用Win32API的方法。

    关键字:平台调用,InvokeDllImport

    一.背景

    最近公司在做一个面向电信小灵通用户的SP信息服务软件,其中需要和省电信公司的短信网关通信,对方提供了一个开发包SmGwAPI.DLLwin32动态链接库)和一些文档,由于实在不想使用VCDEPHI来开发该项目,所以最终决定使用dotNET平台调用技术来使用该API

    二.准备知识

    先了解一下Win32动态链接库在VC里是如何定义的:

    extern "C"  __declspec(dllexport)  int Validate(const char *);

           extern "C" 表示生成的DLL中的函数名称与定义时一致,否则就会生成形如

    ?MyMessage@@YAHPBDZ@Z 类似的函数名称。

    导入上面的函数:

    using System.Runtime.InteropServices;

    [DllImport("Register.dll")]

    public extern static int Validate(string str1);

    导入系统函数:

    using System.Runtime.InteropServices;

    [DllImport("user32.dll")]

    public static extern int MessageBox(int hWnd, String text, String caption, uint type);

    三.平台调用

    1.      DllImport

    先看一个示例:

    [DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,

    CharSet=CharSet.Unicode, ExactSpelling=true,

    CallingConvention=CallingConvention.StdCall)]

    public static extern bool MoveFile(String src, String dst);

    EntryPoint:指定函数入口,可以用来重新命名函数。(DumpBin.EXE

    [DllImport("Register.dll" EntryPoint="?MyMessage@@YAHPBDZ@Z ")]

    public extern static int MyMessage (string str1);

    ExactSpellingCharSet:名称匹配

    DllImportAttribute.ExactSpelling 字段为 true 时(Visual Basic .NET 中默认值为true),平台调用将只搜索您指定的名称。例如,如果指定 MessageBox,则平台调用将搜索 MessageBox,如果它找不到完全相同的拼写则失败。

           ExactSpelling 字段为 false(它是 C++ 托管扩展和 C# 中的默认值),平台调用将首先搜索指定的别名 (MessageBox),如果没有找到未处理的别名,则将搜索已处理的名称。当CharSet=CharSet.Ansi时搜索MessageBoxA,找不到则失败;当CharSet= CharSet.Unicode时搜索MessageBoxW,找不到则失败;当CharSet=CharSet.Auto 平台调用在运行时根据目标平台在 ANSI Unicode 格式之间进行选择。

    2.      参数传递

    先看原函数的定义(已简化)

    int __stdcall SMGPSendSingle(

    const int nNeedReply,

            const char *sServiceID,

    char *sMsgID,

            int *nErrorCode);

    1

        [DllImport("SmGwAPI.Dll")]

        public extern static int SMGPSendSingle(

               int  nNeedReply,

               string sServiceID,

               StringBuilder sMsgID,

               ref int nErrorCode   );

        (2)

    [DllImport("SmGwAPI.Dll")]

        public extern static int SMGPSendSingle(

               int  nNeedReply,

               string sServiceID,

               [MarshalAs(UnmanagedType.LPArray)] byte[]  sMsgID,

               ref int nErrorCode   );

    如果sMsgID返回的内容是ASCII码或UNICODE码的字符串,那么使用以上两种定义均可获得正确结果,如果sMsgID返回的内容是二进制码、BCD码等,就必须使用第二种定义方式,才能正确获得返回信息。

    3.      结构

    原定义(已简化

    typedef struct

    {

    unsigned int nIsReport;

    char       sMsgID[10+1];

    char       sMsgContent[252+1];

    }DeliverResp;

    SMGPAPI_EXPORTS SMGPDeliver(const int nTimeoutIn, DeliverResp *pDeliverResp);

    封装处理:

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

        public struct DeliverResp

        {

               public uint nIsReport;         

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

               public string sMsgID;          

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

               public string sMsgContent;        

        }

                 

    [DllImport("SmGwAPI.Dll")]

    public extern static int SMGPDeliver(int nTimeoutIn, ref DeliverResp pDeliverResp);            

    如果sMsgID返回的内容是ASCII码或UNICODE码的字符串,那么使用上面定义可获得正确结果,如果sMsgID返回的内容是二进制码、BCD码等,就必须使用下面的定义方式,才能正确获得返回信息。

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

        public struct DeliverResp

        {

               public uint nIsReport;

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

           public byte[] sMsgID;

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

               public string sMsgContent;

        }

    [DllImport("SmGwAPI.Dll")]

    public extern static int SMGPDeliver(int nTimeoutIn, ref DeliverResp pDeliverResp);     

    4.    参数对应表

     

    C/C++

    C#

    Int, Long

    int

    Int *

    Ref int

    LPCSTR, const char *

    [MarshalAs(UnmanagedType.LPSTR)]

    string

    LPCTSTR, const TCHAR *

    [MarshalAs(UnmanagedType.LPTSTR)]

    string

    LPSTR, char *

    [MarshalAs(UnmanagedType.LPSTR)]

    stringBuilder

    LPTSTR, TCHAR *

    [MarshalAs(UnmanagedType.LPTSTR)]

    stringBuilder

    Byte [n] str

    [MarshalAs(UnmanagedType.LPArray)]

     byte[]str

    WORD

    uInt16

    Byte, unsigned char

    byte

    Short

    Int16

    float

    single

    double

    double

    DWORD, unsigned long, Ulong

    [MarshalAs(UnmanagedType.U4)]

    UInt32

    bool

    bool

    HANDLE, LPDWORD, LPVOID, void*

    IntPtr

    NULL pointer

    IntPtr.Zero

  • 相关阅读:
    LintCode Python 简单级题目 488.快乐数
    LintCode Python 简单级题目 100.删除排序数组中的重复数字 101.删除排序数组中的重复数字II
    LintCode Python 简单级题目 373.奇偶分割数组
    LintCode Python 简单级题目 39.恢复旋转排序数组
    LintCode Python 简单级题目 35.翻转链表
    LintCode Python 简单级题目 451.两两交换链表中的节点
    LintCode Python 简单级题目 174.删除链表中倒数第n个节点
    aws查看官方centos镜像imageid
    linux shell脚本查找重复行/查找非重复行/去除重复行/重复行统计
    php配置优化-生产环境应用版
  • 原文地址:https://www.cnblogs.com/seabluescn/p/917390.html
Copyright © 2011-2022 走看看