[PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_DATA

Windows specific forum
GoodNPlenty
Enthusiast
Enthusiast
Posts: 107
Joined: Wed May 13, 2009 8:38 am
Location: Arizona, USA

[PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_DATA

Post by GoodNPlenty »

I'm having an issue with defining the SP_DRVINFO_DATA and SP_DRVINFO_DETAIL_DATA structures and having them work between PB 5.20 b15 x86/x64 and PB 5.11 x64. I've created a hack using compiler directives that works in 5.20 b15 x86/x64 and PB 5.11 x86, but not PB 5.11 x64. I'm sure I overlooked something simple. I've attached the source code that will illustrate the problem. I appreciate any help you can provide.

Code: Select all

EnableExplicit

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows 
  CompilerError "Error: Windows Only"
  End
CompilerEndIf

CompilerIf #PB_Compiler_Unicode = #False
  CompilerError "Error: Must Compile with Unicode"
  End
CompilerEndIf

If OSVersion() < #PB_OS_Windows_2000
  MessageBox_(#Null, "Invalid Operating System", "Requires Windows 2000 or Later", #MB_ICONERROR)
  End
EndIf

#SPDIT_COMPATDRIVER = $00000002
#CR_SUCCESS         = $00000000
#DI_QUIETINSTALL    = $00800000
#DI_NOFILECOPY      = $01000000
#MAX_CLASS_NAME_LEN = 32
#LINE_LEN           = 256 	    ;// Windows 9x max for displayable strings from a device INF.

Structure SP_DEVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  ClassGuid.GUID
  DevInst.l
  *Reserved
EndStructure

Structure SP_DEVINSTALL_PARAMS Align #PB_Structure_AlignC 
  cbSize.l
  Flags.l
  FlagsEx.l
  hwndParent.i  
  *InstallMsgHandler
	*InstallMsgHandlerContext
	*FileQueue
  *ClassInstallReserved
  Reserved.l
  DriverPath.c[#MAX_PATH]
EndStructure

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  	cbSize.l
  	DriverType.l
  	*Reserved
    Description.c[#LINE_LEN]
    MfgName.c[#LINE_LEN]
    ProviderName.c[#LINE_LEN]
  	DriverDate.FILETIME
  	DriverVersion.i
  EndStructure
   
  Structure SP_DRVINFO_DETAIL_DATA Align #PB_Structure_AlignC
  	cbSize.l
  	InfDate.FILETIME
  	CompatIDsOffset.l
    CompatIDsLength.l
    *Reserved
    SectionName.c[#LINE_LEN]
    InfFileName.c[#MAX_PATH]
    DrvDescription.c[#LINE_LEN]
    HardwareID.c[#ANYSIZE_ARRAY]
  EndStructure
CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x86
  Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  	cbSize.l
  	DriverType.l
  	*Reserved
  	Padding.l ; Why do I have to pad this for x86?
    Description.c[#LINE_LEN]
    MfgName.c[#LINE_LEN]
    ProviderName.c[#LINE_LEN]
  	DriverDate.FILETIME
  	DriverVersion.i
  EndStructure
   
  Structure SP_DRVINFO_DETAIL_DATA; Align #PB_Structure_AlignC ; Causes failure for x86?
  	cbSize.l
  	InfDate.FILETIME
  	CompatIDsOffset.l
    CompatIDsLength.l
    *Reserved
    SectionName.c[#LINE_LEN]
    InfFileName.c[#MAX_PATH]
    DrvDescription.c[#LINE_LEN]
    HardwareID.c[#ANYSIZE_ARRAY]
  EndStructure
CompilerElse
  CompilerError "Error: Unsupported Processor"
  End
CompilerEndIf

Prototype CM_Get_DevNode_Status(*Status, *ProblemNumber, DevInst, Flags) 

; Based on ABBKlaus procedure 
Procedure.s GetLastError(LastError.i)
  Protected *Buffer, BufferLength.i, Flags.i, ErrorMessage$
  Flags = #FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM
  
  BufferLength = FormatMessage_(Flags, 0, LastError, GetUserDefaultLangID_(), @*Buffer, 0, 0)
  If BufferLength
    ErrorMessage$ = PeekS(*Buffer)
    LocalFree_(*Buffer)
    ErrorMessage$ = RemoveString(ErrorMessage$, Chr(13)+Chr(10))
    ProcedureReturn "Error Code: " + Str(LastError) + " Error Message: " + ErrorMessage$
  Else
    ProcedureReturn Str(LastError)
  EndIf
EndProcedure

Procedure DebugDriverInfoData_DetailStructures()
  Select #PB_Compiler_Processor
    Case #PB_Processor_x64
      Debug "#======================================"
      Debug "# Pure Basic x64 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "#======================================"
    Case #PB_Processor_x86
      Debug "#======================================"
      Debug "# Pure Basic x86 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "#======================================"
  EndSelect
  Debug "SP_DRVINFO_DATA "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA))
  Debug "Alignment Boundry   : "+Str(SizeOf(SP_DRVINFO_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\cbSize))
  Debug "DriverType      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverType))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverType))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Reserved))
  Debug "Description     "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Description))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Description))
  Debug "MfgName         "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\MfgName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\MfgName))
  Debug "ProviderName    "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\ProviderName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\ProviderName))
  Debug "DriverDate      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverDate))
  Debug "DriverVersion   "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverVersion))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverVersion))
  Debug "#======================================"
  Debug ""
  Debug "SP_DRVINFO_DETAIL_DATA "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA))
  Debug "Alignment Boundry          : "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\cbSize))
  Debug "InfDate         "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfDate))
  Debug "CompatIDsOffset "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))  
  Debug "CompatIDsLength "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\Reserved))
  Debug "SectionName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\SectionName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\SectionName))
  Debug "InfFileName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfFileName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfFileName))
  Debug "DrvDescription  "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))
  Debug "HardwareID      "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\HardwareID))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\HardwareID))
  Debug "#======================================"
  Debug ""
EndProcedure

Procedure GetDriverAndInfClassInfo()
  Protected DeviceInfoData.SP_DEVINFO_DATA
  Protected DeviceInstallParms.SP_DEVINSTALL_PARAMS
  Protected DriverInfoData.SP_DRVINFO_DATA
  Protected *DriverInfoDetailData.SP_DRVINFO_DETAIL_DATA
  
  Protected.i libSetupAPI, hDevice, DeviceIndex, ConfigReturn, DriverIndex, InfPathLen, DriverInfoDetailSize, ActualDriverInfoDetailSize
  Protected.i Status, Problem, Result, InstanceIdStatus, GetDriverInfoDetailStatus, DeviceInstanceIdSize
  Protected SectionName$, InfFileName$, InfClassFileName$, InfPath$, DrvDescription$, HardwareID$, ClassName$, ClassGUID$, CopyFiles$, InstanceID$
  Protected CM_Get_DevNode_Status_.CM_Get_DevNode_Status
  Protected ClassGUID.GUID
  Protected *DeviceInstanceId
  
  DeviceInfoData\cbSize     = SizeOf(SP_DEVINFO_DATA)
  DeviceInstallParms\cbSize = SizeOf(SP_DEVINSTALL_PARAMS)
  DriverInfoData\cbSize     = SizeOf(SP_DRVINFO_DATA)
  
  DebugDriverInfoData_DetailStructures()
  
  ClassName$  = Space(#MAX_CLASS_NAME_LEN)
  InfPath$    = GetEnvironmentVariable("SystemRoot")+"\inf"
  InfPathLen  = (Len(InfPath$)*SizeOf(Character))+SizeOf(Character)
  
  libSetupAPI = OpenLibrary(#PB_Any, "setupapi.dll")
  If libSetupAPI
    CM_Get_DevNode_Status_ = GetFunction(libSetupAPI, "CM_Get_DevNode_Status")
    If Not CM_Get_DevNode_Status_
      Debug "GetFunction Error: Unable to GetFunction CM_Get_DevNode_Status"
      CloseLibrary(libSetupAPI)
      End
    EndIf
  Else    
    Debug "OpenLibrary Error: Unable to OpenLibrary(setupapi.dll)"
    End
  EndIf
  
  hDevice = SetupDiGetClassDevs_(#Null, 0, 0, #DIGCF_ALLCLASSES|#DIGCF_PRESENT)
  If hDevice = #INVALID_HANDLE_VALUE
    Debug "ERROR: SetupDiGetClassDevs: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf
  
  If Not SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)
    Debug "ERROR: SetupDiEnumDeviceInfo: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf    
  
  While GetLastError_() <> #ERROR_NO_MORE_ITEMS
    Debug "================================================================================"
    InstanceIdStatus = SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, #Null, 0, @DeviceInstanceIdSize)
    If InstanceIdStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      DeviceInstanceIdSize = (DeviceInstanceIdSize * SizeOf(Character))
      *DeviceInstanceId = AllocateMemory(DeviceInstanceIdSize + SizeOf(Character))
      If *DeviceInstanceId
        If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
          InstanceID$ = PeekS(*DeviceInstanceId)
          FreeMemory(*DeviceInstanceId)
          ConfigReturn = CM_Get_DevNode_Status_(@Status, @Problem, DeviceInfoData\DevInst, 0)
          If ConfigReturn = #CR_SUCCESS
            If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
              DeviceInstallParms\Flags = #DI_QUIETINSTALL|#DI_NOFILECOPY
              CopyMemory(@InfPath$, @DeviceInstallParms\DriverPath, InfPathLen)  
              If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
                If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                  DriverIndex = 0
                  Repeat
                    If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                      GetDriverInfoDetailStatus = SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, 0, 0, @DriverInfoDetailSize)
                      If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        *DriverInfoDetailData = AllocateMemory(DriverInfoDetailSize + SizeOf(Character))
                        If *DriverInfoDetailData
                          *DriverInfoDetailData\cbSize = SizeOf(SP_DRVINFO_DETAIL_DATA)
                          If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            SectionName$    = PeekS(@*DriverInfoDetailData\SectionName)
                            InfFileName$    = PeekS(@*DriverInfoDetailData\InfFileName)
                            DrvDescription$ = PeekS(@*DriverInfoDetailData\DrvDescription)
                            HardwareID$     = PeekS(@*DriverInfoDetailData\HardwareID)                      
                            If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "Device Index    : "+Str(DeviceIndex)
                              Debug "Driver Index    : "+Str(DriverIndex)
                              Debug "DeviceInstanceID: "+InstanceID$
                              Debug "Hardware ID     : "+HardwareID$
                              Debug "Drv Description : "+DrvDescription$
                              Debug "Inf File Name   : "+InfFileName$
                              Debug "Section Name    : "+SectionName$
                              Debug "Class Name      : "+ClassName$
                            Else      ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "ERROR: SetupDiGetINFClass : "+GetLastError(GetLastError_())
                            EndIf     ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                          Else        ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            Debug "ERROR: SetupDiGetDriverInfoDetail: "+GetLastError(GetLastError_())
                          EndIf       ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                          FreeMemory(*DriverInfoDetailData)
                        Else          ;// If *DriverInfoDetailData
                          Debug "ERROR: Memory Allocation SetupDiGetDriverInfoDetail"
                        EndIf         ;// If *DriverInfoDetailData                          
                      Else            ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        Debug "ERROR: SetupDiGetDriverInfoDetail"
                        Debug GetLastError(GetLastError_())
                      EndIf           ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                    ElseIf GetLastError_() = #ERROR_NO_MORE_ITEMS
                      Break
                    Else  
                      Debug GetLastError(GetLastError_())
                    EndIf             ;// If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                    DriverIndex = DriverIndex + 1
                  ForEver  
                  SetupDiDestroyDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                EndIf                 ;// If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
              EndIf                   ;// If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
            EndIf                     ;// If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
          EndIf                       ;// If ConfigReturn = #CR_SUCCESS
        EndIf                         ;// If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
      Else                            ;// If *DeviceInstanceId
        Debug "ERROR: Memory Allocation SetupDiGetDeviceInstanceId"
      EndIf                           ;// If *DeviceInstanceId
    Else                              ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      Debug "ERROR: SetupDiGetDeviceInstanceId"
    EndIf                             ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
    DeviceIndex = DeviceIndex + 1
    SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)    
  Wend                                ;// While GetLastError_() <> #ERROR_NO_MORE_ITEMS
  
  SetupDiDestroyDeviceInfoList_(hDevice)
  If Result = #ERROR_NO_MORE_ITEMS : Result = #True : EndIf
  
  CloseLibrary(libSetupAPI)
  
  ProcedureReturn Result
EndProcedure

GetDriverAndInfClassInfo()
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by JHPJHP »

Notice a few things, let me know if this solves the problem:

- removed the padding
- changed DriverVersion from Integer to LARGE_INTEGER

Code: Select all

Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  DriverType.l
  *Reserved
  Description.c[#LINE_LEN]
  MfgName.c[#LINE_LEN]
  ProviderName.c[#LINE_LEN]
  DriverDate.FILETIME
  DriverVersion.LARGE_INTEGER 
EndStructure
Also, I believe the reason for SP_DRVINFO_DETAIL_DATA failing when using Align is that the structure size is being modified from 1570 bytes to 1572 bytes (documentation seems to indicate size needs to be 1570 bytes)... see the following - worked for me on Windows 7 64bit (only used to demonstrate my point):

Code: Select all

Structure SP_DRVINFO_DETAIL_DATA Align #PB_Structure_AlignC - 2
  cbSize.l
  InfDate.FILETIME
  CompatIDsOffset.l
  CompatIDsLength.l
  *Reserved
  SectionName.c[#LINE_LEN]
  InfFileName.c[#MAX_PATH]
  DrvDescription.c[#LINE_LEN]
  HardwareID.c[1]
EndStructure
GoodNPlenty
Enthusiast
Enthusiast
Posts: 107
Joined: Wed May 13, 2009 8:38 am
Location: Arizona, USA

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by GoodNPlenty »

JHPJHP wrote:Notice a few things, let me know if this solves the problem:
- removed the padding
- changed DriverVersion from Integer to LARGE_INTEGER
Thank You JHPJHP the LARGE_INTEGER fixed SP_DRVINFO_DATA
JHPJHP wrote: Also, I believe the reason for SP_DRVINFO_DETAIL_DATA failing when using Align is that the structure size is being modified from 1570 bytes to 1572 bytes (documentation seems to indicate size needs to be 1570 bytes)... see the following - worked for me on Windows 7 64bit (only used to demonstrate my point):

Code: Select all

Structure SP_DRVINFO_DETAIL_DATA Align #PB_Structure_AlignC - 2
  cbSize.l
  InfDate.FILETIME
  CompatIDsOffset.l
  CompatIDsLength.l
  *Reserved
  SectionName.c[#LINE_LEN]
  InfFileName.c[#MAX_PATH]
  DrvDescription.c[#LINE_LEN]
  HardwareID.c[1]
EndStructure
The above works for 5.20 x86 creating a structure size of 1570, but does not work for x64 creating a structure size of 1574. By using Align #PB_Structure_AlignC (removing the -2) works for x64 creating the required structure size of 1584.
I'm not sure how to change this structure to work for x86 and x64 without using compiler directives.
If anyone has any ideas I would appreciate the help.
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by JHPJHP »

Don't know how safe this is, might be more reliable to stick with compiler directives, but see the following:
- works on both x86 & x64
- compiler directives removed
- line 202 (previously line 224 - original post) modified

Code: Select all

*DriverInfoDetailData\cbSize = SizeOf(SP_DRVINFO_DETAIL_DATA) - (SizeOf(SP_DRVINFO_DETAIL_DATA)%8/2)

Code: Select all

EnableExplicit

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows 
  CompilerError "Error: Windows Only"
  End
CompilerEndIf

CompilerIf #PB_Compiler_Unicode = #False
  CompilerError "Error: Must Compile with Unicode"
  End
CompilerEndIf

If OSVersion() < #PB_OS_Windows_2000
  MessageBox_(#Null, "Invalid Operating System", "Requires Windows 2000 or Later", #MB_ICONERROR)
  End
EndIf

#SPDIT_COMPATDRIVER = $00000002
#CR_SUCCESS         = $00000000
#DI_QUIETINSTALL    = $00800000
#DI_NOFILECOPY      = $01000000
#MAX_CLASS_NAME_LEN = 32
#LINE_LEN           = 256        ;// Windows 9x max for displayable strings from a device INF.

Structure SP_DEVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  ClassGuid.GUID
  DevInst.l
  *Reserved
EndStructure

Structure SP_DEVINSTALL_PARAMS Align #PB_Structure_AlignC 
  cbSize.l
  Flags.l
  FlagsEx.l
  hwndParent.i  
  *InstallMsgHandler
   *InstallMsgHandlerContext
   *FileQueue
  *ClassInstallReserved
  Reserved.l
  DriverPath.c[#MAX_PATH]
EndStructure

Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  DriverType.l
  *Reserved
  Description.c[#LINE_LEN]
  MfgName.c[#LINE_LEN]
  ProviderName.c[#LINE_LEN]
  DriverDate.FILETIME
  DriverVersion.LARGE_INTEGER
EndStructure

Structure SP_DRVINFO_DETAIL_DATA Align #PB_Structure_AlignC
  cbSize.l
  InfDate.FILETIME
  CompatIDsOffset.l
  CompatIDsLength.l
  *Reserved
  SectionName.c[#LINE_LEN]
  InfFileName.c[#MAX_PATH]
  DrvDescription.c[#LINE_LEN]
  HardwareID.c[#ANYSIZE_ARRAY]
EndStructure

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x86
CompilerElse
  CompilerError "Error: Unsupported Processor"
  End
CompilerEndIf

Prototype CM_Get_DevNode_Status(*Status, *ProblemNumber, DevInst, Flags) 

; Based on ABBKlaus procedure 
Procedure.s GetLastError(LastError.i)
  Protected *Buffer, BufferLength.i, Flags.i, ErrorMessage$
  Flags = #FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM
  
  BufferLength = FormatMessage_(Flags, 0, LastError, GetUserDefaultLangID_(), @*Buffer, 0, 0)
  If BufferLength
    ErrorMessage$ = PeekS(*Buffer)
    LocalFree_(*Buffer)
    ErrorMessage$ = RemoveString(ErrorMessage$, Chr(13)+Chr(10))
    ProcedureReturn "Error Code: " + Str(LastError) + " Error Message: " + ErrorMessage$
  Else
    ProcedureReturn Str(LastError)
  EndIf
EndProcedure

Procedure DebugDriverInfoData_DetailStructures()
  Select #PB_Compiler_Processor
    Case #PB_Processor_x64
      Debug "#======================================"
      Debug "# Pure Basic x64 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "#======================================"
    Case #PB_Processor_x86
      Debug "#======================================"
      Debug "# Pure Basic x86 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "#======================================"
  EndSelect
  Debug "SP_DRVINFO_DATA "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA))
  Debug "Alignment Boundry   : "+Str(SizeOf(SP_DRVINFO_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\cbSize))
  Debug "DriverType      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverType))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverType))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Reserved))
  Debug "Description     "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Description))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Description))
  Debug "MfgName         "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\MfgName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\MfgName))
  Debug "ProviderName    "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\ProviderName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\ProviderName))
  Debug "DriverDate      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverDate))
  Debug "DriverVersion   "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverVersion))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverVersion))
  Debug "#======================================"
  Debug ""
  Debug "SP_DRVINFO_DETAIL_DATA "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA))
  Debug "Alignment Boundry          : "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\cbSize))
  Debug "InfDate         "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfDate))
  Debug "CompatIDsOffset "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))  
  Debug "CompatIDsLength "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\Reserved))
  Debug "SectionName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\SectionName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\SectionName))
  Debug "InfFileName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfFileName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfFileName))
  Debug "DrvDescription  "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))
  Debug "HardwareID      "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\HardwareID))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\HardwareID))
  Debug "#======================================"
  Debug ""
EndProcedure

Procedure GetDriverAndInfClassInfo()
  Protected DeviceInfoData.SP_DEVINFO_DATA
  Protected DeviceInstallParms.SP_DEVINSTALL_PARAMS
  Protected DriverInfoData.SP_DRVINFO_DATA
  Protected *DriverInfoDetailData.SP_DRVINFO_DETAIL_DATA
  
  Protected.i libSetupAPI, hDevice, DeviceIndex, ConfigReturn, DriverIndex, InfPathLen, DriverInfoDetailSize, ActualDriverInfoDetailSize
  Protected.i Status, Problem, Result, InstanceIdStatus, GetDriverInfoDetailStatus, DeviceInstanceIdSize
  Protected SectionName$, InfFileName$, InfClassFileName$, InfPath$, DrvDescription$, HardwareID$, ClassName$, ClassGUID$, CopyFiles$, InstanceID$
  Protected CM_Get_DevNode_Status_.CM_Get_DevNode_Status
  Protected ClassGUID.GUID
  Protected *DeviceInstanceId
  
  DeviceInfoData\cbSize     = SizeOf(SP_DEVINFO_DATA)
  DeviceInstallParms\cbSize = SizeOf(SP_DEVINSTALL_PARAMS)
  DriverInfoData\cbSize     = SizeOf(SP_DRVINFO_DATA)
  
  DebugDriverInfoData_DetailStructures()
  
  ClassName$  = Space(#MAX_CLASS_NAME_LEN)
  InfPath$    = GetEnvironmentVariable("SystemRoot")+"\inf"
  InfPathLen  = (Len(InfPath$)*SizeOf(Character))+SizeOf(Character)
  
  libSetupAPI = OpenLibrary(#PB_Any, "setupapi.dll")
  If libSetupAPI
    CM_Get_DevNode_Status_ = GetFunction(libSetupAPI, "CM_Get_DevNode_Status")
    If Not CM_Get_DevNode_Status_
      Debug "GetFunction Error: Unable to GetFunction CM_Get_DevNode_Status"
      CloseLibrary(libSetupAPI)
      End
    EndIf
  Else    
    Debug "OpenLibrary Error: Unable to OpenLibrary(setupapi.dll)"
    End
  EndIf
  
  hDevice = SetupDiGetClassDevs_(#Null, 0, 0, #DIGCF_ALLCLASSES|#DIGCF_PRESENT)
  If hDevice = #INVALID_HANDLE_VALUE
    Debug "ERROR: SetupDiGetClassDevs: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf
  
  If Not SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)
    Debug "ERROR: SetupDiEnumDeviceInfo: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf    
  
  While GetLastError_() <> #ERROR_NO_MORE_ITEMS
    Debug "================================================================================"
    InstanceIdStatus = SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, #Null, 0, @DeviceInstanceIdSize)
    If InstanceIdStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      DeviceInstanceIdSize = (DeviceInstanceIdSize * SizeOf(Character))
      *DeviceInstanceId = AllocateMemory(DeviceInstanceIdSize + SizeOf(Character))
      If *DeviceInstanceId
        If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
          InstanceID$ = PeekS(*DeviceInstanceId)
          FreeMemory(*DeviceInstanceId)
          ConfigReturn = CM_Get_DevNode_Status_(@Status, @Problem, DeviceInfoData\DevInst, 0)
          If ConfigReturn = #CR_SUCCESS
            If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
              DeviceInstallParms\Flags = #DI_QUIETINSTALL|#DI_NOFILECOPY
              CopyMemory(@InfPath$, @DeviceInstallParms\DriverPath, InfPathLen)  
              If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
                If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                  DriverIndex = 0
                  Repeat
                    If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                      GetDriverInfoDetailStatus = SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, 0, 0, @DriverInfoDetailSize)
                      If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        *DriverInfoDetailData = AllocateMemory(DriverInfoDetailSize + SizeOf(Character))
                        If *DriverInfoDetailData
                          *DriverInfoDetailData\cbSize = SizeOf(SP_DRVINFO_DETAIL_DATA) - (SizeOf(SP_DRVINFO_DETAIL_DATA)%8/2)
                          If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            SectionName$    = PeekS(@*DriverInfoDetailData\SectionName)
                            InfFileName$    = PeekS(@*DriverInfoDetailData\InfFileName)
                            DrvDescription$ = PeekS(@*DriverInfoDetailData\DrvDescription)
                            HardwareID$     = PeekS(@*DriverInfoDetailData\HardwareID)                      
                            If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "Device Index    : "+Str(DeviceIndex)
                              Debug "Driver Index    : "+Str(DriverIndex)
                              Debug "DeviceInstanceID: "+InstanceID$
                              Debug "Hardware ID     : "+HardwareID$
                              Debug "Drv Description : "+DrvDescription$
                              Debug "Inf File Name   : "+InfFileName$
                              Debug "Section Name    : "+SectionName$
                              Debug "Class Name      : "+ClassName$
                            Else      ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "ERROR: SetupDiGetINFClass : "+GetLastError(GetLastError_())
                            EndIf     ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                          Else        ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            Debug "ERROR: SetupDiGetDriverInfoDetail: "+GetLastError(GetLastError_())
                          EndIf       ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                          FreeMemory(*DriverInfoDetailData)
                        Else          ;// If *DriverInfoDetailData
                          Debug "ERROR: Memory Allocation SetupDiGetDriverInfoDetail"
                        EndIf         ;// If *DriverInfoDetailData                          
                      Else            ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        Debug "ERROR: SetupDiGetDriverInfoDetail"
                        Debug GetLastError(GetLastError_())
                      EndIf           ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                    ElseIf GetLastError_() = #ERROR_NO_MORE_ITEMS
                      Break
                    Else  
                      Debug GetLastError(GetLastError_())
                    EndIf             ;// If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                    DriverIndex = DriverIndex + 1
                  ForEver  
                  SetupDiDestroyDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                EndIf                 ;// If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
              EndIf                   ;// If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
            EndIf                     ;// If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
          EndIf                       ;// If ConfigReturn = #CR_SUCCESS
        EndIf                         ;// If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
      Else                            ;// If *DeviceInstanceId
        Debug "ERROR: Memory Allocation SetupDiGetDeviceInstanceId"
      EndIf                           ;// If *DeviceInstanceId
    Else                              ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      Debug "ERROR: SetupDiGetDeviceInstanceId"
    EndIf                             ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
    DeviceIndex = DeviceIndex + 1
    SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)    
  Wend                                ;// While GetLastError_() <> #ERROR_NO_MORE_ITEMS
  
  SetupDiDestroyDeviceInfoList_(hDevice)
  If Result = #ERROR_NO_MORE_ITEMS : Result = #True : EndIf
  
  CloseLibrary(libSetupAPI)
  
  ProcedureReturn Result
EndProcedure

GetDriverAndInfClassInfo()
Last edited by JHPJHP on Thu Sep 05, 2013 2:46 am, edited 1 time in total.
GoodNPlenty
Enthusiast
Enthusiast
Posts: 107
Joined: Wed May 13, 2009 8:38 am
Location: Arizona, USA

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by GoodNPlenty »

Thanks JHPJHP for your ingenious solution. I appreciate all of your help.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by ChrisR »

It's quite old but I'm reopening it, thanks for this nice code.
I added a few lines for my need with markers (;Add--Begin ;Add--End) (#DI_FLAGSEX_INSTALLEDDRIVER, OEM Drivers, SetupGetInfDriverStoreLocation_, ...)

I'd need a helping hand to retrieve the Driver Version from @DriverInfoData\DriverVersion,I don't know how to do.
Also can you check SetupGetInfDriverStoreLocation function, seems to work but I don't know much, my 1st try with Prototype...

Code: Select all

;Driver Info (Structures SP_DRVINFO_DATA and DETAIL_DATA) by GoodNPlenty and JHPJHP 
;https://www.purebasic.fr/english/viewtopic.php?p=423755#p423755

EnableExplicit

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
  CompilerError "Error: Windows Only"
  End
CompilerEndIf

CompilerIf #PB_Compiler_Unicode = #False
  CompilerError "Error: Must Compile with Unicode"
  End
CompilerEndIf

If OSVersion() < #PB_OS_Windows_2000
  MessageBox_(#Null, "Invalid Operating System", "Requires Windows 2000 or Later", #MB_ICONERROR)
  End
EndIf

#SPDIT_COMPATDRIVER         = $00000002
#CR_SUCCESS                 = $00000000
#DI_QUIETINSTALL            = $00800000
#DI_NOFILECOPY              = $01000000
#DI_FLAGSEX_INSTALLEDDRIVER	= $04000000
#MAX_CLASS_NAME_LEN         = 32
#LINE_LEN                   = 256        ;// Windows 9x max for displayable strings from a device INF.

Structure SP_DEVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  ClassGuid.GUID
  DevInst.l
  *Reserved
EndStructure

Structure SP_DEVINSTALL_PARAMS Align #PB_Structure_AlignC
  cbSize.l
  Flags.l
  FlagsEx.l
  hwndParent.i 
  *InstallMsgHandler
  *InstallMsgHandlerContext
  *FileQueue
  *ClassInstallReserved
  Reserved.l
  DriverPath.c[#MAX_PATH]
EndStructure

Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  DriverType.l
  *Reserved
  Description.c[#LINE_LEN]
  MfgName.c[#LINE_LEN]
  ProviderName.c[#LINE_LEN]
  DriverDate.FILETIME
  DriverVersion.LARGE_INTEGER
EndStructure

Structure SP_DRVINFO_DETAIL_DATA Align #PB_Structure_AlignC
  cbSize.l
  InfDate.FILETIME
  CompatIDsOffset.l
  CompatIDsLength.l
  *Reserved
  SectionName.c[#LINE_LEN]
  InfFileName.c[#MAX_PATH]
  DrvDescription.c[#LINE_LEN]
  HardwareID.c[#ANYSIZE_ARRAY]
EndStructure

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x86
CompilerElse
  CompilerError "Error: Unsupported Processor"
  End
CompilerEndIf

Prototype CM_Get_DevNode_Status(*Status, *ProblemNumber, DevInst, Flags)
;Add--Begin
Prototype SetupGetInfDriverStoreLocation(InfFileName, AlternatePlatformInfo.l, LocaleName.l, InfDriverStorePath, InfDriverStorePathSize.l, RequiredSize.l)
;Add--End

Procedure.s GetLastError(LastError.i)
  ; Based on ABBKlaus procedure
  Protected *Buffer, BufferLength.i, Flags.i, ErrorMessage$
  Flags = #FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM
  
  BufferLength = FormatMessage_(Flags, 0, LastError, GetUserDefaultLangID_(), @*Buffer, 0, 0)
  If BufferLength
    ErrorMessage$ = PeekS(*Buffer)
    LocalFree_(*Buffer)
    ErrorMessage$ = RemoveString(ErrorMessage$, Chr(13)+Chr(10))
    ProcedureReturn "Error Code: " + Str(LastError) + " Error Message: " + ErrorMessage$
  Else
    ProcedureReturn Str(LastError)
  EndIf
EndProcedure

Procedure DebugDriverInfoData_DetailStructures()
  Select #PB_Compiler_Processor
    Case #PB_Processor_x64
      Debug "================================================================================"
      Debug "# Pure Basic x64 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "================================================================================"
    Case #PB_Processor_x86
      Debug "================================================================================"
      Debug "# Pure Basic x86 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "================================================================================"
  EndSelect
  Debug "SP_DRVINFO_DATA_V2 "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA))
  Debug "Alignment Boundry   : "+Str(SizeOf(SP_DRVINFO_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\cbSize))
  Debug "DriverType      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverType))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverType))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Reserved))
  Debug "Description     "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Description))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Description))
  Debug "MfgName         "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\MfgName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\MfgName))
  Debug "ProviderName    "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\ProviderName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\ProviderName))
  Debug "DriverDate      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverDate))
  Debug "DriverVersion   "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverVersion))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverVersion))
  Debug "================================================================================"
  Debug ""
  Debug "SP_DRVINFO_DETAIL_DATA "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA))
  Debug "Alignment Boundry          : "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\cbSize))
  Debug "InfDate         "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfDate))
  Debug "CompatIDsOffset "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset)) 
  Debug "CompatIDsLength "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\Reserved))
  Debug "SectionName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\SectionName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\SectionName))
  Debug "InfFileName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfFileName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfFileName))
  Debug "DrvDescription  "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))
  Debug "HardwareID      "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\HardwareID))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\HardwareID))
  Debug "================================================================================"
  Debug "LIST OEM Drivers :"
EndProcedure

Procedure.s InitialCaps(text.s)
  ;Fastest way for InitialCaps by Demivec and wilbert
  ;https://www.purebasic.fr/english/viewtopic.php?p=406482#p406482
  Protected *b.Character = @text, cur, wordStarted = #False
  
  cur = *b\c
  While cur
    Select cur
      Case 97 To 122
        If Not wordStarted
          *b\c = cur - 32
          wordStarted = #True
        EndIf
      Case 65 To 90
        If wordStarted
          *b\c = cur + 32
        Else
          wordStarted = #True
        EndIf
      Case 39, '-', '_' ;apostrophe, hyphen and underscore treated as part of word
      Default
        wordStarted = #False
    EndSelect
    
    *b + SizeOf(Character)
    cur = *b\c
  Wend 
  
  ProcedureReturn text
EndProcedure

Procedure.s ValidPath(Path.s, ReplaceChar.s)
  ;Forbidden path & Filename in Windows : /\:*?"<>  ...
  If CheckFilename(Path) = 0
    Path = ReplaceString(Path, "/", ReplaceChar)
    Path = ReplaceString(Path, "\", ReplaceChar)
    Path = ReplaceString(Path, ":", ReplaceChar)
    Path = ReplaceString(Path, "*", ReplaceChar)
    Path = ReplaceString(Path, "?", ReplaceChar)
    Path = ReplaceString(Path, "<", ReplaceChar)
    Path = ReplaceString(Path, ">", ReplaceChar)
    Path = ReplaceString(Path, "|", ReplaceChar)
  EndIf
  ProcedureReturn Path
EndProcedure

Procedure GetDriverAndInfClassInfo()
  Protected DeviceInfoData.SP_DEVINFO_DATA
  Protected DeviceInstallParms.SP_DEVINSTALL_PARAMS
  Protected DriverInfoData.SP_DRVINFO_DATA
  Protected *DriverInfoDetailData.SP_DRVINFO_DETAIL_DATA
  
  Protected.i libSetupAPI, hDevice, DeviceIndex, ConfigReturn, DriverIndex, InfPathLen, DriverInfoDetailSize, ActualDriverInfoDetailSize
  Protected.i Status, Problem, Result, InstanceIdStatus, GetDriverInfoDetailStatus, DeviceInstanceIdSize
  Protected SectionName$, InfFileName$, InfClassFileName$, InfPath$, DrvDescription$, HardwareID$, ClassName$, ClassGUID$, CopyFiles$, InstanceID$
  Protected CM_Get_DevNode_Status_.CM_Get_DevNode_Status
  Protected ClassGUID.GUID
  Protected *DeviceInstanceId
  ;Add--Begin
  Protected SetupGetInfDriverStoreLocation_.SetupGetInfDriverStoreLocation
  Protected ProviderName$, ClassDescription$, InfDriverStorePath$ , sysTime.SYSTEMTIME
  ;Add--End
  
  DeviceInfoData\cbSize     = SizeOf(SP_DEVINFO_DATA)
  DeviceInstallParms\cbSize = SizeOf(SP_DEVINSTALL_PARAMS)
  DriverInfoData\cbSize     = SizeOf(SP_DRVINFO_DATA)
  
  DebugDriverInfoData_DetailStructures()
  
  ClassName$  = Space(#MAX_CLASS_NAME_LEN)
  InfPath$    = GetEnvironmentVariable("SystemRoot")+"\inf"
  InfPathLen  = (Len(InfPath$)*SizeOf(Character))+SizeOf(Character)
  
  libSetupAPI = OpenLibrary(#PB_Any, "setupapi.dll")
  If libSetupAPI
    CM_Get_DevNode_Status_ = GetFunction(libSetupAPI, "CM_Get_DevNode_Status")
    If Not CM_Get_DevNode_Status_
      Debug "GetFunction Error: Unable to GetFunction CM_Get_DevNode_Status"
      CloseLibrary(libSetupAPI)
      End
    EndIf
    ;Add--Begin
    SetupGetInfDriverStoreLocation_ = GetFunction(libSetupAPI, "SetupGetInfDriverStoreLocationW")
    If Not SetupGetInfDriverStoreLocation_
      Debug "GetFunction Error: Unable to GetFunction SetupGetInfDriverStoreLocation"
      CloseLibrary(libSetupAPI)
      End
    EndIf
    ;Add--End
  Else   
    Debug "OpenLibrary Error: Unable to OpenLibrary(setupapi.dll)"
    End
  EndIf
  
  hDevice = SetupDiGetClassDevs_(#Null, 0, 0, #DIGCF_ALLCLASSES|#DIGCF_PRESENT)
  If hDevice = #INVALID_HANDLE_VALUE
    Debug "ERROR: SetupDiGetClassDevs: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf
  
  If Not SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)
    Debug "ERROR: SetupDiEnumDeviceInfo: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf   
  
  While GetLastError_() <> #ERROR_NO_MORE_ITEMS
    InstanceIdStatus = SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, #Null, 0, @DeviceInstanceIdSize)
    If InstanceIdStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      DeviceInstanceIdSize = (DeviceInstanceIdSize * SizeOf(Character))
      *DeviceInstanceId = AllocateMemory(DeviceInstanceIdSize + SizeOf(Character))
      If *DeviceInstanceId
        If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
          InstanceID$ = PeekS(*DeviceInstanceId)
          FreeMemory(*DeviceInstanceId)
          ConfigReturn = CM_Get_DevNode_Status_(@Status, @Problem, DeviceInfoData\DevInst, 0)
          If ConfigReturn = #CR_SUCCESS
            If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
              DeviceInstallParms\Flags = #DI_QUIETINSTALL|#DI_NOFILECOPY
              ;Add--Begin
              DeviceInstallParms\FlagsEx = #DI_FLAGSEX_INSTALLEDDRIVER
              ;Add--End
              CopyMemory(@InfPath$, @DeviceInstallParms\DriverPath, InfPathLen) 
              If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
                If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                  DriverIndex = 0
                  Repeat
                    If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                      ;Add--Begin
                      ;Only OEM drivers. Perhaps there is a better method via Api, left 3 inf file name = oem (oemXX.inf) 
                      If PeekS(@DriverInfoData\ProviderName, #PB_Ascii) = "Microsoft"
                        Break
                      EndIf
                      ;Add--End
                      GetDriverInfoDetailStatus = SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, 0, 0, @DriverInfoDetailSize)
                      If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        *DriverInfoDetailData = AllocateMemory(DriverInfoDetailSize + SizeOf(Character))
                        If *DriverInfoDetailData
                          *DriverInfoDetailData\cbSize = SizeOf(SP_DRVINFO_DETAIL_DATA) - (SizeOf(SP_DRVINFO_DETAIL_DATA)%8/2)
                          If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            Debug "================================================================================"
                            SectionName$    = PeekS(@*DriverInfoDetailData\SectionName)
                            InfFileName$    = PeekS(@*DriverInfoDetailData\InfFileName)
                            DrvDescription$ = PeekS(@*DriverInfoDetailData\DrvDescription)
                            HardwareID$     = PeekS(@*DriverInfoDetailData\HardwareID)                     
                            If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "Device Index        : "+Str(DeviceIndex)
                              Debug "Driver Index        : "+Str(DriverIndex)
                              Debug "DeviceInstanceID    : "+InstanceID$
                              Debug "Hardware ID         : "+HardwareID$
                              Debug "Inf File Name       : "+InfFileName$
                              Debug "Section Name        : "+SectionName$
                              Debug "Class Name          : "+ClassName$
                              ;Add--Begin
                              ;if DrvDescription$ used for Filename
                              DrvDescription$ = ValidPath(DrvDescription$, "-")
                              Debug "Drv Description     : "+DrvDescription$
                              ClassDescription$ = Space(#MAX_PATH)
                              If SetupDiGetClassDescription_(@ClassGUID, @ClassDescription$, #MAX_PATH, 0)
                                Debug "Class Description   : "+ClassDescription$
                              EndIf
                              InfDriverStorePath$ = Space(#MAX_PATH)
                              If SetupGetInfDriverStoreLocation_(@InfFileName$, 0, 0, @InfDriverStorePath$, #MAX_PATH, 0)
                                Debug "Inf DriverStore Path: "+InfDriverStorePath$
                                Protected DriverStoreFolder$ = GetFilePart(RTrim(GetPathPart(InfDriverStorePath$), "\"))
                                Protected OrgInfFileName$ = GetFilePart(InfDriverStorePath$)
                                Debug "DriverStore Folder  : "+DriverStoreFolder$
                                Debug "Original Inf File   : "+OrgInfFileName$
                              EndIf
                              ProviderName$ = PeekS(@DriverInfoData\ProviderName, #PB_Ascii)
                              ProviderName$ = InitialCaps(ProviderName$)
                              Debug "Provider Name       : "+ProviderName$
                              FileTimeToSystemTime_(@DriverInfoData\DriverDate, sysTime)
                              Debug "Driver Date         : "+Str(sysTime\wYear)+"\"+RSet(Str(sysTime\wMonth),2,"0")+"\"+RSet(Str(sysTime\wDay),2,"0")
                              Debug "Driver Version      : HOW TO retrieve it from @DriverInfoData\DriverVersion ?"
                              ;Add--End
                            Else      ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "ERROR: SetupDiGetINFClass : "+GetLastError(GetLastError_())
                            EndIf     ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                          Else        ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            Debug "ERROR: SetupDiGetDriverInfoDetail: "+GetLastError(GetLastError_())
                          EndIf       ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                          FreeMemory(*DriverInfoDetailData)
                        Else          ;// If *DriverInfoDetailData
                          Debug "ERROR: Memory Allocation SetupDiGetDriverInfoDetail"
                        EndIf         ;// If *DriverInfoDetailData                         
                      Else            ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        Debug "ERROR: SetupDiGetDriverInfoDetail"
                        Debug GetLastError(GetLastError_())
                      EndIf           ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                    ElseIf GetLastError_() = #ERROR_NO_MORE_ITEMS
                      Break
                    Else 
                      Debug GetLastError(GetLastError_())
                    EndIf             ;// If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                    DriverIndex = DriverIndex + 1
                  ForEver 
                  SetupDiDestroyDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                EndIf                 ;// If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
              EndIf                   ;// If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
            EndIf                     ;// If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
          EndIf                       ;// If ConfigReturn = #CR_SUCCESS
        EndIf                         ;// If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
      Else                            ;// If *DeviceInstanceId
        Debug "ERROR: Memory Allocation SetupDiGetDeviceInstanceId"
      EndIf                           ;// If *DeviceInstanceId
    Else                              ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      Debug "ERROR: SetupDiGetDeviceInstanceId"
    EndIf                             ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
    DeviceIndex = DeviceIndex + 1
    SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)   
  Wend                                ;// While GetLastError_() <> #ERROR_NO_MORE_ITEMS
  
  SetupDiDestroyDeviceInfoList_(hDevice)
  If Result = #ERROR_NO_MORE_ITEMS : Result = #True : EndIf
  
  CloseLibrary(libSetupAPI)
  
  ProcedureReturn Result
EndProcedure

GetDriverAndInfClassInfo()
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by ChrisR »

I don't know if it's the right way to do it ?
To get the driver version, I changed the structure SP_DRVINFO_DATA ike this:

Code: Select all

Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  DriverType.l
  *Reserved
  Description.c[#LINE_LEN]
  MfgName.c[#LINE_LEN]
  ProviderName.c[#LINE_LEN]
  DriverDate.FILETIME
  DriverVersion.LARGE_INTEGER
EndStructure
==>

Code: Select all

Structure DrvVersion
  DrvRealeaseVer.w
  DrvBuildVer.w
  DrvMinorVer.w
  DrvMajorVer.w
EndStructure

Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  DriverType.l
  *Reserved
  Description.c[#LINE_LEN]
  MfgName.c[#LINE_LEN]
  ProviderName.c[#LINE_LEN]
  DriverDate.FILETIME
  DriverVersion.DrvVersion
EndStructure

DriverVersion$ = Str(PeekW(@DriverInfoData\DriverVersion\DrvMajorVer)) + "." +
                 Str(PeekW(@DriverInfoData\DriverVersion\DrvMinorVer)) + "." +
                 Str(PeekW(@DriverInfoData\DriverVersion\DrvBuildVer)) + "." +
                 Str(PeekW(@DriverInfoData\DriverVersion\DrvRealeaseVer))
Debug DriverVersion$
The result looks good
fryquez
Enthusiast
Enthusiast
Posts: 362
Joined: Mon Dec 21, 2015 8:12 pm

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by fryquez »

It's correctly done :)
Seems these API's can't differ between build-in and OEM drivers, so maybe checking the inf path against *\Inf\oem*.inf is the best solution.

Code: Select all

;Driver Info (Structures SP_DRVINFO_DATA and DETAIL_DATA) by GoodNPlenty and JHPJHP
;https://www.purebasic.fr/english/viewtopic.php?p=423755#p423755

EnableExplicit

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
  CompilerError "Error: Windows Only"
  End
CompilerEndIf

CompilerIf #PB_Compiler_Unicode = #False
  CompilerError "Error: Must Compile with Unicode"
  End
CompilerEndIf

If OSVersion() < #PB_OS_Windows_2000
  MessageBox_(#Null, "Invalid Operating System", "Requires Windows 2000 or Later", #MB_ICONERROR)
  End
EndIf

#SPDIT_COMPATDRIVER         = $00000002
#CR_SUCCESS                 = $00000000
#DI_QUIETINSTALL            = $00800000
#DI_NOFILECOPY              = $01000000
#DI_FLAGSEX_INSTALLEDDRIVER   = $04000000
#MAX_CLASS_NAME_LEN         = 32
#LINE_LEN                   = 256        ;// Windows 9x max for displayable strings from a device INF.

Structure SP_DEVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  ClassGuid.GUID
  DevInst.l
  *Reserved
EndStructure

Structure SP_DEVINSTALL_PARAMS Align #PB_Structure_AlignC
  cbSize.l
  Flags.l
  FlagsEx.l
  hwndParent.i
  *InstallMsgHandler
  *InstallMsgHandlerContext
  *FileQueue
  *ClassInstallReserved
  Reserved.l
  DriverPath.c[#MAX_PATH]
EndStructure

Structure SP_DRVINFO_DATA Align #PB_Structure_AlignC
  cbSize.l
  DriverType.l
  *Reserved
  Description.c[#LINE_LEN]
  MfgName.c[#LINE_LEN]
  ProviderName.c[#LINE_LEN]
  DriverDate.FILETIME
  DriverVersion.u[4]
EndStructure

Structure SP_DRVINFO_DETAIL_DATA Align #PB_Structure_AlignC
  cbSize.l
  InfDate.FILETIME
  CompatIDsOffset.l
  CompatIDsLength.l
  *Reserved
  SectionName.c[#LINE_LEN]
  InfFileName.c[#MAX_PATH]
  DrvDescription.c[#LINE_LEN]
  HardwareID.c[#ANYSIZE_ARRAY]
EndStructure

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x86
CompilerElse
  CompilerError "Error: Unsupported Processor"
  End
CompilerEndIf

Prototype CM_Get_DevNode_Status(*Status, *ProblemNumber, DevInst, Flags)
;Add--Begin
Prototype SetupGetInfDriverStoreLocation(InfFileName, AlternatePlatformInfo.l, LocaleName.l, InfDriverStorePath, InfDriverStorePathSize.l, RequiredSize.l)
;Add--End

Procedure.s GetLastError(LastError.i)
  ; Based on ABBKlaus procedure
  Protected *Buffer, BufferLength.i, Flags.i, ErrorMessage$
  Flags = #FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM
 
  BufferLength = FormatMessage_(Flags, 0, LastError, GetUserDefaultLangID_(), @*Buffer, 0, 0)
  If BufferLength
    ErrorMessage$ = PeekS(*Buffer)
    LocalFree_(*Buffer)
    ErrorMessage$ = RemoveString(ErrorMessage$, Chr(13)+Chr(10))
    ProcedureReturn "Error Code: " + Str(LastError) + " Error Message: " + ErrorMessage$
  Else
    ProcedureReturn Str(LastError)
  EndIf
EndProcedure

Procedure DebugDriverInfoData_DetailStructures()
  Select #PB_Compiler_Processor
    Case #PB_Processor_x64
      Debug "================================================================================"
      Debug "# Pure Basic x64 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "================================================================================"
    Case #PB_Processor_x86
      Debug "================================================================================"
      Debug "# Pure Basic x86 Compiler Version: "+Str(#PB_Compiler_Version)
      Debug "================================================================================"
  EndSelect
  Debug "SP_DRVINFO_DATA_V2 "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA))
  Debug "Alignment Boundry   : "+Str(SizeOf(SP_DRVINFO_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\cbSize))
  Debug "DriverType      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverType))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverType))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Reserved))
  Debug "Description     "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\Description))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\Description))
  Debug "MfgName         "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\MfgName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\MfgName))
  Debug "ProviderName    "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\ProviderName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\ProviderName))
  Debug "DriverDate      "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverDate))
  Debug "DriverVersion   "+"Size: "+Str(SizeOf(SP_DRVINFO_DATA\DriverVersion))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DATA\DriverVersion))
  Debug "================================================================================"
  Debug ""
  Debug "SP_DRVINFO_DETAIL_DATA "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA))
  Debug "Alignment Boundry          : "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA)%8)
  Debug "cbSize          "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\cbSize))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\cbSize))
  Debug "InfDate         "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfDate))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfDate))
  Debug "CompatIDsOffset "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsOffset))
  Debug "CompatIDsLength "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\CompatIDsLength))
  Debug "Reserved        "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\Reserved))+"   Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\Reserved))
  Debug "SectionName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\SectionName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\SectionName))
  Debug "InfFileName     "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\InfFileName))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\InfFileName))
  Debug "DrvDescription  "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\DrvDescription))
  Debug "HardwareID      "+"Size: "+Str(SizeOf(SP_DRVINFO_DETAIL_DATA\HardwareID))+" Offset: "+Str(OffsetOf(SP_DRVINFO_DETAIL_DATA\HardwareID))
  Debug "================================================================================"
  Debug "LIST OEM Drivers :"
EndProcedure

Procedure.s InitialCaps(text.s)
  ;Fastest way for InitialCaps by Demivec and wilbert
  ;https://www.purebasic.fr/english/viewtopic.php?p=406482#p406482
  Protected *b.Character = @text, cur, wordStarted = #False
 
  cur = *b\c
  While cur
    Select cur
      Case 97 To 122
        If Not wordStarted
          *b\c = cur - 32
          wordStarted = #True
        EndIf
      Case 65 To 90
        If wordStarted
          *b\c = cur + 32
        Else
          wordStarted = #True
        EndIf
      Case 39, '-', '_' ;apostrophe, hyphen and underscore treated as part of word
      Default
        wordStarted = #False
    EndSelect
   
    *b + SizeOf(Character)
    cur = *b\c
  Wend
 
  ProcedureReturn text
EndProcedure

Procedure.s ValidPath(Path.s, ReplaceChar.s)
  ;Forbidden path & Filename in Windows : /\:*?"<>  ...
  If CheckFilename(Path) = 0
    Path = ReplaceString(Path, "/", ReplaceChar)
    Path = ReplaceString(Path, "\", ReplaceChar)
    Path = ReplaceString(Path, ":", ReplaceChar)
    Path = ReplaceString(Path, "*", ReplaceChar)
    Path = ReplaceString(Path, "?", ReplaceChar)
    Path = ReplaceString(Path, "<", ReplaceChar)
    Path = ReplaceString(Path, ">", ReplaceChar)
    Path = ReplaceString(Path, "|", ReplaceChar)
  EndIf
  ProcedureReturn Path
EndProcedure

Procedure GetDriverAndInfClassInfo()
  Protected DeviceInfoData.SP_DEVINFO_DATA
  Protected DeviceInstallParms.SP_DEVINSTALL_PARAMS
  Protected DriverInfoData.SP_DRVINFO_DATA
  Protected *DriverInfoDetailData.SP_DRVINFO_DETAIL_DATA
 
  Protected.i libSetupAPI, hDevice, DeviceIndex, ConfigReturn, DriverIndex, InfPathLen, DriverInfoDetailSize, ActualDriverInfoDetailSize
  Protected.i Status, Problem, Result, InstanceIdStatus, GetDriverInfoDetailStatus, DeviceInstanceIdSize
  Protected SectionName$, InfFileName$, InfClassFileName$, InfPath$, DrvDescription$, HardwareID$, ClassName$, ClassGUID$, CopyFiles$, InstanceID$
  Protected CM_Get_DevNode_Status_.CM_Get_DevNode_Status
  Protected ClassGUID.GUID
  Protected *DeviceInstanceId
  ;Add--Begin
  Protected SetupGetInfDriverStoreLocation_.SetupGetInfDriverStoreLocation
  Protected ProviderName$, ClassDescription$, InfDriverStorePath$ , sysTime.SYSTEMTIME
  ;Add--End
 
  DeviceInfoData\cbSize     = SizeOf(SP_DEVINFO_DATA)
  DeviceInstallParms\cbSize = SizeOf(SP_DEVINSTALL_PARAMS)
  DriverInfoData\cbSize     = SizeOf(SP_DRVINFO_DATA)
 
  DebugDriverInfoData_DetailStructures()
 
  ClassName$  = Space(#MAX_CLASS_NAME_LEN)
  InfPath$    = GetEnvironmentVariable("SystemRoot")+"\inf"
  InfPathLen  = (Len(InfPath$)*SizeOf(Character))+SizeOf(Character)
 
  libSetupAPI = OpenLibrary(#PB_Any, "setupapi.dll")
  If libSetupAPI
    CM_Get_DevNode_Status_ = GetFunction(libSetupAPI, "CM_Get_DevNode_Status")
    If Not CM_Get_DevNode_Status_
      Debug "GetFunction Error: Unable to GetFunction CM_Get_DevNode_Status"
      CloseLibrary(libSetupAPI)
      End
    EndIf
    ;Add--Begin
    SetupGetInfDriverStoreLocation_ = GetFunction(libSetupAPI, "SetupGetInfDriverStoreLocationW")
    If Not SetupGetInfDriverStoreLocation_
      Debug "GetFunction Error: Unable to GetFunction SetupGetInfDriverStoreLocation"
      CloseLibrary(libSetupAPI)
      End
    EndIf
    ;Add--End
  Else   
    Debug "OpenLibrary Error: Unable to OpenLibrary(setupapi.dll)"
    End
  EndIf
 
  hDevice = SetupDiGetClassDevs_(#Null, 0, 0, #DIGCF_ALLCLASSES|#DIGCF_PRESENT)
  If hDevice = #INVALID_HANDLE_VALUE
    Debug "ERROR: SetupDiGetClassDevs: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf
 
  If Not SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)
    Debug "ERROR: SetupDiEnumDeviceInfo: "+GetLastError(GetLastError_())
    ProcedureReturn GetLastError_()
  EndIf   
 
  While GetLastError_() <> #ERROR_NO_MORE_ITEMS
    InstanceIdStatus = SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, #Null, 0, @DeviceInstanceIdSize)
    If InstanceIdStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      DeviceInstanceIdSize = (DeviceInstanceIdSize * SizeOf(Character))
      *DeviceInstanceId = AllocateMemory(DeviceInstanceIdSize + SizeOf(Character))
      If *DeviceInstanceId
        If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
          InstanceID$ = PeekS(*DeviceInstanceId)
          FreeMemory(*DeviceInstanceId)
          ConfigReturn = CM_Get_DevNode_Status_(@Status, @Problem, DeviceInfoData\DevInst, 0)
          If ConfigReturn = #CR_SUCCESS
            If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
              DeviceInstallParms\Flags = #DI_QUIETINSTALL|#DI_NOFILECOPY
              ;Add--Begin
              DeviceInstallParms\FlagsEx = #DI_FLAGSEX_INSTALLEDDRIVER
              ;Add--End
              CopyMemory(@InfPath$, @DeviceInstallParms\DriverPath, InfPathLen)
              If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
                If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                  DriverIndex = 0
                  Repeat
                    If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                      ;Add--Begin
                      ;Only OEM drivers. Perhaps there is a better method via Api, left 3 inf file name = oem (oemXX.inf)
                      ;If PeekS(@DriverInfoData\ProviderName, #PB_Ascii) = "Microsoft"
                      ;  Break
                      ;EndIf
                     
                      ;Add--End
                      GetDriverInfoDetailStatus = SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, 0, 0, @DriverInfoDetailSize)
                      If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        *DriverInfoDetailData = AllocateMemory(DriverInfoDetailSize + SizeOf(Character))
                        If *DriverInfoDetailData
                          *DriverInfoDetailData\cbSize = SizeOf(SP_DRVINFO_DETAIL_DATA) - (SizeOf(SP_DRVINFO_DETAIL_DATA)%8/2)
                          If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                           
                           
                            If Not PathMatchSpec_(@*DriverInfoDetailData\InfFileName, "*\Inf\oem*.inf")
                              DriverIndex + 1
                              FreeMemory(*DriverInfoDetailData)
                              Continue
                            EndIf
                           
                           
                            Debug "================================================================================"
                            SectionName$    = PeekS(@*DriverInfoDetailData\SectionName)
                            InfFileName$    = PeekS(@*DriverInfoDetailData\InfFileName)
                            DrvDescription$ = PeekS(@*DriverInfoDetailData\DrvDescription)
                            HardwareID$     = PeekS(@*DriverInfoDetailData\HardwareID)                     
                            If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "Device Index        : "+Str(DeviceIndex)
                              Debug "Driver Index        : "+Str(DriverIndex)
                              Debug "DeviceInstanceID    : "+InstanceID$
                              Debug "Hardware ID         : "+HardwareID$
                              Debug "Inf File Name       : "+InfFileName$
                              Debug "Section Name        : "+SectionName$
                              Debug "Class Name          : "+ClassName$
                              ;Add--Begin
                              ;if DrvDescription$ used for Filename
                              DrvDescription$ = ValidPath(DrvDescription$, "-")
                              Debug "Drv Description     : "+DrvDescription$
                              ClassDescription$ = Space(#MAX_PATH)
                              If SetupDiGetClassDescription_(@ClassGUID, @ClassDescription$, #MAX_PATH, 0)
                                Debug "Class Description   : "+ClassDescription$
                              EndIf
                              InfDriverStorePath$ = Space(#MAX_PATH)
                              If SetupGetInfDriverStoreLocation_(@InfFileName$, 0, 0, @InfDriverStorePath$, #MAX_PATH, 0)
                                Debug "Inf DriverStore Path: "+InfDriverStorePath$
                                Protected DriverStoreFolder$ = GetFilePart(RTrim(GetPathPart(InfDriverStorePath$), "\"))
                                Protected OrgInfFileName$ = GetFilePart(InfDriverStorePath$)
                                Debug "DriverStore Folder  : "+DriverStoreFolder$
                                Debug "Original Inf File   : "+OrgInfFileName$
                              EndIf
                              ProviderName$ = PeekS(@DriverInfoData\ProviderName, #PB_Ascii)
                              ProviderName$ = InitialCaps(ProviderName$)
                              Debug "Provider Name       : "+ProviderName$
                              FileTimeToSystemTime_(@DriverInfoData\DriverDate, sysTime)
                              Debug "Driver Date         : "+Str(sysTime\wYear)+"\"+RSet(Str(sysTime\wMonth),2,"0")+"\"+RSet(Str(sysTime\wDay),2,"0")
                             
                              Protected DriverVersion$
                              DriverVersion$ = Str(DriverInfoData\DriverVersion[3]) + "." +
                              Str(DriverInfoData\DriverVersion[2]) + "." +
                              Str(DriverInfoData\DriverVersion[1]) + "." +
                              Str(DriverInfoData\DriverVersion[0])
                             
                              Debug "Driver Version      : " +DriverVersion$
                             
                              ;Add--End
                            Else      ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                              Debug "ERROR: SetupDiGetINFClass : "+GetLastError(GetLastError_())
                            EndIf     ;// If SetupDiGetINFClass_(@InfFileName$ , @ClassGUID, @ClassName$, #MAX_CLASS_NAME_LEN, #Null)
                          Else        ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                            Debug "ERROR: SetupDiGetDriverInfoDetail: "+GetLastError(GetLastError_())
                          EndIf       ;// If SetupDiGetDriverInfoDetail_(hDevice, @DeviceInfoData, @DriverInfoData, *DriverInfoDetailData,  DriverInfoDetailSize, @ActualDriverInfoDetailSize)
                          FreeMemory(*DriverInfoDetailData)
                        Else          ;// If *DriverInfoDetailData
                          Debug "ERROR: Memory Allocation SetupDiGetDriverInfoDetail"
                        EndIf         ;// If *DriverInfoDetailData                         
                      Else            ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                        Debug "ERROR: SetupDiGetDriverInfoDetail"
                        Debug GetLastError(GetLastError_())
                      EndIf           ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
                    ElseIf GetLastError_() = #ERROR_NO_MORE_ITEMS
                      Break
                    Else
                      Debug GetLastError(GetLastError_())
                    EndIf             ;// If SetupDiEnumDriverInfo_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER, DriverIndex, @DriverInfoData)
                    DriverIndex = DriverIndex + 1
                  ForEver
                  SetupDiDestroyDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
                EndIf                 ;// If SetupDiBuildDriverInfoList_(hDevice, @DeviceInfoData, #SPDIT_COMPATDRIVER)
              EndIf                   ;// If SetupDiSetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
            EndIf                     ;// If SetupDiGetDeviceInstallParams_(hDevice, @DeviceInfoData, @DeviceInstallParms)
          EndIf                       ;// If ConfigReturn = #CR_SUCCESS
        EndIf                         ;// If SetupDiGetDeviceInstanceId_(hDevice, @DeviceInfoData, *DeviceInstanceId, DeviceInstanceIdSize, #Null)
      Else                            ;// If *DeviceInstanceId
        Debug "ERROR: Memory Allocation SetupDiGetDeviceInstanceId"
      EndIf                           ;// If *DeviceInstanceId
    Else                              ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
      Debug "ERROR: SetupDiGetDeviceInstanceId"
    EndIf                             ;// If GetDriverInfoDetailStatus = #False And GetLastError_() = #ERROR_INSUFFICIENT_BUFFER
    DeviceIndex = DeviceIndex + 1
    SetupDiEnumDeviceInfo_(hDevice, DeviceIndex, @DeviceInfoData)   
  Wend                                ;// While GetLastError_() <> #ERROR_NO_MORE_ITEMS
 
  SetupDiDestroyDeviceInfoList_(hDevice)
  If Result = #ERROR_NO_MORE_ITEMS : Result = #True : EndIf
 
  CloseLibrary(libSetupAPI)
 
  ProcedureReturn Result
EndProcedure

GetDriverAndInfClassInfo()
Last edited by fryquez on Mon Jan 11, 2021 8:47 am, edited 1 time in total.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by ChrisR »

Hi fryquez,
Nice to see you and thanks a lot for checking me out, I sometimes lack confidence in myself.
DriverVersion.w[4] in SP_DRVINFO_DATA Structure is indeed better
And I wondered what was best for oem drivers, ProviderName = "Microsoft" or oem*.inf
So thanks for PathMatchSpec_(@*DriverInfoDetailData\InfFileName, "*\Inf\oem*.inf"), I discover it.
fryquez
Enthusiast
Enthusiast
Posts: 362
Joined: Mon Dec 21, 2015 8:12 pm

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by fryquez »

Hi Chris,
I forgot to add a FreeMemory() before leaving the loop.
Also better to use DriverVersion.u[4] maybe in 20 years driver versions going over 32767 and we get negative numbers :lol:
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by ChrisR »

Good, thanks :)
I assumed that I would have reached the end of the service before the negative numbers
But, not sure, given the acceleration of Windows 10 Builds 10240 > 20277 >.. in 5 years
There may be a market opportunity, in ~6 years we're good for bugs as for Y2K
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: [PB 5.20 Beta15] Structures SP_DRVINFO_DATA and DETAIL_D

Post by ChrisR »

Not to pollute this topic, I continued my tool here Export Host Third-Party Driver Packages
Thank you again for sharing this nice code :)
Post Reply