unit U_USB; interface uses Windows, SysUtils, Variants, Classes, ShellApi, Forms, ioctl, FastStrings; const CR_SUCCESS = $00000000; MAX_PATH = 260; ANYSIZE_ARRAY = 1; SetupApiModuleName = 'SetupApi.dll'; setupapi = 'SetupApi.dll'; DIGCF_PRESENT = $00000002; DIGCF_DEVICEINTERFACE = $00000010; GUID_CLASS_USBHUB:TGUID='{f18a0e88-c30c-11d0-8815-00a0c906bed8}'; GUID_CLASS_USB_DEVICE:TGUID='{A5DCBF10-6530-11D2-901F-00C04FB951ED}'; GUID_CLASS_USB_HOST_CONTROLLER:TGUID='{3ABF6F2D-71C4-462a-8A92-1E6861E6AF27}'; GUID_DEVINTERFACE_VOLUME:TGUID='{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}'; GUID_DEVINTERFACE_DISK:TGUID='{53f56307-b6bf-11d0-94f2-00a0c91efb8b}'; GUID_DEVCLASS_DISKDRIVE: TGUID = (D1: $4D36E967; D2: $E325; D3: $11CE; D4: ($BF, $C1, $08, $00, $2B, $E1, $03, $18)); SPDRP_DEVICEDESC = $00000000; // DeviceDesc (R/W) {$EXTERNALSYM SPDRP_DEVICEDESC} SPDRP_HARDWAREID = $00000001; // HardwareID (R/W) {$EXTERNALSYM SPDRP_HARDWAREID} SPDRP_COMPATIBLEIDS = $00000002; // CompatibleIDs (R/W) {$EXTERNALSYM SPDRP_COMPATIBLEIDS} SPDRP_UNUSED0 = $00000003; // unused {$EXTERNALSYM SPDRP_UNUSED0} SPDRP_SERVICE = $00000004; // Service (R/W) {$EXTERNALSYM SPDRP_SERVICE} SPDRP_UNUSED1 = $00000005; // unused {$EXTERNALSYM SPDRP_UNUSED1} SPDRP_UNUSED2 = $00000006; // unused {$EXTERNALSYM SPDRP_UNUSED2} SPDRP_CLASS = $00000007; // Class (R--tied to ClassGUID) {$EXTERNALSYM SPDRP_CLASS} SPDRP_CLASSGUID = $00000008; // ClassGUID (R/W) {$EXTERNALSYM SPDRP_CLASSGUID} SPDRP_DRIVER = $00000009; // Driver (R/W) {$EXTERNALSYM SPDRP_DRIVER} SPDRP_CONFIGFLAGS = $0000000A; // ConfigFlags (R/W) {$EXTERNALSYM SPDRP_CONFIGFLAGS} SPDRP_MFG = $0000000B; // Mfg (R/W) {$EXTERNALSYM SPDRP_MFG} SPDRP_FRIENDLYNAME = $0000000C; // FriendlyName (R/W) {$EXTERNALSYM SPDRP_FRIENDLYNAME} SPDRP_LOCATION_INFORMATION = $0000000D; // LocationInformation (R/W) {$EXTERNALSYM SPDRP_LOCATION_INFORMATION} SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = $0000000E; // PhysicalDeviceObjectName (R) {$EXTERNALSYM SPDRP_PHYSICAL_DEVICE_OBJECT_NAME} SPDRP_CAPABILITIES = $0000000F; // Capabilities (R) {$EXTERNALSYM SPDRP_CAPABILITIES} SPDRP_UI_NUMBER = $00000010; // UiNumber (R) {$EXTERNALSYM SPDRP_UI_NUMBER} SPDRP_UPPERFILTERS = $00000011; // UpperFilters (R/W) {$EXTERNALSYM SPDRP_UPPERFILTERS} SPDRP_LOWERFILTERS = $00000012; // LowerFilters (R/W) {$EXTERNALSYM SPDRP_LOWERFILTERS} SPDRP_BUSTYPEGUID = $00000013; // BusTypeGUID (R) {$EXTERNALSYM SPDRP_BUSTYPEGUID} SPDRP_LEGACYBUSTYPE = $00000014; // LegacyBusType (R) {$EXTERNALSYM SPDRP_LEGACYBUSTYPE} SPDRP_BUSNUMBER = $00000015; // BusNumber (R) {$EXTERNALSYM SPDRP_BUSNUMBER} SPDRP_ENUMERATOR_NAME = $00000016; // Enumerator Name (R) {$EXTERNALSYM SPDRP_ENUMERATOR_NAME} SPDRP_SECURITY = $00000017; // Security (R/W, binary form) {$EXTERNALSYM SPDRP_SECURITY} SPDRP_SECURITY_SDS = $00000018; // Security (W, SDS form) {$EXTERNALSYM SPDRP_SECURITY_SDS} SPDRP_DEVTYPE = $00000019; // Device Type (R/W) {$EXTERNALSYM SPDRP_DEVTYPE} SPDRP_EXCLUSIVE = $0000001A; // Device is exclusive-access (R/W) {$EXTERNALSYM SPDRP_EXCLUSIVE} SPDRP_CHARACTERISTICS = $0000001B; // Device Characteristics (R/W) {$EXTERNALSYM SPDRP_CHARACTERISTICS} SPDRP_ADDRESS = $0000001C; // Device Address (R) {$EXTERNALSYM SPDRP_ADDRESS} {$IFDEF WINXP_UP} SPDRP_UI_NUMBER_DESC_FORMAT = $0000001D; // UiNumberDescFormat (R/W) {$EXTERNALSYM SPDRP_UI_NUMBER_DESC_FORMAT} SPDRP_DEVICE_POWER_DATA = $0000001E; // Device Power Data (R) {$EXTERNALSYM SPDRP_DEVICE_POWER_DATA} SPDRP_REMOVAL_POLICY = $0000001F; // Removal Policy (R) {$EXTERNALSYM SPDRP_REMOVAL_POLICY} SPDRP_REMOVAL_POLICY_HW_DEFAULT = $00000020; // Hardware Removal Policy (R) {$EXTERNALSYM SPDRP_REMOVAL_POLICY_HW_DEFAULT} SPDRP_REMOVAL_POLICY_OVERRIDE = $00000021; // Removal Policy Override (RW) {$EXTERNALSYM SPDRP_REMOVAL_POLICY_OVERRIDE} SPDRP_INSTALL_STATE = $00000022; // Device Install State (R) {$EXTERNALSYM SPDRP_INSTALL_STATE} SPDRP_MAXIMUM_PROPERTY = $00000023; // Upper bound on ordinals {$EXTERNALSYM SPDRP_MAXIMUM_PROPERTY} {$ELSE} SPDRP_UI_NUMBER_DESC_FORMAT = $0000001E; // UiNumberDescFormat (R/W) {$EXTERNALSYM SPDRP_UI_NUMBER_DESC_FORMAT} SPDRP_MAXIMUM_PROPERTY = $0000001F; // Upper bound on ordinals {$EXTERNALSYM SPDRP_MAXIMUM_PROPERTY} {$ENDIF WINXP_UP} SPCRP_SECURITY = $00000017; // Security (R/W, binary form) {$EXTERNALSYM SPCRP_SECURITY} SPCRP_SECURITY_SDS = $00000018; // Security (W, SDS form) {$EXTERNALSYM SPCRP_SECURITY_SDS} SPCRP_DEVTYPE = $00000019; // Device Type (R/W) {$EXTERNALSYM SPCRP_DEVTYPE} SPCRP_EXCLUSIVE = $0000001A; // Device is exclusive-access (R/W) {$EXTERNALSYM SPCRP_EXCLUSIVE} SPCRP_CHARACTERISTICS = $0000001B; // Device Characteristics (R/W) {$EXTERNALSYM SPCRP_CHARACTERISTICS} SPCRP_MAXIMUM_PROPERTY = $0000001C; // Upper bound on ordinals {$EXTERNALSYM SPCRP_MAXIMUM_PROPERTY} type HDEVINFON = THandle; HDEVINFO = Pointer; PSP_DEVINFO_DATA = ^SP_DEVINFO_DATA; PSPDevInfoData = ^TSPDevInfoData; SP_DEVINFO_DATA = packed record cbSize: DWORD; ClassGuid: TGUID; DevInst: DWORD; Reserved: DWORD; end; TSPDevInfoData = SP_DEVINFO_DATA; PSTORAGE_DEVICE_NUMBER = ^STORAGE_DEVICE_NUMBER; STORAGE_DEVICE_NUMBER = packed record DeviceType: DWORD; DeviceNumber: Longint; PartitionNumber: Longint; end; TSTORAGE_DEVICE_NUMBER = STORAGE_DEVICE_NUMBER; type PSPDeviceInterfaceData = ^TSPDeviceInterfaceData; SP_DEVICE_INTERFACE_DATA = packed record cbSize: DWORD; InterfaceClassGuid: TGUID; Flags: DWORD; Reserved: DWORD; end; TSPDeviceInterfaceData = SP_DEVICE_INTERFACE_DATA; type PSPDeviceInterfaceDetailData = ^TSPDeviceInterfaceDetailData; SP_DEVICE_INTERFACE_DETAIL_DATA_A = packed record cbSize: DWORD; DevicePath: array [0..ANYSIZE_ARRAY - 1] of AnsiChar; end; TSPDeviceInterfaceDetailData = SP_DEVICE_INTERFACE_DETAIL_DATA_A; TUSBDev = class(TObject) private public FDeviceID: DWORD; FDevicePath: Ansistring; FCapabilities: DWORD; FClassDescr: Ansistring; FClassGUID: Ansistring; FCompatibleIDs: TStringList; FConfigFlags: DWORD; FDeviceDescr: Ansistring; FDriver: Ansistring; FFriendlyName: Ansistring; FHardwareID: TStringList; FLowerFilters: TStringList; FMfg: Ansistring; FUpperFilters: TStringList; FAddress: Ansistring; FBusNumber: DWORD; FBusType: Ansistring; FCharacteristics: Ansistring; FDevType: DWORD; FEnumeratorName: Ansistring; FExclusive: DWORD; FLegacyBusType: DWORD; FLocationInfo: Ansistring; FPhysDevObjName: Ansistring; FSecuritySDS: Ansistring; FService: Ansistring; FUINumber: DWORD; FUINumberFormat: Ansistring; FDevData: TSPDevInfoData; FPnPHandle: HDEVINFO; constructor Create; procedure GetInfoForDev(APnPHandle: HDEVINFO; ADevData: TSPDevInfoData; ADevicePath: PAnsiChar); function GetRegistryPropertyDWord(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): DWORD; function GetRegistryPropertyString(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): Ansistring; function GetRegistryPropertyStringList(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): TStringList; end; function GetTempDir: Ansistring; function GetDevNum(aPath: Ansistring): LongInt; function USBDeviceFind(GUID:TGUID; aPhysDevObjName: Ansistring): TUSBDev; //function GetDEVID(aDevPath: string): string; function GetDEVID(aDevPath: Ansistring): Ansistring; //function GetDEVIDOther(aDevPath: string): string; function GetDEVIDOther(aDevPath: AnsiString): AnsiString; //function GetDEVIDOtherSCSI(aDevPath: string): string; function GetDEVIDOtherSCSI(aDevPath: AnsiString): AnsiString; //function IsRemoveable(aDevPath: string): Boolean; function IsRemoveable(aDevPath: Ansistring): Boolean; function IsRemoveableUSBHard(aDevPath: Ansistring): Boolean; //procedure EjectDrive(aDrive: string); procedure EjectDrive(aDrive: Ansistring); procedure SelfRemoteEject; function EnumDiskDriveVista(aDevSerial: Ansistring): Ansistring; function USBDeviceSerial(GUID:TGUID; aPhysDevNumber: LongInt): Ansistring; function USBDeviceSerialSCSI(GUID:TGUID; aPhysDevNumber: LongInt): Ansistring; var G_PARENT_SCSI: Ansistring; G_FHardwareID0: Ansistring; implementation function SetupDiGetDeviceRegistryProperty(DeviceInfoSet: HDEVINFO; const DeviceInfoData: TSPDevInfoData; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSize: DWORD; var RequiredSize: DWORD): LongBool; stdcall; external SetupApiModuleName name 'SetupDiGetDeviceRegistryPropertyA'; function SetupDiGetClassDevs(ClassGuid: PGUID; const Enumerator: PAnsiChar; hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall; external SetupApiModuleName name 'SetupDiGetClassDevsA'; function SetupDiEnumDeviceInfo(DeviceInfoSet: HDEVINFO; MemberIndex: DWORD; var DeviceInfoData: TSPDevInfoData): LongBool; stdcall; external SetupApiModuleName name 'SetupDiEnumDeviceInfo'; function SetupDiEnumDeviceInterfaces(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; const InterfaceClassGuid: TGUID; MemberIndex: DWORD; var DeviceInterfaceData: TSPDeviceInterfaceData): LongBool; stdcall; external SetupApiModuleName name 'SetupDiEnumDeviceInterfaces'; function SetupDiGetDeviceInterfaceDetail(DeviceInfoSet: HDEVINFO; DeviceInterfaceData: PSPDeviceInterfaceData; DeviceInterfaceDetailData: PSPDeviceInterfaceDetailData; DeviceInterfaceDetailDataSize: DWORD; var RequiredSize: DWORD; Device: PSPDevInfoData): LongBool; stdcall; external SetupApiModuleName name 'SetupDiGetDeviceInterfaceDetailA'; //function GetVolumeNameForVolumeMountPoint(volumeName: string; // uniqueVolumeName: PChar; // uniqueNameBufferCapacity: integer): LongBool; stdcall; external 'kernel32.dll' name 'GetVolumeNameForVolumeMountPointA'; function SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO): LongBool; stdcall; external SetupApiModuleName name 'SetupDiDestroyDeviceInfoList'; function GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint: LPCSTR; lpszVolumeName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall; external 'kernel32.dll' name 'GetVolumeNameForVolumeMountPointA'; function CM_Get_Parent(pdnDevInst: PDWORD; dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Get_Device_ID_Size(pulLen: PDWORD; dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Get_Device_IDA(dnDevInst: DWORD; Buffer: PAnsiChar; BufferLen: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Locate_DevNodeA(pdnDevInst: PDWORD; pDeviceID: PAnsiChar; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Request_Device_EjectA(dnDevInst: DWORD; pVetoType: Pointer; pszVetoName: PAnsiChar; ulNameLength: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Query_And_Remove_SubTree(dnDevInst: DWORD; pVetoType: Pointer; pszVetoName: PAnsiChar; ulNameLength: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi name 'CM_Query_And_Remove_SubTreeA'; function SetupDiGetClassDevsA(ClassGuid: PGUID; Enumerator: PAnsiChar; hwndParent: HWND; Flags: DWORD): HDEVINFON; stdcall; external setupapi name 'SetupDiGetClassDevsA'; function SetupDiEnumDeviceInfoN(DeviceInfoSet: HDEVINFON; MemberIndex: DWORD; DeviceInfoData: PSP_DEVINFO_DATA): boolean; stdcall; external setupapi name 'SetupDiEnumDeviceInfo'; function SetupDiDestroyDeviceInfoListN(DeviceInfoSet: HDEVINFON): boolean; stdcall; external setupapi name 'SetupDiDestroyDeviceInfoList'; function GetDeviceName(aDevInst: THandle): Ansistring; var IDLen: Integer; begin Result := ''; if (CM_Get_Device_ID_Size(@IDLen, aDevInst, 0) = CR_SUCCESS) and (IDLen > 0) then begin SetLength(Result, IDLen); if CM_Get_Device_IDA(aDevInst, PAnsiChar(Result), IDLen + 1, 0) <> CR_SUCCESS then Result := '' end end; // при создании лицензии передается результаты функции GetDEVIDOther(aDrive); // при проверке - передается из зашифрованого файлика строчка. function EnumDiskDriveVista(aDevSerial: Ansistring): Ansistring; var hDevInfoSet: HDEVINFON; DevInfo: SP_DEVINFO_DATA; i: Integer; str1: Ansistring; begin result := ''; DevInfo.cbSize := sizeof(SP_DEVINFO_DATA); hDevInfoSet := SetupDiGetClassDevsA(@GUID_DEVCLASS_DISKDRIVE, nil, 0, 2); i := 0; if hDevInfoSet <> INVALID_HANDLE_VALUE then begin while (SetupDiEnumDeviceInfoN(hDevInfoSet, i, @DevInfo)) do begin str1 := GetDeviceName(DevInfo.DevInst); if pos(aDevSerial, AnsiLowerCase(str1)) > 0 then begin result := AnsiLowerCase(str1); break; end; Inc(i) end; SetupDiDestroyDeviceInfoListN(hDevInfoSet); end end; { TUSBDev } constructor TUSBDev.Create; begin inherited; end; procedure TUSBDev.GetInfoForDev(APnPHandle: HDEVINFO; ADevData: TSPDevInfoData; ADevicePath: PAnsiChar); begin FDeviceID := ADevData.DevInst; FDevicePath := ADevicePath; FDevData := ADevData; FPnPHandle := APnPHandle; // primary information FCapabilities := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_CAPABILITIES); FClassDescr := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_CLASS); FClassGUID := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_CLASSGUID); FCompatibleIDs := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_COMPATIBLEIDS); FConfigFlags := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_CONFIGFLAGS); FDeviceDescr := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_DEVICEDESC); FDriver := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_DRIVER); FFriendlyName := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_FRIENDLYNAME); FHardwareID := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_HARDWAREID); FLowerFilters := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_LOWERFILTERS); FMfg := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_MFG); FUpperFilters := GetRegistryPropertyStringList(APnPHandle, ADevData, SPDRP_UPPERFILTERS); FService := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_SERVICE); // secondary information not all likely to exist for a HID device FAddress := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_ADDRESS); FBusNumber := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_BUSNUMBER); FBusType := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_BUSTYPEGUID); FCharacteristics := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_CHARACTERISTICS); FDevType := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_DEVTYPE); FEnumeratorName := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_ENUMERATOR_NAME); FExclusive := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_EXCLUSIVE); FLegacyBusType := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_LEGACYBUSTYPE); FLocationInfo := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_LOCATION_INFORMATION); FPhysDevObjName := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME); FSecuritySDS := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_SECURITY_SDS); FUINumber := GetRegistryPropertyDWord(APnPHandle, ADevData, SPDRP_UI_NUMBER); FUINumberFormat := GetRegistryPropertyString(APnPHandle, ADevData, SPDRP_UI_NUMBER_DESC_FORMAT); end; function TUSBDev.GetRegistryPropertyDWord(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): DWORD; var BytesReturned: DWORD; RegDataType: DWORD; begin BytesReturned := 0; RegDataType := 0; Result := 0; SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, Prop, RegDataType, PBYTE(@Result), SizeOf(Result), BytesReturned); end; function TUSBDev.GetRegistryPropertyString(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): Ansistring; var BytesReturned: DWORD; RegDataType: DWORD; Buffer: array [0..1023] of AnsiChar; begin BytesReturned := 0; RegDataType := 0; Buffer[0] := #0; SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, Prop, RegDataType, PByte(@Buffer[0]), SizeOf(Buffer), BytesReturned); Result := Buffer; end; function TUSBDev.GetRegistryPropertyStringList(PnPHandle: HDEVINFO; const DevData: TSPDevInfoData; Prop: DWORD): TStringList; var BytesReturned: DWORD; RegDataType: DWORD; Buffer: array [0..16383] of AnsiChar; P: PAnsiChar; begin BytesReturned := 0; RegDataType := 0; Buffer[0] := #0; SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, Prop, RegDataType, PBYTE(@Buffer[0]), SizeOf(Buffer), BytesReturned); Result := TStringList.Create; P := @Buffer[0]; while P[0] <> #0 do begin Result.Add(P); P := P + StrLen(P) + 1; end; end; function GetTempDir: Ansistring; var buff: pchar; s: string; begin // Tolik 24/06/2019 -- s := ''; s := GetEnvironmentVariable('tmp'); if ((s = '') or (not DirectoryExists(s))) then begin s := GetEnvironmentVariable('temp'); if ((s = '') or (not DirectoryExists(s))) then s := 'c:\'; end; { // Tolik 21/06/2019 - - //getmem(buff, 1255); getmem(buff, 1255*2); // s := ''; if (GetEnvironmentVariable('tmp', buff, 1254) > 0) and (DirectoryExists(buff)) then begin s := buff; end else if (GetEnvironmentVariable('temp',buff, 1254) >0) and (DirectoryExists(buff)) then begin s := buff; end else s := 'c:\'; freemem(buff, 1255); } // result := s; end; function USBDeviceFind(GUID:TGUID; aPhysDevObjName: Ansistring): TUSBDev; var PnPHandle: HDEVINFO; DevData: TSPDevInfoData; DeviceInterfaceData: TSPDeviceInterfaceData; FunctionClassDeviceData: PSPDeviceInterfaceDetailData; Success: LongBool; Devn: Integer; BytesReturned: DWORD; aUSBDev: TUSBDev; begin try Result := nil; PnPHandle:= SetupDiGetClassDevs(@Guid, nil, 0,DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then Exit; try Devn := 0; repeat DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData); Success := SetupDiEnumDeviceInterfaces(PnPHandle, nil, Guid, Devn, DeviceInterfaceData); if Success then begin DevData.cbSize := SizeOf(SP_DEVINFO_DATA); DeviceInterfaceData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DATA); BytesReturned := 0; SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData); if (BytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin FunctionClassDeviceData := AllocMem(BytesReturned); try FunctionClassDeviceData.cbSize := 5; if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, FunctionClassDeviceData, BytesReturned, BytesReturned, @DevData) then begin aUSBDev := TUSBDev.Create; aUSBDev.GetInfoForDev(PnPHandle, DevData, @FunctionClassDeviceData.DevicePath); if aPhysDevObjName = aUSBDev.FPhysDevObjName then begin result := aUSBDev; break; end else aUSBDev.Free; end; Inc(Devn); finally FreeMem(FunctionClassDeviceData); end; end; end; until not Success; finally if result = nil then SetupDiDestroyDeviceInfoList(PnPHandle); end; finally end; end; function USBDeviceEject(GUID:TGUID; aPhysDevNumber: LongInt): Boolean; var PnPHandle: HDEVINFO; DevData: TSPDevInfoData; DeviceInterfaceData: TSPDeviceInterfaceData; FunctionClassDeviceData: PSPDeviceInterfaceDetailData; Success: LongBool; Devn: Integer; BytesReturned: DWORD; i: integer; aUSBDev: TUSBDev; Parent: DWORD; VetoName: PAnsiChar; begin try Result := False; PnPHandle:= SetupDiGetClassDevs(@Guid, nil, 0,DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then Exit; try Devn := 0; repeat DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData); Success := SetupDiEnumDeviceInterfaces(PnPHandle, nil, Guid, Devn, DeviceInterfaceData); if Success then begin DevData.cbSize := SizeOf(SP_DEVINFO_DATA); DeviceInterfaceData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DATA); BytesReturned := 0; SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData); if (BytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin FunctionClassDeviceData := AllocMem(BytesReturned); try FunctionClassDeviceData.cbSize := 5; if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, FunctionClassDeviceData, BytesReturned, BytesReturned, @DevData) then begin aUSBDev := TUSBDev.Create; aUSBDev.GetInfoForDev(PnPHandle, DevData, @FunctionClassDeviceData.DevicePath); if aPhysDevNumber = GetDevNum(aUSBDev.FDevicePath) then begin if CM_Get_Parent(@Parent, aUSBDev.FDevData.DevInst, 0) = 0 then begin sleep(200); // Tolik 21/06/2019 -- //VetoName := GetMemory(260); VetoName := GetMemory(260*2); // // if (CM_Request_Device_EjectA(aUSBDev.FDevData.DevInst, nil, VetoName, 260, 0) <> 0) then // if (CM_Query_And_Remove_SubTree(aUSBDev.FDevData.DevInst, nil, VetoName, 260, 0) <> 0) then // if (CM_Query_And_Remove_SubTree(Parent, nil, VetoName, 260, 0) <> 0) then if (CM_Request_Device_EjectA(Parent, nil, VetoName, 260, 0) <> 0) then begin if (CM_Locate_DevNodeA(@Parent, VetoName, 0) <> 0) then begin FreeMemory(VetoName); exit; end; FreeMemory(VetoName); if (CM_Request_Device_EjectA(Parent, nil, nil, 0, 0) <> 0) then exit else result := True; end else result := True; FreeMemory(VetoName); end; aUSBDev.Free; break; end else aUSBDev.Free; end; Inc(Devn); finally FreeMem(FunctionClassDeviceData); end; end; end; until not Success; finally end; finally SetupDiDestroyDeviceInfoList(PnPHandle); end; end; function USBDeviceSerial(GUID:TGUID; aPhysDevNumber: LongInt): Ansistring; var PnPHandle: HDEVINFO; DevData: TSPDevInfoData; DeviceInterfaceData: TSPDeviceInterfaceData; FunctionClassDeviceData: PSPDeviceInterfaceDetailData; Success: LongBool; Devn: Integer; BytesReturned: DWORD; i: integer; aUSBDev: TUSBDev; Parent: DWORD; VetoName: PAnsiChar; begin try Result := ''; PnPHandle:= SetupDiGetClassDevs(@Guid, nil, 0,DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then Exit; try Devn := 0; repeat DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData); Success := SetupDiEnumDeviceInterfaces(PnPHandle, nil, Guid, Devn, DeviceInterfaceData); if Success then begin DevData.cbSize := SizeOf(SP_DEVINFO_DATA); DeviceInterfaceData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DATA); BytesReturned := 0; SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData); if (BytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin FunctionClassDeviceData := AllocMem(BytesReturned); try FunctionClassDeviceData.cbSize := 5; if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, FunctionClassDeviceData, BytesReturned, BytesReturned, @DevData) then begin aUSBDev := TUSBDev.Create; aUSBDev.GetInfoForDev(PnPHandle, DevData, @FunctionClassDeviceData.DevicePath); if aPhysDevNumber = GetDevNum(aUSBDev.FDevicePath) then begin result := aUSBDev.FDevicePath; aUSBDev.Free; break; end else aUSBDev.Free; end; Inc(Devn); finally FreeMem(FunctionClassDeviceData); end; end; end; until not Success; finally end; finally SetupDiDestroyDeviceInfoList(PnPHandle); end; end; function USBDeviceSerialSCSI(GUID:TGUID; aPhysDevNumber: LongInt): Ansistring; var PnPHandle: HDEVINFO; DevData: TSPDevInfoData; DeviceInterfaceData: TSPDeviceInterfaceData; FunctionClassDeviceData: PSPDeviceInterfaceDetailData; Success: LongBool; Devn: Integer; BytesReturned: DWORD; i: integer; aUSBDev: TUSBDev; Parent: DWORD; VetoName: PAnsiChar; begin try Result := ''; G_PARENT_SCSI := ''; G_FHardwareID0 := ''; PnPHandle:= SetupDiGetClassDevs(@Guid, nil, 0,DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then Exit; try Devn := 0; repeat DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData); Success := SetupDiEnumDeviceInterfaces(PnPHandle, nil, Guid, Devn, DeviceInterfaceData); if Success then begin DevData.cbSize := SizeOf(SP_DEVINFO_DATA); DeviceInterfaceData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DATA); BytesReturned := 0; SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData); if (BytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin FunctionClassDeviceData := AllocMem(BytesReturned); try FunctionClassDeviceData.cbSize := 5; if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, FunctionClassDeviceData, BytesReturned, BytesReturned, @DevData) then begin aUSBDev := TUSBDev.Create; aUSBDev.GetInfoForDev(PnPHandle, DevData, @FunctionClassDeviceData.DevicePath); if aPhysDevNumber = GetDevNum(aUSBDev.FDevicePath) then begin if CM_Get_Parent(@Parent, aUSBDev.FDevData.DevInst, 0) = 0 then begin //Tolik 21/06/2019 -- //VetoName := GetMemory(260); VetoName := GetMemory(256*2); // CM_Get_Device_IDA(Parent, VetoName, 200, 0); G_PARENT_SCSI := VetoName; if Pos('USB\', G_PARENT_SCSI) = 1 then begin if aUSBDev.FHardwareID.Count > 0 then G_FHardwareID0 := aUSBDev.FHardwareID[0]; end else G_PARENT_SCSI := ''; //showmessage('veto name - ' + VetoName); //showmessage('Hardware ids - ' + aUSBDev.FHardwareID[0]); FreeMemory(VetoName); end; if G_PARENT_SCSI <> '' then begin result := aUSBDev.FDevicePath; aUSBDev.Free; break; end else aUSBDev.Free; end else begin aUSBDev.Free; end; end; Inc(Devn); finally FreeMem(FunctionClassDeviceData); end; end; end; until not Success; finally end; finally SetupDiDestroyDeviceInfoList(PnPHandle); end; end; function GetDevNum(aPath: Ansistring): LongInt; var hFile: THandle; DevNum: TSTORAGE_DEVICE_NUMBER; tmp: Dword; begin result := 0; hFile := CreateFileA(PAnsiChar(aPath), 0 {GENERIC_READ} { $C0}, FILE_SHARE_READ OR FILE_SHARE_WRITE {4}, nil, OPEN_EXISTING {3}, 0 {FILE_ATTRIBUTE_NORMAL}, 0); // hFile := CreateFile(PChar(aPath), $C0, 4, nil, 3, FILE_ATTRIBUTE_NORMAL, 0); if hFile > 0 then begin DeviceIoControl(hFile, IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @DevNum, sizeof(DevNum), Tmp, nil); Result := DevNum.DeviceNumber; end; CloseHandle(hFile); end; function GetDEVID(aDevPath: Ansistring): Ansistring; var TempStr: Ansistring; //ResDosDev : Array [1..MAX_PATH] of Char; ResDosDev : Array [1..MAX_PATH] of AnsiChar; aUSBDev: TUSBDev; DevNumber: LongInt; begin result := ''; try If (QueryDosDeviceA(PAnsiChar(aDevPath), @ResDosDev, MAX_PATH) <> 0) then begin //TempStr := StrPas(@ResDosDev); //TempStr := StrPas(ResDosDev); TempStr := StrPas(PAnsiChar(@ResDosDev)); aUSBDev := USBDeviceFind(GUID_DEVINTERFACE_VOLUME, TempStr); if assigned(aUSBDev) then begin if (Pos('removablemedia', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) or (Pos('usbstor', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) then// or (Pos('scsi#disk', AnsiLowerCase(TempStr)) > 0) then begin DevNumber := GetDevNum(aUSBDev.FDevicePath); tempstr := AnsiLowerCase(USBDeviceSerial(GUID_DEVINTERFACE_DISK, DevNumber)); end; tempstr := copy(tempstr, pos('&rev', tempstr), pos('{', tempstr) - pos('&rev', tempstr) - 1); tempstr := FastReplace(tempstr, '#', '\'); result := tempstr; SetupDiDestroyDeviceInfoList(aUSBDev.FPnPHandle); aUSBDev.Free; end; end; except end; end; function GetDEVIDOther(aDevPath: Ansistring): Ansistring; var TempStr: Ansistring; ResDosDev : Array [1..MAX_PATH] of AnsiChar; aUSBDev: TUSBDev; DevNumber: LongInt; begin result := ''; try If (QueryDosDeviceA(PAnsiChar(aDevPath), @ResDosDev, MAX_PATH) <> 0) then begin TempStr := StrPas(PAnsiChar(@ResDosDev)); aUSBDev := USBDeviceFind(GUID_DEVINTERFACE_VOLUME, TempStr); if assigned(aUSBDev) then begin DevNumber := GetDevNum(aUSBDev.FDevicePath); SetupDiDestroyDeviceInfoList(aUSBDev.FPnPHandle); aUSBDev.Free; result := USBDeviceSerial(GUID_DEVINTERFACE_DISK, DevNumber); if result <> '' then begin if (Pos('usbstor', AnsiLowerCase(result)) <= 0) and (Pos('scsi#disk', AnsiLowerCase(result)) <= 0) then result := '' else begin //если scsi - получить другой серийник и отдельно парента заполнить; if (Pos('scsi#disk', AnsiLowerCase(result)) > 0) then begin //ShowMessage(result); Result := GetDEVIDOtherSCSI(aDevPath); end; end; end; end; end; except end; end; function GetDEVIDOtherSCSI(aDevPath: Ansistring): Ansistring; var TempStr: Ansistring; TempStr2: Ansistring; TempStrExcl: Ansistring; ResDosDev : Array [1..MAX_PATH] of AnsiChar; aUSBDev: TUSBDev; DevNumber: LongInt; tempstrlist: TStringList; i: integer; begin result := ''; try If (QueryDosDeviceA(PAnsiChar(aDevPath), @ResDosDev, MAX_PATH) <> 0) then begin TempStr := StrPas(PAnsiChar(@ResDosDev)); aUSBDev := USBDeviceFind(GUID_DEVINTERFACE_VOLUME, TempStr); if assigned(aUSBDev) then begin DevNumber := GetDevNum(aUSBDev.FDevicePath); SetupDiDestroyDeviceInfoList(aUSBDev.FPnPHandle); aUSBDev.Free; result := USBDeviceSerialSCSI(GUID_DEVINTERFACE_DISK, DevNumber); if result <> '' then begin if (Pos('usbstor', AnsiLowerCase(result)) <= 0) and (Pos('scsi#disk', AnsiLowerCase(result)) <= 0) then result := '' else begin //if (Pos('scsi#disk', AnsiLowerCase(result)) <= 0) then begin tempstr := ''; if FileExists(ExtractFileDir(Application.ExeName) + '\usb_rev.ini') then begin tempstrlist := TStringList.Create; tempstrlist.LoadFromFile(ExtractFileDir(Application.ExeName) + '\usb_rev.ini'); tempstr := trim(ansilowercase(tempstrlist.Text)); tempstrlist.Free; end else begin tempstr := ansilowercase(G_FHardwareID0); if Pos('____', tempstr) > 0 then begin tempstr := trim(copy(tempstr, Pos('____', tempstr), $FFFF)); tempstr := trim(FastReplace(TempStr, '_', '')); end; end; TempStr2 := ''; if length(G_PARENT_SCSI) > 0 then begin for i := length(G_PARENT_SCSI) downto 1 do begin if G_PARENT_SCSI[i] <> '\' then TempStr2 := G_PARENT_SCSI[i] + TempStr2 else break; end; end; TempStr2 := Trim(AnsiLowerCase(TempStr2)); if FileExists(ExtractFileDir(Application.ExeName) + '\usb_excl.ini') then begin tempstrlist := TStringList.Create; tempstrlist.LoadFromFile(ExtractFileDir(Application.ExeName) + '\usb_excl.ini'); TempStrExcl := trim(ansilowercase(tempstrlist.Text)); tempstrlist.Free; end else begin TempStrExcl := 'msft30'; end; TempStr2 := FastReplace(TempStr2, TempStrExcl, '', False); result := 'scsi#disk&rev_' + TempStr + '#' + TempStr2 + '&0#{'; end; end; end; end; end; except end; end; //function IsRemoveable(aDevPath: string): Boolean; function IsRemoveable(aDevPath: Ansistring): Boolean; var TempStr: Ansistring; ResDosDev : Array [1..MAX_PATH] of AnsiChar; aUSBDev: TUSBDev; DevNumber: LongInt; begin try result := False; If (QueryDosDeviceA(PAnsiChar(aDevPath), @ResDosDev, MAX_PATH) <> 0) then begin TempStr := StrPas(PAnsiChar(@ResDosDev)); aUSBDev := USBDeviceFind(GUID_DEVINTERFACE_VOLUME, TempStr); if assigned(aUSBDev) then begin if (Pos('removablemedia', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) or (Pos('usbstor', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) then //or (Pos('scsi#disk', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) then begin Result := True; end; SetupDiDestroyDeviceInfoList(aUSBDev.FPnPHandle); aUSBDev.Free; end; end; except end; end; function IsRemoveableUSBHard(aDevPath: Ansistring): Boolean; var TempStr: string; ResDosDev : Array [1..MAX_PATH] of AnsiChar; aUSBDev: TUSBDev; DevNumber: LongInt; begin try result := False; G_PARENT_SCSI := ''; tempstr := GetDEVIDOther(aDevPath); // если SCSI - автоматически вызовет GetDEVIDOtherSCSI который заполнит и GParent //if tempstr <> '' then // ShowMessage('IsRemoveableUSBHard tempstr = ' + tempstr); if (Pos('removablemedia', AnsiLowerCase(TempStr)) > 0) or (Pos('usbstor', AnsiLowerCase(TempStr)) > 0) or (Pos('scsi#disk', AnsiLowerCase(TempStr)) > 0) then begin if (Pos('scsi#disk', AnsiLowerCase(TempStr)) > 0) then begin //проверить парента - должен быть USB // по идеи сюда уже не должны попасть //ShowMessage('G_PARENT_SCSI = ' + G_PARENT_SCSI); if Pos('USB\', G_PARENT_SCSI) = 1 then Result := True; end else Result := True; end; except end; end; procedure EjectDrive(aDrive: Ansistring); var aUSBDev: TUSBDev; DevNumber: LongInt; ResDosDev : Array [1..MAX_PATH] of AnsiChar; TempStr: Ansistring; begin try If (QueryDosDeviceA(PAnsiChar(aDrive), @ResDosDev, MAX_PATH) <> 0) then begin sleep(1500); TempStr := StrPas(PAnsiChar(@ResDosDev)); aUSBDev := USBDeviceFind(GUID_DEVINTERFACE_VOLUME, TempStr); if assigned(aUSBDev) then begin if (Pos('removablemedia', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) or (Pos('usbstor', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) or (Pos('scsi#disk', AnsiLowerCase(aUSBDev.FDevicePath)) > 0)then begin DevNumber := GetDevNum(aUSBDev.FDevicePath); USBDeviceEject(GUID_DEVINTERFACE_DISK, DevNumber); end {TODO: USB Fixed} else tempstr := GetDEVIDOther(aDrive); if (Pos('removablemedia', AnsiLowerCase(TempStr)) > 0) or (Pos('usbstor', AnsiLowerCase(TempStr)) > 0) or (Pos('scsi#disk', AnsiLowerCase(aUSBDev.FDevicePath)) > 0) then begin DevNumber := GetDevNum(aUSBDev.FDevicePath); USBDeviceEject(GUID_DEVINTERFACE_DISK, DevNumber); end; {TODO: END} SetupDiDestroyDeviceInfoList(aUSBDev.FPnPHandle); aUSBDev.Free; end; end; except end; end; procedure SelfRemoteEject; var TempStr1: Ansistring; Handle: THandle; begin try TempStr1 := ExtractFileDir(Application.ExeName); DeleteFile(PChar(GetTempDir + '\EjectUSB.exe')); // if Not FileExists(GetTempDir + '\EjectUSB.exe') then CopyFile(PChar(TempStr1 + '\EjectUSB.exe'), PChar(GetTempDir + '\EjectUSB.exe'), False); TempStr1 := copy(TempStr1, 1, 2); // sleep(100); Handle := GetDesktopWindow; ShellExecute(Handle, PChar('open'), PChar(GetTempDir + '\EjectUSB.exe'), PChar(TempStr1), PChar(GetTempDir), SW_HIDE); except end; end; end.