C#调用dll中的函数

文章来源:http://blog.csdn.net/strmagic/archive/2007/11/02/1863462.aspx

大家在实际工作学习C#的时候,可能会问:为什么我们要为一些已经存在的功能(比如Windows中的一些功能,C++中已经编写好的一些方法)要重新编写代码,C#有没有方法可以直接都用这些原本已经存在的功能呢?答案是肯定的,大家可以通过C#中的DllImport直接调用这些功能。

DllImport所在的名字空间usingSystem.Runtime.InteropServices;

MSDN中对DllImportAttribute的解释是这样的:可将该属性应用于方法。DllImportAttribute属性提供对从非托管DLL导出的函数进行调用所必需的信息。作为最低要求,必须提供包含入口点的DLL的名称。

DllImport属性定义如下:

namespaceSystem.Runtime.InteropServices

{

 [AttributeUsage(AttributeTargets.Method)]

 publicclassDllImportAttribute:System.Attribute

 {

publicDllImportAttribute(stringdllName){...}

publicCallingConventionCallingConvention;

publicCharSetCharSet;

publicstringEntryPoint;

publicboolExactSpelling;

publicboolPreserveSig;

publicboolSetLastError;

publicstringValue{get{...}}

 }

}

说明:

1、DllImport只能放置在方法声明上。

2、DllImport具有单个定位参数:指定包含被导入方法的dll名称的dllName参数。

3、DllImport具有五个命名参数:

 a、CallingConvention参数指示入口点的调用约定。如果未指定CallingConvention,则使用默认值CallingConvention.Winapi。

 b、CharSet参数指示用在入口点中的字符集。如果未指定CharSet,则使用默认值CharSet.Auto。

 c、EntryPoint参数给出dll中入口点的名称。如果未指定EntryPoint,则使用方法本身的名称。

 d、ExactSpelling参数指示EntryPoint是否必须与指示的入口点的拼写完全匹配。如果未指定ExactSpelling,则使用默认值false。

 e、PreserveSig参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有HRESULT返回值和该返回值的一个名为retval的附加输出参数的签名。如果未指定PreserveSig,则使用默认值true。

 f、SetLastError参数指示方法是否保留Win32"上一错误"。如果未指定SetLastError,则使用默认值false。

4、它是一次性属性类。

5、此外,用DllImport属性修饰的方法必须具有extern修饰符。

DllImport的用法:

DllImport("MyDllImport.dll")]

privatestaticexternintmySum(inta,intb);

一在C#程序设计中使用Win32类库

常用对应类型:

1、DWORD是4字节的整数,因此我们可以使用int或uint作为C#对应类型。

2、bool类型与BOOL对应。

示例一:调用Beep()API来发出声音

Beep()是在kernel32.lib中定义的,在MSDN中的定义,Beep具有以下原型:

BOOLBeep(DWORDdwFreq,//声音频率

DWORDdwDuration//声音持续时间);

用C#编写以下原型:

[DllImport("kernel32.dll")]

publicstaticexternboolBeep(intfrequency,intduration);

示例二:枚举类型和常量

MessageBeep()是在user32.lib中定义的,在MSDN中的定义,MessageBeep具有以下原型:

BOOLMessageBeep(UINTuType//声音类型

);

用C#编写一下原型:

publicenumBeepType

{

 SimpleBeep=-1,

 IconAsterisk=0x00000040,

 IconExclamation=0x00000030,

 IconHand=0x00000010,

 IconQuestion=0x00000020,

 Ok=0x00000000,

}

uType参数实际上接受一组预先定义的常量,对于uType参数,使用enum类型是合乎情理的。

[DllImport("user32.dll")]

publicstaticexternboolMessageBeep(BeepTypebeepType);

示例三:处理结构

有时我需要确定我笔记本的电池状况。Win32为此提供了电源管理函数,搜索MSDN可以找到GetSystemPowerStatus()函数。

BOOLGetSystemPowerStatus(

 LPSYSTEM_POWER_STATUSlpSystemPowerStatus

);

此函数包含指向某个结构的指针,我们尚未对此进行过处理。要处理结构,我们需要用C#定义结构。我们从非托管的定义开始:

typedefstruct_SYSTEM_POWER_STATUS{

BYTE ACLineStatus;

BYTE BatteryFlag;

BYTE BatteryLifePercent;

BYTE Reserved1;

DWORD BatteryLifeTime;

DWORD BatteryFullLifeTime;

}SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS;

然后,通过用C#类型代替C类型来得到C#版本。

structSystemPowerStatus

{

 byteACLineStatus;

 bytebatteryFlag;

 bytebatteryLifePercent;

 bytereserved1;

 intbatteryLifeTime;

 intbatteryFullLifeTime;

}

这样,就可以方便地编写出C#原型:

[DllImport("kernel32.dll")]

publicstaticexternboolGetSystemPowerStatus(

 refSystemPowerStatussystemPowerStatus);

在此原型中,我们用“ref”指明将传递结构指针而不是结构值。这是处理通过指针传递的结构的一般方法。

此函数运行良好,但是最好将ACLineStatus和batteryFlag字段定义为enum:

enumACLineStatus:byte

{

 Offline=0,

 Online=1,

 Unknown=255,

}

enumBatteryFlag:byte

{

 High=1,

 Low=2,

 Critical=4,

 Charging=8,

 NoSystemBattery=128,

 Unknown=255,

}

请注意,由于结构的字段是一些字节,因此我们使用byte作为该enum的基本类型

示例四:处理字符串

二C#中调用C++代码

int类型

[DllImport(“MyDLL.dll")]

//返回个int类型

publicstaticexternintmySum(inta1,intb1);

//DLL中申明

extern“C”__declspec(dllexport)intWINAPImySum(inta2,intb2)

{

//a2b2不能改变a1b1

//a2=..

//b2=...

returna+b;

}

//参数传递int 类型 

publicstaticexternintmySum(refinta1,refintb1);

//DLL中申明

extern“C”__declspec(dllexport)intWINAPImySum(int*a2,int*b2)

{

//可以改变a1,b1

*a2=...

*b2=...

returna+b;

}

DLL需传入char*类型

[DllImport(“MyDLL.dll")]

//传入值

publicstaticexternintmySum(stringastr1,stringbstr1);

//DLL中申明

extern“C”__declspec(dllexport)intWINAPImySum(char*astr2,char*bstr2)

{

//改变astr2bstr2,astr1bstr1不会被改变

returna+b;

}

DLL需传出char*类型

[DllImport(“MyDLL.dll")]

//传出值

publicstaticexternintmySum(StringBuilderabuf,StringBuilderbbuf);

//DLL中申明

extern“C”__declspec(dllexport)intWINAPImySum(char*astr,char*bstr)

{

//传出char* 改变astr bstr-->abuf,bbuf可以被改变

returna+b;

}

DLL回调函数

BOOLEnumWindows(WNDENUMPROClpEnumFunc,LPARAMlParam)

usingSystem;

usingSystem.Runtime.InteropServices;

publicdelegateboolCallBack(inthwnd,intlParam);//定义委托函数类型

publicclassEnumReportApp

{

[DllImport("user32")]

publicstaticexternintEnumWindows(CallBackx,inty);

publicstaticvoidMain(){

CallBackmyCallBack=newCallBack(EnumReportApp.Report);EnumWindows(myCallBack,0);

}

publicstaticboolReport(inthwnd,intlParam)

{

Console.Write("Windowhandleis");

Console.WriteLine(hwnd);returntrue;

}

}

DLL  传递结构  

BOOLPtInRect(constRECT*lprc,POINTpt);

usingSystem.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]

publicstructPoint{

publicintx;

publicinty;

}

[StructLayout(LayoutKind.Explicit)]

publicstructRect

{

[FieldOffset(0)]publicintleft;

[FieldOffset(4)]publicinttop;

[FieldOffset(8)]publicintright;

[FieldOffset(12)]publicintbottom;

}

ClassXXXX{

[DllImport("User32.dll")]

publicstaticexternboolPtInRect(refRectr,Pointp);

}

相关推荐