Что нового

[Автоматизация] Определение серийного номера HDD.

Heler

Знающий
Сообщения
70
Репутация
11
Привет! Понадобилось сделать привязку программы к определенной машине. Нашел способ получить серийный номер раздела HDD. Но этот вариант не катит, ибо после форматирования он меняется. Подскажите пожалуйста как получить серийный номер HDD а не раздела.
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
Вот код для получения серийного номера харда. Как мне получить его в Autoit скрипте?

Код:
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <windows.h>
#include <winioctl.h>
    char            HardDriveSerialNumber [1024]; // здесь будет храниться наш SN
CString GetHDDSerial()
{
    BYTE                                bIDCmd = 0;   // крманда IDE или ATAPI IDENTIFY
    SENDCMDINPARAMS            scip;             // см MSDN для описания
    USHORT              *pIdSector;        // указатель на адрес сектора HDD, в котором хранится разная полезная инфа =)
    GETVERSIONINPARAMS    VP;                        // см MSDN для описания
    int                                    i = 0;                // номер диска
    BYTE                                IdOutCmd[sizeof(SENDCMDOUTPARAMS)+512-1];
    DWORD                                br;                        // байт прочтено

// выделяем памаять под переменную VP
    memset((void*)&VP,0,sizeof(VP));    
// создаем хэндл диска PHYSICALDRIVEX - номер диска
    HANDLE hDisk = CreateFile("\\\\.\\PHYSICALDRIVE0",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
    if ( hDisk != INVALID_HANDLE_VALUE )
    {
        if (DeviceIoControl(hDisk,DFP_GET_VERSION,NULL,0,&VP,sizeof(VP),&br,NULL))
        {
            if (VP.bIDEDeviceMap>0)
            {
                bIDCmd=(VP.bIDEDeviceMap>>i&0x10)?\
IDE_ATAPI_IDENTIFY:IDE_ATA_IDENTIFY;
                if ( bIDCmd == IDE_ATA_IDENTIFY )
                {
                    memset ( &scip, 0, sizeof(scip) );
                    memset ( IdOutCmd, 0, sizeof(IdOutCmd) );

                    scip.irDriveRegs.bFeaturesReg = 0;
                    scip.irDriveRegs.bSectorCountReg = 1;
                    scip.irDriveRegs.bSectorNumberReg = 1;
                    scip.irDriveRegs.bCylLowReg = 0;
                    scip.irDriveRegs.bCylHighReg = 0;
                    scip.irDriveRegs.bDriveHeadReg = 0xA0 | ((i & 1) << 4);
                    scip.irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
                    scip.bDriveNumber = i;
                    scip.cBufferSize = 512;

                    if (DeviceIoControl(hDisk,DFP_RECEIVE_DRIVE_DATA,
                        (LPVOID)&scip,
                        sizeof(SENDCMDINPARAMS)-1,
                        (LPVOID)IdOutCmd,
                        sizeof(SENDCMDOUTPARAMS)+512-1,
                        &br,NULL))
                    {
                        DWORD diskdata [256];        // нужные нам данные
                        int ijk = 0;

                        pIdSector = (USHORT*)((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer; // получаем указатель на сектор
                        
                        for (ijk = 0; ijk < 256; ijk++)
                            diskdata [ijk] = pIdSector [ijk];        // заполняем наши данные

                        strcpy(HardDriveSerialNumber,ConvertToString(diskdata,10,19)); // конвертируем в строку SN
                        return HardDriveSerialNumber;
                    }
                }
            }
        }
    }
    return "Some Stupid Error";
}

// ф-я конвертирования в строку данных
char *ConvertToString(DWORD diskdata [256],int firstIndex,int lastIndex)
{
    static char string [1024];
    int index = 0;
    int position = 0;

    //  each integer has two characters stored in it backwards
    for (index = firstIndex; index <= lastIndex; index++)
    {
        //  get high byte for 1st character
        string [position] = (char) (diskdata [index] / 256);
        position++;

        //  get low byte for 2nd character
        string [position] = (char) (diskdata [index] % 256);
        position++;
    }

    //  end the string 
    string [position] = '\0';

    //  cut off the trailing blanks
    for (index = position - 1; index > 0 && ' ' == string [index]; index--)
        string [index] = '\0';

    return string;
}
 

amel27

Продвинутый
Сообщения
146
Репутация
55
Heler, WMI поддерживает HDD SerialNumber только начиная с Vista
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
amel27, спасибо. Вчера это заметил методом проб =) Решил использовать параметр "$objItem.PNPDeviceID". Он мне показался уникален. ;)
 

amel27

Продвинутый
Сообщения
146
Репутация
55
Heler сказал(а):
Решил использовать параметр "$objItem.PNPDeviceID". Он мне показался уникален.

Он уникален, но состоит из ID модели и ID PnP перечислителя шины, т.е. может измениться при любом изменении конфигурации - подключении новых устройств, переброса контроллера/диска из слота в слот, сброса BIOS и т.д.

Heler сказал(а):
Вот код для получения серийного номера харда. Как мне получить его в Autoit скрипте

где-то так:

Код:
#include <WinAPI.au3>

$sID = _DriveATA_GetSerial()
If @error Then ConsoleWrite("ERR: "& @error &":"& @extended &@CRLF)
ConsoleWrite($sID &@CRLF)

Func _DriveATA_GetSerial($iDrvNum = 0)
    Local $tVP = DllStructCreate("byte bVersion;byte bRevision;byte bReserved;"& _
        "byte bIDEDeviceMap;ulong fCapabilities;ulong dwReserved[4]")
    Local $pVP = DllStructGetPtr($tVP), $zVP = DllStructGetSize($tVP)
    Local $tSCIP = DllStructCreate("ulong cBufferSize;byte irDriveRegs[8];byte bDriveNumber;"& _
        "byte bReserved[3];ulong dwReserved[4];byte bBuffer[1]")
    Local $pSCIP = DllStructGetPtr($tSCIP), $zSCIP = DllStructGetSize($tSCIP)
    Local $tSCOP = DllStructCreate("ulong cBufferSize;byte[4];ulong[2];byte bBuffer[1];byte[512]")
    Local $pSCOP = DllStructGetPtr($tSCOP), $zSCOP = DllStructGetSize($tSCOP)
    Local $tDR = DllStructCreate("byte bFeaturesReg;byte bSectorCountReg;byte bSectorNumberReg;"& _
        "byte bCylLowReg;byte bCylHighReg;byte bDriveHeadReg;byte bCommandReg;byte bReserved", _
        DllStructGetPtr($tSCIP, "irDriveRegs") )
    Local $tBytes = DllStructCreate("dword"), $pBytes = DllStructGetPtr($tBytes)
    Local $aRet, $bIDCnd = 0xEC, $tSerial, $sSerial

    $iDrvNum = Abs(Int($iDrvNum))
    Local $hDisk = _WinAPI_CreateFile("\\.\PHYSICALDRIVE"& $iDrvNum, 2, 6, 6)
    If $hDisk=0 Then Return SetError(1, 0, "")

    $aRet = DllCall("kernel32.dll", "int", "DeviceIoControl", _
        "hwnd", $hDisk, "dword", 0x00074080, "ptr", 0, "dword", 0, _
        "ptr", $pVP, "dword", $zVP, "ptr", $pBytes, "ptr", 0)
    If $aRet[0]=0 Then Return SetError(2, _WinAPI_GetLastError(), _WinAPI_CloseHandle($hDisk))
    If DllStructGetData($tVP, "bIDEDeviceMap")<=0 Then Return SetError(3,0,_WinAPI_CloseHandle($hDisk))
    If BitAND(BitShift(DllStructGetData($tVP, "bIDEDeviceMap"),$iDrvNum),0x10) Then _
        Return SetError(4,0,_WinAPI_CloseHandle($hDisk))

    DllStructSetData($tDR, "bSectorCountReg", 1)
    DllStructSetData($tDR, "bSectorNumberReg", 1)
    DllStructSetData($tDR, "bDriveHeadReg", BitOR(BitShift(BitAND($iDrvNum,1),-4),0xA0) )
    DllStructSetData($tDR, "bCommandReg", 0xEC)
    
    DllStructSetData($tSCIP, "bDriveNumber", $iDrvNum)
    DllStructSetData($tSCIP, "cBufferSize", 512)
    
    $aRet = DllCall("kernel32.dll", "int", "DeviceIoControl", _
        "hwnd", $hDisk, "dword", 0x0007c088, "ptr", $pSCIP, "dword", $zSCIP-1, _
        "ptr", $pSCOP, "dword", $zSCOP-1, "ptr", $pBytes, "ptr", 0)
    If $aRet[0]=0 Then Return SetError(5, _WinAPI_GetLastError(), _WinAPI_CloseHandle($hDisk))
    _WinAPI_CloseHandle($hDisk)

    $tSerial = DllStructCreate("char[30]", DllStructGetPtr($tSCOP, "bBuffer")+20)
    $sSerial = StringRegExpReplace(DllStructGetData($tSerial,1), "(.)(.)", "\2\1")
    
    Return $sSerial
EndFunc
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
Спасибо что предупредили. Получаю вот такое в консоль:

ERR: 2:0
True


P.S. ОС Vista
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
Так получше. Спасибо большое :smile: Выводит:

S0HVJ13LB01309 
 

vovsla

Осваивающий
Сообщения
607
Репутация
36
А почему не хотел по ID устройства посмотреть? Это проще всего, можно из реестра выдернуть.
 

amel27

Продвинутый
Сообщения
146
Репутация
55
Heler сказал(а):

я лишь перевел предложенный код на AutoIT, хотя сам исходник далек от идеала - во-первых, он работает только для ATA дисков, во-вторых, для SATA только в режиме IDE (либо надо убирать строку проверки bIDEDeviceMap, которая в чистом SATA не используется), более продвинутый код можно взять, например, отсюда или из исходников утилиты DiskID32, линк на которую давал выше
 
Автор
H

Heler

Знающий
Сообщения
70
Репутация
11
amel27, код работает исправно на WinXp и Vista, а вот на Win7 выводит:

ERR: 1:0
Подскажите пожалуйста, как подправить код чтоб и на семерке работало. ;)

---------------------------------------------------------------------------------------

Проблему решил. Нужно было запускать скрипт от администратора. :blum:
 
Верх