Показать сообщение отдельно

  #5614  
Старый 16.02.2010, 22:07
transserg
Участник форума
Регистрация: 02.07.2008
Сообщений: 132
Провел на форуме:
1035284

Репутация: 52
Отправить сообщение для transserg с помощью ICQ
По умолчанию

Nightmarе
получает серийник флешки =) (физический а не тома)
писал на основе примера
Код:
unit FlashSerial;
interface
uses
  Windows,StringTools;


{$ALIGN 8}

const
  DeviceMask = '%c:';
  VolumeMask = '\\.\' + DeviceMask;

  setupapi = 'SetupApi.dll';
  cfgmgr = 'cfgmgr32.dll';  

  // Константы и типы из winioctl.h

const
  FILE_DEVICE_CONTROLLER = $00000004;
  FILE_DEVICE_FILE_SYSTEM = $00000009;
  FILE_DEVICE_MASS_STORAGE = $0000002D;

  METHOD_BUFFERED = $00000000;
  FILE_ANY_ACCESS = $00000000;
  FILE_READ_ACCESS = $00000001;
  FILE_WRITE_ACCESS = $00000002;

  IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
  IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER;

  FSCTL_LOCK_VOLUME = (FILE_DEVICE_FILE_SYSTEM shl 16) or
    (FILE_ANY_ACCESS shl 14) or ($6 shl 2) or METHOD_BUFFERED;

  FSCTL_DISMOUNT_VOLUME = (FILE_DEVICE_FILE_SYSTEM shl 16) or
    (FILE_ANY_ACCESS shl 14) or ($8 shl 2) or METHOD_BUFFERED;

  IOCTL_STORAGE_MEDIA_REMOVAL = (IOCTL_STORAGE_BASE shl 16) or
    (FILE_READ_ACCESS shl 14) or ($0201 shl 2) or METHOD_BUFFERED;

  IOCTL_STORAGE_EJECT_MEDIA = (IOCTL_STORAGE_BASE shl 16) or
    (FILE_READ_ACCESS shl 14) or ($0202 shl 2) or METHOD_BUFFERED; 

  IOCTL_STORAGE_GET_DEVICE_NUMBER = (IOCTL_STORAGE_BASE shl 16) or
    (FILE_ANY_ACCESS shl 14) or ($0420 shl 2) or METHOD_BUFFERED;

  IOCTL_SCSI_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or
    ((FILE_WRITE_ACCESS or FILE_READ_ACCESS) shl 14) or
    ($0401 shl 2) or METHOD_BUFFERED;

  GUID_DEVINTERFACE_DISK: TGUID = (
    D1:$53f56307; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b));

type
  DEVICE_TYPE = DWORD;

  PStorageDeviceNumber = ^TStorageDeviceNumber;
  TStorageDeviceNumber = packed record
    DeviceType: DEVICE_TYPE;
    DeviceNumber: DWORD;
    PartitionNumber: DWORD;
  end;

  // Константы и типы из setupapi.h
const
  ANYSIZE_ARRAY = 1024;

  DIGCF_PRESENT         = $00000002;
  DIGCF_DEVICEINTERFACE = $00000010;

type
  HDEVINFO = THandle;

  PSPDevInfoData = ^TSPDevInfoData;
  SP_DEVINFO_DATA = packed record
    cbSize: DWORD;
    ClassGuid: TGUID;
    DevInst: DWORD; // DEVINST handle
    Reserved: ULONG_PTR;
  end;
  TSPDevInfoData = SP_DEVINFO_DATA;

  PSPDeviceInterfaceData = ^TSPDeviceInterfaceData;
  SP_DEVICE_INTERFACE_DATA = packed record
    cbSize: DWORD;
    InterfaceClassGuid: TGUID;
    Flags: DWORD;
    Reserved: ULONG_PTR;
  end;
  TSPDeviceInterfaceData = SP_DEVICE_INTERFACE_DATA;

  PSPDeviceInterfaceDetailDataA = ^TSPDeviceInterfaceDetailDataA;
  PSPDeviceInterfaceDetailData = PSPDeviceInterfaceDetailDataA;
  SP_DEVICE_INTERFACE_DETAIL_DATA_A = packed record
    cbSize: DWORD;
    DevicePath: array [0..ANYSIZE_ARRAY - 1] of AnsiChar;
  end;
  TSPDeviceInterfaceDetailDataA = SP_DEVICE_INTERFACE_DETAIL_DATA_A;
  TSPDeviceInterfaceDetailData = TSPDeviceInterfaceDetailDataA;

  function SetupDiGetClassDevsA(ClassGuid: PGUID; const Enumerator: PAnsiChar;
    hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall; external setupapi;

  function SetupDiDestroyDeviceInfoList(
    DeviceInfoSet: HDEVINFO): LongBool; stdcall; external setupapi;

  function SetupDiEnumDeviceInterfaces(DeviceInfoSet: HDEVINFO;
    DeviceInfoData: PSPDevInfoData; const InterfaceClassGuid: TGUID;
    MemberIndex: DWORD; var DeviceInterfaceData: TSPDeviceInterfaceData):
    LongBool; stdcall; external setupapi;

  function SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet: HDEVINFO;
    DeviceInterfaceData: PSPDeviceInterfaceData;
    DeviceInterfaceDetailData: PSPDeviceInterfaceDetailDataA;
    DeviceInterfaceDetailDataSize: DWORD; var RequiredSize: DWORD;
    Device: PSPDevInfoData): LongBool; stdcall; external setupapi;

  // Константы и типы из cfgmgr32.h

const
  CR_SUCCESS = 0;

  PNP_VetoTypeUnknown          = 0;
  PNP_VetoLegacyDevice         = 1;
  PNP_VetoPendingClose         = 2;
  PNP_VetoWindowsApp           = 3;
  PNP_VetoWindowsService       = 4;
  PNP_VetoOutstandingOpen      = 5;
  PNP_VetoDevice               = 6;
  PNP_VetoDriver               = 7;
  PNP_VetoIllegalDeviceRequest = 8;
  PNP_VetoInsufficientPower    = 9;
  PNP_VetoNonDisableable       = 10;
  PNP_VetoLegacyDriver         = 11;  
  PNP_VetoInsufficientRights   = 12;
type
  DEVINST = DWORD;
  CONFIGRET = DWORD;

  PPNP_VETO_TYPE = ^PNP_VETO_TYPE;
  PNP_VETO_TYPE = DWORD;

  function CM_Get_Parent(var dnDevInstParent: DEVINST;
    dnDevInst: DEVINST; ulFlags: ULONG): CONFIGRET; stdcall;
    external cfgmgr;

  function CM_Request_Device_EjectA(dnDevInst: DEVINST;
    pVetoType: PPNP_VETO_TYPE; pszVetoName: PWideChar;
    ulNameLength: ULONG; ulFlags: ULONG): CONFIGRET; stdcall;
    external setupapi;
{  CMAPI CONFIGRET WINAPI
    CM_Get_Device_ID_Size(
      OUT PULONG  pulLen,
      IN DEVINST  dnDevInst,
      IN ULONG  ulFlags
    );}
  function CM_Get_Device_ID_Size(pulLen:PULONG;dnDevInst: DEVINST;ulFlags: ULONG): CONFIGRET; stdcall;
    external setupapi;
{CMAPI CONFIGRET WINAPI
  CM_Get_Device_ID(
    IN DEVINST  dnDevInst,
    OUT PTCHAR  Buffer,
    IN ULONG  BufferLen,
    IN ULONG  ulFlags
    );
    }
  function CM_Get_Device_IDA(dnDevInst: DEVINST;Buffer:PChar;BufferLen:ULONG;ulFlags: ULONG): CONFIGRET; stdcall;
    external setupapi;    
  // Константы и типы из ntddscsi.h

const
  SCSI_IOCTL_DATA_IN = 1;
  SCSIOP_MECHANISM_STATUS = $BD;

type
  USHORT = Word;

  PSCSI_PASS_THROUGH_DIRECT = ^SCSI_PASS_THROUGH_DIRECT;
  _SCSI_PASS_THROUGH_DIRECT = {packed} record
    Length: USHORT;
    ScsiStatus: UCHAR;
    PathId: UCHAR;
    TargetId: UCHAR;
    Lun: UCHAR;
    CdbLength: UCHAR;
    SenseInfoLength: UCHAR;
    DataIn: UCHAR;
    DataTransferLength: ULONG;
    TimeOutValue: ULONG;
    DataBuffer: ULONG;
    SenseInfoOffset: ULONG;
    Cdb: array [0..15] of UCHAR;
  end;
  SCSI_PASS_THROUGH_DIRECT = _SCSI_PASS_THROUGH_DIRECT;

  TSCSIPassThroughDirectBuffer = record
    Header: SCSI_PASS_THROUGH_DIRECT;
    SenseBuffer: array [0..31] of UCHAR;
    DataBuffer: array [0..191] of UCHAR;
  end;

function GetFlashSerial(const Value: Char): PChar;
function GetFlashS(const Dr:Char):PChar;
implementation

function GetPath(Path:PChar):PChar;
  var
    I: Integer;
    temp:PChar;
  begin
    GetMem(temp,MAX_PATH);
    for I := lstrlen(path) downto 0 do
      if Path[i]<>'\' then
          temp:=PChar(path[i]+temp)
      else
        Break;
    Result:=temp;
  end;

function GetFlashS(const Dr:Char):PChar;
  var
    temp:PChar;
  begin
    temp:=GetFlashSerial(Dr);
    Result:=GetPath(temp);
  end;

function GetFlashSerial(const Value: Char): PChar;
  var
    hFile, hDevInfo, hDrive, hDevInstance: THandle;
    sdn: TStorageDeviceNumber;
    dwDeviceNumber, dwBytesReturned, dwSize: DWORD;
    FlashGuid: TGUID;
    I: Integer;
    DeviceInfoData: TSPDevInfoData;
    DeviceInterfaceData: TSPDeviceInterfaceData;
    DeviceInterfaceDetailData: TSPDeviceInterfaceDetailData;
    Size:DWORD;
    Buf:array[0..MAX_PATH] of char;
    BufD:PChar;
  begin
    Result := '';
    hDevInstance := INVALID_HANDLE_VALUE;

    // Открываем том
    GetMem(BufD,MAX_PATH);
    wsprintf(BufD,VolumeMask,Value);
    hFile := CreateFile(BufD, 0,FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hFile = INVALID_HANDLE_VALUE then
      begin
        Exit;
      end;
    try
      // Получаем номер устройства в системе
      if not DeviceIoControl(hFile,IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @sdn,SizeOf(TStorageDeviceNumber), dwBytesReturned, nil) then
        begin
          Exit;
        end;

      dwDeviceNumber := sdn.DeviceNumber;
      FlashGuid := GUID_DEVINTERFACE_DISK;
      // Подготавливаем список устройств в системе, для поиска хэндла устройства
      hDevInfo := SetupDiGetClassDevsA(@FlashGuid, nil, 0,DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
      if hDevInfo = INVALID_HANDLE_VALUE then
        begin
          Exit;
        end;
      try

        I := 0;
        // Крутим цикл по всем устройствам
        DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
        while SetupDiEnumDeviceInterfaces(hDevInfo, nil, FlashGuid, I, DeviceInterfaceData) do
          begin

            Inc(I);

            // Узнаем необходимый размер буффера для получения пути к устройству
            SetupDiGetDeviceInterfaceDetailA(hDevInfo, @DeviceInterfaceData,nil, 0, dwSize, nil);
            if dwSize = 0 then
              begin
                Exit;
              end;

            DeviceInfoData.cbSize :=  SizeOf(TSPDevInfoData);
            // Узкий момент, размер структуры должен быть обьявлен как пятерка.
            // Почему? Это не ко мне, а к тем кто это придумал -
            // в противном случае вызов SetupDiGetDeviceInterfaceDetailA
            // будет не успешен
            DeviceInterfaceDetailData.cbSize := 5;
            // Получаем путь к устройству
            if not SetupDiGetDeviceInterfaceDetailA(hDevInfo, @DeviceInterfaceData,@DeviceInterfaceDetailData, dwSize, dwSize, @DeviceInfoData) then
              begin
                Exit;
              end;
            // Открываем устройство
            hDrive := CreateFile(PChar(@DeviceInterfaceDetailData.DevicePath[0]),0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
            if hFile = INVALID_HANDLE_VALUE then
              begin
                Exit;
              end;
            try
              // Получаем номер устройства в системе
              if not DeviceIoControl(hDrive,IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @sdn,SizeOf(TStorageDeviceNumber), dwBytesReturned, nil) then
                begin
                  Exit;
                end;
              // Если данное устройство - наше, запоминаем хэндл
              if sdn.DeviceNumber = dwDeviceNumber then
                begin
                  hDevInstance := DeviceInfoData.DevInst;
                  Break;
                end;
            finally
              CloseHandle(hDrive);
            end;
          end;
      finally
          SetupDiDestroyDeviceInfoList(hDevInfo);
      end;
    finally
      CloseHandle(hFile);
    end;
    // Смотрим - нашелся ли хэндл устройства
    if hDevInstance <> INVALID_HANDLE_VALUE then
      begin
        // Получаем хэндл родителя
        CM_Get_Device_ID_Size(@size,hDevInstance,0);
        if CM_Get_Device_IDA(hDevInstance,buf,size*2,0)=0 then
          Result:=Buf;
      end;
  end;

end.
 
Ответить с цитированием