回 帖 发 新 帖 刷新版面

主题:关于使用WMI读取硬盘序列号的疑问的一些说明

本坛有几个相关的帖子
比如本人的:
http://bbs.pfan.cn/post-307523.html
其他网友的:
http://bbs.pfan.cn/post-282435-1.html
结果引起较大争论,有的人可以获取,有的人不能。其实还是有些问题没有说清楚,所以此处补充一下。
1、硬盘SN是什么?
   标准中规定IDE接口的硬盘中有一个电子标签(SCSI硬盘标准好象没有这个,所以不能对它取硬盘SN),实际就是若干字节的ascii码,规定不同硬盘标签不一样,类似于网卡的MAC。
   但是实际应用中据说三星硬盘没有序列号(或者说电子标签为空),不过这一点我不能确定,我怀疑可是使用后面描述的因为没有考虑到首字符为空格造成不能正确获取(这实际上是电子标签不标准)。
2、DOS下的获取
   学过微机原理的都知道,访问硬件时一个通常的方法是使用IN和OUT指令往特定端口读写数据,获取硬盘序列号也是使用这个方法,具体就不多说了。
3、windows下为何变成一个难题
   因为windows不让直接访问硬件,而此问题又必须访问硬件才行,我们去下载或找到的别人的代码或DLL什么的都是使用这个原理的,但是这么干难度真的非常大,很多玩VFP的朋友不具有这个能力。
4、为什么使用WMI能行?
   微软自己也要查这个SN,所以在WMI中加入了这个功能,但是去调用时需要注意WMI是如何提供此类信息的:SELECT这个SQL命令,当成一个数据库表来访问。
5、什么版本的windows可以用WMI?
   Windows 2K/XP和Windows 98 都支持WMI;如果为NT 4.0和Windows 95加上了 Service Pack 4或更高版本,NT 4.0和Win95也支持WMI。VISTA和WIN7当然也行。
   可以参考这里:  http://baike.baidu.com/view/442461.htm
6、访问WMI需要权限
   如果没有权限可能就不能得到正确的结果,这一点就是不使用WMI方法也是一样的。
7、WMI的版本差异
   有的方法在XP下面能工作,在win7或vista下面就不行,原因就是版本的问题。
综上,想要很简单的找到一个完美的方法几乎不可能,本人总结了一下WMI的使用要点如下(相关程序发在2楼)
如果硬盘号前面不是空格,直接使用WMI的最好,但是需要判断是XP还是vista或WIN7,XP就使用WMI的方法1的直接结果,否则最好使用WMI的方法2进行转换。
如果硬盘号前面是空格,在XP下面使用WMI不能得到正确结果,需要使用传统方法,而在vista或WIN7下面,传统方法需要关闭UAC才能得到正确结果,所以应该使用WMI来突破权限的限制,建议使用WMI的方法2,因为不用进行UAC的判断(这点很重要,也可能没关UAC但是运行时使用了管理员权限),只有方法2才结果才是固定的。


综上可得最佳方案:
1、获取操作系统各类;
2、如果是2000、XP或2003则使用传统方法;
3、如果是VISTA或WINDOWS 7则使用WMI的方法2,并且需要对结果进行转换(其实传统方法一样要转换的!)。

回复列表 (共2个回复)

沙发

**VFP读CPU序号、硬盘序号、网卡MAC地址、硬盘型号、IP地址 
LOCAL oWMI AS OBJECT,oLocal AS OBJECT,oHARDWARE AS OBJECT,object1 AS OBJECT,lcCPUID,LcMAC,lcHDID,lcHDINFO,lcIP,lcHDID2,lcHDID2ASC
oWMI=CREATEOBJECT("WbemScripting.SWbemLocator")  
oLocal=oWMI.ConnectServer(".",  "root\cimv2")  

*取CPU ID
oHARDWARE=oLocal.ExecQuery("SELECT  *  FROM  Win32_Processor")  
FOR EACH object1 IN oHARDWARE  
lcCPUID=object1.Properties_('ProcessorId').VALUE  
EXIT  
ENDFOR  

*取硬盘物理ID

*此方法在XP下面有一个BUG,以即如果硬盘序列是前面有空格的(象我的ST 500G就是),
*在XP下面会取到一个NULL值(此机器为SATA硬盘)!不过在偶的笔记本上好象又是正常的
*但是VISTA下面工作正常
*在windows7下面如果关闭UAC,结果是ASCII字符串形式,但是不关闭UAC时和下面的方法一样
oHARDWARE=oLocal.ExecQuery("SELECT * FROM Win32_PhysicalMedia")  
FOR EACH object1 IN oHARDWARE  
lcHDID=object1.Properties_('SerialNumber').VALUE  
EXIT  
ENDFOR

*取MAC和IP  
oHARDWARE=oLocal.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration Where IPEnabled=1")  
FOR EACH object1 IN oHARDWARE  
LcMAC=object1.Properties_('MACAddress').VALUE  
LcIP=object1.Properties_('IPAddress').VALUE  
EXIT  
ENDFOR 

*取硬盘型号
oHARDWARE=oLocal.ExecQuery("SELECT * FROM Win32_DiskDrive")  
FOR EACH object1 IN oHARDWARE  
lcHDINFO=object1.Properties_('Model').VALUE
*硬盘物理ID(另一方法)
*此属性在XP和2003下面不存在,VISTA和WIN7可以通过
lcHDID2=object1.Properties_('SerialNumber').VALUE  
EXIT
ENDFOR
*下面把它转换成ASCII字符串
lcHDID2ASC=''
FOR i=1 TO LEN(lcHDID2) STEP 4
  lcHDID2ASC=lcHDID2ASC+CHR(INT(VAL('0x'+SUBSTR(lcHDID2,i+2,2))))+CHR(INT(VAL('0x'+SUBSTR(lcHDID2,i,2))))
ENDFOR 


*显示结果   
?'CPU序号:',lcCPUID  

*以下两个方法得出结果好象不一样,其实只是第1种已经转换成标准字符串了,第2种是原始形式的
*(以16进制描述的ASCII码值,注意2个字节为一组,顺序颠倒)
?'硬盘序号:',lcHDID
?'硬盘物理ID(另一方法):',lcHDID2,'ASCII字符形式为:',lcHDID2ASC


?'网卡MAC地址:',LcMAC   
?'网卡IP地址:',LcIP   
?'硬盘型号:',lcHDINFO
 
 

板凳

最后,希望大家认真看清楚了上面楼主和1楼的所有文字,再归纳出你需要的代码(这个应该不难吧,虽然我没有做这个完整的代码,因为实际上本人并不使用VF开发系统,只是使用VFP操作DBF表,没有这个需求),不要简单地说行或不行。

我来回复

您尚未登录,请登录后再回复。点此登录或注册