WinCE获取SD卡序列号
//=====================================================================
//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的调用,如:
handle hdisk = createfile(text("dsk2:"),
generic_read,
file_share_read | file_share_write,
null,
open_existing,
0,
null);
这段代码没什么问题,可能大家比较关心的是"dsk2:"这个参数的来源。或是说,我如何确定这个参数。很多朋友可能会错认为,当我们sd卡插入到设备中,在"我的设备"会出现"storage card"分区,那么createfile的第一个形参就应该是它。但实际上这样是错误的,传入的形参并不是分区名,而应该是驱动名。而这个驱动名的确认,可以通过"控制面板"的"存储器"确认,如图:
图中的"dsk1:"是设备中nand flash的驱动,而"dsk2:"则是sd卡的。可能有朋友问了,我如何判断哪个是sd卡的呢?其实这是一个很简单的事情:没插入sd卡的时候查看一次,插入sd卡的时候再查看一次,多出的那个就是sd卡了。囧~
接着我们就必须调用deviceiocontrol函数了,如下代码所示:
pstorage_identification pstoreinfo = (pstorage_identification) new byte[300];
deviceiocontrol(hdisk,
ioctl_disk_get_storageid,
null,
0,
pstoreinfo,
buffer_size,
&dwbytesret,
null);
ioctl_disk_get_storageid是设备请求标识符,这个应该也好理解。如果你的代码编译时该标识符没有定义,那么你应该是没有包含diskio.h文件。可能比较费解的是pstoreinfo,为什么要new个300byte的空间,然后又转换为pstorage_identification指针呢?这个我们必须要从storage_identification结构说起。
storage_identification结构定义如下:
typedef struct _storage_identification {
dword dwsize;
dword dwflags;
dword dwmanufactureidoffset;
dword dwserialnumoffset;
} 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还有一些地方需要注意的。这两个号码合起来的长度是不固定的,但我们能通过末尾是否为 来判断标识符是否结束。另外还有一点,manufactureid和serialnumber之间是没有分隔符的,我们只能通过(dwserialnumoffset - dwmanufactureidoffset)来确定。但这个还是需要有前提条件的,就是dwserialnumoffset和dwmanufactureidoffset都不能为0,因为为0时,就意味着该标识符无效。简单点来说,如果dwserialnumoffset这个偏移量的数值为0,那么意味着返回的数值中并没有manufactureid。
结构明白之后,我们就很容易获取这两个标志的起始地址了:
char *pmanufactureid = reinterpret_cast<char *>(pstoreinfo) + pstoreinfo->dwmanufactureidoffset;
char *pserialnum = reinterpret_cast<char *>(pstoreinfo) + pstoreinfo->dwserialnumoffset;
接下来的事情可能就不用细说了,无非就是根据起始地址来复制字符串。最后,就是调用closehandle来关闭驱动句柄了。
流程介绍完毕,但还不是文章的结尾。本文的最后,让我们来看看一个完整的获取标识符的函数,代码如下所示:
bool getstorageidentification(std::wstring &strdiskname,std::string &strmanufactureid,std::string &strserialnum)
{
bool bres = false;
pstorage_identification pstoreinfo = null;
handle hdisk = invalid_handle_value;
__try
{
//the buffer for storing data
const dword buffer_size = 300;
//allocate the size for the struct
pstoreinfo = (pstorage_identification) new byte[buffer_size];
if(pstoreinfo == null)
{
__leave;
}
//open the driver
hdisk = createfile(strdiskname.c_str(), generic_read, file_share_read | file_share_write, null, open_existing, 0, null);
if(hdisk == invalid_handle_value)
{
__leave;
}
//get the id from the driver
dword dwbytesret = 0;
if (deviceiocontrol(hdisk, ioctl_disk_get_storageid, null, 0, pstoreinfo, buffer_size, &dwbytesret, null) == false)
{
__leave;
}
//get the manufacture id
if (pstoreinfo->dwmanufactureidoffse
上一篇: gradle配置国内镜像
下一篇: 线性表的C语言实现