使用.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

原文地址:https://www.cnblogs.com/seabluescn/p/917390.html