Hi qwerty12, first off all, again thank you for your help without you it would have taken me very long to get so far. It have taken me even these days to figure it out what you have done.
Thx for the comments they helped me, i just deleted the ones i understand, I added also a additional function to get the Device Instance ID.
It's not necessary because an implicit conversion takes place on assigment isn't it?
- [line115-120] If the DllCall "CM_Get_Device_IDW" fails LastError is 0 in the MsgBox dialogue, but the DllCall returns 0 if it succeed
Code: Select all
; /////////////////////////////// INFO /////////////////////////////////////////
/*
Identify USB devices
Infos:
https://docs.microsoft.com/de-de/windows-hardware/drivers/install/device-information-sets
*/
; ////////////////////////////// AHK FLAGS /////////////////////////////////////
#NoEnv
; #Warn
SendMode Input
SetWorkingDir %A_ScriptDir%
; //////////////////////////////// FLAGS ///////////////////////////////////////
; Setupapi.h
DIGCF_DEFAULT := 0x00000001 ; only valid with DIGCF_DEVICEINTERFACE
DIGCF_PRESENT := 0x00000002
DIGCF_ALLCLASSES := 0x00000004
DIGCF_PROFILE := 0x00000008
DIGCF_DEVICEINTERFACE := 0x00000010
;Devpkey.h
; -
; ////////////////////////////// MAIN //////////////////////////////////////////
; Ensure setupapi.dll remains loaded between each DllCall
hModule := DllCall("LoadLibrary", "Str", "setupapi.dll", "Ptr")
if (!hModule) {
MsgBox % "LoadLibrary failed. A_LastError: " . A_LastError
ExitApp 1
}
; get handle (DeviceInfoList)
handle := DllCall("setupapi.dll\SetupDiGetClassDevs", "Ptr", 0, "Str", "USB", "Ptr", 0, "UInt", DIGCF_PRESENT | DIGCF_ALLCLASSES, "Ptr")
If (!handle) {
MsgBox SetupDiGetClassDevs call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%
}
; enumerate devices from set
; DEFINE
; ¯¯¯¯¯¯
; array holding file string
Member := Object()
; structure SP_DEVINFO_DATA (SP_DEVINFO_DATA structure)
StructSize := 4 + 16 + 4 + A_PtrSize
VarSetCapacity(SP_DEVINFO_DATA, StructSize, 0)
NumPut(StructSize, SP_DEVINFO_DATA, 0, "UInt") ; fill in cbSize
; structure DEVPKEY_Device_DeviceDesc (DEVPROPKEY structure)
VarSetCapacity(DEVPKEY_Device_DeviceDesc, 20)
,DllCall("ole32\CLSIDFromString", "WStr", "{A45C254E-DF1C-4EFD-8020-67D146A850E0}", "Ptr", &DEVPKEY_Device_DeviceDesc) ; fill in fmtid member of DEVPROPKEY struct
,NumPut(2, DEVPKEY_Device_DeviceDesc, 16, "UInt") ; fill in pid
; structure DEVPKEY_Device_FriendlyName (DEVPROPKEY structure)
VarSetCapacity(DEVPKEY_Device_FriendlyName, 20) ; you might consider looking at DEVPKEY_Device_BusReportedDeviceDesc too/instead
,DllCall("ole32\CLSIDFromString", "WStr", "{A45C254E-DF1C-4EFD-8020-67D146A850E0}", "Ptr", &DEVPKEY_Device_FriendlyName)
,NumPut(14, DEVPKEY_Device_FriendlyName, 16, "UInt")
; structure DEVPKEY_Device_HardwareIds (DEVPROPKEY structure)
VarSetCapacity(DEVPKEY_Device_HardwareIds, 20)
,DllCall("ole32\CLSIDFromString", "WStr", "{A45C254E-DF1C-4EFD-8020-67D146A850E0}", "Ptr", &DEVPKEY_Device_HardwareIds)
,NumPut(3, DEVPKEY_Device_HardwareIds, 16, "UInt")
; ENUMERATE
; ¯¯¯¯¯¯¯¯¯
Loop
{
; get item from list
If (!DllCall("setupapi.dll\SetupDiEnumDeviceInfo", "Ptr", handle, "UInt", A_Index - 1, "Ptr", &SP_DEVINFO_DATA)) {
If (A_LastError != 259) ;ERROR_NO_MORE_ITEMS
MsgBox SetupDiEnumDeviceInfo call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%`nA_Index: %A_Index%
break
}
; Empty all of these variables so that the values obtained from previous calls aren't used if SetupDiGetDevicePropertyW fails
wszDeviceDesc := wszFriendlyName := hardwareIDs := DeviceID := ""
if (!DllCall("setupapi\SetupDiGetDevicePropertyW", "Ptr", handle, "Ptr", &SP_DEVINFO_DATA, "Ptr", &DEVPKEY_Device_DeviceDesc, "UInt*", PropType, "Ptr", 0, "UInt", 0, "UInt*", RequiredSize, "UInt", 0) && A_LastError == 122) { ; ERROR_INSUFFICIENT_BUFFER
VarSetCapacity(wszDeviceDesc, RequiredSize)
if (!DllCall("setupapi\SetupDiGetDevicePropertyW", "Ptr", handle, "Ptr", &SP_DEVINFO_DATA, "Ptr", &DEVPKEY_Device_DeviceDesc, "UInt*", PropType, "WStr", wszDeviceDesc, "UInt", RequiredSize, "Ptr", 0, "UInt", 0))
MsgBox SetupDiGetDevicePropertyW (DEVPKEY_Device_DeviceDesc) call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%`nA_Index: %A_Index%
}
if (!DllCall("setupapi\SetupDiGetDevicePropertyW", "Ptr", handle, "Ptr", &SP_DEVINFO_DATA, "Ptr", &DEVPKEY_Device_FriendlyName, "UInt*", PropType, "Ptr", 0, "UInt", 0, "UInt*", RequiredSize, "UInt", 0) && A_LastError == 122) { ; ERROR_INSUFFICIENT_BUFFER
VarSetCapacity(wszFriendlyName, RequiredSize)
if (!DllCall("setupapi\SetupDiGetDevicePropertyW", "Ptr", handle, "Ptr", &SP_DEVINFO_DATA, "Ptr", &DEVPKEY_Device_FriendlyName, "UInt*", PropType, "WStr", wszFriendlyName, "UInt", RequiredSize, "Ptr", 0, "UInt", 0))
MsgBox SetupDiGetDevicePropertyW (DEVPKEY_Device_FriendlyName) call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%`nA_Index: %A_Index%
}
if (!DllCall("setupapi\SetupDiGetDevicePropertyW", "Ptr", handle, "Ptr", &SP_DEVINFO_DATA, "Ptr", &DEVPKEY_Device_HardwareIds, "UInt*", PropType, "Ptr", 0, "UInt", 0, "UInt*", RequiredSize, "UInt", 0) && A_LastError == 122) {
VarSetCapacity(wmszHardwareIDs, RequiredSize)
if (!DllCall("setupapi\SetupDiGetDevicePropertyW", "Ptr", handle, "Ptr", &SP_DEVINFO_DATA, "Ptr", &DEVPKEY_Device_HardwareIds, "UInt*", PropType, "Ptr", &wmszHardwareIDs, "UInt", RequiredSize, "Ptr", 0, "UInt", 0))
MsgBox SetupDiGetDevicePropertyW (DEVPKEY_Device_HardwareIds) call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%`nA_Index: %A_Index%
else {
; Reading from this string is a little different, as it's a string containing multiple strings, delimited by a standard \0, but with a \0\0 at the very end
lpHardwareID := &wmszHardwareIDs
while (*lpHardwareID) {
wszHardwareID := StrGet(lpHardwareID,, "UTF-16") ; Read string from buffer up to \0
hardwareIDs .= wszHardwareID . ", " ; append said string to new string, delimited by a comma and space pair
lpHardwareID += (DllCall("ntdll\wcslen", "Ptr", lpHardwareID, "CDecl UPtr") + 1) * 2 ; Advance to next null-terminated string
}
if ((cchhardwareIDs := StrLen(hardwareIDs)) && cchhardwareIDs > 2)
NumPut(0, hardwareIDs, (cchhardwareIDs - 2) * (A_IsUnicode ? 2 : 1), A_IsUnicode ? "UShort" : "Char") ; Remove the last extra comma and space pair
}
}
DevInst := NumGet(SP_DEVINFO_DATA, 20, "UInt")
If (!DllCall("Cfgmgr32\CM_Get_Device_ID_Size", "UInt*", RequiredSize, "UInt", DevInst, "UInt", 0)) {
VarSetCapacity(wszDeviceID, RequiredSize)
If (!DllCall("Cfgmgr32\CM_Get_Device_IDW", "UInt", DevInst, "Ptr", &wszDeviceID, "UInt", RequiredSize, "UInt", 0)) {
lpDeviceID := &wszDeviceID
DeviceID := StrGet(lpDeviceID,, "UTF-16")
}
else
MsgBox CM_Get_Device_IDW call failed.`nReturn value: %r%`nErrorLevel: %ErrorLevel%`nLine: %A_LineNumber%`nLast Error: %A_LastError%`nA_Index: %A_Index%
}
; save value in array - I use Format here, but it doesn't add much. I guess plain string concatenation is a possibility...
Member.Push(Format("{1:s}{2:s}{3:s}{4:s}" , wszDeviceDesc ? wszDeviceDesc . " " : ""
, wszFriendlyName ? "(" . wszFriendlyName . ")" : ""
, hardwareIDs ? " - " . hardwareIDs : ""
, DeviceID ? " - " . DeviceID : ""))
}
; destroy handle (DeviceInfoList)
DllCall("setupapi\SetupDiDestroyDeviceInfoList", "Ptr", handle) ; you don't need error checking here: if it frees, it frees. No point in otherwise fretting. You already checked to see if handle != NULL and you got the DllCall right for this function
; write to file
for _, add_line in Member
FileAppend, %add_line%`n, device_enumeration.txt, UTF-16
; Unload setupapi.dll, Cfgmgr32.dll
DllCall("FreeLibrary", "Ptr", hModule)