Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.10.2011, 20:59   #1
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
Вопрос Как взять серийный номер винчестера через IOCTL

Добрый всем. Возникла задача - с помощью винапи узнать серийник всех физических дисков. Задачу решил на половину - на одних компах серийные номера определяются, на других они пустые.
Выкладываю сюда, все что сам понял, нашел и сваял:

Константы InOut Controls:
http://source.winehq.org/source/include/ntddstor.h
http://source.winehq.org/source/include/winioctl.h#L22

По функции DeviceIoControl:
http://msdn.microsoft.com/en-us/libr...16(VS.85).aspx
http://msdn.microsoft.com/en-us/libr...(v=VS.85).aspx
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

Моя реализация кода:
Код:
function GetDriveSNList(out AsDriveSNList:AnsiString):Boolean;
type
  STORAGE_PROPERTY_QUERY=record
    PropertyId:DWORD;
    QueryType:DWORD;
    AdditionalParameters:array[0..3] of Byte;
  end;

  STORAGE_DEVICE_DESCRIPTOR=record
    Version:DWORD;
    Size:DWORD;
    DeviceType:Byte;
    DeviceTypeModifier:Byte;
    RemovableMedia:Boolean;
    CommandQueueing:Boolean;
    VendorIdOffset:DWORD;
    ProductIdOffset:DWORD;
    ProductRevisionOffset:DWORD;
    SerialNumberOffset:DWORD;
    STORAGE_BUS_TYPE:DWORD;
    RawPropertiesLength:DWORD;
    RawDeviceProperties:array[0..511] of Byte;
  end;

const
  cntIOCTL_STORAGE_QUERY=$2D1400;
  cntSPQsize=SizeOf(STORAGE_PROPERTY_QUERY);
  cntSDDsize=SizeOf(STORAGE_DEVICE_DESCRIPTOR);

var
  i,j,len:Integer;
  LhDrive:THandle;
  LPropQuery:STORAGE_PROPERTY_QUERY;
  LDevDesc:STORAGE_DEVICE_DESCRIPTOR;
  LBytesTransfer:Cardinal;
  LqIOCTL:Boolean;
  LBt1,LBt2:Byte;
  LsDrive,LsHexSN,LsStrSN:AnsiString;
begin
  Result:=True;
  AsDriveSNList:='';
  try
    i:=0;
    while True do
    begin
      try
        try
          //пытаемся открыть доступ к физическому диску
          LsDrive:=Format('\\.\PhysicalDrive%d',[i]);
          LhDrive:=CreateFileA(PAnsiChar(LsDrive),0,
                               FILE_SHARE_READ and FILE_SHARE_WRITE,
                               nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
          if LhDrive=INVALID_HANDLE_VALUE then Abort;

          //взводим нужные структуры данных
          ZeroMemory(@LPropQuery,cntSPQsize);
          ZeroMemory(@LDevDesc,cntSDDsize);
          LDevDesc.Size:=cntSDDsize;

          //пытаемся выполнить запрос к драйверу устройства
          LqIOCTL:=DeviceIoControl(LhDrive,cntIOCTL_STORAGE_QUERY,
                                   @LPropQuery,cntSPQsize,
                                   @LDevDesc,cntSDDsize,
                                   LBytesTransfer,nil);
          if not LqIOCTL then Abort;

          //узнаем SN текущего винчестера
          if LDevDesc.SerialNumberOffset=0 then Abort;
          LsHexSN:=PAnsiChar(@LDevDesc)+LDevDesc.SerialNumberOffset;
          len:=Length(LsHexSN);
          LsStrSN:='';
          if Odd(len) then Abort;
          j:=1;
          while j<len do
          begin
            LBt1:=StrToInt('$'+Copy(LsHexSN,j,2));
            Inc(j,2);
            LBt2:=StrToInt('$'+Copy(LsHexSN,j,2));
            Inc(j,2);
            LsStrSN:=LsStrSN+AnsiChar(LBt2)+AnsiChar(LBt1);
          end;
          LsStrSN:=Trim(LsStrSN);//на моем винте перед самим серийником из 8 байтов предшествует 12 байт символов-пробелов
          AsDriveSNList:=AsDriveSNList+Format('%s'#13#10,[LsStrSN]);
        finally
          CloseHandle(LhDrive);
          Inc(i);
        end;
      except
        Break;
      end;
      if Length(AsDriveSNList)=0 then Abort;
    end;
  except
    Result:=False;
    AsDriveSNList:=Format('%s<ERROR ON REQUESTING HARDWARE DATA>',[AsDriveSNList]);
  end;
end;
Функция возвращает серийные номера найденных в системе винчесеров в виде анси-строки с разделителем #13#10 между значениями. Было бы отлично, если бы кто-нибудь потестировал этот код на своих компах и поделился результатами.

А вообще суть темы в том, что я делаю неправильно в этом коде? Есть подозрение, что неверно портирована одна из структур STORAGE_DEVICE_DESCRIPTOR или STORAGE_PROPERTY_QUERY.

Камрады программистской мысли, если знаете решение, поделитесь пожалуйста правильным подходом или ткните вразумительной ссылкой на сие чтиво. Хотя последнее врядли - этот вопрос уже поднимается 5 лет точно судя по всем просмотренным мной форумам. Решение через WMI не предлагать, только WinApi, если это вообще возможно. Жду предложений!
"ковыряю изнутри" (с)

Последний раз редактировалось 3D Hunter; 18.10.2011 в 21:02.
3D Hunter вне форума Ответить с цитированием
Старый 23.10.2011, 20:41   #2
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Неужели никто не сталкивался с подобным решением задачи?
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 23.10.2011, 22:26   #3
raxp
Старожил
 
Регистрация: 29.09.2009
Сообщений: 9,713
По умолчанию

Цитата:
на одних компах серийные номера определяются, на других они пустые
а что возвращает при этом GetOverlappedResult(), там где не удается получить?

И еще, под другими "компами" имеются ввиду машины с семеркой, есть какая-либо статистика?
Разработки и научно-технические публикации :: Видеоблог :: Твиттер
Radar systems engineer & Software developer of industrial automation
raxp вне форума Ответить с цитированием
Старый 24.10.2011, 10:53   #4
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

В разделе железа вроде выкладывали пару месяцев назад исходник на эту тему.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 29.10.2011, 14:00   #5
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

посмотрел темы по этому поводу... щас буду исходники юзать что народ приложил... а вот мой код на одних компах определяет сериники, а на других видит их пустыми, т.е. в списке пустые строки и все. Статистика и закономерность не выявлена, на одних машинах под вин 2003 сервер видит, под другой с той же ОС не видит. На семерке тоже самое, на моем ноуте видит, на ноуте друга нет, хотя винты у нах одинаковые модели! GetOverlappedResult щас буду шарить...
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 01.11.2011, 12:59   #6
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

все исходники тем в разделе железа нерабочие! проверено! у друга ноутбук леново, и винт упорно не хочет идентифицироваться любым из предложенных решений!

А что делает функция GetOverlappedResult и что тако структура _Overlapped?
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 01.11.2011, 15:23   #7
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

в продолжение исследований выявлен такой факт:

серийный номер винчестера может быть представлен как номерами ANSI-символов, так и сразу буквенными значениями.
В принципе, это решило часть проблем... но есть винты, у которых сдвиг ненулевой по серийнику, но длина получаемой строки равна нулю. Было предположение что данные могут отдаватсься драйвером в oem-кодировке, но это не так.
Если у кого есть мысли или идеи, пишите! А я разбираюсь дальше...

P.S. Кстати, Overlapped'ом с помощью GetOverlappedResult() сосчитал реальный размер в байтах, он не нулевой, число больше любого из сдвигов структуры STORAGE_DEVICE_DESCRIPTOR.
На тех компах, где серийник пустой, GetLastError возвращает стабильно 87 (The parameter is incorrect).

На 3х машинах стоит по винту:
1) ST9250315AS с прошивкой 0001SDM1
2) ST9160314AS с прошивкой 0001SDM1
3) ST9250315AS с прошивкой 0001SDM1

Видно, что прошивка одинаковая, и SerialNumberOffset=0! Хотя в моем ноутбуке такой же винт что на машинах 1) и 3), но в нем все определяется на ура...
Кто знает, в чем причина?
"ковыряю изнутри" (с)

Последний раз редактировалось 3D Hunter; 01.11.2011 в 15:58.
3D Hunter вне форума Ответить с цитированием
Старый 01.11.2011, 16:00   #8
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Привожу код с комментами этой функции:

Код:

uses
  Windows, SysUtils, IpTypes, IpHlpApi, dialogs;

...

function GetDriveList(out ADrvInfo:AnsiString):Boolean;

type
  //http://msdn.microsoft.com/en-us/library/ff800839(v=VS.85)
  STORAGE_PROPERTY_ID=(StorageDeviceProperty=$0,
                       StorageAdapterProperty=$1,
                       StorageDeviceIdProperty=$2,
                       StorageDeviceUniqueIdProperty=$3,
                       StorageDeviceWriteCacheProperty=$4,
                       StorageMiniportProperty=$5,
                       StorageAccessAlignmentProperty=$6,
                       StorageDeviceSeekPenaltyProperty=$7,
                       StorageDeviceTrimProperty=$8,
                       StorageDeviceWriteAggregationProperty=$9,
                       StorageDeviceDeviceTelemetryProperty=$A,
                       StorageDeviceLBProvisioningProperty=$B,
                       StorageDeviceZeroPowerODDProperty=$C,
                       StorageDeviceCopyOffloadProperty=$D,
                       StorageDeviceResiliencyProperty=$E);

  //http://msdn.microsoft.com/en-us/library/ff800841(v=VS.85)
  STORAGE_QUERY_TYPE=(PropertyStandardQuery=$0,
                      PropertyExistsQuery=$1,
                      PropertyMaskQuery=$2,
                      PropertyQueryMaxDefined=$3);

  //http://msdn.microsoft.com/en-us/library/aa363465(VS.85).aspx
  STORAGE_BUS_TYPE=(BusTypeUnknown=$0,
                    BusTypeScsi=$1,
                    BusTypeAtapi=$2,
                    BusTypeAta=$3,
                    BusType1394=$4,
                    BusTypeSsa=$5,
                    BusTypeFibre=$6,
                    BusTypeUsb=$7,
                    BusTypeRAID=$8,
                    BusTypeiSCSI=$9,
                    BusTypeSas=$A,
                    BusTypeSata=$B,
                    BusTypeMaxReserved=$7F);

  //http://msdn.microsoft.com/en-us/library/ff800840
  STORAGE_PROPERTY_QUERY=record
    PropertyId:STORAGE_PROPERTY_ID;
    QueryType:STORAGE_QUERY_TYPE;
    AdditionalParameters:array[0..65535] of Byte;
  end;

  //http://msdn.microsoft.com/en-us/library/ff800835(v=VS.85).aspx
  STORAGE_DEVICE_DESCRIPTOR=record
    Version:DWORD;
    Size:DWORD;
    DeviceType:Byte;
    DeviceTypeModifier:Byte;
    RemovableMedia:Boolean;
    CommandQueueing:Boolean;
    VendorIdOffset:DWORD;
    ProductIdOffset:DWORD;
    ProductRevisionOffset:DWORD;
    SerialNumberOffset:DWORD;
    BusType:STORAGE_BUS_TYPE;
    RawPropertiesLength:DWORD;
    RawDeviceProperties:array[0..65535] of Byte;
  end;

const
  SPQ_SIZE=SizeOf(STORAGE_PROPERTY_QUERY);
  SDD_SIZE=SizeOf(STORAGE_DEVICE_DESCRIPTOR);
  PHYS_DRIVE_COUNT=16;

var
  i,j,len:Integer;
  LBt1,LBt2:Byte;
  LhDrive:THandle;
  LPropQuery:STORAGE_PROPERTY_QUERY;
  LDevDesc:STORAGE_DEVICE_DESCRIPTOR;
  LBytesTransfer:Cardinal;
  LqIOCTL:Boolean;
  LsDrive,
  LStr,
  LsDrvProduct,
  LsDrvRevision,
  LsDrvSerial:AnsiString;
  LqSnBinaryMode:Boolean;
  LOverlapped:TOverlapped;

begin
  Result:=True;
  try
    i:=0;
    ADrvInfo:='';
    while i<PHYS_DRIVE_COUNT-1 do
    begin
      try
        //пытаемся открыть доступ к физическому диску
        LsDrive:=Format('\\.\PhysicalDrive%d',[i]);
        LhDrive:=CreateFileA(PAnsiChar(LsDrive),0,
                             FILE_SHARE_READ or FILE_SHARE_WRITE,
                             nil,OPEN_EXISTING,0,0);
        if LhDrive=INVALID_HANDLE_VALUE then Continue;
"ковыряю изнутри" (с)

Последний раз редактировалось 3D Hunter; 01.11.2011 в 16:04.
3D Hunter вне форума Ответить с цитированием
Старый 01.11.2011, 16:01   #9
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

продолжение...

Код:
        //взводим нужные структуры данных
        ZeroMemory(@LPropQuery,SPQ_SIZE);
        ZeroMemory(@LDevDesc,SDD_SIZE);
        LDevDesc.Size:=SDD_SIZE;

        //пытаемся выполнить запрос к драйверу устройства
        LqIOCTL:=DeviceIoControl(LhDrive,IOCTL_STORAGE_QUERY_PROPERTY,
                                 @LPropQuery,SPQ_SIZE,
                                 @LDevDesc,SDD_SIZE,
                                 LBytesTransfer,@LOverlapped);
        if not LqIOCTL then Continue;

        if GetOverlappedResult(LhDrive,LOverlapped,LBytesTransfer,True) then
          ShowMessage('OverlappedResult: '+IntToStr(LBytesTransfer));
        ShowMessage('LastError: '+IntToStr(GetLastError));

        //узнаем Имя и SN текущего винчестера
        if (LDevDesc.ProductIdOffset=0)
           or
           (LDevDesc.ProductRevisionOffset=0)
           or
           (LDevDesc.SerialNumberOffset=0)
        then Continue;

        //извлекаем имя диска
        LsDrvProduct:=PAnsiChar(Cardinal(@LDevDesc)+LDevDesc.ProductIdOffset);
        //извлекаем версию прошивки диска
        LsDrvRevision:=PAnsiChar(Cardinal(@LDevDesc)+LDevDesc.ProductRevisionOffset);
        //извлекаем серийный номер диска
        LsDrvSerial:=PAnsiChar(Cardinal(@LDevDesc)+LDevDesc.SerialNumberOffset);

        //обрезаем возможные пробелы
        LsDrvProduct:=Trim(LsDrvProduct);
        LsDrvRevision:=Trim(LsDrvRevision);
        LsDrvSerial:=Trim(LsDrvSerial);

ShowMessage('LsDrvProduct: '+LsDrvProduct+' | '+IntToStr(LDevDesc.ProductIdOffset)+#13#10+
            'LsDrvRevision: '+LsDrvRevision+' | '+IntToStr(LDevDesc.ProductRevisionOffset)+#13#10+
            'LsDrvSerial: '+LsDrvSerial+' | '+IntToStr(LDevDesc.SerialNumberOffset)+#13#10);

        LqSnBinaryMode:=True;//форсируем режим "если серийный номер бинарный"
        len:=Length(LsDrvSerial);//узнаем длину серийного номера
        for j:=1 to len do//определяем режим отображения серийного номера
        if (not (LsDrvSerial[j] in ['0'..'9','a'..'f','A'..'F'])) then
        begin
          LqSnBinaryMode:=False;//серийный номер представлен печатаемыми символами
          Break;
        end;

        //обрабатываем серийный номер взависимости от режима:
        //если он представлен номерами ANSI-символов, то преобразуем в строку
        case LqSnBinaryMode of
          True:
            begin
              LStr:='';
              if Odd(len) then Continue;
              j:=1;
              while j<len do
              begin
                LBt1:=StrToInt('$'+Copy(LsDrvSerial,j,2));
                Inc(j,2);
                LBt2:=StrToInt('$'+Copy(LsDrvSerial,j,2));
                Inc(j,2);
                LStr:=LStr+AnsiChar(LBt2)+AnsiChar(LBt1);
              end;
            end;
          False:
            begin
              LStr:='';
              j:=1;
              while j<len do
              begin
                LStr:=LStr+LsDrvSerial[j+1]+LsDrvSerial[j];
                Inc(j,2);
              end;
            end;
        end;
        LsDrvSerial:=Trim(LStr);

        //формирование данных по диску в строку
        ADrvInfo:=Format('%s%s'#1'%s'#1'%s'#2,
                       [ADrvInfo,LsDrvProduct,LsDrvRevision,LsDrvSerial]);
      finally
        CloseHandle(LhDrive);
        Inc(i);
      end;
    end;
  except
    Result:=False;
  end;
end;
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 19.11.2011, 19:37   #10
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

люди, так никто не знает ответа? Может дело в каком-то нюансе, и всего-то...
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Серийный номер винчестера NetSpace Компьютерное железо 28 30.03.2012 14:17
Серийный номер hdd через wmi xil C# (си шарп) 3 08.09.2011 12:04
Серийный номер HDD ?! $T@LKER Общие вопросы Delphi 32 26.02.2011 10:55
по букве тома определить физический серийный номер накопителя, а не номер тома @лександр Помощь студентам 6 23.09.2010 15:05
J2me как скачать и получить серийный номер для Эмулятора Nokia?? Tik-Tik Общие вопросы по Java, Java SE, Kotlin 0 26.08.2009 20:00