The previous posted code served as a basis for this one.
GetVolumeNameForVolumeMountPoint returns the volume name
and the IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS command is used to get the hard disk number associated with the drive letter.
; Get hard disk number from drive letter
; Read/write access to I/O control handle of hard disk requires admin rights
RequestExecutionLevel admin
OutFile "HDDNumber.exe"
Name "HDDNumber"
!include "LogicLib.nsh"
; File Access Modes
!define GENERIC_READ 0x80000000
!define GENERIC_WRITE 0x40000000
; File Sharing Modes
!define FILE_SHARE_READ 0x00000001
!define FILE_SHARE_WRITE 0x00000002
; File Creation Flags
!define OPEN_EXISTING 3
!define INVALID_HANDLE_VALUE -1
; Maximum length of volume GUID (including terminating zero)
!define MAXLEN_VOLUME_GUID 51
; I/O control command
!define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 0x00560000
!define EXTENTS_BUFFER_SIZE 512
; Get hard disk number from drive letter
; provided as a parameter to this function.
; The hard disk number is returned in $0.
Function HDDNumber
; Save registers
Exch $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
; Get volume name associated with drive letter
System::Call "kernel32::GetVolumeNameForVolumeMountPoint(t r1, t r3r3, i ${MAXLEN_VOLUME_GUID}) i.r2"
${If} $2 != 0
; Get handle of volume
StrCpy $3 $3 -1
System::Call "kernel32::CreateFile(t r3, \\
i ${GENERIC_READ}|${GENERIC_WRITE}, \\
i ${FILE_SHARE_READ}|${FILE_SHARE_WRITE}, \\
i 0, i ${OPEN_EXISTING}, i 0, i 0) i.r2"
${If} $2 != ${INVALID_HANDLE_VALUE}
; Allocate output buffer
System::Alloc ${EXTENTS_BUFFER_SIZE}
Pop $4
IntOp $5 0 + 0
; Send IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS command
System::Call "kernel32::DeviceIoControl(i r2, \\
i ${IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS}, \\
i 0, i 0, \\
i r4, i ${EXTENTS_BUFFER_SIZE}, \\
*i r5r5, i 0) i.r3"
${If} $3 != 0
; Extract HDD number
System::Call "*$4(i .r5, i, i .r0)"
${If} $5 == 0
StrCpy $0 "Error: Invalid DISK_EXTENT data"
${EndIf}
${Else}
StrCpy $0 "Error: DeviceIoControl failed"
${EndIf}
System::Free $4
System::Call "kernel32::CloseHandle(i r2) i.r3"
${Else}
StrCpy $0 "Error: CreateFile failed for $3"
${EndIf}
${Else}
StrCpy $0 "Error: GetVolumeNameForVolumeMountPoint failed for $1"
${EndIf}
; Restore registers
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
FunctionEnd
Function .onInit
InitPluginsDir
StrCpy $1 "C:\\"
Push $1
Call HDDNumber
MessageBox MB_OK "HDD Number for $1=$0"
Quit
FunctionEnd
Section
SectionEnd