{*******************************************************} { } { Tocsg.Driver } { } { Copyright (C) 2022 kku } { } {*******************************************************} unit Tocsg.Driver; interface uses Winapi.Windows, EM.winioctl, System.Classes, System.SysUtils, Tocsg.Obj; const FAIL_EJECT = '!FAIL'; METHOD_BUFFERED = 0; METHOD_IN_DIRECT = 1; METHOD_OUT_DIRECT = 2; METHOD_NEITHER = 3; IOCTL_DISK_BASE = FILE_DEVICE_DISK; IOCTL_VOLUME_BASE = DWORD('V'); {$EXTERNALSYM IOCTL_VOLUME_BASE} IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = ( (IOCTL_VOLUME_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or (0 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS} /////// GPT를 인식하기 위해 추가 2011-02-10 sunk IOCTL_DISK_GET_PARTITION_INFO = ( (IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0001 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_GET_PARTITION_INFO} IOCTL_DISK_SET_PARTITION_INFO = ( (IOCTL_DISK_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0002 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_SET_PARTITION_INFO} IOCTL_DISK_GET_DRIVE_LAYOUT = ( (IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0003 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_GET_DRIVE_LAYOUT} IOCTL_DISK_SET_DRIVE_LAYOUT = ( (IOCTL_DISK_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0004 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_SET_DRIVE_LAYOUT} IOCTL_VOLUME_IS_CLUSTERED = ( (IOCTL_VOLUME_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or (12 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_VOLUME_IS_CLUSTERED} IOCTL_DISK_GET_PARTITION_INFO_EX = ( (IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0012 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_GET_PARTITION_INFO_EX} IOCTL_DISK_SET_PARTITION_INFO_EX = ( (IOCTL_DISK_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0013 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_SET_PARTITION_INFO_EX} IOCTL_DISK_GET_DRIVE_LAYOUT_EX = ( (IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0014 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_GET_DRIVE_LAYOUT_EX} IOCTL_DISK_SET_DRIVE_LAYOUT_EX = ( (IOCTL_DISK_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or ($0015 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_SET_DRIVE_LAYOUT_EX} IOCTL_STORAGE_GET_DEVICE_NUMBER = ( (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0420 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_STORAGE_GET_DEVICE_NUMBER} IOCTL_DISK_GET_LENGTH_INFO = ( (IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0017 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_GET_LENGTH_INFO} IOCTL_DISK_GET_DRIVE_GEOMETRY_EX = ( (IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0028 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_DISK_GET_DRIVE_GEOMETRY_EX} IOCTL_STORAGE_QUERY_PROPERTY = ( (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0500 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_STORAGE_QUERY_PROPERTY} IOCTL_STORAGE_GET_MEDIA_TYPES_EX = ( (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0301 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_STORAGE_GET_MEDIA_TYPES_EX} IOCTL_STORAGE_MEDIA_REMOVAL = ( (IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0201 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_STORAGE_MEDIA_REMOVAL} IOCTL_STORAGE_EJECTION_CONTROL = $2D0940;//CTL_CODE(IOCTL_STORAGE_BASE, $0250, METHOD_BUFFERED, FILE_ANY_ACCESS); //$2D0940 {$EXTERNALSYM IOCTL_STORAGE_EJECTION_CONTROL} IOCTL_STORAGE_EJECT_MEDIA = ( (IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0202 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM IOCTL_STORAGE_EJECT_MEDIA} FSCTL_LOCK_VOLUME = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($0006 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_LOCK_VOLUME} FSCTL_UNLOCK_VOLUME = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($0007 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_UNLOCK_VOLUME} FSCTL_DISMOUNT_VOLUME = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($0008 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_DISMOUNT_VOLUME} FSCTL_IS_VOLUME_MOUNTED = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($000A shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_IS_VOLUME_MOUNTED} FSCTL_FILESYSTEM_GET_STATISTICS = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($0018 shl 2) or METHOD_BUFFERED); // FILESYSTEM_STATISTICS {$EXTERNALSYM FSCTL_FILESYSTEM_GET_STATISTICS} FSCTL_GET_NTFS_VOLUME_DATA = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($0019 shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_GET_NTFS_VOLUME_DATA} FSCTL_GET_NTFS_FILE_RECORD = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($001A shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_GET_NTFS_FILE_RECORD} FSCTL_GET_VOLUME_BITMAP = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($001B shl 2) or METHOD_NEITHER); {$EXTERNALSYM FSCTL_GET_VOLUME_BITMAP} FSCTL_GET_RETRIEVAL_POINTERS = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($001C shl 2) or METHOD_NEITHER); {$EXTERNALSYM FSCTL_GET_RETRIEVAL_POINTERS} FSCTL_MOVE_FILE = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_SPECIAL_ACCESS shl 14) or ($001D shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_MOVE_FILE} FSCTL_IS_VOLUME_DIRTY = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($001E shl 2) or METHOD_BUFFERED); {$EXTERNALSYM FSCTL_IS_VOLUME_DIRTY} FSCTL_ALLOW_EXTENDED_DASD_IO = ( (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or ($0020 shl 2) or METHOD_NEITHER); {$EXTERNALSYM FSCTL_ALLOW_EXTENDED_DASD_IO} GUID_DEVINTERFACE_DISK: TGUID = ( D1:$53f56307; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_DISK} GUID_DEVINTERFACE_CDROM: TGUID = ( D1:$53f56308; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); // GUID_DEVINTERFACE_CDROM: TGUID = '{53f56308-b6bf-11d0-94f2-00a0c91efb8b}'; {$EXTERNALSYM GUID_DEVINTERFACE_CDROM} GUID_DEVINTERFACE_PARTITION: TGUID = ( D1:$53f5630a; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_PARTITION} GUID_DEVINTERFACE_TAPE: TGUID = ( D1:$53f5630b; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_TAPE} GUID_DEVINTERFACE_WRITEONCEDISK: TGUID = ( D1:$53f5630c; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_WRITEONCEDISK} GUID_DEVINTERFACE_VOLUME: TGUID = ( D1:$53f5630d; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_VOLUME} GUID_DEVINTERFACE_MEDIUMCHANGER: TGUID = ( D1:$53f56310; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_MEDIUMCHANGER} GUID_DEVINTERFACE_FLOPPY: TGUID = ( D1:$53f56311; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_FLOPPY} GUID_DEVINTERFACE_CDCHANGER: TGUID = ( D1:$53f56312; D2:$b6bf; D3:$11d0; D4:($94, $f2, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_CDCHANGER} GUID_DEVINTERFACE_STORAGEPORT: TGUID = ( D1:$2accfe60; D2:$c130; D3:$11d2; D4:($b0, $82, $00, $a0, $c9, $1e, $fb, $8b)); {$EXTERNALSYM GUID_DEVINTERFACE_STORAGEPORT} GUID_DEVINTERFACE_COMPORT: TGUID = ( D1:$86e0d1e0; D2:$8089; D3:$11d0; D4:($9c, $e4, $08, $00, $3e, $30, $1f, $73)); {$EXTERNALSYM GUID_DEVINTERFACE_COMPORT} GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR: TGUID = ( D1:$4D36E978; D2:$E325; D3:$11CE; D4:($BF, $C1, $08, $00, $2B, $E1, $03, $18)); {$EXTERNALSYM GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR} GUID_DEVCLASS_NET: TGUID = ( D1:$4d36e972; D2:$e325; D3:$11ce; D4:($bf, $c1, $08, $00, $2b, $e1, $03, $18)); {$EXTERNALSYM GUID_DEVCLASS_NET} GUID_DEVCLASS_BLUETOOTH: TGUID = ( D1:$e0cbf06c; D2:$cd8b; D3:$4647; D4:($bb, $8a, $26, $3b, $43, $f0, $f9, $74)); {$EXTERNALSYM GUID_DEVCLASS_BLUETOOTH} GUID_DEVCLASS_USB: TGUID = ( D1:$36fc9e60; D2:$c465; D3:$11cf; D4:($80, $56, $44, $45, $53, $54, $00, $00)); {$EXTERNALSYM GUID_DEVCLASS_USB} GUID_DEVCLASS_USB_DEVICE: TGUID = ( D1:$88bae032; D2:$5a81; D3:$49f0; D4:($bc, $3d, $a4, $ff, $13, $82, $16, $d6)); {$EXTERNALSYM GUID_DEVCLASS_USB} GUID_DEVCLASS_WPD: TGUID = ( D1:$eec5ad98; D2:$8080; D3:$425f; D4:($92, $2a, $da, $bf, $3d, $e3, $f6, $9a)); {$EXTERNALSYM GUID_DEVCLASS_WPD} DIGCF_DEFAULT = $00000001; DIGCF_PRESENT = $00000002; DIGCF_ALLCLASSES = $00000004; DIGCF_PROFILE = $00000008; DIGCF_DEVICEINTERFACE = $00000010; SPDRP_DEVICEDESC = $00000000; // 설명 SPDRP_HARDWAREID = $00000001; SPDRP_COMPATIBLEIDS = $00000002; SPDRP_UNUSED0 = $00000003; SPDRP_SERVICE = $00000004; SPDRP_UNUSED1 = $00000005; SPDRP_UNUSED2 = $00000006; SPDRP_CLASS = $00000007; SPDRP_CLASSGUID = $00000008; SPDRP_DRIVER = $00000009; SPDRP_CONFIGFLAGS = $0000000A; SPDRP_MFG = $0000000B; // 업체명 SPDRP_FRIENDLYNAME = $0000000C; SPDRP_LOCATION_INFORMATION = $0000000D; SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = $0000000E; SPDRP_CAPABILITIES = $0000000F; SPDRP_UI_NUMBER = $00000010; SPDRP_UPPERFILTERS = $00000011; SPDRP_LOWERFILTERS = $00000012; SPDRP_BUSTYPEGUID = $00000013; SPDRP_LEGACYBUSTYPE = $00000014; SPDRP_BUSNUMBER = $00000015; SPDRP_ENUMERATOR_NAME = $00000016; SPDRP_SECURITY = $00000017; SPDRP_SECURITY_SDS = $00000018; SPDRP_DEVTYPE = $00000019; SPDRP_EXCLUSIVE = $0000001A; SPDRP_CHARACTERISTICS = $0000001B; SPDRP_ADDRESS = $0000001C; SPDRP_UI_NUMBER_DESC_FORMAT = $0000001D; SPDRP_DEVICE_POWER_DATA = $0000001E; SPDRP_REMOVAL_POLICY = $0000001F; SPDRP_LOCATION_PATHS = $00000023; SPDRP_BASE_CONTAINERID = $00000024; SPDRP_MAXIMUM_PROPERTY = $00000025; DN_ROOT_ENUMERATED = $00000001; // Was enumerated by ROOT DN_DRIVER_LOADED = $00000002; // Has Register_Device_Driver DN_ENUM_LOADED = $00000004; // Has Register_Enumerator DN_STARTED = $00000008; // Is currently configured DN_MANUAL = $00000010; // Manually installed DN_NEED_TO_ENUM = $00000020; // May need reenumeration DN_NOT_FIRST_TIME = $00000040; // Has received a config DN_HARDWARE_ENUM = $00000080; // Enum generates hardware ID DN_LIAR = $00000100; // Lied about can reconfig once DN_HAS_MARK = $00000200; // Not CM_Create_DevInst lately DN_HAS_PROBLEM = $00000400; // Need device installer DN_FILTERED = $00000800; // Is filtered DN_MOVED = $00001000; // Has been moved DN_DISABLEABLE = $00002000; // Can be disabled DN_REMOVABLE = $00004000; // Can be removed DN_PRIVATE_PROBLEM = $00008000; // Has a private problem DN_MF_PARENT = $00010000; // Multi function parent DN_MF_CHILD = $00020000; // Multi function child DN_WILL_BE_REMOVED = $00040000; // DevInst is being removed CR_SUCCESS = 0; CM_PROB_NOT_CONFIGURED = $00000001; // no config for device CM_PROB_DEVLOADER_FAILED = $00000002; // service load failed CM_PROB_OUT_OF_MEMORY = $00000003; // out of memory CM_PROB_ENTRY_IS_WRONG_TYPE = $00000004; // CM_PROB_LACKED_ARBITRATOR = $00000005; // CM_PROB_BOOT_CONFIG_CONFLICT = $00000006; // boot config conflict CM_PROB_FAILED_FILTER = $00000007; // CM_PROB_DEVLOADER_NOT_FOUND = $00000008; // Devloader not found CM_PROB_INVALID_DATA = $00000009; // Invalid ID CM_PROB_FAILED_START = $0000000A; // CM_PROB_LIAR = $0000000B; // CM_PROB_NORMAL_CONFLICT = $0000000C; // config conflict CM_PROB_NOT_VERIFIED = $0000000D; // CM_PROB_NEED_RESTART = $0000000E; // requires restart CM_PROB_REENUMERATION = $0000000F; // CM_PROB_PARTIAL_LOG_CONF = $00000010; // CM_PROB_UNKNOWN_RESOURCE = $00000011; // unknown res type CM_PROB_REINSTALL = $00000012; // CM_PROB_REGISTRY = $00000013; // CM_PROB_VXDLDR = $00000014; // WINDOWS 95 ONLY CM_PROB_WILL_BE_REMOVED = $00000015; // devinst will remove CM_PROB_DISABLED = $00000016; // devinst is disabled CM_PROB_DEVLOADER_NOT_READY = $00000017; // Devloader not ready CM_PROB_DEVICE_NOT_THERE = $00000018; // device doesn't exist CM_PROB_MOVED = $00000019; // CM_PROB_TOO_EARLY = $0000001A; // CM_PROB_NO_VALID_LOG_CONF = $0000001B; // no valid log config CM_PROB_FAILED_INSTALL = $0000001C; // install failed CM_PROB_HARDWARE_DISABLED = $0000001D; // device disabled CM_PROB_CANT_SHARE_IRQ = $0000001E; // can't share IRQ CM_PROB_FAILED_ADD = $0000001F; // driver failed add CM_PROB_DISABLED_SERVICE = $00000020; // service's Start = 4 CM_PROB_TRANSLATION_FAILED = $00000021; // resource translation failed CM_PROB_NO_SOFTCONFIG = $00000022; // no soft config CM_PROB_BIOS_TABLE = $00000023; // device missing in BIOS table CM_PROB_IRQ_TRANSLATION_FAILED = $00000024; // IRQ translator failed CM_PROB_FAILED_DRIVER_ENTRY = $00000025; // DriverEntry() failed. CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD = $00000026; // Driver should have unloaded. CM_PROB_DRIVER_FAILED_LOAD = $00000027; // Driver load unsuccessful. CM_PROB_DRIVER_SERVICE_KEY_INVALID = $00000028; // Error accessing driver's service key CM_PROB_LEGACY_SERVICE_NO_DEVICES = $00000029; // Loaded legacy service created no devices CM_PROB_DUPLICATE_DEVICE = $0000002A; // Two devices were discovered with the same name CM_PROB_FAILED_POST_START = $0000002B; // The drivers set the device state to failed CM_PROB_HALTED = $0000002C; // This device was failed post start via usermode CM_PROB_PHANTOM = $0000002D; // The devinst currently exists only in the registry CM_PROB_SYSTEM_SHUTDOWN = $0000002E; // The system is shutting down CM_PROB_HELD_FOR_EJECT = $0000002F; // The device is offline awaiting removal CM_PROB_DRIVER_BLOCKED = $00000030; // One or more drivers is blocked from loading CM_PROB_REGISTRY_TOO_LARGE = $00000031; // System hive has grown too large CM_PROB_SETPROPERTIES_FAILED = $00000032; // Failed to apply one or more registry properties CM_PROB_WAITING_ON_DEPENDENCY = $00000033; // Device is stalled waiting on a dependency to start CM_PROB_UNSIGNED_DRIVER = $00000034; // Failed load driver due to unsigned image. CM_PROB_USED_BY_DEBUGGER = $00000035; // Device is being used by kernel debugger CM_PROB_DEVICE_RESET = $00000036; // Device is being reset CM_PROB_CONSOLE_LOCKED = $00000037; // Device is blocked while console is locked CM_PROB_NEED_CLASS_CONFIG = $00000038; // Device needs extended class configuration to start CM_PROB_GUEST_ASSIGNMENT_FAILED = $00000039; // Assignment to guest partition failed CM_REMOVE_UI_OK = $00000000; CM_REMOVE_UI_NOT_OK = $00000001; CM_REMOVE_NO_RESTART = $00000002; CM_REMOVE_BITS = $00000003; DIF_SELECTDEVICE = $00000001; DIF_INSTALLDEVICE = $00000002; DIF_ASSIGNRESOURCES = $00000003; DIF_PROPERTIES = $00000004; DIF_REMOVE = $00000005; DIF_FIRSTTIMESETUP = $00000006; DIF_FOUNDDEVICE = $00000007; DIF_SELECTCLASSDRIVERS = $00000008; DIF_VALIDATECLASSDRIVERS = $00000009; DIF_INSTALLCLASSDRIVERS = $0000000A; DIF_CALCDISKSPACE = $0000000B; DIF_DESTROYPRIVATEDATA = $0000000C; DIF_VALIDATEDRIVER = $0000000D; DIF_DETECT = $0000000F; DIF_INSTALLWIZARD = $00000010; DIF_DESTROYWIZARDDATA = $00000011; DIF_PROPERTYCHANGE = $00000012; DIF_ENABLECLASS = $00000013; DIF_DETECTVERIFY = $00000014; DIF_INSTALLDEVICEFILES = $00000015; DIF_UNREMOVE = $00000016; DIF_SELECTBESTCOMPATDRV = $00000017; DIF_ALLOW_INSTALL = $00000018; DIF_REGISTERDEVICE = $00000019; DIF_NEWDEVICEWIZARD_PRESELECT = $0000001A; DIF_NEWDEVICEWIZARD_SELECT = $0000001B; DIF_NEWDEVICEWIZARD_PREANALYZE = $0000001C; DIF_NEWDEVICEWIZARD_POSTANALYZE = $0000001D; DIF_NEWDEVICEWIZARD_FINISHINSTALL = $0000001E; DIF_UNUSED1 = $0000001F; DIF_INSTALLINTERFACES = $00000020; DIF_DETECTCANCEL = $00000021; DIF_REGISTER_COINSTALLERS = $00000022; DIF_ADDPROPERTYPAGE_ADVANCED = $00000023; DIF_ADDPROPERTYPAGE_BASIC = $00000024; DIF_RESERVED1 = $00000025; DIF_TROUBLESHOOTER = $00000026; DIF_POWERMESSAGEWAKE = $00000027; DIF_ADDREMOTEPROPERTYPAGE_ADVANCED = $00000028; DIF_UPDATEDRIVER_UI = $00000029; DIF_FINISHINSTALL_ACTION = $0000002A; DIF_RESERVED2 = $00000030; DICS_FLAG_GLOBAL = $00000001; // make change in all hardware profiles DICS_FLAG_CONFIGSPECIFIC = $00000002; // make change in specified profile only DICS_FLAG_CONFIGGENERAL = $00000004; // 1 or more hardware profile-specific DICS_ENABLE = $00000001; DICS_DISABLE = $00000002; DICS_PROPCHANGE = $00000003; DICS_START = $00000004; DICS_STOP = $00000005; // changes to follow. // // Support for GUID Partition Table (GPT) disks. // // // There are currently two ways a disk can be partitioned. With a traditional // AT-style master boot record (PARTITION_STYLE_MBR) and with a new, GPT // partition table (PARTITION_STYLE_GPT). RAW is for an unrecognizable // partition style. There are a very limited number of things you can // do with a RAW partititon. // type GUID = TGUID; {$NODEFINE GUID} LPGUID = ^GUID; {$NODEFINE LPGUID} CLSID = TGUID; {$NODEFINE CLSID} ULONG64 = Int64; {$EXTERNALSYM ULONG64} PULONG64 = ^ULONG64; {$EXTERNALSYM PULONG64} DWORD64 = Int64; {$EXTERNALSYM DWORD64} PDWORD64 = ^DWORD64; {$EXTERNALSYM PDWORD64} UINT64 = Int64; {$EXTERNALSYM UINT64} PUINT64 = ^UINT64; {$EXTERNALSYM PUINT64} PPREVENT_MEDIA_REMOVAL = ^PREVENT_MEDIA_REMOVAL; {$EXTERNALSYM PPREVENT_MEDIA_REMOVAL} _PREVENT_MEDIA_REMOVAL = record PreventMediaRemoval: ByteBool; end; {$EXTERNALSYM _PREVENT_MEDIA_REMOVAL} PREVENT_MEDIA_REMOVAL = _PREVENT_MEDIA_REMOVAL; {$EXTERNALSYM PREVENT_MEDIA_REMOVAL} TPreventMediaRemoval = PREVENT_MEDIA_REMOVAL; PPreventMediaRemoval = PPREVENT_MEDIA_REMOVAL; PSTORAGE_DEVICE_NUMBER = ^STORAGE_DEVICE_NUMBER; {$EXTERNALSYM PSTORAGE_DEVICE_NUMBER} _STORAGE_DEVICE_NUMBER = record // // The FILE_DEVICE_XXX type for this device. // DeviceType: DEVICE_TYPE; // // The number of this device // DeviceNumber: DWORD; // // If the device is partitionable, the partition number of the device. // Otherwise -1 // PartitionNumber: DWORD; end; {$EXTERNALSYM _STORAGE_DEVICE_NUMBER} STORAGE_DEVICE_NUMBER = _STORAGE_DEVICE_NUMBER; {$EXTERNALSYM STORAGE_DEVICE_NUMBER} TStorageDeviceNumber = STORAGE_DEVICE_NUMBER; PStorageDeviceNumber = PSTORAGE_DEVICE_NUMBER; _PARTITION_STYLE = ( PARTITION_STYLE_MBR, PARTITION_STYLE_GPT, PARTITION_STYLE_RAW); {$EXTERNALSYM _PARTITION_STYLE} PARTITION_STYLE = _PARTITION_STYLE; {$EXTERNALSYM PARTITION_STYLE} TPartitionStyle = PARTITION_STYLE; // // The following structure defines information in a GPT partition that is // not common to both GPT and MBR partitions. // PPARTITION_INFORMATION_GPT = ^PARTITION_INFORMATION_GPT; {$EXTERNALSYM PPARTITION_INFORMATION_GPT} _PARTITION_INFORMATION_GPT = record PartitionType: GUID; // Partition type. See table 16-3. PartitionId: GUID; // Unique GUID for this partition. Attributes: DWORD64; // See table 16-4. Name: array [0..35] of WCHAR; // Partition Name in Unicode. end; {$EXTERNALSYM _PARTITION_INFORMATION_GPT} PARTITION_INFORMATION_GPT = _PARTITION_INFORMATION_GPT; {$EXTERNALSYM PARTITION_INFORMATION_GPT} TPartitionInformationGpt = PARTITION_INFORMATION_GPT; PPartitionInformationGpt = PPARTITION_INFORMATION_GPT; { _PREVENT_MEDIA_REMOVAL = record PreventMediaRemoval : Boolean; end; PREVENT_MEDIA_REMOVAL = _PREVENT_MEDIA_REMOVAL; } // // The following are GPT partition attributes applicable for any // partition type. These attributes are not OS-specific // const GPT_ATTRIBUTE_PLATFORM_REQUIRED = $0000000000000001; {$EXTERNALSYM GPT_ATTRIBUTE_PLATFORM_REQUIRED} // // The following are GPT partition attributes applicable when the // PartitionType is PARTITION_BASIC_DATA_GUID. // GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER = DWORD($8000000000000000); {$EXTERNALSYM GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER} GPT_BASIC_DATA_ATTRIBUTE_HIDDEN = $4000000000000000; {$EXTERNALSYM GPT_BASIC_DATA_ATTRIBUTE_HIDDEN} GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY = $1000000000000000; {$EXTERNALSYM GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY} // // The following structure defines information in an MBR partition that is not // common to both GPT and MBR partitions. // type PPARTITION_INFORMATION_MBR = ^PARTITION_INFORMATION_MBR; {$EXTERNALSYM PPARTITION_INFORMATION_MBR} _PARTITION_INFORMATION_MBR = record PartitionType: BYTE; BootIndicator: BOOLEAN; RecognizedPartition: BOOLEAN; HiddenSectors: DWORD; end; {$EXTERNALSYM _PARTITION_INFORMATION_MBR} PARTITION_INFORMATION_MBR = _PARTITION_INFORMATION_MBR; {$EXTERNALSYM PARTITION_INFORMATION_MBR} TPartitionInformationMbr = PARTITION_INFORMATION_MBR; PPartitionInformationMbr = PPARTITION_INFORMATION_MBR; // // The structure SET_PARTITION_INFO_EX is used with the ioctl // IOCTL_SET_PARTITION_INFO_EX to set information about a specific // partition. Note that for MBR partitions, you can only set the partition // signature, whereas GPT partitions allow setting of all fields that // you can get. // SET_PARTITION_INFORMATION_MBR = SET_PARTITION_INFORMATION; {$EXTERNALSYM SET_PARTITION_INFORMATION_MBR} TSetPartitionInformationMbr = SET_PARTITION_INFORMATION_MBR; SET_PARTITION_INFORMATION_GPT = PARTITION_INFORMATION_GPT; {$EXTERNALSYM SET_PARTITION_INFORMATION_GPT} TSetPartitionInformationGpt = SET_PARTITION_INFORMATION_GPT; PSET_PARTITION_INFORMATION_EX = ^SET_PARTITION_INFORMATION_EX; {$EXTERNALSYM PSET_PARTITION_INFORMATION_EX} _SET_PARTITION_INFORMATION_EX = record PartitionStyle: PARTITION_STYLE; case Integer of 0: (Mbr: SET_PARTITION_INFORMATION_MBR); 1: (Gpt: SET_PARTITION_INFORMATION_GPT); end; {$EXTERNALSYM _SET_PARTITION_INFORMATION_EX} SET_PARTITION_INFORMATION_EX = _SET_PARTITION_INFORMATION_EX; {$EXTERNALSYM SET_PARTITION_INFORMATION_EX} TSetPartitionInformationEx = SET_PARTITION_INFORMATION_EX; PSetPartitionInformationEx = PSET_PARTITION_INFORMATION_EX; // // The structure CREATE_DISK_GPT with the ioctl IOCTL_DISK_CREATE_DISK // to initialize an virgin disk with an empty GPT partition table. // PCREATE_DISK_GPT = ^CREATE_DISK_GPT; {$EXTERNALSYM PCREATE_DISK_GPT} _CREATE_DISK_GPT = record DiskId: GUID; // Unique disk id for the disk. MaxPartitionCount: DWORD; // Maximim number of partitions allowable. end; {$EXTERNALSYM _CREATE_DISK_GPT} CREATE_DISK_GPT = _CREATE_DISK_GPT; {$EXTERNALSYM CREATE_DISK_GPT} TCreateDiskGpt = CREATE_DISK_GPT; PCreateDiskGpt = PCREATE_DISK_GPT; // // The structure CREATE_DISK_MBR with the ioctl IOCTL_DISK_CREATE_DISK // to initialize an virgin disk with an empty MBR partition table. // PCREATE_DISK_MBR = ^CREATE_DISK_MBR; {$EXTERNALSYM PCREATE_DISK_MBR} _CREATE_DISK_MBR = record Signature: DWORD; end; {$EXTERNALSYM _CREATE_DISK_MBR} CREATE_DISK_MBR = _CREATE_DISK_MBR; {$EXTERNALSYM CREATE_DISK_MBR} TCreateDiskMbr = CREATE_DISK_MBR; PCreateDiskMbr = PCREATE_DISK_MBR; PCREATE_DISK = ^CREATE_DISK; {$EXTERNALSYM PCREATE_DISK} _CREATE_DISK = record PartitionStyle: PARTITION_STYLE; case Integer of 0: (Mbr: CREATE_DISK_MBR); 1: (Gpt: CREATE_DISK_GPT); end; {$EXTERNALSYM _CREATE_DISK} CREATE_DISK = _CREATE_DISK; {$EXTERNALSYM CREATE_DISK} TCreateDisk = CREATE_DISK; PCreateDisk = PCREATE_DISK; // // The structure GET_LENGTH_INFORMATION is used with the ioctl // IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of the // disk, partition, or volume. // PGET_LENGTH_INFORMATION = ^GET_LENGTH_INFORMATION; {$EXTERNALSYM PGET_LENGTH_INFORMATION} _GET_LENGTH_INFORMATION = record Length: LARGE_INTEGER; end; {$EXTERNALSYM _GET_LENGTH_INFORMATION} GET_LENGTH_INFORMATION = _GET_LENGTH_INFORMATION; {$EXTERNALSYM GET_LENGTH_INFORMATION} TGetLengthInformation = GET_LENGTH_INFORMATION; PGetLengthInformation = PGET_LENGTH_INFORMATION; // // The PARTITION_INFORMATION_EX structure is used with the // IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, // IOCTL_DISK_GET_PARTITION_INFO_EX and IOCTL_DISK_GET_PARTITION_INFO_EX calls. // PPARTITION_INFORMATION_EX = ^PARTITION_INFORMATION_EX; {$EXTERNALSYM PPARTITION_INFORMATION_EX} _PARTITION_INFORMATION_EX = record PartitionStyle: PARTITION_STYLE; StartingOffset: LARGE_INTEGER; PartitionLength: LARGE_INTEGER; PartitionNumber: DWORD; RewritePartition: BOOLEAN; case Integer of 0: (Mbr: PARTITION_INFORMATION_MBR); 1: (Gpt: PARTITION_INFORMATION_GPT); end; {$EXTERNALSYM _PARTITION_INFORMATION_EX} PARTITION_INFORMATION_EX = _PARTITION_INFORMATION_EX; {$EXTERNALSYM PARTITION_INFORMATION_EX} TPartitionInformationEx = PARTITION_INFORMATION_EX; PPartitionInformationEx = PPARTITION_INFORMATION_EX; // // GPT specific drive layout information. // PDRIVE_LAYOUT_INFORMATION_GPT = ^DRIVE_LAYOUT_INFORMATION_GPT; {$EXTERNALSYM PDRIVE_LAYOUT_INFORMATION_GPT} _DRIVE_LAYOUT_INFORMATION_GPT = record DiskId: GUID; StartingUsableOffset: LARGE_INTEGER; UsableLength: LARGE_INTEGER; MaxPartitionCount: DWORD; end; {$EXTERNALSYM _DRIVE_LAYOUT_INFORMATION_GPT} DRIVE_LAYOUT_INFORMATION_GPT = _DRIVE_LAYOUT_INFORMATION_GPT; {$EXTERNALSYM DRIVE_LAYOUT_INFORMATION_GPT} TDriveLayoutInformationGpt = DRIVE_LAYOUT_INFORMATION_GPT; PDriveLayoutInformationGpt = PDRIVE_LAYOUT_INFORMATION_GPT; // // MBR specific drive layout information. // PDRIVE_LAYOUT_INFORMATION_MBR = ^DRIVE_LAYOUT_INFORMATION_MBR; {$EXTERNALSYM PDRIVE_LAYOUT_INFORMATION_MBR} _DRIVE_LAYOUT_INFORMATION_MBR = record Signature: DWORD; end; {$EXTERNALSYM _DRIVE_LAYOUT_INFORMATION_MBR} DRIVE_LAYOUT_INFORMATION_MBR = _DRIVE_LAYOUT_INFORMATION_MBR; {$EXTERNALSYM DRIVE_LAYOUT_INFORMATION_MBR} TDriveLayoutInformationMbr = DRIVE_LAYOUT_INFORMATION_MBR; PDriveLayoutInformationMbr = PDRIVE_LAYOUT_INFORMATION_MBR; // // The structure DRIVE_LAYOUT_INFORMATION_EX is used with the // IOCTL_SET_DRIVE_LAYOUT_EX and IOCTL_GET_DRIVE_LAYOUT_EX calls. // PDRIVE_LAYOUT_INFORMATION_EX = ^DRIVE_LAYOUT_INFORMATION_EX; {$EXTERNALSYM PDRIVE_LAYOUT_INFORMATION_EX} _DRIVE_LAYOUT_INFORMATION_EX = record PartitionStyle: DWORD; PartitionCount: DWORD; Union: record case Integer of 0: (Mbr: DRIVE_LAYOUT_INFORMATION_MBR); 1: (Gpt: DRIVE_LAYOUT_INFORMATION_GPT); end; PartitionEntry: array [0..0] of PARTITION_INFORMATION_EX; end; {$EXTERNALSYM _DRIVE_LAYOUT_INFORMATION_EX} DRIVE_LAYOUT_INFORMATION_EX = _DRIVE_LAYOUT_INFORMATION_EX; {$EXTERNALSYM DRIVE_LAYOUT_INFORMATION_EX} TDriveLayoutInformationEx = DRIVE_LAYOUT_INFORMATION_EX; PDriveLayoutInformationEx = PDRIVE_LAYOUT_INFORMATION_EX; /////// GPT를 인식하기 위해 추가 2011-02-10 sunk // 파일 클러스터 관련 ----------------------------------------------------- type // // Structure for FSCTL_GET_VOLUME_BITMAP // PSTARTING_LCN_INPUT_BUFFER = ^STARTING_LCN_INPUT_BUFFER; {$EXTERNALSYM PSTARTING_LCN_INPUT_BUFFER} STARTING_LCN_INPUT_BUFFER = record StartingLcn: LARGE_INTEGER; end; {$EXTERNALSYM STARTING_LCN_INPUT_BUFFER} TStartingLcnInputBuffer = STARTING_LCN_INPUT_BUFFER; PStartingLcnInputBuffer = PSTARTING_LCN_INPUT_BUFFER; PVOLUME_BITMAP_BUFFER = ^VOLUME_BITMAP_BUFFER; {$EXTERNALSYM PVOLUME_BITMAP_BUFFER} VOLUME_BITMAP_BUFFER = record StartingLcn: LARGE_INTEGER; BitmapSize: LARGE_INTEGER; Buffer: array [0..0] of BYTE; end; {$EXTERNALSYM VOLUME_BITMAP_BUFFER} TVolumeBitmapBuffer = VOLUME_BITMAP_BUFFER; PVolumeBitmapBuffer = PVOLUME_BITMAP_BUFFER; // // Structure for FSCTL_GET_RETRIEVAL_POINTERS // PSTARTING_VCN_INPUT_BUFFER = ^STARTING_VCN_INPUT_BUFFER; {$EXTERNALSYM PSTARTING_VCN_INPUT_BUFFER} STARTING_VCN_INPUT_BUFFER = record StartingVcn: LARGE_INTEGER; end; {$EXTERNALSYM STARTING_VCN_INPUT_BUFFER} TStartingVcnInputBuffer = STARTING_VCN_INPUT_BUFFER; PStartingVcnInputBuffer = PSTARTING_VCN_INPUT_BUFFER; TRPBExtends = record NextVcn: LARGE_INTEGER; Lcn: LARGE_INTEGER; end; PRETRIEVAL_POINTERS_BUFFER = ^RETRIEVAL_POINTERS_BUFFER; {$EXTERNALSYM PRETRIEVAL_POINTERS_BUFFER} RETRIEVAL_POINTERS_BUFFER = record ExtentCount: DWORD; StartingVcn: LARGE_INTEGER; Extends: array [0..0] of TRPBExtends; end; {$EXTERNALSYM RETRIEVAL_POINTERS_BUFFER} TRetrievalPointersBuffer = RETRIEVAL_POINTERS_BUFFER; PRetrievalPointersBuffer = PRETRIEVAL_POINTERS_BUFFER; // // Structures for FSCTL_GET_NTFS_FILE_RECORD // PNTFS_FILE_RECORD_INPUT_BUFFER = ^NTFS_FILE_RECORD_INPUT_BUFFER; {$EXTERNALSYM PNTFS_FILE_RECORD_INPUT_BUFFER} NTFS_FILE_RECORD_INPUT_BUFFER = record FileReferenceNumber: LARGE_INTEGER; end; {$EXTERNALSYM NTFS_FILE_RECORD_INPUT_BUFFER} TNtfsFileRecordInputBuffer = NTFS_FILE_RECORD_INPUT_BUFFER; PNtfsFileRecordInputBuffer = PNTFS_FILE_RECORD_INPUT_BUFFER; PNTFS_FILE_RECORD_OUTPUT_BUFFER = ^NTFS_FILE_RECORD_OUTPUT_BUFFER; {$EXTERNALSYM PNTFS_FILE_RECORD_OUTPUT_BUFFER} NTFS_FILE_RECORD_OUTPUT_BUFFER = record FileReferenceNumber: LARGE_INTEGER; FileRecordLength: DWORD; FileRecordBuffer: array [0..0] of BYTE; end; {$EXTERNALSYM NTFS_FILE_RECORD_OUTPUT_BUFFER} TNtfsFileRecordOutputBuffer = NTFS_FILE_RECORD_OUTPUT_BUFFER; PNtfsFileRecordOutputBuffer = PNTFS_FILE_RECORD_OUTPUT_BUFFER; // // Structure for FSCTL_MOVE_FILE // PMOVE_FILE_DATA = ^MOVE_FILE_DATA; {$EXTERNALSYM PMOVE_FILE_DATA} MOVE_FILE_DATA = record FileHandle: THandle; StartingVcn: LARGE_INTEGER; StartingLcn: LARGE_INTEGER; ClusterCount: DWORD; end; {$EXTERNALSYM MOVE_FILE_DATA} TMoveFileData = MOVE_FILE_DATA; PMoveFileData = PMOVE_FILE_DATA; // 추가 22_0616 16:13:02 kku --------------------------------------------------- PHDEVINFO = ^HDEVINFO; HDEVINFO = THandle; PCONFIGRET = ^CONFIGRET; CONFIGRET = DWORD; PDEVINST = ^DEVINST; DEVINST = DWORD; PPNP_VETO_TYPE = ^PNP_VETO_TYPE; PNP_VETO_TYPE = DWORD; HMACHINE = THandle; PSPDeviceInterfaceData = ^TSPDeviceInterfaceData; // 64bit에서는 packed 처리하면 안된다.. 22_0616 23:18:35 kku SP_DEVICE_INTERFACE_DATA = {$IFNDEF WIN64} packed {$ENDIF} record cbSize : DWORD; InterfaceClassGuid : TGUID; Flags : DWORD; Reserved : ULONG_PTR; end; TSPDeviceInterfaceData = SP_DEVICE_INTERFACE_DATA; PSPDeviceInterfaceDetailDataA = ^TSPDeviceInterfaceDetailDataA; PSPDeviceInterfaceDetailDataW = ^TSPDeviceInterfaceDetailDataW; SP_DEVICE_INTERFACE_DETAIL_DATA_A = {$IFNDEF WIN64} packed {$ENDIF} record cbSize : DWORD; DevicePath : array [0..0] of AnsiChar; end; SP_DEVICE_INTERFACE_DETAIL_DATA_W = {$IFNDEF WIN64} packed {$ENDIF} record cbSize : DWORD; DevicePath : array [0..0] of WideChar; end; TSPDeviceInterfaceDetailDataA = SP_DEVICE_INTERFACE_DETAIL_DATA_A; TSPDeviceInterfaceDetailDataW = SP_DEVICE_INTERFACE_DETAIL_DATA_W; TSPDeviceInterfaceDetailData = TSPDeviceInterfaceDetailDataW; PSPDeviceInterfaceDetailData = ^TSPDeviceInterfaceDetailDataW; PSPDevInfoData = ^TSPDevInfoData; SP_DEVINFO_DATA = {$IFNDEF WIN64} packed {$ENDIF} record cbSize : DWORD; ClassGuid : TGUID; DevInst : DWORD; Reserved : ULONG_PTR; end; TSPDevInfoData = SP_DEVINFO_DATA; DI_FUNCTION = UINT; PSPClassInstallHeader = ^TSPClassInstallHeader; SP_CLASSINSTALL_HEADER = {$IFNDEF WIN64} packed {$ENDIF} record cbSize: DWORD; InstallFunction: DI_FUNCTION; end; TSPClassInstallHeader = SP_CLASSINSTALL_HEADER; PSPPropChangeParams = ^TSPPropChangeParams; SP_PROPCHANGE_PARAMS = {$IFNDEF WIN64} packed {$ENDIF} record ClassInstallHeader: TSPClassInstallHeader; StateChange: DWORD; Scope: DWORD; HwProfile: DWORD; end; TSPPropChangeParams = SP_PROPCHANGE_PARAMS; function SetupDiGetClassDevsW(ClassGuid: PGUID; const Enumerator: PWideChar; hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall; external 'SetupApi.dll' name 'SetupDiGetClassDevsW'; function SetupDiGetClassDevsA(ClassGuid: PGUID; const Enumerator: PAnsiChar; hwndParent:HWND; Flags: DWORD): HDEVINFO; stdcall; external 'SetupApi.dll' name 'SetupDiGetClassDevsA'; function SetupDiGetClassDevs(ClassGuid: PGUID; const Enumerator: PChar; hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall; external 'SetupApi.dll' name 'SetupDiGetClassDevsW'; function SetupDiEnumDeviceInfo(DeviceInfoSet: HDEVINFO; MemberIndex: DWORD; var DeviceInfoData: TSPDevInfoData): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiEnumDeviceInfo'; function SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet: HDEVINFO; const DeviceInfoData: TSPDevInfoData; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSize: DWORD; var RequiredSize: DWORD): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiGetDeviceRegistryPropertyA'; function SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet: HDEVINFO; const DeviceInfoData: TSPDevInfoData; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSize: DWORD; var RequiredSize: DWORD): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiGetDeviceRegistryPropertyW'; function SetupDiGetDeviceRegistryProperty(DeviceInfoSet: HDEVINFO; const DeviceInfoData: TSPDevInfoData; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSize: DWORD; var RequiredSize: DWORD): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiGetDeviceRegistryPropertyW'; function SetupDiSetClassInstallParamsA(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; ClassInstallParams: PSPClassInstallHeader; ClassInstallParamsSize: DWORD): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiSetClassInstallParamsA'; function SetupDiSetClassInstallParamsW(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; ClassInstallParams: PSPClassInstallHeader; ClassInstallParamsSize: DWORD): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiSetClassInstallParamsW'; function SetupDiSetClassInstallParams(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; ClassInstallParams: PSPClassInstallHeader; ClassInstallParamsSize: DWORD): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiSetClassInstallParamsW'; function SetupDiCallClassInstaller(InstallFunction: DI_FUNCTION; DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData): LongBool; stdcall; external 'SetupApi.dll' name 'SetupDiCallClassInstaller'; function SetupDiEnumDeviceInterfaces(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; const InterfaceClassGuid: TGUID; MemberIndex: DWORD; var DeviceInterfaceData: TSPDeviceInterfaceData): BOOL; stdcall; external 'SetupApi.dll'; function SetupDiGetDeviceInterfaceDetailW(DeviceInfoSet: HDEVINFO; DeviceInterfaceData: PSPDeviceInterfaceData; DeviceInterfaceDetailData: PSPDeviceInterfaceDetailData; DeviceInterfaceDetailDataSize: DWORD; var RequiredSize: DWORD; Device: PSPDevInfoData): BOOL; stdcall; external 'SetupApi.dll' name 'SetupDiGetDeviceInterfaceDetailW'; function SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet: HDEVINFO; DeviceInterfaceData: PSPDeviceInterfaceData; DeviceInterfaceDetailData: PSPDeviceInterfaceDetailDataA; DeviceInterfaceDetailDataSize: DWORD; var RequiredSize: DWORD; Device: PSPDevInfoData): BOOL; stdcall; external 'SetupApi.dll' name 'SetupDiGetDeviceInterfaceDetailA'; function SetupDiGetDeviceInterfaceDetail(DeviceInfoSet: HDEVINFO; DeviceInterfaceData: PSPDeviceInterfaceData; DeviceInterfaceDetailData: PSPDeviceInterfaceDetailData; DeviceInterfaceDetailDataSize: DWORD; var RequiredSize: DWORD; Device: PSPDevInfoData): BOOL; stdcall; external 'SetupApi.dll' name 'SetupDiGetDeviceInterfaceDetailW'; function SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO): BOOL; stdcall; external 'SetupApi.dll' name 'SetupDiDestroyDeviceInfoList'; function SetupDiRemoveDevice(DeviceInfoSet: HDEVINFO; var DeviceInfoData: TSPDevInfoData): BOOL; stdcall; external 'SetupApi.dll' name 'SetupDiRemoveDevice'; function CM_Get_Parent(var dnDevInstParent: DEVINST; dnDevInst: DEVINST; ulFlags: ULONG): CONFIGRET; stdcall; external 'CfgMgr32.dll'; function CM_Query_And_Remove_SubTreeW(dnAncestor: DEVINST; pVetoType: PPNP_VETO_TYPE; pszVetoName: PWideChar; ulNameLength: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'SetupApi.dll' name 'CM_Query_And_Remove_SubTreeW'; function CM_Query_And_Remove_SubTreeA(dnAncestor: DEVINST;pVetoType: PPNP_VETO_TYPE; pszVetoName: PAnsiChar; ulNameLength: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'SetupApi.dll' name 'CM_Query_And_Remove_SubTreeA'; function CM_Query_And_Remove_SubTree(dnAncestor: DEVINST;pVetoType: PPNP_VETO_TYPE; pszVetoName: PChar; ulNameLength: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'SetupApi.dll' name 'CM_Query_And_Remove_SubTreeW'; function CM_Request_Device_EjectW(dnDevInst: DEVINST; pVetoType: PPNP_VETO_TYPE; pszVetoName: PWideChar; ulNameLength: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'SetupApi.dll' name 'CM_Request_Device_EjectW'; function CM_Request_Device_EjectA(dnDevInst: DEVINST; pVetoType: PPNP_VETO_TYPE; pszVetoName: PAnsiChar; ulNameLength: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'SetupApi.dll' name 'CM_Request_Device_EjectA'; function CM_Request_Device_Eject(dnDevInst: DEVINST; pVetoType: PPNP_VETO_TYPE; pszVetoName: PChar; ulNameLength: ULONG; ulFlags: ULONG):CONFIGRET; stdcall; external 'SetupApi.dll' name 'CM_Request_Device_EjectW'; function CM_Get_Device_IDA(dnDevInst: DEVINST; Buffer: PAnsiChar; BufferLen: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'cfgmgr32.dll' name 'CM_Get_Device_IDA'; function CM_Get_Device_IDW(dnDevInst: DEVINST; Buffer: PWideChar; BufferLen: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'cfgmgr32.dll' name 'CM_Get_Device_IDW'; function CM_Get_Device_ID(dnDevInst: DEVINST; Buffer: PChar; BufferLen: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; external 'cfgmgr32.dll' name 'CM_Get_Device_IDW'; function CM_Get_DevNode_Status(var ulStatus: ULONG; var ulProblemNumber: ULONG; dnDevInst: DEVINST; ulFlags: ULONG): CONFIGRET; stdcall; external 'cfgmgr32.dll' name 'CM_Get_DevNode_Status'; function CM_Get_DevNode_Status_Ex(var ulStatus: ULONG; var ulProblemNumber: ULONG; dnDevInst: DEVINST; ulFlags: ULONG; hMachine: HMACHINE): CONFIGRET; stdcall; external 'cfgmgr32.dll' name 'CM_Get_DevNode_Status_Ex'; // 추가 22_0616 16:13:02 kku --------------------------------------------------- // ------------------------------------------------------------------------ function CTL_CODE(const dwDeviceType, dwFunc, dwMethod, dwAccess: DWORD): DWORD; function ConvSerialToStr(sSerNum: AnsiString): AnsiString; type TTgDriver = class(TTgObject) protected sDeviceName_: String; hDevice_: THandle; function GetDeviceHandle: THandle; virtual; public Constructor Create; virtual; Destructor Destroy; override; function OpenDevice(const sDeviceName: String; dwDesireAccess: DWORD = GENERIC_READ or GENERIC_WRITE; dwShareMode: DWORD = FILE_SHARE_READ or FILE_SHARE_WRITE; dwFlagsAndAttributes: DWORD = 0): Integer; virtual; function CloseDevice: Boolean; virtual; function ReadIO(dwCode: DWORD; pBuf: Pointer; dwSize: DWORD; pdwByteReturn: PDWORD = nil): Boolean; function WriteIO(dwCode: DWORD; pBuf: Pointer; dwSize: DWORD; pdwByteReturn: PDWORD = nil): Boolean; function ReadWriteIO(dwCode: DWORD; pInBuf: Pointer; dwInSize: DWORD; pOutBuf: Pointer; dwOutSize: DWORD; pdwByteReturn: PDWORD = nil): Boolean; function IsOpen: Boolean; virtual; property Handle: THandle read GetDeviceHandle; property DeviceName: String read sDeviceName_; end; { var IOCTL_DISK_GET_LENGTH_INFO: DWORD; IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: DWORD; IOCTL_STORAGE_QUERY_PROPERTY: DWORD; IOCTL_STORAGE_GET_MEDIA_TYPES_EX: DWORD; IOCTL_STORAGE_EJECTION_CONTROL: DWORD; IOCTL_STORAGE_MEDIA_REMOVAL: DWORD; IOCTL_STORAGE_EJECT_MEDIA: DWORD; FSCTL_DISMOUNT_VOLUME : DWORD; FSCTL_LOCK_VOLUME : DWORD; FSCTL_UNLOCK_VOLUME : DWORD; FSCTL_IS_VOLUME_MOUNTED:DWORD; FSCTL_ALLOW_EXTENDED_DASD_IO : DWORD; //IOCTL_STORAGE_EJECT_MEDIA : DWORD; IOCTL_WDMAUD_OPEN_DEVICE : DWORD = $1d8014; IOCTL_WDMAUD_REMOVE_DEVICE : DWORD = $1d8008; IOCTL_WDMAUD_AUX_GET_VOLUME : DWORD = $1d801c; //IOCTL_STORAGE_GET_DEVICE_NUMBER : DWORD = $2D1080; } type PDriveInfo = ^TDriveInfo; TDriveInfo = record sDrive, sSerial, sClass, sClassGuid, sDesc, sFriendlyName: String; llSize: LONGLONG; nDiskNum: Integer; end; function FlushDriveBuffers(const sDrive: String): Boolean; function DeviceIoCtrl(hDevice : DWORD; dwCode: DWORD; pdwByteReturn: PDWORD = nil): Boolean; function GetDriveDetail(sDrive: String; pInfo: PDriveInfo; bAddInfo: Boolean = false): Boolean; function ForceEjectDrive(sDrive: String): Boolean; function EjectDrive(sDrive: String; aIgrList: TStringList = nil; bOnlyUsb: Boolean = true; bForceEject: Boolean = false): String; function EjectDrive2(sDrive: String; aIgrList: TStringList = nil; bOnlyUsb: Boolean = true; bForceEject: Boolean = false; bForceEjectFirst: Boolean = false): String; // 내장 cdrom 제거 23_0223 16:23:32 kku function SetUsbDevEnableByDevPath(sDevPath: String; bVal: Boolean): Boolean; function RemoveUsbDevEnableByDevPath(sDevPath: String): Integer; implementation uses Tocsg.Path, Tocsg.Safe, Tocsg.Exception, Tocsg.Convert, Tocsg.Disk, Tocsg.Trace, Tocsg.Shell, Tocsg.Process; //CTL_CODE(IOCTL_STORAGE_BASE, $0250, METHOD_BUFFERED, FILE_READ_ACCESS); function CTL_CODE(const dwDeviceType, dwFunc, dwMethod, dwAccess: DWORD): DWORD; begin Result := (dwDeviceType shl 16) or (dwAccess shl 14) or (dwFunc shl 2) or dwMethod; end; function ConvSerialToStr(sSerNum: AnsiString): AnsiString; var i, nStrLen: Integer; sPair: AnsiString; B: Byte; Ch: AnsiChar Absolute B; begin Result := ''; nStrLen := Length(sSerNum); if Odd(nStrLen) then exit; i := 1; while i < nStrLen do begin sPair := Copy(sSerNum, i, 2); HexToBin(PAnsiChar(sPair), PAnsiChar(@B), 1); Result := Result + AnsiChar(B); Inc(i, 2); end; i := 1; nStrLen := Length(Result); while i < nStrLen do begin Ch := Result[i]; Result[i] := Result[i + 1]; Result[i + 1] := Ch; Inc(i, 2); end; end; { TTgDriver } Constructor TTgDriver.Create; begin Inherited Create; hDevice_ := 0; end; Destructor TTgDriver.Destroy; begin CloseDevice; Inherited; end; function TTgDriver.GetDeviceHandle: THandle; begin Result := hDevice_; end; // 성공 - 0, 그외 실패 function TTgDriver.OpenDevice(const sDeviceName: String; dwDesireAccess: DWORD = GENERIC_READ or GENERIC_WRITE; dwShareMode: DWORD = FILE_SHARE_READ or FILE_SHARE_WRITE; dwFlagsAndAttributes: DWORD = 0): Integer; var h: THandle; begin if hDevice_ <> 0 then CloseDevice; if sDeviceName = '' then begin Result := ERROR_FILE_NOT_FOUND; exit; end; // if (GetVersion and $ff) >= 5 then // sDeviceName := '\\.\Global\' + sDriverName // else // sDeviceName := '\\.\' + sDriverName; h := CreateFile(PChar(sDeviceName), dwDesireAccess, dwShareMode, nil, OPEN_EXISTING, dwFlagsAndAttributes,//FILE_FLAG_NO_BUFFERING or FILE_FLAG_SEQUENTIAL_SCAN, 0); if h = INVALID_HANDLE_VALUE then begin Result := GetLastError; exit; end; hDevice_ := h; sDeviceName_ := sDeviceName; // 일단 플러시 실패해도 상관없으니깐 그냥 실행만 시켜준다. // 09_1111 추가 sunk // if FlushFileBuffers(h) then // 물리 디스크는 안되나부다.. // _Trace('OpenDevice() - FlushFileBuffers .. success') // else // _Trace('OpenDevice() - FlushFileBuffers .. fail'); Result := ERROR_SUCCESS; end; function TTgDriver.CloseDevice: Boolean; begin Result := false; if hDevice_ <> 0 then begin CloseHandle(hDevice_); hDevice_ := 0; Result := true; end; end; function TTgDriver.ReadIO(dwCode: DWORD; pBuf: Pointer; dwSize: DWORD; pdwByteReturn: PDWORD = nil): Boolean; var dwByteReturned: DWORD; begin Result := false; if hDevice_ = 0 then exit; dwByteReturned := 0; Result := DeviceIoControl(hDevice_, dwCode, nil, 0, pBuf, dwSize, dwByteReturned, nil); if Result and (pdwByteReturn <> nil) then pdwByteReturn^ := dwByteReturned; end; function TTgDriver.WriteIO(dwCode: DWORD; pBuf: Pointer; dwSize: DWORD; pdwByteReturn: PDWORD = nil): Boolean; var dwByteReturned: DWORD; begin Result := false; if hDevice_ = 0 then exit; Result := DeviceIoControl(hDevice_, dwCode, pBuf, dwSize, nil, 0, dwByteReturned, nil); if Result and (pdwByteReturn <> nil) then pdwByteReturn^ := dwByteReturned; end; // 드라이버에 데이터 보내고 받기 // 성공 - bytereturn // 드라이버가 열러있지 않음, 오류 - -1 function TTgDriver.ReadWriteIO(dwCode: DWORD; pInBuf: Pointer; dwInSize: DWORD; pOutBuf: Pointer; dwOutSize: DWORD; pdwByteReturn: PDWORD = nil): Boolean; var dwByteReturned: DWORD; begin Result := false; if hDevice_ = 0 then exit; Result := DeviceIoControl(hDevice_, dwCode, pInBuf, dwInSize, pOutBuf, dwOutSize, dwByteReturned, nil); if Result and (pdwByteReturn <> nil) then pdwByteReturn^ := dwByteReturned; end; function TTgDriver.IsOpen: Boolean; begin Result := (hDevice_ <> 0) and (hDevice_ <> INVALID_HANDLE_VALUE); end; function FlushDriveBuffers(const sDrive: String): Boolean; var hVolume: THandle; sDrivePath: String; begin Result := false; sDrivePath := Format('\\.\%s:', [sDrive[1]]); hVolume := CreateFile(PChar(sDrivePath), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hVolume < 1 then exit; Result := FlushFileBuffers(hVolume); CloseHandle(hVolume); end; function DeviceIoCtrl(hDevice : DWORD; dwCode: DWORD; pdwByteReturn: PDWORD = nil): Boolean; var dwByteReturned: DWORD; begin Result := false; if hDevice = 0 then exit; Result := DeviceIoControl(hDevice, dwCode, nil, 0, nil, 0, dwByteReturned, nil); if Result and (pdwByteReturn <> nil) then pdwByteReturn^ := dwByteReturned; end; function GetDevPropertyStr(hDev: HDEVINFO; spdd: TSPDevInfoData; dwProperty: DWORD): String; var c: Integer; pBuf: Pointer; dwBufSize, dwPropertyRegDataType: DWORD; begin Result := ''; try pBuf := nil; dwBufSize := 0; try while not SetupDiGetDeviceRegistryProperty(hDev, spdd, dwProperty, dwPropertyRegDataType, pBuf, dwBufSize, dwBufSize) do begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin if pBuf <> nil then FreeMem(pBuf); pBuf := AllocMem(dwBufSize); end else break; end; if pBuf <> nil then Result := String(PChar(pBuf)); finally if pBuf <> nil then FreeMem(pBuf); end; except on E: Exception do ETgException.TraceException(E, 'Fail .. GetDevPropertyStr()'); end; end; function GetDriveDetail(sDrive: String; pInfo: PDriveInfo; bAddInfo: Boolean = false): Boolean; var sVol: String; Drv: TTgDriver; sdn: STORAGE_DEVICE_NUMBER; dwIdx, dwLen: DWORD; DevGuid: TGuid; hDev: HDEVINFO; sdid: TSPDeviceInterfaceData; pBuf: TBytes; spdd: TSPDevInfoData; DevInstParent: DEVINST; sDevName: array [0..255] of Char; begin Result := false; ZeroMemory(pInfo, SizeOf(TDriveInfo)); pInfo.sDrive := sDrive; pInfo.nDiskNum := -1; pInfo.llSize := GetDriveSize(sDrive); // if pInfo.llSize = 0 then // begin // var DrvEx: TDriveExtent := GetDriveExtent(sDrive); // pInfo.llSize := DrvEx.liExtentLength.QuadPart; // end; if sDrive = '' then exit; sVol := Format('\\.\%s:', [sDrive[1]]); Guard(Drv, TTgDriver.Create); if Drv.OpenDevice(sVol, 0) <> ERROR_SUCCESS then exit; if not Drv.ReadIO(IOCTL_STORAGE_GET_DEVICE_NUMBER, @sdn, SizeOf(sdn), @dwLen) then exit; Drv.CloseDevice; if sdn.DeviceNumber = -1 then exit; pInfo.nDiskNum := sdn.DeviceNumber; case GetDriveType(PChar(sDrive)) of // DRIVE_FIXED, // DRIVE_REMOVABLE : DevGuid := GUID_DEVINTERFACE_DISK; DRIVE_CDROM : DevGuid := GUID_DEVINTERFACE_CDROM; else DevGuid := GUID_DEVINTERFACE_DISK; end; hDev := SetupDiGetClassDevs(@DevGuid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if hDev = INVALID_HANDLE_VALUE then exit; try dwIdx := 0; while True do begin ZeroMemory(@sdid, SizeOf(sdid)); sdid.cbSize := SizeOf(sdid); if not SetupDiEnumDeviceInterfaces(hDev, nil, DevGuid, dwIdx, sdid) then break; SetupDiGetDeviceInterfaceDetail(hDev, @sdid, nil, 0, dwLen, nil); if (dwLen > 0) and (dwLen < 204800) then begin SetLength(pBuf, dwLen); PSPDeviceInterfaceDetailData(@pBuf[0]).cbSize := SizeOf(TSPDeviceInterfaceDetailData); ZeroMemory(@spdd, SizeOf(spdd)); spdd.cbSize := SizeOf(spdd); if SetupDiGetDeviceInterfaceDetail(hDev, @sdid, PSPDeviceInterfaceDetailData(@pBuf[0]), dwLen, dwLen, @spdd) then begin if Drv.OpenDevice(PChar(@pBuf[4]), 0) = ERROR_SUCCESS then begin if not Drv.ReadIO(IOCTL_STORAGE_GET_DEVICE_NUMBER, @sdn, SizeOf(sdn), @dwLen) then exit; Drv.CloseDevice; if sdn.DeviceNumber = pInfo.nDiskNum then begin pInfo.sFriendlyName := GetDevPropertyStr(hDev, spdd, SPDRP_FRIENDLYNAME); if bAddInfo then begin pInfo.sClass := GetDevPropertyStr(hDev, spdd, SPDRP_CLASS); pInfo.sClassGuid := GetDevPropertyStr(hDev, spdd, SPDRP_CLASSGUID); pInfo.sDesc := GetDevPropertyStr(hDev, spdd, SPDRP_DEVICEDESC); end; ZeroMemory(@sDevName, SizeOf(sDevName)); CM_Get_Parent(DevInstParent, spdd.DevInst, 0); CM_Get_Device_ID(DevInstParent, sDevName, 256, 0); pInfo.sSerial := sDevName; Result := true; exit; end; end; end; end; Inc(dwIdx); end; finally SetupDiDestroyDeviceInfoList(hDev); end; end; // for BS1 function ForceEjectDrive(sDrive: String): Boolean; var sEjectMd: String; begin TTgTrace.T('ForceEjectDrive() ..', 1); Result := false; try // if not DirectoryExists(sDrive) then // exit; sEjectMd := GetRunExePathDir + 'Bs1uef.dat'; if not FileExists(sEjectMd) then sEjectMd := GetRunExePathDir + 'conf\Bs1uef.dat'; if FileExists(sEjectMd) then begin ExecuteAppWaitUntilTerminate(sEjectMd, Format('%s: -f', [sDrive[1]]), SW_HIDE, 10000); if not DirectoryExists(sDrive) then Result := true; end; except on E: Exception do ETgException.TraceException(E, 'Fail .. ForceEjectDrive()'); end; end; function LockAndDismountVolume(const DriveLetter: Char): Boolean; var h: THandle; bytes: DWORD; path: string; i: Integer; begin path := Format('\\.\%s:', [UpCase(DriveLetter)]); h := CreateFile(PChar(path), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if h = INVALID_HANDLE_VALUE then Exit(False); try // 락은 충돌 잦으니 여러 번 재시도 for i := 1 to 20 do if DeviceIoControl(h, FSCTL_LOCK_VOLUME, nil, 0, nil, 0, bytes, nil) then Break else Sleep(150); // 잠시 대기 후 재시도 if not DeviceIoControl(h, FSCTL_LOCK_VOLUME, nil, 0, nil, 0, bytes, nil) then Exit(False); // 언마운트(파일시스템 분리) Result := DeviceIoControl(h, FSCTL_DISMOUNT_VOLUME, nil, 0, nil, 0, bytes, nil); finally CloseHandle(h); end; end; function EjectDrive(sDrive: String; aIgrList: TStringList = nil; bOnlyUsb: Boolean = true; bForceEject: Boolean = false): String; var sVol: String; sDevName: array [0..255] of Char; Drv: TTgDriver; sdn: STORAGE_DEVICE_NUMBER; dwIdx, dwLen: DWORD; VetoType: PNP_VETO_TYPE; sVetoName: PChar; nType, nDiskNum: Integer; DevGuid: TGuid; hDev: HDEVINFO; sdid: TSPDeviceInterfaceData; pBuf: TBytes; spdd: TSPDevInfoData; DevInstParent: DEVINST; bIsCdRom, bSuccess: Boolean; DrvEx: TDriveExtent; i: Integer; begin Result := FAIL_EJECT; if sDrive = '' then begin // TTgTrace.T('Fail .. EjectDrive() .. 1'); exit; end; // bIsCdRom := GetDriveType(PChar(sDrive)) = DRIVE_CDROM; sVol := Format('\\.\%s:', [sDrive[1]]); Guard(Drv, TTgDriver.Create); if Drv.OpenDevice(sVol, 0) <> ERROR_SUCCESS then begin // TTgTrace.T('Fail .. EjectDrive() .. 2'); exit; end; ZeroMemory(@sdn, SizeOf(sdn)); sdn.DeviceNumber := 999; if not Drv.ReadIO(IOCTL_STORAGE_GET_DEVICE_NUMBER, @sdn, SizeOf(sdn), @dwLen) then exit; Drv.CloseDevice; nDiskNum := sdn.DeviceNumber; // DrvEx := GetDriveExtent(sDrive); // if DrvEx.liExtentLength.QuadPart = 0 then // begin // TTgTrace.T('Fail .. EjectDrive() .. Size null .. Drive=%s', [sDrive]); // exit; // end; // nDiskNum := DrvEx.dwDiskNumber; if (nDiskNum = -1) or (nDiskNum = 999) then begin // TTgTrace.T('Fail .. EjectDrive() .. Not found disknum .. Drive=%s', [sDrive], 1); exit; end; // TTgTrace.T('EjectDrive() .. Drive=%s, DiskNum=%d', [sDrive, nDiskNum], 1); nType := GetDriveType(PChar(sDrive)); case nType of DRIVE_FIXED, DRIVE_REMOVABLE : DevGuid := GUID_DEVINTERFACE_DISK; DRIVE_CDROM : DevGuid := GUID_dEVINTERFACE_CDROM; end; hDev := SetupDiGetClassDevs(@DevGuid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if hDev = INVALID_HANDLE_VALUE then begin // TTgTrace.T('Fail .. EjectDrive() .. 5'); exit; end; try dwIdx := 0; while True do begin ZeroMemory(@sdid, SizeOf(sdid)); sdid.cbSize := SizeOf(sdid); if not SetupDiEnumDeviceInterfaces(hDev, nil, DevGuid, dwIdx, sdid) then break; // TTgTrace.T('EjectDrive() .. SetupDiGetDeviceInterfaceDetail .. Init'); SetupDiGetDeviceInterfaceDetail(hDev, @sdid, nil, 0, dwLen, nil); if (dwLen > 0) and (dwLen < 204800) then begin SetLength(pBuf, dwLen); PSPDeviceInterfaceDetailData(@pBuf[0]).cbSize := SizeOf(TSPDeviceInterfaceDetailData); ZeroMemory(@spdd, SizeOf(spdd)); spdd.cbSize := SizeOf(spdd); if SetupDiGetDeviceInterfaceDetail(hDev, @sdid, PSPDeviceInterfaceDetailData(@pBuf[0]), dwLen, dwLen, @spdd) then begin // TTgTrace.T('EjectDrive() .. SetupDiGetDeviceInterfaceDetail .. Success'); if Drv.OpenDevice(PChar(@pBuf[4]), 0) = ERROR_SUCCESS then begin // TTgTrace.T('EjectDrive() .. OpenDevice .. Success'); if not Drv.ReadIO(IOCTL_STORAGE_GET_DEVICE_NUMBER, @sdn, SizeOf(sdn), @dwLen) then begin // TTgTrace.T('EjectDrive() .. ReadIO .. Fail'); exit; end; // TTgTrace.T('EjectDrive() .. ReadIO .. Success, DiskNum=%d', [sdn.DeviceNumber]); Drv.CloseDevice; if sdn.DeviceNumber = nDiskNum then begin DevInstParent := 0; ZeroMemory(@sDevName, SizeOf(sDevName)); CM_Get_Parent(DevInstParent, spdd.DevInst, 0); CM_Get_Device_ID(DevInstParent, sDevName, 256, 0); // TTgTrace.T('EjectDrive() .. DevName=%s', [sDevName]); // if bIsCdRom and (Pos('CDROM', UpperCase(sDevName)) = 0) then // begin // TTgTrace.T('EjectDrive() .. No CDROM, DiskNum=%d', [sdn.DeviceNumber]); // Inc(dwIdx); // continue; // end; // TTgTrace.T('EjectDrive() .. Found CDROM, DiskNum=%d', [sdn.DeviceNumber]); // if bOnlyUsb and (Pos('USB', UpperCase(sDevName)) <> 1) then // begin // TTgTrace.T('Fail .. EjectDrive() .. 7'); // exit; // end; if aIgrList <> nil then begin // if aIgrList.CaseSensitive then // aIgrList.CaseSensitive := false; // if aIgrList.IndexOf(sDevName) <> -1 then // begin // Result := ''; // exit; // end; // 비교방식 변경 25_0324 10:12:22 kku var sChkDevName: String := UpperCase(sDevName); for i := 0 to aIgrList.Count - 1 do if Pos(UpperCase(aIgrList[i]), sDevName) > 0 then begin Result := ''; exit; end; end; // TTgTrace.T('EjectDrive() .. DevName=%s, DiskNum=%d', [sDevName, nDiskNum], 1); VetoType := 0; sVetoName := nil; // var ss: TStringStream; // Guard(ss, TStringStream.Create('', TEncoding.ANSI)); // if GetCmdTextToStream('mountvol.exe', Format('%s: /L', [sDrive[1]]), ss, 5000) then // begin // ExecutePath('mountvol.exe', Format('%s: /D', [sDrive[1]])); // Sleep(500); // bSuccess := CM_Request_Device_Eject(DevInstParent, @VetoType, sVetoName, MAX_PATH, 0) = CR_SUCCESS; // ExecutePath('mountvol.exe', Format('%s: %s', [sDrive[1], StringReplace(Trim(ss.DataString), #13#10, '', [rfReplaceAll])])); //// if not DirectoryExists(sDrive) then //// Result := sDevName; // end; // LockAndDismountVolume(sDrive[1]); bSuccess := CM_Request_Device_Eject(DevInstParent, @VetoType, sVetoName, MAX_PATH, 0) = CR_SUCCESS; if bSuccess and (VetoType = 0) then begin // ShowMessage(Format('%d - %s', [sdn.DeviceNumber, sDevName])); Result := sDevName; end else begin TTgTrace.T('Fail .. EjectDrive() .. VetoType=%d, LastError=%d', [VetoType, GetLastError], 1); if bForceEject then begin if ForceEjectDrive(sDrive) then Result := sDevName; end; // ExecutePath('mountvol.exe', Format('%s: /P', [sDrive[1]])); // Sleep(500); // if not DirectoryExists(sDrive) then // begin // Result := sDevName; // end; end; exit; end; end; // else // TTgTrace.T('EjectDrive() .. OpenDevice .. Fail'); end; // else // TTgTrace.T('EjectDrive() .. SetupDiGetDeviceInterfaceDetail .. Fail'); end; Inc(dwIdx); end; finally SetupDiDestroyDeviceInfoList(hDev); end; // if Result = FAIL_EJECT then // TTgTrace.T('Fail .. EjectDrive() .. end'); end; function EjectDrive2(sDrive: String; aIgrList: TStringList = nil; bOnlyUsb: Boolean = true; bForceEject: Boolean = false; bForceEjectFirst: Boolean = false): String; var sVol: String; sDevName: array [0..255] of Char; Drv: TTgDriver; sdn: STORAGE_DEVICE_NUMBER; dwIdx, dwLen: DWORD; VetoType: PNP_VETO_TYPE; sVetoName: PChar; nType, nDiskNum: Integer; DevGuid: TGuid; hDev: HDEVINFO; sdid: TSPDeviceInterfaceData; pBuf: TBytes; spdd: TSPDevInfoData; DevInstParent: DEVINST; bSuccess: Boolean; DrvEx: TDriveExtent; i: Integer; begin Result := FAIL_EJECT; if sDrive = '' then exit; sVol := Format('\\.\%s:', [sDrive[1]]); Guard(Drv, TTgDriver.Create); if Drv.OpenDevice(sVol, 0) <> ERROR_SUCCESS then exit; ZeroMemory(@sdn, SizeOf(sdn)); sdn.DeviceNumber := 999; if not Drv.ReadIO(IOCTL_STORAGE_GET_DEVICE_NUMBER, @sdn, SizeOf(sdn), @dwLen) then exit; Drv.CloseDevice; // nDiskNum := sdn.DeviceNumber; // nDiskNum := GetDriveExtent(sDrive).dwDiskNumber; // DrvEx := GetDriveExtent(sDrive); // if DrvEx.liExtentLength.QuadPart = 0 then // begin // TTgTrace.T('Fail .. EjectDrive2() .. Size null .. Drive=%s', [sDrive]); // exit; // end; // nDiskNum := DrvEx.dwDiskNumber; if (nDiskNum = -1) or (nDiskNum = 999) then begin TTgTrace.T('Fail .. EjectDrive2() .. Not found disknum .. Drive=%s', [sDrive], 1); exit; end; TTgTrace.T('EjectDrive2() .. Drive=%s, DiskNum=%d', [sDrive, nDiskNum], 1); // TTgTrace.T('EjectDrive2() .. Drive=%s, DiskNum=%d', [sDrive, nDiskNum]); nType := GetDriveType(PChar(sDrive)); case nType of DRIVE_FIXED, DRIVE_REMOVABLE : DevGuid := GUID_DEVINTERFACE_DISK; DRIVE_CDROM : DevGuid := GUID_DEVINTERFACE_CDROM; end; hDev := SetupDiGetClassDevs(@DevGuid, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE); if hDev = INVALID_HANDLE_VALUE then exit; try dwIdx := 0; while True do begin ZeroMemory(@sdid, SizeOf(sdid)); sdid.cbSize := SizeOf(sdid); if not SetupDiEnumDeviceInterfaces(hDev, nil, DevGuid, dwIdx, sdid) then break; SetupDiGetDeviceInterfaceDetail(hDev, @sdid, nil, 0, dwLen, nil); if (dwLen > 0) and (dwLen < 204800) then begin SetLength(pBuf, dwLen); PSPDeviceInterfaceDetailData(@pBuf[0]).cbSize := SizeOf(TSPDeviceInterfaceDetailData); ZeroMemory(@spdd, SizeOf(spdd)); spdd.cbSize := SizeOf(spdd); if SetupDiGetDeviceInterfaceDetail(hDev, @sdid, PSPDeviceInterfaceDetailData(@pBuf[0]), dwLen, dwLen, @spdd) then begin if Drv.OpenDevice(PChar(@pBuf[4]), 0) = ERROR_SUCCESS then begin if not Drv.ReadIO(IOCTL_STORAGE_GET_DEVICE_NUMBER, @sdn, SizeOf(sdn), @dwLen) then exit; Drv.CloseDevice; if sdn.DeviceNumber = nDiskNum then begin DevInstParent := 0; ZeroMemory(@sDevName, SizeOf(sDevName)); CM_Get_Parent(DevInstParent, spdd.DevInst, 0); CM_Get_Device_ID(DevInstParent, sDevName, 256, 0); // if Pos('CDROM', UpperCase(sDevName)) = 0 then // begin // Inc(dwIdx); // continue; // end; if bOnlyUsb and (Pos('USB', UpperCase(sDevName)) <> 1) then exit; TTgTrace.T('EjectDrive2() .. DevName=%s, DiskNum=%d', [sDevName, nDiskNum], 1); // TTgTrace.T('EjectDrive() .. DevName=%s, DiskNum=%d', [sDevName, nDiskNum]); if aIgrList <> nil then begin // if aIgrList.CaseSensitive then // aIgrList.CaseSensitive := false; // if aIgrList.IndexOf(sDevName) <> -1 then // begin // Result := ''; // exit; // end; // 비교방식 변경 25_0324 10:12:22 kku var sChkDevName: String := UpperCase(sDevName); for i := 0 to aIgrList.Count - 1 do if Pos(UpperCase(aIgrList[i]), sDevName) > 0 then begin Result := ''; exit; end; end; VetoType := 0; sVetoName := nil; if bForceEjectFirst then begin if ForceEjectDrive(sDrive) then begin Result := sDevName; exit; end else bSuccess := CM_Query_And_Remove_SubTree(DevInstParent, @VetoType, sVetoName, MAX_PATH, CM_REMOVE_NO_RESTART) = CR_SUCCESS; end else begin bSuccess := CM_Query_And_Remove_SubTree(DevInstParent, @VetoType, sVetoName, MAX_PATH, CM_REMOVE_NO_RESTART) = CR_SUCCESS; // EjectDrive()와 다른점 23_0223 16:24:47 kku // bSuccess := CM_Query_And_Remove_SubTree(DevInstParent, nil, nil, 0, CM_REMOVE_NO_RESTART) = CR_SUCCESS; // EjectDrive()와 다른점 23_0223 16:24:47 kku end; if bSuccess and (VetoType = 0) then begin // ShowMessage(Format('%d - %s', [sdn.DeviceNumber, sDevName])); Result := sDevName; end else begin TTgTrace.T('Fail .. EjectDrive2() .. VetoType=%d, LastError=%d', [VetoType, GetLastError], 1); if bForceEject then begin if ForceEjectDrive(sDrive) then Result := sDevName; end; // var ss: TStringStream; // Guard(ss, TStringStream.Create('', TEncoding.ANSI)); // if GetCmdTextToStream('mountvol.exe', Format('%s: /P', [sDrive[1]]), ss, 5000) then // begin // ExecutePath('mountvol.exe', Format('%s: /P', [sDrive[1]])); // Sleep(500); // if not DirectoryExists(sDrive) then // Result := sDevName; // end; end; exit; end; end; end; end; Inc(dwIdx); end; finally SetupDiDestroyDeviceInfoList(hDev); end; end; function SetUsbDevEnableByDevPath(sDevPath: String; bVal: Boolean): Boolean; var hDev: HDEVINFO; sdd: TSPDevInfoData; i, c: Integer; dwBufSize, dwStatus, dwProblem, dwPropertyRegDataType: DWORD; pBuf: Pointer; sInfo: String; InfoList: TStringList; begin Result := false; try hDev := SetupDiGetClassDevs(@GUID_DEVCLASS_USB, nil, 0, DIGCF_PRESENT); if hDev = INVALID_HANDLE_VALUE then exit; pBuf := nil; try ZeroMemory(@sdd, SizeOf(sdd)); sdd.cbSize := SizeOf(sdd); Guard(InfoList, TStringList.Create); i := 0; while SetupDiEnumDeviceInfo(hDev, i, sdd) do begin dwBufSize := 0; if pBuf <> nil then begin FreeMem(pBuf); pBuf := nil; end; while not SetupDiGetDeviceRegistryProperty(hDev, sdd, SPDRP_HARDWAREID, dwPropertyRegDataType, pBuf, dwBufSize, dwBufSize) do begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin if pBuf <> nil then FreeMem(pBuf); pBuf := AllocMem(dwBufSize); end else break; end; if pBuf <> nil then begin sInfo := ''; InfoList.Clear; for c := 0 to (dwBufSize div 2) - 1 do begin if PChar(pBuf)[c] = #0 then begin if sInfo <> '' then begin InfoList.Add(sInfo); sInfo := ''; end; end else sInfo := sInfo + PChar(pBuf)[c]; end; if sInfo <> '' then InfoList.Add(sInfo); for c := 0 to InfoList.Count - 1 do begin if Pos(InfoList[c], sDevPath) > 0 then begin dwStatus := 0; dwProblem := 0; if CM_Get_DevNode_Status(dwStatus, dwProblem, sdd.DevInst, 0) = CR_SUCCESS then begin var PropChangeParams: TSPPropChangeParams; ZeroMemory(@PropChangeParams, SizeOf(PropChangeParams)); PropChangeParams.ClassInstallHeader.cbSize := SizeOf(TSPClassInstallHeader); PropChangeParams.ClassInstallHeader.InstallFunction := DIF_PROPERTYCHANGE; PropChangeParams.Scope := DICS_FLAG_GLOBAL; PropChangeParams.StateChange := BooleanToInt(bVal, DICS_ENABLE, DICS_DISABLE); if SetupDiSetClassInstallParams(hDev, @sdd, PSPClassInstallHeader(@PropChangeParams), SizeOf(PropChangeParams)) then begin // 64bit OS 에서는 64bit 프로그램 에서만 실행 가능하다 22_0621 13:59:21 kku Result := SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDev, @sdd); end; end; exit; end; end; end; Inc(i); end; finally SetupDiDestroyDeviceInfoList(hDev); if pBuf <> nil then FreeMem(pBuf); end; except on E: Exception do ETgException.TraceException(E, 'Fail .. SetUsbDevEnableByDevPath()'); end; end; // Result .. -1 = Fail API, 0 = Not found, 1 = Success, 2 = Fail Remove function _RemoveUsbDevEnableByDevPath(pClassGuid: PGUID; sDevPath: String): Integer; var hDev: HDEVINFO; sdd: TSPDevInfoData; i, c: Integer; dwBufSize, dwStatus, dwProblem, dwPropertyRegDataType: DWORD; pBuf: Pointer; sInfo: String; InfoList: TStringList; begin Result := -1; try hDev := SetupDiGetClassDevs(pClassGuid, nil, 0, DIGCF_PRESENT); if hDev = INVALID_HANDLE_VALUE then exit; pBuf := nil; try ZeroMemory(@sdd, SizeOf(sdd)); sdd.cbSize := SizeOf(sdd); Guard(InfoList, TStringList.Create); i := 0; while SetupDiEnumDeviceInfo(hDev, i, sdd) do begin dwBufSize := 0; if pBuf <> nil then begin FreeMem(pBuf); pBuf := nil; end; while not SetupDiGetDeviceRegistryProperty(hDev, sdd, SPDRP_HARDWAREID, dwPropertyRegDataType, pBuf, dwBufSize, dwBufSize) do begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin if pBuf <> nil then FreeMem(pBuf); pBuf := AllocMem(dwBufSize); end else break; end; if pBuf <> nil then begin sInfo := ''; InfoList.Clear; for c := 0 to (dwBufSize div 2) - 1 do begin if PChar(pBuf)[c] = #0 then begin if sInfo <> '' then begin InfoList.Add(sInfo); sInfo := ''; end; end else sInfo := sInfo + PChar(pBuf)[c]; end; if sInfo <> '' then InfoList.Add(sInfo); for c := 0 to InfoList.Count - 1 do begin if Pos(InfoList[c], sDevPath) > 0 then begin dwStatus := 0; dwProblem := 0; if CM_Get_DevNode_Status(dwStatus, dwProblem, sdd.DevInst, 0) = CR_SUCCESS then begin if SetupDiRemoveDevice(hDev, sdd) then Result := 1 else Result := 2; end; exit; end; end; end; Inc(i); end; Result := 0; finally SetupDiDestroyDeviceInfoList(hDev); if pBuf <> nil then FreeMem(pBuf); end; except on E: Exception do ETgException.TraceException(E, 'Fail .. SetUsbDevEnableByDevPath()'); end; end; function RemoveUsbDevEnableByDevPath(sDevPath: String): Integer; begin Result := _RemoveUsbDevEnableByDevPath(@GUID_DEVCLASS_USB, sDevPath); if Result = 0 then begin // 애플 장치는 여기로 (범용 직렬 버스 장치) 따로 잡힌다... 그래서 별도 추가 처리 22_0707 09:23:40 kku Result := _RemoveUsbDevEnableByDevPath(@GUID_DEVCLASS_USB_DEVICE, sDevPath); end; if Result = 0 then begin // MTP 장치등... 추가 23_0323 13:47:12 kku Result := _RemoveUsbDevEnableByDevPath(@GUID_DEVCLASS_WPD, sDevPath); end; end; { initialization IOCTL_DISK_GET_LENGTH_INFO := CTL_CODE(IOCTL_DISK_BASE, $0017, METHOD_BUFFERED, FILE_READ_ACCESS); IOCTL_DISK_GET_DRIVE_GEOMETRY_EX := CTL_CODE(IOCTL_DISK_BASE, $0028, METHOD_BUFFERED, FILE_ANY_ACCESS); IOCTL_STORAGE_QUERY_PROPERTY := CTL_CODE(IOCTL_STORAGE_BASE, $0500, METHOD_BUFFERED, FILE_ANY_ACCESS);//$2D1400 IOCTL_STORAGE_GET_MEDIA_TYPES_EX := CTL_CODE(IOCTL_STORAGE_BASE, $0301, METHOD_BUFFERED, FILE_ANY_ACCESS); IOCTL_STORAGE_MEDIA_REMOVAL := CTL_CODE(IOCTL_STORAGE_BASE, $0201, METHOD_BUFFERED, FILE_READ_ACCESS); IOCTL_STORAGE_EJECTION_CONTROL := $2D0940;//CTL_CODE(IOCTL_STORAGE_BASE, $0250, METHOD_BUFFERED, FILE_ANY_ACCESS); //$2D0940 IOCTL_STORAGE_EJECT_MEDIA := CTL_CODE(IOCTL_STORAGE_BASE, $0202, METHOD_BUFFERED, FILE_READ_ACCESS); FSCTL_DISMOUNT_VOLUME := CTL_CODE(FILE_DEVICE_FILE_SYSTEM,8,METHOD_BUFFERED,FILE_ANY_ACCESS); FSCTL_LOCK_VOLUME := CTL_CODE(FILE_DEVICE_FILE_SYSTEM,6,METHOD_BUFFERED,FILE_ANY_ACCESS); FSCTL_UNLOCK_VOLUME := CTL_CODE(FILE_DEVICE_FILE_SYSTEM,7,METHOD_BUFFERED,FILE_ANY_ACCESS); FSCTL_IS_VOLUME_MOUNTED := CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10,METHOD_BUFFERED,FILE_ANY_ACCESS); FSCTL_ALLOW_EXTENDED_DASD_IO := CTL_CODE(FILE_DEVICE_FILE_SYSTEM,32,METHOD_BUFFERED,FILE_ANY_ACCESS); //IOCTL_STORAGE_MEDIA_REMOVAL := ($2d shl 16) or (1 shl 14) or ($201 shl 2) or 0; //IOCTL_STORAGE_EJECT_MEDIA := ($2d shl 16) or (1 shl 14) or ($202 shl 2) or 0; } end.