使用 Microsoft .NET Framework 精简版检索 Windows CE 设备 ID(转)

本文介绍如何使用.NET Framework精简版和Visual C#.NET在Windows CE设备上通过KernelIoControl函数和IOCTL代码检索设备ID,适用于资产管理及软件授权。

适用于:
Microsoft® .NET Framework 精简版
Microsoft Visual Studio® .NET 2003
Microsoft Windows® CE .NET

摘要:学习如何使用 .NET Framework 精简版从 Windows CE 设备中检索设备 ID。

简介

Microsoft® Windows® CE 提供了一种用于唯一标识 Windows CE 设备的机制。为实现此功能,Microsoft 已经提供了标准的结构和 I/O 控制 (IOCTL) 代码,可供需要唯一标识的 OEM 使用。IOCTL 代码是用于向设备硬件直接发送命令的位掩码。并非所有 OEM 都需要对其设备进行唯一标识,因此 Microsoft 选择在 OEM 特定函数调用中使用 IOCTL 代码,以减少不需要唯一标识的 OEM 的工作量。

设备 ID 可用于在资产管理中标识单个设备。此外,设备 ID 还可用于授权软件。使用设备 ID 生成引用代码,可以将应用程序授权给单个设备。

检索设备 ID 并不是一项简单的任务。NET Framework 精简版中未提供对设备 ID 查询的托管支持,而必须使用平台调用服务 (P/Invoke) 调用非托管的 Win32 API 函数,即 KernelIoControl

本文假定您在 .NET Framework 精简版和 Visual C#® .NET 方面有一定的使用经验,并且已安装了 Visual Studio .NET 2003 Final Beta(可从 MSDN® Subscriber Downloads 站点下载)。

平台调用服务 (P/Invoke)

通过平台调用服务,托管代码可以调用本机(非 ActiveX)DLL 中实现的非托管函数。P/Invoke 语义方面的用法与在 .NET Framework 完整版中相同,但 .NET Framework 精简版对于非托管和托管代码之间封送的对象和类型只提供有限的支持。

P/Invoke 位于 System.Runtime.InteropService 命名空间中。在应用程序代码中,应该声明要调用的非托管函数。此操作可以通过 DllImport 属性执行。说明包括模块名称(特定的 DLL 文件名)、入口点名称(要调用的非托管函数的名称)、调用约定和 SetLastError 标志。调用约定描述了将参数传递给非托管方法的方式。在 .NET Framework 精简版中,所支持的唯一调用约定是 WinAPI 约定,此约定与 C++ 中的 __cdecl 约定对应。默认情况下,C# 将 SetLastError 标志设置为 false。将其设置为 true 允许您调用 Marshal.GetLastWin32Error,以检索引发的上一个非托管错误。

例如,要调用非托管 DLL(即 coredll.dll)中的 FindWindow 函数,应在项目中包含以下代码:

[DllImport("coredll.dll","FindWindow",SetLastError=true)]
public extern IntPtr FindWindow(string ClassName, string WindowName);

IOCTL 代码

IOCTL_HAL_GET_DEVICEID IOCTL 将返回指定给 Windows CE 设备的当前设备 ID。检索设备 ID 的请求是通过将 IOCTL_HAL_GET_DEVICEID 传递给 KernelIoControl 完成的。

IOCTL_HAL_GET_DEVICEID IOCTL 包含四条信息:

  • 设备类型
  • 访问检查值(任意/读取/写入)
  • 要执行的函数(在此实例中,检索设备 ID)
  • 缓冲区传递方式的方法代码

要定义 IOCTL,需要以下常量:

private static Int32 FILE_DEVICE_HAL = 0x00000101;
private static Int32 FILE_ANY_ACCESS = 0x0;
private static Int32 METHOD_BUFFERED = 0x0;

在 C# 中,IOCTL_HAL_GET_DEVICEID 被定义为:

private static Int32 IOCTL_HAL_GET_DEVICEID = 
    ((FILE_DEVICE_HAL) << 16) | ((FILE_ANY_ACCESS) << 14) 
     | ((21) << 2) | (METHOD_BUFFERED);

这些值和 IOCTL_HAL_GET_DEVICEID 的定义取自 C++ 头文件 winioctl.h

KernelIoControl 方法

Microsoft 以标准的 IOCTL 发送方法的形式提供了 KernelIoControl 方法。KernelIoControl 不对 IOCTL 进行任何处理,只是将其发送至请求的设备。

在 C# 中,KernelIoControl 函数的声明如下:

[DllImport("coredll.dll")]
private static extern bool KernelIoControl(Int32 IoControlCode, IntPtr
  InputBuffer, Int32 InputBufferSize, byte[] OutputBuffer, Int32
  OutputBufferSize, ref Int32 BytesReturned);

参数定义如下:

  • IoControlCode。设置为 IOCTL_HAL_GET_DEVICEID,以检索 DEVICE_ID 结构。
  • InputBuffer。由 OEM 根据其特定用途定义。
  • InputBufferSize。设置为 OEM InputBuffer 数据的大小。
  • OutputBufferDEVICE_ID 数据缓冲区。
  • OutputBufferSize。设置为调用函数前 DEVICE_ID 数据缓冲区的大小。
  • BytesReturned。设置为调用函数后 DEVICE_ID 数据的大小。

如果 OEM 提供了对 IOCTL_HAL_GET_DEVICEID IOCTL 的支持,则 KernelIoControl 将返回 true。如果 OEM 未提供对 IOCTL_HAL_GET_DEVICEID 的支持或请求失败,则返回 false。如果返回 false,请调用 Marshal.GetLastWin32Error 以查看详细信息。错误代码 122 表示已分配的 DEVICE_ID 缓冲区过小,无法存储所有信息。这种情况下,OutputBuffer 的前 4 个字节将包含所需的缓冲区大小。只需重新分配 OutputBuffer 的大小并再次请求信息即可。

设备 ID 实际上是两个 ID:预设 ID 和平台 ID。调用 KernelIoControl 可以将输出缓冲区设置为包含预设 ID 和平台 ID 的字节数组。要将字节数组转换为有用的形式,请将预设 ID 和平台 ID 从字节数组中分离出来,并集中到类似全局唯一标识符 (GUID) 的字符串中,如下例所示:

综合程序

下面是调用 KernelIoControl 以检索设备 ID 的示例。

private static string GetDeviceID()
{
    byte[] OutputBuffer = new byte[256];
    Int32 OutputBufferSize, BytesReturned;
    OutputBufferSize = OutputBuffer.Length;
    BytesReturned = 0;

    // 调用 KernelIoControl 传递以前定义的
    // IOCTL_HAL_GET_DEVICEID 参数
    // 无需向此调用传递任何输入缓冲区,
    // 因此 InputBuffer 和 InputBufferSize 都被设置为 null
    // 值
    bool retVal = KernelIoControl(IOCTL_HAL_GET_DEVICEID, 
            IntPtr.Zero
            0,
            OutputBuffer,
            OutputBufferSize,
            ref BytesReturned);

    // 如果请求失败,则立即退出该方法
    if (retVal == false)
    {
        return null;

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10294527/viewspace-126761/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10294527/viewspace-126761/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值