; #### Flags for _CM_Get_Class_Devs ####
; ================================================================================
Const $DIGCF_DEFAULT = 1
Const $DIGCF_PRESENT = 2
Const $DIGCF_ALLCLASSES = 4
Const $DIGCF_PROFILE = 8
Const $DIGCF_DEVICEINTERFACE = 16
; ================================================================================
; #### Access rights for _CM_Create_File ####
; ================================================================================
Const $GENERIC_ALL = 0x10000000
Const $GENERIC_EXECUTE = 0x20000000
Const $GENERIC_WRITE = 0x40000000
Const $GENERIC_READ = 0x80000000
; ================================================================================
; #### IO Control codes #####
; ================================================================================
Const $IOCTL_STORAGE_BASE = 0x2D
Const $IOCTL_STORAGE_MEDIA_REMOVAL = 0x2D4804
Const $IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808
Const $IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080
; ================================================================================
; #### DDK, SDK Structures ####
; ================================================================================
Const $tagSP_DEVINFO_DATA = "dword Size;byte Guid[16];dword DevInst;ulong_ptr Reserved"
Const $tagSP_DEVICE_INTERFACE_DATA = "dword Size;byte Guid[16];dword Flags;ulong_ptr Reserved"
Const $tagSTORAGE_DEVICE_NUMBER = "int DeviceType;ulong DeviceNumber;ulong PartitionNumber"
; ================================================================================
; #### Handle value, Interface class GUID ####
; ================================================================================
Const $CM_DRP_REMOVAL_POLICY = 0x20
Const $DN_REMOVABLE = 0x00004000
Const $SPDRP_REMOVAL_POLICY = 0x1F
Const $SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x20
Const $INVALID_HANDLE_VALUE = 0xFFFFFFFF
Const $GUID_DEVINTERFACE_DISK = "{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}"
; ================================================================================
; #### Removal policies ####
; ================================================================================
Const $CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL = 1
Const $CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL = 2
Const $CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL = 3
; ================================================================================
Func _CM_Create_File($sFilePath, $iDesiredAccess, $iShareMode, $pSecur, $iCreationFlags, $iAttrFlags, $hTemplate = 0)
Local $hFile
$hFile = DllCall("Kernel32.dll", "long", "CreateFile", "str", $sFilePath, "dword", $iDesiredAccess, _
"dword", $iShareMode, "ptr", $pSecur, "dword", $iCreationFlags, _
"dword", $iAttrFlags, "long", $hTemplate)
If $hFile[0] = $INVALID_HANDLE_VALUE Then
Return SetError(_CM_Get_Last_Error(), 0, -1)
Else
Return $hFile[0]
EndIf
EndFunc ;==>_CM_Create_File
Func _CM_Close_Handle($hHandle)
Local $iResult
$iResult = DllCall("Kernel32.dll", "int", "CloseHandle", "long", $hHandle)
Return $iResult[0]
EndFunc ;==>_CM_Close_Handle
Func _CM_Get_Last_Error()
Local $iResult = DllCall("Kernel32.dll", "long", "GetLastError")
Return $iResult[0]
EndFunc ;==>_CM_Get_Last_Error
Func _CM_Device_IO_Control($hFile, $iControlCode, $pIn, $iIn, $pOut, $iOut, $pOverlapped = 0)
Local $iResult
If IsDllStruct($pIn) Then $pIn = DllStructGetPtr($pIn)
If IsDllStruct($pOut) Then $pOut = DllStructGetPtr($pOut)
If IsDllStruct($pOverlapped) Then $pOverlapped = DllStructGetPtr($pOverlapped)
$iResult = DllCall("Kernel32.dll", "int", "DeviceIoControl", "long", $hFile, _
"dword", $iControlCode, "ptr", $pIn, "dword", $iIn, _
"ptr", $pOut, "dword", $iOut, "dword*", 0, "ptr", $pOverlapped)
If $iResult[0] Then
Return 1
Else
Return SetError(_CM_Get_Last_Error(), 0, 0)
EndIf
EndFunc ;==>_CM_Device_IO_Control
Func _CM_Get_Drive_Disk_Number($hDrive)
Local $fResult, $tBuffer, $iType, $iNumber
$tBuffer = DllStructCreate($tagSTORAGE_DEVICE_NUMBER)
$fResult = _CM_Device_IO_Control($hDrive, $IOCTL_STORAGE_GET_DEVICE_NUMBER, _
0, 0, $tBuffer, DllStructGetSize($tBuffer), 0)
If $fResult = 0 Then Return SetError(@error, -1, -1)
$iType = DllStructGetData($tBuffer, "DeviceType")
$iNumber = DllStructGetData($tBuffer, "DeviceNumber")
Return SetError(_CM_Free_Var($tBuffer), $iType, $iNumber)
EndFunc ;==>_CM_Get_Drive_Disk_Number
Func _CM_GUID_From_String($sGUID)
Local $tGUID, $iResult, $pGUID
$tGUID = DllStructCreate("byte GUID[16]")
$pGUID = DllStructGetPtr($tGUID)
$iResult = DllCall("Ole32.dll", "int", "CLSIDFromString", "wstr", $sGUID, "ptr", $pGUID)
Return SetError($iResult[0], 0, $tGUID)
EndFunc ;==>_CM_GUID_From_String
Func _CM_Free_Var(ByRef $vVar)
$vVar = 0
Return $vVar
EndFunc ;==>_CM_Free_Var
Func _CM_Get_Class_Devs($iFlags, $pGUID = 0, $sEnumerator = "", $hWnd = 0)
Local $iResult, $sType = "ptr"
If $sEnumerator <> "" Then $sType = "str"
If IsDllStruct($pGUID) Then $pGUID = DllStructGetPtr($pGUID)
$iResult = DllCall("Setupapi.dll", "ptr", "SetupDiGetClassDevs", "ptr", $pGUID, _
$sType, $sEnumerator, "hWnd", $hWnd, "dword", $iFlags)
If $iResult[0] = $INVALID_HANDLE_VALUE Then
Return SetError(_CM_Get_Last_Error(), 0, -1)
Else
Return $iResult[0]
EndIf
EndFunc ;==>_CM_Get_Class_Devs
Func _CM_Enum_Device_Interfaces($hDevs, $pSP_DEVINFO_DATA, $pClassGUID, $iIndex, ByRef $tSP_DEVICE_INTERFACE_DATA)
Local $iResult, $pSP_DEVICE_INTERFACE_DATA
If IsDllStruct($pClassGUID) Then $pClassGUID = DllStructGetPtr($pClassGUID)
If IsDllStruct($pSP_DEVINFO_DATA) Then
$pSP_DEVINFO_DATA = DllStructGetPtr($pSP_DEVINFO_DATA)
EndIf
If IsDllStruct($tSP_DEVICE_INTERFACE_DATA) = 0 Then
$tSP_DEVICE_INTERFACE_DATA = DllStructCreate($tagSP_DEVICE_INTERFACE_DATA)
DllStructSetData($tSP_DEVICE_INTERFACE_DATA, "Size", 28)
EndIf
$pSP_DEVICE_INTERFACE_DATA = DllStructGetPtr($tSP_DEVICE_INTERFACE_DATA)
$iResult = DllCall("Setupapi.dll", "int", "SetupDiEnumDeviceInterfaces", "ptr", $hDevs, _
"ptr", $pSP_DEVINFO_DATA, "ptr", $pClassGUID, "dword", $iIndex, _
"ptr", $pSP_DEVICE_INTERFACE_DATA)
If $iResult[0] <> 0 Then
Return 1
Else
Return SetError(_CM_Get_Last_Error(), 0, 0)
EndIf
EndFunc ;==>_CM_Enum_Device_Interfaces
Func _CM_Get_Device_Interface_Detail($hDevs, $pSP_DEVICE_INTERFACE_DATA, ByRef $tSP_DEVINFO_DATA)
Local $iResult, $pSP_DEVINFO_DATA, $tDevInterfaceDetail, $sDevPath, $iSysError = 0
If IsDllStruct($pSP_DEVICE_INTERFACE_DATA) Then
$pSP_DEVICE_INTERFACE_DATA = DllStructGetPtr($pSP_DEVICE_INTERFACE_DATA)
EndIf
If IsDllStruct($tSP_DEVINFO_DATA) = 0 Then
$tSP_DEVINFO_DATA = DllStructCreate($tagSP_DEVINFO_DATA)
DllStructSetData($tSP_DEVINFO_DATA, "Size", 28)
EndIf
$pSP_DEVINFO_DATA = DllStructGetPtr($tSP_DEVINFO_DATA)
$iResult = DllCall("Setupapi.dll", "int", "SetupDiGetDeviceInterfaceDetail", "ptr", $hDevs, _
"ptr", $pSP_DEVICE_INTERFACE_DATA, "ptr", 0, "dword", 0, _
"dword*", 0, "ptr", $pSP_DEVINFO_DATA)
If $iResult[5] - 4 < 1 Then Return SetError(_CM_Get_Last_Error(), 0, "")
$tDevInterfaceDetail = DllStructCreate("dword;char[" & $iResult[5] - 4 & "]")
DllStructSetData($tDevInterfaceDetail, 1, 5)
$iResult = DllCall("Setupapi.dll", "int", "SetupDiGetDeviceInterfaceDetail", _
"ptr", $hDevs, "ptr", $pSP_DEVICE_INTERFACE_DATA, _
"ptr", DllStructGetPtr($tDevInterfaceDetail), "dword", $iResult[5], _
"dword*", 0, "ptr", $pSP_DEVINFO_DATA)
If $iResult[0] = 0 Then $iSysError = _CM_Get_Last_Error()
$sDevPath = DllStructGetData($tDevInterfaceDetail, 2)
Return SetError($iSysError, _CM_Free_Var($tDevInterfaceDetail), $sDevPath)
EndFunc ;==>_CM_Get_Device_Interface_Detail
Func _CM_Get_Drive_Type($sDrive)
Local $iResult, $hDevs, $tDevInfo, $tDevIfInfo, $hDevInst, $iIndex, $iFlags, $tGUID, $hDisk, $iDiskNumber, $sDevicePath
Local $aType[8] = ["UNKNOWN", "NO_ROOT_DIR", "REMOVABLE", "FIXED", "REMOTE", "CDROM", "RAMDISK", "REMOVABLE_DISK"]
$iResult = DllCall("Kernel32.dll", "uint", "GetDriveType", "str", $sDrive)
If $iResult[0] <> 3 Then Return $aType[$iResult[0]]
$sDrive = "\\." & $sDrive
If StringRight($sDrive, 1) = "" Then $sDrive = StringTrimRight($sDrive, 1)
$hDisk = _CM_Create_File($sDrive, bitOR($GENERIC_READ, $GENERIC_WRITE), 3, 0, 3, 0)
$iDiskNumber = _CM_Get_Drive_Disk_Number($hDisk)
$iResult = _CM_Close_Handle($hDisk)
If $iDiskNumber = -1 Then Return "UNKNOWN"
$iFlags = bitOR($DIGCF_PRESENT, $DIGCF_DEVICEINTERFACE)
$tGUID = _CM_GUID_From_String($GUID_DEVINTERFACE_DISK)
$hDevs = _CM_Get_Class_Devs($iFlags, $tGUID)
If $hDevs < 1 Then Return "UNKNOWN"
$iFlags = bitOR($GENERIC_READ, $GENERIC_WRITE)
While _CM_Enum_Device_Interfaces($hDevs, 0, $tGUID, $iIndex, $tDevIfInfo)
$iIndex += 1
$sDevicePath = _CM_Get_Device_Interface_Detail($hDevs, $tDevIfInfo, $tDevInfo)
$hDisk = _CM_Create_File($sDevicePath, $iFlags, 3, 0, 3, 0)
If $hDisk < 1 Then ContinueLoop
If _CM_Get_Drive_Disk_Number($hDisk) <> $iDiskNumber Then
ContinueLoop _CM_Close_Handle($hDisk)
EndIf
_CM_Close_Handle($hDisk)
$iResult = _CM_Get_Device_Registry_Property($hDevs, $tDevInfo, $SPDRP_REMOVAL_POLICY)
_CM_Destroy_Device_Info_List($hDevs)
If bitAND($iResult, $CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL) = 2 Then
Return SetExtended(_CM_Free_Var($tDevInfo), "REMOVABLE_DISK")
Else
Return SetExtended(_CM_Free_Var($tDevInfo), "FIXED")
EndIf
WEnd
EndFunc ;==>_CM_Get_Drive_Type
Func _CM_Safely_Eject_Device($sDrive)
Local $iDiskNum, $hDisk, $fResult, $sDevicePath, $iAccessMask, $iIndex, $iDevNodeStat
Local $sDeviceID, $iMask, $tClassGUID, $hDevs, $tDevInfo, $tDevIfInfo, $hDevInst, $hDevInst1
$iAccessMask = bitOR($GENERIC_READ, $GENERIC_WRITE)
If StringRight($sDrive, 1) = "" Then $sDrive = StringTrimRight($sDrive, 1)
$hDisk = _CM_Create_File("\\." & $sDrive, $iAccessMask, 3, 0, 3, 0)
If $hDisk < 1 Then Return SetError(@error, 0, 0)
$iDiskNum = _CM_Get_Drive_Disk_Number($hDisk)
If $iDiskNum = -1 Then Return SetError(@error, _CM_Close_Handle($hDisk), 0)
_CM_Close_Handle($hDisk)
Switch _CM_Get_Drive_Type($sDrive)
Case "CDROM"
$hDisk = _CM_Create_File("\\.\CdRom" & $iDiskNum, $iAccessMask, 3, 0, 3, 0)
If $hDisk < 1 Then Return SetError(@error, 0, 0)
$fResult = _CM_Device_IO_Control($hDisk, $IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0)
Return SetError(@error, _CM_Close_Handle($hDisk), $fResult)
Case "REMOVABLE", "REMOVABLE_DISK"
$iMask = bitOR($DIGCF_PRESENT, $DIGCF_DEVICEINTERFACE)
$tClassGUID = _CM_GUID_From_String($GUID_DEVINTERFACE_DISK)
$hDevs = _CM_Get_Class_Devs($iMask, $tClassGUID)
While _CM_Enum_Device_Interfaces($hDevs, 0, $tClassGUID, $iIndex, $tDevIfInfo)
$iIndex += 1
$sDevicePath = _CM_Get_Device_Interface_Detail($hDevs, $tDevIfInfo, $tDevInfo)
$hDisk = _CM_Create_File($sDevicePath, $iAccessMask, 3, 0, 3, 0)
If $hDisk < 1 Then ContinueLoop
If _CM_Get_Drive_Disk_Number($hDisk) <> $iDiskNum Then
ContinueLoop _CM_Close_Handle($hDisk)
EndIf
_CM_Close_Handle($hDisk)
_CM_Destroy_Device_Info_List($hDevs)
$hDevInst = DllStructGetData($tDevInfo, "DevInst")
$hDevInst1 = $hDevInst
$iDevNodeStat = _CM_Get_DevNode_Status($hDevInst)
If bitAND($iDevNodeStat, $DN_REMOVABLE) <> $DN_REMOVABLE Then
$hDevInst1 = _CM_Get_Parent($hDevInst)
$iDevNodeStat = _CM_Get_DevNode_Status($hDevInst1)
If bitAND($iDevNodeStat, $DN_REMOVABLE) <> $DN_REMOVABLE Then
Return SetError(50, 0, 0)
EndIf
EndIf
$sDeviceID = _CM_Get_Device_ID($hDevInst1)
Select
Case _CM_Create_Device_Devs($sDeviceID, $hDevs, $tDevInfo) = 0
Return SetError(@error, 0, 0)
Case _CM_Remove_Device($hDevs, $tDevInfo) = 0
Return SetError(@error, _CM_Destroy_Device_Info_List($hDevs), 0)
Case Else
Return _CM_Destroy_Device_Info_List($hDevs) * 0 + 1
EndSelect
WEnd
Case Else
Return SetError(50, 0, 0)
EndSwitch
EndFunc ;==>_CM_Safely_Eject_Device
Func _CM_Get_Device_ID($hDevInst)
Local $iResult
$iResult = DllCall("Setupapi.dll", "int", "CM_Get_Device_ID", "dword", $hDevInst, _
"str", "", "ulong", 260, "ulong", 0)
Return SetError($iResult[0], 0, $iResult[2])
EndFunc ;==>_CM_Get_Device_ID
Func _CM_Create_Device_Info_List($pClassGUID = 0, $hWnd = 0)
Local $iResult
If IsDllStruct($pClassGUID) Then $pClassGUID = DllStructGetPtr($pClassGUID)
$iResult = DllCall("Setupapi.dll", "ptr", "SetupDiCreateDeviceInfoList", _
"ptr", $pClassGUID, "hWnd", $hWnd)
Return SetError(_CM_Get_Last_Error(), 0, $iResult[0])
EndFunc ;==>_CM_Create_Device_Info_List
Func _CM_Open_Device_Info($hDevs, $sDeviceID, ByRef $tSP_DEVINFO_DATA, $iFlags = 0)
Local $iResult, $pSP_DEVINFO_DATA
If Not IsDllStruct($tSP_DEVINFO_DATA) Then
$tSP_DEVINFO_DATA = DllStructCreate($tagSP_DEVINFO_DATA)
DllStructSetData($tSP_DEVINFO_DATA, "Size", 28)
EndIf
$pSP_DEVINFO_DATA = DllStructGetPtr($tSP_DEVINFO_DATA)
$iResult = DllCall("Setupapi.dll", "int", "SetupDiOpenDeviceInfo", "ptr", $hDevs, _
"str", $sDeviceID, "hWnd", 0, "dword", $iFlags, _
"ptr", $pSP_DEVINFO_DATA)
Return SetError(_CM_Get_Last_Error(), 0, $iResult[0])
EndFunc ;==>_CM_Open_Device_Info
Func _CM_Set_Selected_Device($hDevs, $pSP_DEVINFO_DATA)
Local $iResult
If IsDllStruct($pSP_DEVINFO_DATA) Then
$pSP_DEVINFO_DATA = DllStructGetPtr($pSP_DEVINFO_DATA)
EndIf
$iResult = DllCall("Setupapi.dll", "int", "SetupDiSetSelectedDevice", "ptr", $hDevs, _
"ptr", $pSP_DEVINFO_DATA)
Return SetError(_CM_Get_Last_Error(), 0, $iResult[0])
EndFunc ;==>_CM_Set_Selected_Device
Func _CM_Get_DevNode_Status($hDevInst)
Local $iResult
$iResult = DllCall("Setupapi.dll", "long", "CM_Get_DevNode_Status", "ulong*", 0, _
"ulong*", 0, "dword", $hDevInst, "ulong", 0)
Return SetError($iResult[0], $iResult[2], $iResult[1])
EndFunc ;==>_CM_Get_DevNode_Status
Func _CM_Get_Parent($hDevInst)
Local $iResult
$iResult = DllCall("Setupapi.dll", "long", "CM_Get_Parent", "dword*", 0, _
"dword", $hDevInst, "ulong", 0)
Return SetError($iResult[0], 0, $iResult[1])
EndFunc ;==>_CM_Get_Parent
Func _CM_Create_Device_Devs($sDeviceID, ByRef $hDevs, ByRef $tSP_DEVINFO_DATA)
$hDevs = _CM_Create_Device_Info_List()
If $hDevs < 1 Then Return SetError(@error, 0, 0)
Select
Case _CM_Open_Device_Info($hDevs, $sDeviceID, $tSP_DEVINFO_DATA) = 0
Return SetError(@error, _CM_Destroy_Device_Info_List($hDevs), 0)
Case _CM_Set_Selected_Device($hDevs, $tSP_DEVINFO_DATA) = 0
Return SetError(@error, _CM_Destroy_Device_Info_List($hDevs), 0)
Case Else
Return 1
EndSelect
EndFunc ;==>_CM_Create_Device_Devs
Func _CM_Remove_Device($hDevs, $pSP_DEVINFO_DATA)
Local $iResult
If IsDllStruct($pSP_DEVINFO_DATA) Then
$pSP_DEVINFO_DATA = DllStructGetPtr($pSP_DEVINFO_DATA)
EndIf
$iResult = DllCall("Setupapi.dll", "int", "SetupDiRemoveDevice", "ptr", $hDevs, _
"ptr", $pSP_DEVINFO_DATA)
Return SetError(_CM_Get_Last_Error(), 0, $iResult[0])
EndFunc ;==>_CM_Remove_Device
Func _CM_Destroy_Device_Info_List($hDevs)
Local $iResult
$iResult = DllCall("Setupapi.dll", "int", "SetupDiDestroyDeviceInfoList", "ptr", $hDevs)
Return SetError(_CM_Get_Last_Error(), 0, $iResult[0])
EndFunc ;==>_CM_Destroy_Device_Info_List
Func _CM_Get_Device_Registry_Property($hDevs, $pSP_DEVINFO_DATA, $iProperty)
Local $iResult, $vResult, $tBuffer, $pBuffer, $sChr
If IsDllStruct($pSP_DEVINFO_DATA) Then
$pSP_DEVINFO_DATA = DllStructGetPtr($pSP_DEVINFO_DATA)
EndIf
$iResult = DllCall("Setupapi.dll", "int", "SetupDiGetDeviceRegistryProperty", _
"ptr", $hDevs, "ptr", $pSP_DEVINFO_DATA, "dword", $iProperty, _
"dword*", 0, "ptr", 0, "dword", 0, "dword*", 0)
Switch $iResult[4]
Case 1, 2, 7
$tBuffer = DllStructCreate("char Data[" & $iResult[7] & "]")
Case 4, 5
$tBuffer = DllStructCreate("dword Data")
Case 6
$tBuffer = DllStructCreate("wchar Data[" & $iResult[7] / 2 & "]")
Case Else
$tBuffer = DllStructCreate("byte Data[" & $iResult[7] & "]")
EndSwitch
$pBuffer = DllStructGetPtr($tBuffer)
$iResult = DllCall("Setupapi.dll", "int", "SetupDiGetDeviceRegistryProperty", _
"ptr", $hDevs, "ptr", $pSP_DEVINFO_DATA, "dword", $iProperty, _
"dword*", 0, "ptr", $pBuffer, "dword", $iResult[7], "dword*", 0)
If $iResult[0] = 0 Then Return SetError(_CM_Get_Last_Error(), _CM_Free_Var($tBuffer), "")
If $iResult[4] <> 7 Then
$vResult = DllStructGetData($tBuffer, "Data")
Else
For $i = 1 To $iResult[7]
$sChr = DllStructGetData($tBuffer, "Data", $i)
If $sChr = Chr(0) Then
$vResult &= @LF
Else
$vResult &= $sChr
EndIf
Next
EndIf
Return SetExtended(_CM_Free_Var($tBuffer), $vResult)
EndFunc ;==>_CM_Get_Device_Registry_Property