取得硬盘序列号的自定义函数.
*-------------------------------------
?getidesn(0) &&取第一道(IDE1)主盘序列号 或:?getidesn()
?getidesn(1) &&取第一道(IDE1)从盘序列号
?getidesn(2) &&取第二道(IDE2)主盘序列号
?getidesn(3) &&取第二道(IDE2)从盘序列号
FUNCTION getidesn
PARAMETERS m.i
IF PARAMETERS()=0
m.i=0
ENDIF
ON ERROR RETU ''
*-- 功 能:取得系统所有硬盘参数
*-- 外部函数 - 取得当前平台和操作系统的版本信息
DECLARE INTEGER GetVersionEx IN kernel32.DLL STRING
*-- 外部函数 - 打开对象
DECLARE INTEGER CreateFile IN kernel32.DLL STRING,INTEGER,INTEGER,STRING,INTEGER,INTEGER,INTEGER
*-- 外部函数 - 关闭一个对象
DECLARE INTEGER CloseHandle IN kernel32.DLL INTEGER
*-- 外部函数 - 向设备发送控制代码。返回非零值表示成功,返回零失败
DECLARE INTEGER DeviceIoControl IN Kernel32.DLL INTEGER,INTEGER,STRING,INTEGER,STRING @,INTEGER,INTEGER @,INTEGER
*-- 定义变量
LOCAL M.hDevice,M.bIDCmd,M.lpOutBuffer,M.lpBytesReturned,M.bDfpDriveMap
*-- 操作系统版本
m.lpVersionInformation = DecToAscii(148,4)+REPLICATE(CHR(0),144)
IF GetVersionEx(@M.lpVersionInformation) = 0
RETURN ''
ENDIF
m.dwPlatformId = AsciiToDec(SUBSTR(M.lpVersionInformation,17,4))
STORE 0 TO M.hDevice,M.bDfpDriveMap
*-- 获得用于 SMART IOCTL 的句柄
DO CASE
CASE M.dwPlatformId = 1
*-- 环境 Windows 95/98/Me
m.hDevice = CreateFile("\\.\SMARTVSD",0,0,0,1,0,0)
CASE M.dwPlatformId = 2
*-- 环境 Windows NT/2000/XP
m.hDevice = CreateFile("\\.\PhysicalDrive"+STR(M.i,1),0xC0000000,3,0,3,0,0)
OTHERWISE
*-- 本程序不能运行的环境
RETURN ''
ENDCASE
IF M.hDevice = -1
RETU ''
ENDIF
*-- 获得 SMART IOCTL 版本信息
m.VersionParams = REPLICATE(CHR(0),24)
IF DeviceIoControl(M.hDevice,0x74080,0,0,@M.VersionParams,LEN(M.VersionParams),@M.lpBytesReturned,0) = 0
RETU ''
ENDIF
*-- 如果是 IDE 驱动器就发出命令
IF BITAND(AsciiToDec(SUBSTR(M.VersionParams,4,1)),1) = 1
*-- 定义数据接收缓冲区
m.OutCmd = REPLICATE(CHR(0),4)+REPLICATE(CHR(0),13)
*-- 判断是否允许执行 SMART 命令
IF BITAND(AsciiToDec(SUBSTR(M.VersionParams,4,1)),0x10) = 0
*-- 为执行 SMART 命令设置数据结构
m.scip = REPLICATE(CHR(0),4)+CHR(0xD8)+CHR(0)+CHR(0)+CHR(0x4F)+CHR(0xC2)+CHR(0xA0)+CHR(0xB0)+CHR(0)+CHR(M.i)+REPLICATE(CHR(0),19)
*-- 向驱动器发送 0xD8 命令
IF DeviceIoControl(M.hDevice,0x7c084,@M.scip,LEN(M.scip),@M.OutCmd,LEN(M.OutCmd)-1,@M.lpBytesReturned,0) # 0
*-- 设置驱动器映射标志
m.bDfpDriveMap = BITOR(M.bDfpDriveMap,1)
ELSE
RETU ''
ENDIF
ENDIF
*-- 获得本机 IDE 驱动器的扇区ID。ATAPI 驱动器则使用 0xA1 命令,其余使用 0xEC 命令。
m.bIDCmd = IIF( BITAND(AsciiToDec(SUBSTR(M.VersionParams,4,1)),1)=1,0xEC,0xA1)
*-- 设置数据结构
m.scip = DecToAscii(512,4)+REPLICATE(CHR(0),5)+CHR(0xA0)+CHR(M.bIDCmd)+CHR(0)+CHR(M.i)+REPLICATE(CHR(0),19)
*-- 读取驱动器参数
m.lpOutBuffer = M.OutCmd + REPLICATE(CHR(0),512)
IF DeviceIoControl(M.hDevice,0x7c088,@M.scip,LEN(M.scip),@M.lpOutBuffer,LEN(M.lpOutBuffer)-1,@M.lpBytesReturned,0) # 0
m.szOutBuffer = REPLICATE(CHR(0),41)
ELSE
RETU ''
ENDIF
ENDIF
*-- 关闭 SMART
CloseHandle(M.hDevice)
RETURN AsciiToString(SUBSTR(M.lpOutBuffer,37,20))
*-- 将ASCII字符串转换成十进制数
PROCEDURE AsciiToDec
LPARAMETER Bytes
LOCAL ln_i,ln_j
m.ln_j = 0
FOR M.ln_i = LEN(M.Bytes) TO 1 STEP -1
m.ln_j = M.ln_j * 256 + ASC(SUBSTR(M.Bytes,M.ln_i,1))
ENDFOR
RETURN M.ln_j
*-- 将十进制数转换成ASCII字符串
PROCEDURE DecToAscii
LPARAMETER tn_i,tn_j
LOCAL lc_i,ln_i
m.lc_i = ''
FOR M.ln_i = 1 TO M.tn_j
m.lc_i = M.lc_i + CHR(MOD(M.tn_i,256))
m.tn_i = INT(M.tn_i / 256)
ENDFOR
RETURN M.lc_i
*-- 将低位字节在前的字符串恢复正常
PROCEDURE AsciiToString
LPARAMETER tc_i
LOCAL lc_i,ln_i
m.lc_i = ''
FOR M.ln_i = 1 TO LEN(M.tc_i) STEP 2
m.lc_i = M.lc_i + SUBSTR(M.tc_i,M.ln_i+1,1) + SUBSTR(M.tc_i,M.ln_i,1)
ENDFOR
RETURN M.lc_i