分享

WinCE获取SD卡序列号

 lhzstudio 2012-05-15

//=====================================================================
//TITLE:
//    WinCE获取SD卡序列号
//AUTHOR:
//    norains
//DATE:
//    Thursday  25-February-2011
//Environment:
//    Visual Studio 2005
//    Windows CE 6.0
//    Telechips TCC89x
//=====================================================================

 

     WinCE的设备,估计会和SD卡打交道的应该不在少数。特别是一些软件,比如导航地图之类,加密数据用的就是SD卡的序列号。不过,严格来说,在WinCE下面并没有专门针对于SD卡序列号的获取函数,而是针对Storage的。只不过SD卡也是Storage的一种,所以自然也能够被获取。

 

     SD卡序列号的获取,是需要通过驱动的的。这么一说的话,熟悉的朋友可能就明白流程了:首先调用CreateFile打开驱动,接着使用DeviceIoControl来获取序列号,最后则是调用CloseHandle进行关闭。

 

     一步一步来,先看看CreateFile的调用,如:

  1. HANDLE hDisk = CreateFile(TEXT("DSK2:"),  
  2.                           GENERIC_READ,   
  3.                           FILE_SHARE_READ | FILE_SHARE_WRITE,   
  4.                           NULL,   
  5.                           OPEN_EXISTING,   
  6.                           0,   
  7.                           NULL);  

 

     这段代码没什么问题,可能大家比较关心的是"DSK2:"这个参数的来源。或是说,我如何确定这个参数。很多朋友可能会错认为,当我们SD卡插入到设备中,在"我的设备"会出现"Storage Card"分区,那么CreateFile的第一个形参就应该是它。但实际上这样是错误的,传入的形参并不是分区名,而应该是驱动名。而这个驱动名的确认,可以通过"控制面板"的"存储器"确认,如图:


     图中的"DSK1:"是设备中NAND FLASH的驱动,而"DSK2:"则是SD卡的。可能有朋友问了,我如何判断哪个是SD卡的呢?其实这是一个很简单的事情:没插入SD卡的时候查看一次,插入SD卡的时候再查看一次,多出的那个就是SD卡了。囧~

 接着我们就必须调用DeviceIoControl函数了,如下代码所示:

  1. PSTORAGE_IDENTIFICATION pStoreInfo = (PSTORAGE_IDENTIFICATION) new BYTE[300];    
  2.   
  3. DeviceIoControl(hDisk,     
  4.                 IOCTL_DISK_GET_STORAGEID,     
  5.                 NULL,     
  6.                 0,     
  7.                 pStoreInfo,     
  8.                 BUFFER_SIZE,     
  9.                 &dwBytesRet,     
  10.                 NULL);  

 

     IOCTL_DISK_GET_STORAGEID是设备请求标识符,这个应该也好理解。如果你的代码编译时该标识符没有定义,那么你应该是没有包含Diskio.h文件。可能比较费解的是pStoreInfo,为什么要new个300byte的空间,然后又转换为PSTORAGE_IDENTIFICATION指针呢?这个我们必须要从STORAGE_IDENTIFICATION结构说起。

 

     STORAGE_IDENTIFICATION结构定义如下:

  1. typedef struct _STORAGE_IDENTIFICATION {  
  2.    DWORD dwSize;  
  3.    DWORD dwFlags;  
  4.    DWORD dwManufactureIDOffset;  
  5.    DWORD dwSerialNumOffset;  
  6.  } STORAGE_IDENTIFICATION, *PSTORAGE_IDENTIFICATION;  
  


  dwSize是结构体和标识符的大小,dwFlags标志着标识符是否可用,dwManufactureIDOffset是标识符的中的厂家ID偏移位置,最后的dwSerialNumOffset则是标识符中的序列号偏移位置。完了?是的,完了,就是这几样东西。那么,疑问来了,那标识符在哪里?别急,我们来看看返回回来数据的存储方式,如图:
  
  
  图中的灰色部分为STORAGE_IDENTIFICATION的成员,其大小为sizeof(STORAGE_IDENTIFICATION),是固定值;而蓝色的部分,则是我们分配的内存减去结构体后的大小,容量随着我们分配的内存而改变。在这里稍微返回来看一下代码,为什么我们代码中分配了个300Byte的空间呢?其实300这个数值是随意的,如果你设备的标识符大于这个数值,可以进行修改。但对于SD卡来说,标识符也就是10位,加上STORAGE_IDENTIFICATION的大小,300的空间完全足够了。
  
  接着从图中可以知道,在紧随着结构体之后的是ManufactureID和SerialNumber的数值。那么这两个数值的位置应该如何确定呢?那就是通过dwManufactureIDOffset和dwSerialNumOffset的数值来确定,这也就是为什么图中dwManufactureIDOffset方块延伸出来的箭头会指向ManufactureID前端的原因。
  
  对于ManufactureID和SerialNumber还有一些地方需要注意的。这两个号码合起来的长度是不固定的,但我们能通过末尾是否为'/0'来判断标识符是否结束。另外还有一点,ManufactureID和SerialNumber之间是没有分隔符的,我们只能通过(dwSerialNumOffset - dwManufactureIDOffset)来确定。但这个还是需要有前提条件的,就是dwSerialNumOffset和dwManufactureIDOffset都不能为0,因为为0时,就意味着该标识符无效。简单点来说,如果dwSerialNumOffset这个偏移量的数值为0,那么意味着返回的数值中并没有ManufactureID。
  
  结构明白之后,我们就很容易获取这两个标志的起始地址了:

  1.   char *pManufactureID = reinterpret_cast<char *>(pStoreInfo) + pStoreInfo->dwManufactureIDOffset;   
  2.   char *pSerialNum = reinterpret_cast<char *>(pStoreInfo) + pStoreInfo->dwSerialNumOffset;  

  
  接下来的事情可能就不用细说了,无非就是根据起始地址来复制字符串。最后,就是调用CloseHandle来关闭驱动句柄了。
  
  
  流程介绍完毕,但还不是文章的结尾。本文的最后,让我们来看看一个完整的获取标识符的函数,代码如下所示:
  1.   BOOL GetStorageIdentification(std::wstring &strDiskName,std::string &strManufactureID,std::string &strSerialNum)  
  2.   {  
  3.    BOOL bRes = FALSE;  
  4.     
  5.    PSTORAGE_IDENTIFICATION pStoreInfo = NULL;  
  6.    HANDLE hDisk = INVALID_HANDLE_VALUE;  
  7.     
  8.    __try  
  9.    {  
  10.     //The buffer for storing data   
  11.     const DWORD BUFFER_SIZE = 300;  
  12.     
  13.       
  14.     //Allocate the size for the struct   
  15.     pStoreInfo = (PSTORAGE_IDENTIFICATION) new BYTE[BUFFER_SIZE];  
  16.     if(pStoreInfo == NULL)  
  17.     {  
  18.      __leave;  
  19.     }  
  20.     
  21.     //Open the driver   
  22.     hDisk = CreateFile(strDiskName.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);   
  23.     if(hDisk == INVALID_HANDLE_VALUE)  
  24.     {  
  25.      __leave;  
  26.     }  
  27.     
  28.     //Get the ID from the driver   
  29.     DWORD dwBytesRet = 0;  
  30.     if (DeviceIoControl(hDisk, IOCTL_DISK_GET_STORAGEID, NULL, 0, pStoreInfo, BUFFER_SIZE, &dwBytesRet, NULL) == FALSE)  
  31.     {  
  32.      __leave;  
  33.     }  
  34.     
  35.     //Get the manufacture ID   
  36.     if (pStoreInfo->dwManufactureIDOffset != 0)  
  37.     {  
  38.      char *pManufactureID = reinterpret_cast<char *>(pStoreInfo) + pStoreInfo->dwManufactureIDOffset;   
  39.     
  40.      if(pStoreInfo->dwSerialNumOffset  != 0)  
  41.      {  
  42.       strManufactureID.assign(pManufactureID,pStoreInfo->dwSerialNumOffset - pStoreInfo->dwManufactureIDOffset);  
  43.      }  
  44.      else  
  45.      {  
  46.       strManufactureID = pManufactureID;  
  47.      }  
  48.     }  
  49.     
  50.     if(pStoreInfo->dwSerialNumOffset  != 0)  
  51.     {  
  52.      char *pSerialNum = reinterpret_cast<char *>(pStoreInfo) + pStoreInfo->dwSerialNumOffset;   
  53.      strSerialNum = pSerialNum;  
  54.     }  
  55.     
  56.     bRes = TRUE;  
  57.    }  
  58.    __finally  
  59.    {  
  60.     if(pStoreInfo != NULL)  
  61.     {  
  62.      delete []pStoreInfo;  
  63.     }     
  64.     
  65.     if(hDisk != INVALID_HANDLE_VALUE)  
  66.     {  
  67.      CloseHandle(hDisk);  
  68.     }  
  69.    }  
  70.     
  71.    return bRes;  
  72.   }  
  73.     

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多