最近需要用到Wince底层编程的一些东西,在PPC中用到进程,但是.NET Compact Framework不支持process组件,上网查到这些东西,以前可从来没有接触过底层的东西,觉得比较好,拿出来大家一起看!
一、
P/Invoke
在
.NET Compact Framework
的支持下,可以方便高效地开发出适合于移动设备的应用程序,而不需要去考虑特定的硬件环境。
.NET Compact Framework
向开发者屏蔽了硬件底层的细节,使开发者可以集中精力于业务逻辑的解决方案。
作为
.NET Framework
的一个子集,
.NET Compact Framework
只提供了
.NET Framework
的一部分功能,因此有时在实现一些功能时不得不借助于
Windows CE API
。另外还存在一些第三方的组件
/
资源,或以动态链接库形式提供,或者已经是
COM
组件。相对于
.NET Compact Framework
,它们都属于非托管资源。我们需要一种功能,实现由托管环境访问这些非托管资源。和
.NET Framework
一样,平台调用
P/Invoke(Platform Invocation Services)
提供托管代码调用驻留于
DLL
中的非托管函数的功能。下面是一张P/Invoke原理图,来自
MSDN
。
归纳起来,使用
P/Invoke
的场合包括:
1
、
.NET Compact Framework
没有实现某功能,需要借助
Windows CE API
;
2
、已有
DLL
或
COM
组件等资源,希望能充分利用,减少开发成本和风险;
3
、鉴于
DLL
的执行性能和反编译能力都可能高于
.NET Compact Framework
,借助
DLL
提高程序性能和安全性。当然关于
DLL
的执行性能是否高于托管代码,不能一概而论。
二、
.NET Compact Framework
下的
P/Invoke
先看一个
P/Invoke
的例子。下面使用
DllImport
特征导入
Windows CE
的
API
函数
MessageBoxW
的定义。
public
class APIHelper
{
[DllImport("coredll.dll", SetLastError = true)]
public
static extern int MessageBoxW(IntPtr hWnd, String text, String caption, uint type);
}
然后可以对它进行调用。
private
void button1_Click(object sender, EventArgs e)
{
APIHelper
.MessageBoxW(IntPtr.Zero, "
测试
MessageBoxW
函数
"
,
"api
调用
"
, 0);
}
可以看到,使用 P/Invoke 包括声明和调用两个过程,另外还有一个错误处理的过程。通过声明来指定要调用的非托管函数, .NET Compact Framework 也是使用 DllImport 特性来进行声明,包括模块名、函数名及调用约定。与 .NET Framework 完整版的 DllImport 特性不同, .NET Compact Framework 的一共包括五个公共字段: CallingConvention , CharSet , EntryPoint , PreserveSig 和 SetLastError 。具体各字段的说明可以参考 MSDN 。
EntryPoint
可以指定为函数名或函数的序号值,如
EntryPoint = "MessageBoxW"
或
EntryPoint = "#858"
。值得注意的是
.NET Compact Framework
下
CallingConvention
只支持
CallingConvention.Winapi
,即默认的平台调用;编码方式只支持
Unicode
,因此
CharSet
实际只有
CharSet.Unicode
一个取值。因此在导入定义时省略
CallingConvention
和
CharSet
字段的效果没有分别。
另外,
DllImport
修饰的方法必须用
static
和
extern
关键字来指明方法是在外部实现的,对其可见性修饰符则没有限制。
调用
DllImport
导入的非托管函数时,
CLR
的
P/Invoke
服务从声明中提取出元数据,定位要调用的模块(
coredll.dll
),将其加载到内存,然后根据入口点信息检索非托管函数地址。如果不出现错误,则
P/Invoke
完成参数的封送并调用该函数,并把返回函数的返回值。
P/Invoke
会产生两种错误,一种是上面说到的
P/Invoke
在定位调用模块,检索函数地址时出错。如
P/Invoke
找不到入口点时会出错,并抛出
MissingMethodException
异常;函数的调用约定声明有误时会抛出
NotSupportedException
异常,这时应检查函数的参数及返回值定义是否与模块中函数吻合。
P/Invoke
的另一种错误是执行非托管函数过程中发生的错误。
另一个需要特别注意的是,
.NET Compact Framework
下
P/Invoke
不支持回调,即无法向非托管函数传递一个委托并在非托管函数中被调用。使用需要回调的非托管函数时会引发异常。