js调用广告教程:C# 平台调用教程



平台服务(PInvoke)允许托管代码在DLL中实现非托管
本教程介绍说明使用什么思路方法才能从C#非托管DLL该教程所讨论属性允许您这些并使数据类型得到正确封送
教程
C#代码有以下两种可以直接非托管代码思路方法:
直接从DLL导出
COM对象上接口思路方法(有关更多信息请参见COMInterop第部分:C#客户端教程)
对于这两种技术都必须向C#编译器提供非托管声明并且还可能需要向C#编译器提供如何封送和非托管代码的间传递参数和返回值介绍说明
该教程由下列主题组成:
直接从C#DLL导出
默认封送处理和为非托管思路方法参数指定自定义封送处理
为用户定义结构指定自定义封送处理
注册回调思路方法
该教程包括下列举例:
举例1使用DllImport
举例2重写默认封送处理
举例3指定自定义封送处理
直接从C#DLL导出
若要声明个思路方法使其具有来自DLL导出实现请执行下列操作:
使用C#关键字和extern声明思路方法
将DllImport属性附加到该思路方法DllImport属性允许您指定包含该思路方法DLL名称通常做法是用和导出思路方法相同名称命名C#思路方法但也可以对C#思路方法使用区别名称
还可以为思路方法参数和返回值指定自定义封送处理信息这将重写.NETFramework默认封送处理
举例1
本举例显示如何使用DllImport属性通过msvcrt.dll中puts输出消息
//PInvokeTest.cs
using;
using.Runtime.InteropServices;

PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
publicexternputs(c);
[DllImport("msvcrt.dll")]
ernalextern_flushall;

publicvoidMain
{
puts("Test");
_flushall;
}
}
输出
Test
代码讨论
前面举例显示了声明在非托管DLL中实现C#思路方法最低要求PlatformInvokeTest.puts思路方法用和extern修饰符声明并且具有DllImport属性该属性使用默认名称puts通知编译器此实现来自msvcrt.dll若要对C#思路方法使用区别名称(如put)则必须在DllImport属性中使用EntryPo选项如下所示:
[DllImport("msvcrt.dll",EntryPo="puts")]
有关DllImport属性语法更多信息请参见DllImportAttribute类
默认封送处理和为非托管思路方法参数指定自定义封送处理
当从C#代码中非托管公共语言运行库必须封送参数和返回值
对于每个.NETFramework类型均有个默认非托管类型公共语言运行库将使用此非托管类型在托管到非托管中封送数据例如C#串值默认封送处理是封送为LPTSTR(指向TCHAR缓冲区指针)类型可以在非托管C#声明中使用MarshalAs属性重写默认封送处理
举例2
本举例使用DllImport属性输出它还显示如何通过使用MarshalAs属性重写参数默认封送处理
//Marshal.cs
using;
using.Runtime.InteropServices;

PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
publicexternputs(
[MarshalAs(UnmanagedType.LPStr)]
m);
[DllImport("msvcrt.dll")]
ernalextern_flushall;


publicvoidMain
{
puts("HelloWorld!");
_flushall;
}
}
输出
运行此举例时
HelloWorld!
将显示在控制台上
代码讨论
在前面举例中puts参数默认封送处理已从默认值LPTSTR重写为LPSTR
MarshalAs属性可以放置在思路方法参数、思路方法返回值以及结构和类字段上若要设置思路方法返回值封送处理请将MarshalAs属性和返回属性位置重写起放置在思路方法上属性块中例如若要显式设置puts思路方法返回值封送处理:
...
[DllImport("msvcrt.dll")]
[:MarshalAs(UnmanagedType.I4)]
publicexternputs(
...
有关MarshalAs属性语法更多信息请参见MarshalAsAttribute类


注意In和Out属性可用于批注非托管思路方法参数它们和MIDL源文件中in和out修饰符工作方式类似请注意Out属性和C#参数修饰符out区别有关In和Out属性更多信息请参见InAttribute类和OutAttribute类
为用户定义结构指定自定义封送处理
可以为传递到非托管或从非托管返回结构和类字段指定自定义封送处理属性通过向结构或类字段中添加MarshalAs属性可以做到这还必须使用StructLayout属性设置结构布局还可以控制串成员默认封送处理并设置默认封装大小
举例3
本举例介绍说明如何为结构指定自定义封送处理属性
请考虑下面C结构:
typedefstructtagLOGFONT
{
LONGlfHeight;
LONGlfWidth;
LONGlfEscapement;
LONGlfOrientation;
LONGlfWeight;
BYTElfItalic;
BYTElfUnderline;
BYTElfStrikeOut;
BYTElfCharSet;
BYTElfOutPrecision;
BYTElfClipPrecision;
BYTElfQuality;
BYTElfPitchAndFamily;
TCHARlfFaceName[LF_FACESIZE];
}LOGFONT;
在C#中可以使用StructLayout和MarshalAs属性描述前面结构如下所示:
//logfont.cs
//compilewith:/target:module
using;
using.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
publicLOGFONT
{
publicconstLF_FACESIZE=32;
publiclfHeight;
publiclfWidth;
publiclfEscapement;
publiclfOrientation;
publiclfWeight;
publiclfItalic;
publiclfUnderline;
publiclfStrikeOut;
publiclfCharSet;
publiclfOutPrecision;
publiclfClipPrecision;
publiclfQuality;
publiclfPitchAndFamily;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=LF_FACESIZE)]
publiclfFaceName;
}
有关StructLayout属性语法更多信息请参见StructLayoutAttribute类
然后即可将该结构用在C#代码中如下所示:
//pinvoke.cs
//compilewith:/addmodule:logfont.netmodule
using;
using.Runtime.InteropServices;

PlatformInvokeTest
{
[DllImport("gdi32.dll",CharSet=CharSet.Auto)]
publicexternIntPtrCreateFontIndirect(
[In,MarshalAs(UnmanagedType.LPStruct)]
LOGFONTlplf//characteristics
);

[DllImport("gdi32.dll")]
publicexternboolDeleteObject(
IntPtrhandle
);

publicvoidMain
{
LOGFONTlf=LOGFONT;
lf.lfHeight=9;
lf.lfFaceName="Arial";
IntPtrhandle=CreateFontIndirect(lf);

(IntPtr.Zerohandle)
{
Console.WriteLine("Can’tcreatesalogicalfont.");


}

{

(IntPtr.Size4)
Console.WriteLine("{0:X}",handle.ToInt32);

Console.WriteLine("{0:X}",handle.ToInt64);

//Deletethelogicalfontcreated.
(!DeleteObject(handle))
Console.WriteLine("Can’tdeletethelogicalfont");
}
}
}
运行举例
C30A0AE5
代码讨论
在前面举例中CreateFontIndirect思路方法使用了个LOGFONT类型参数MarshalAs和In属性用于限定此参数将由此思路方法返回数值显示为十 6进制大写
注册回调思路方法
若要注册非托管托管回调请用相同参数列表声明个委托并通过PInvoke传递它个例子在非托管端它将显示为指针有关PInvoke和回调更多信息请参见平台详解
例如考虑以下非托管MyFunction要求callback作为其参数的:
typedefvoid(__stdcall*PFN_MYCALLBACK);
__stdcallMyFunction(PFN_MYCALLBACKcallback);
若要从托管代码MyFunction请声明该委托将DllImport附加到声明并根据需要封送任何参数或返回值:
publicdelegatevoidMyCallback;
[DllImport("MYDLL.DLL")]
publicexternvoidMyFunction(MyCallbackcallback);
同时请确保委托例子生存期覆盖非托管代码生存期;否则委托在经过垃圾回收后将不再可用
Tags:  c调用dll java调用c

延伸阅读

最新评论

发表评论