Aszxqw 2010-10-31
文章来源: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);
}