Jump to content

Recommended Posts

Posted (edited)

IniEx.au3 (INI File Processing Functions) solve many problems, such as the limits of AutoIt Default INI function, and add many other options, since all function work by reference so IniEx.au3 also use less memory, and provide a really good performance in speed
 

#include-Once

; #INDEX# =======================================================================================================================
; Title .........: IniEx
; AutoIt Version : v3.3.9.22++
; Language ......: English
; Description ...: INI File Processing Functions
; Author(s) .....: DXRW4E
; ===============================================================================================================================

; #CURRENT# =====================================================================================================================
;_IniClearCache()
;_IniCloseFileEx()
;_IniDeleteEx()
;_IniFileWriteEx()
;_IniGetFileInformationEx()
;_IniGetFileStringData()
;_IniGetSectionNumberEx()
;_IniOpenFileEx()
;_IniOpenFile()
;_IniReadEx()
;_IniReadSectionEx()
;_IniReadSectionNamesEx()
;_IniRenameSectionEx()
;_IniWriteEx()
;_IniWriteSectionEx()
; ===============================================================================================================================

; #INTERNAL_USE_ONLY# ===========================================================================================================
;__GetSeparatorCharacter()
;__IniFileWriteEx()
;__IniGetFileStringData()
;__IniReadSectionEx()
;__IniSaveCache()
;__IniWriteSectionEx()
; ===============================================================================================================================

; #CONSTANTS# ===================================================================================================================
Global Const $INI_STRIPLEADING            = 1           ; $STR_STRIPLEADING  - strip leading white space
Global Const $INI_STRIPTRAILING           = 2           ; $STR_STRIPTRAILING - strip trailing white space
Global Const $INI_STRIPLEADTRAILING       = 3            ; BitOR($STR_STRIPLEADING,  $STR_STRIPTRAILING)

Global Const $INI_ARRAYDATA               = 4
Global Const $INI_ARRAYDATA_NOCOUNT       = 8
Global Const $INI_NOWRITEREADONLY         = 16
Global Const $INI_FO_UNICODE              = 32          ; $FO_UNICODE
Global Const $INI_FO_UTF16_LE             = 32          ; $FO_UTF16_LE
Global Const $INI_FO_UTF16_BE             = 64          ; $FO_UTF16_BE
Global Const $INI_FO_UTF8                 = 128         ; $FO_UTF8
Global Const $INI_FO_UTF8_NOBOM           = 256         ; $FO_UTF8_NOBOM
Global Const $INI_NOOCCURRENCE            = 512
Global Const $INI_MERGE                   = 1024
Global Const $INI_NOCREATE                = 2048
Global Const $INI_APPENDDATA              = 4096
Global Const $INI_REPLACEONLY             = 8192
Global Const $INI_FO_UTF8_FULL            = 16384       ; $FO_UTF8_FULL
Global Const $INI_NOOVERWRITE             = 32768
Global Const $INI_OVERWRITEALL            = 65536
Global Const $INI_IGNOREDUPLICATE         = 131072
Global Const $INI_DELETE                  = 262144
Global Const $INI_RENAME                  = 524288
Global Const $INI_REMOVE                  = 1048576
;Global Const $INI_RESERVED*               = 2097152
;Global Const $INI_RESERVED*               = 4194304
;Global Const $INI_RESERVED*               = 8388608
Global Const $INI_OPEN_EXISTING           = 16777216
Global Const $INI_CREATEPATH              = 33554432
Global Const $INI_REPAIR_ERROR            = 67108864
Global Const $INI_DISCARDCHANGES          = 134217728
Global Const $INI_OPEN_FILEQUEUE          = 268435456
;Global Const $INI_RESERVED*               = 536870912
Global Const $INI_2DARRAYFIELD            = 1073741824

;;;; THESE ARE SPECIAL FLAGS, ARE USED INTERNALLY ONLY ;;;;
Global Const $INI_INTERNAL_USE_ONLY       = 2147483648
Global Const $INI_FO_STYLE                = BitOR(31, $INI_OPEN_EXISTING, $INI_CREATEPATH, $INI_REPAIR_ERROR, $INI_OPEN_FILEQUEUE)
Global Const $INI_MERGE_NOOCCURRENCE      = BitOR($INI_MERGE, $INI_NOOCCURRENCE)
Global Const $INI_REMOVE_RENAME           = BitOR($INI_REMOVE, $INI_RENAME)
Global Const $INI_REMOVE_DELETE           = BitOR($INI_REMOVE, $INI_DELETE)
Global Const $INI_NOCREATE_REMOVE_DELETE  = BitOR($INI_NOCREATE, $INI_REMOVE, $INI_DELETE)
Global Const $INI_NOOCCURRENCE_IGNOREDUPLICATE = BitOr($INI_NOOCCURRENCE, $INI_IGNOREDUPLICATE)
Global Const $INI_OVERWRITEALL_APPENDDATA = BitOR($INI_OVERWRITEALL, $INI_APPENDDATA)

Global Const $NULL_REF = Null
Global Const $sINI_OPENFILE_EX            = @LF & "[]" & @LF

;;;; DO NOT EVER USE\CHANGE\EDIT THESE VARIABLES ;;;;
;;;;  THESE VARIABLES ARE USED INTERNALLY ONLY   ;;;;
Global Static $INI_NULL_REF = Null
Global Static $_HINI[11][11] = [[10, 0]]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ===============================================================================================================================



; #FUNCTION# ====================================================================================================================
; Name...........: _IniOpenFileEx
; Description ...: The _IniOpenFileEx function opens an INI file and returns a handle to it.
; Syntax.........: _IniOpenFileEx($sFilePath[, $iFlags]])
; Parameters ....: $sFilePath       - INI File Path
;                   $iFlags          - Optional, (add the flags together for multiple operations):
;                  This Flags will be ignored if the $INI_CREATEPATH is not set\used
;                  | A file may fail to open due to access rights or attributes.
;                  | The default mode when writing text is ANSI - use the unicode flags to change this. When writing unicode files
;                  | the Windows default mode (and the fastest in AutoIt due to the least conversion) is UTF16 Little Endian (mode 32).
;                  | $INI_FO_* Flags will be ignored if the $INI_CREATEPATH is not Set\Used
;                  |$INI_FO_UNICODE or $INI_UTF16_LE (32) - Use Unicode UTF16 Little Endian reading and writing mode. Reading does not override existing BOM.
;                  |$INI_FO_UTF16_BE (64)                 - Use Unicode UTF16 Big Endian reading and writing mode. Reading does not override existing BOM.
;                  |$INI_FO_UTF8 (128)                    - Use Unicode UTF8 (with BOM) reading and writing mode. Reading does not override existing BOM.
;                  |$INI_FO_UTF8_NOBOM (256)              - Use Unicode UTF8 (without BOM) reading and writing mode.
;                  |$INI_FO_UTF8_FULL (16384)             - When opening for reading and no BOM is present, use full file UTF8 detection. If this is not used then only the initial part of the file is checked for UTF8.
;                  ;;;;;;;;;;;;
;                  |$INI_OPEN_EXISTING (16777216)      - If the INI File (Path) is Already Open use that (Handle) (Default Always Opens a New)
;                  |$INI_CREATEPATH (33554432)         - Create INI File if does not exist (Default if file not exist Return Error)
;                  |$INI_REPAIR_ERROR (67108864)       - If exist Error when Opening the INI File Repair Error, example as this line (@CRLF & [SectionName & @CRLF) repair in (@CRLF & [SectionName] & @CRLF), Default Return Error
;                  |$INI_OPEN_FILEQUEUE (268435456)    - Open INI file from Memory\Variable, $sFilePath must contain String Text Data of INI file
; Return values .: Success - INI Handle
;                  Failure - Returns 0 or String\Text of error line (check @Extended for error line number)
;                  @Error  - 0 = No error.
;                  |1 = File cannot be opened or found.
;                  |2 = Error when Opening the INI File
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniOpenFileEx($sFilePath, $iFlags = 0)
    If BitAND($iFlags, $INI_OPEN_EXISTING) Then
        For $i = 1 To $_HINI[0][0]
            If $_HINI[$i][2] = $sFilePath Then Return SetError(0, $i, $i)
        Next
    EndIf
    Local $sCS, $_sCS = "\r", $hFilePath, $iFileEncoding, $aFileData, $aErrorLine, $iFO_Style = BitXOR(BitOR($iFlags, $INI_FO_STYLE), $INI_FO_STYLE)
    If BitAND($iFlags, $INI_OPEN_FILEQUEUE) Then
        $aFileData = StringRegExpReplace($sINI_OPENFILE_EX & $sFilePath, '\r(?!\n)', @CRLF)    ;;;;, '(?<!\r)\n', @CRLF)
        $sFilePath = "FileQueue"
        $iFileEncoding = $iFO_Style    ;;(StringIsASCII($aFileData) ? 0 : 32)
    Else
        $hFilePath = FileOpen($sFilePath)
        If $hFilePath = -1 Then
            If Not FileExists($sFilePath) Then
                If Not BitAND($iFlags, $INI_CREATEPATH) Then Return SetError(1, 0, 0)
                $iFO_Style += 10        ;;$iFO_Style = 42
            EndIf
            $hFilePath = FileOpen($sFilePath, $iFO_Style)
            If $hFilePath = -1 Then Return SetError(1, 0, 0)
        EndIf
        $aFileData = StringRegExpReplace($sINI_OPENFILE_EX & FileRead($hFilePath), '\r(?!\n)', @CRLF)    ;;;;, '(?<!\r)\n', @CRLF)
        $iFileEncoding = FileGetEncoding($hFilePath)
        FileClose($hFilePath)
    EndIf
    $aErrorLine = StringRegExp($aFileData, '\n\K[\h\f\xb\x0]*\[[^\]\n]*(?:\n|$)', 1)
    If Not @Error Then
        Local $iErrorLine = @Extended - (StringLen($aErrorLine[0]) - 1)
        If Not BitAND($iFlags, $INI_REPAIR_ERROR) Then Return SetError(2, StringSplit(StringLeft($aFileData, $iErrorLine), @LF)[0] - 2, $aErrorLine[0])
        $aFileData = StringRegExpReplace($aFileData, '(\n[\h\f\xb\x0]*\[[^\]\r\n]*)(?=[\r\n]|$)', "$1]")
    EndIf
    $sCS = __GetSeparatorCharacter($aFileData)
    If $sCS = @CR Then $_sCS = ""
    $aFileData = StringRegExpReplace($aFileData & @CRLF & "[", "\n\K(?>[" & $_sCS & "\n\h\f\xb\x0]*\n|\x0*)(?=[\h\f\xb\x0]*\[)", $sCS & "${0}" & $sCS)
    $aFileData = StringRegExp($aFileData & $sCS, $sCS & "([\h\f\xb\x0]*\[)([^\]\n]*)(\][^\n]*\n)((?>[" & $_sCS & "\n\h\f\xb\x0]*\n)*)([^" & $sCS & "]*)" & $sCS & "([^" & $sCS & "]*)", 3)
    $aFileData[0] = UBound($aFileData) - 1
    If $aFileData[0] < 5 Then Return SetError(1, 0, 0) ; should not happen ever
    $aFileData[$aFileData[0]] = StringTrimRight($aFileData[$aFileData[0]], 2)
    For $iHINI = 1 To $_HINI[0][0]
        If Not $_HINI[$iHINI][0] Then ExitLoop
    Next
    If $iHINI > $_HINI[0][0] Then
        ReDim $_HINI[$iHINI + $iHINI][11]
        $_HINI[0][0] = $iHINI + $iHINI - 1
    EndIf
    $aFileData[2] = $iHINI
    If Not $_sCS Then
        $aFileData[3] = StringAddCR($aFileData[3])
        $aFileData[4] = StringAddCR($aFileData[4])
        $aFileData[5] = StringAddCR($aFileData[5])
    EndIf
    For $i = 7 To $aFileData[0] Step 6
        $_HINI[$iHINI][5] &= @LF & $aFileData[$i] & @CR & $i
        If Not $_sCS Then
            $aFileData[$i + 1] = StringAddCR($aFileData[$i + 1])
            $aFileData[$i + 2] = StringAddCR($aFileData[$i + 2])
            $aFileData[$i + 3] = StringAddCR($aFileData[$i + 3])
            $aFileData[$i + 4] = StringAddCR($aFileData[$i + 4])
        EndIf
    Next
    $_HINI[0][1] += 1    ;;($_HINI[0][1] < 1) ? 1 : $_HINI[0][1] + 1
    $_HINI[$iHINI][0] = $iHINI
    $_HINI[$iHINI][1] = $aFileData
    $_HINI[$iHINI][2] = $sFilePath
    $_HINI[$iHINI][3] = $iFileEncoding
    $_HINI[$iHINI][4] = ($aFileData[0] - 5) / 6
    $_HINI[$iHINI][5] = StringReplace($_HINI[$iHINI][5], "\E", "\e", 0, 1)
    $_HINI[$iHINI][7] = Null
    Return $iHINI
EndFunc   ;==>_IniOpenFileEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniOpenFile
; Description ...: The _IniOpenFile function opens an INI file and returns a handle to it.
; Parameters ....: the same as the _IniOpenFileEx(), See _IniOpenFileEx()
; Return values .: See _IniOpenFileEx()
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: _IniOpenFile() is the same as the _IniOpenFileEx(), only that _IniOpenFile()  force the check\repair of @CR or @LF in @CRLF
;                    performance\speed does not change much with _IniOpenFileEx(), _IniOpenFile() can only be about 1% or 5% or10% slower
; ===============================================================================================================================
Func _IniOpenFile($sFilePath, $iFlags = 0)
    If BitAND($iFlags, $INI_OPEN_EXISTING) Then
        For $i = 1 To $_HINI[0][0]
            If $_HINI[$i][2] = $sFilePath Then Return SetError(0, $i, $i)
        Next
    EndIf
    Local $hFilePath, $iFileEncoding, $aFileData, $aErrorLine, $iFO_Style = BitXOR(BitOR($iFlags, $INI_FO_STYLE), $INI_FO_STYLE)
    If BitAND($iFlags, $INI_OPEN_FILEQUEUE) Then
        $aFileData = StringRegExpReplace($sINI_OPENFILE_EX & $sFilePath, '\r\n?', @LF)
        $sFilePath = "FileQueue"
        $iFileEncoding = $iFO_Style    ;;(StringIsASCII($aFileData) ? 0 : 32)
    Else
        $hFilePath = FileOpen($sFilePath)
        If $hFilePath = -1 Then
            If Not FileExists($sFilePath) Then
                If Not BitAND($iFlags, $INI_CREATEPATH) Then Return SetError(1, 0, 0)
                $iFO_Style += 10        ;;$iFO_Style = 42
            EndIf
            $hFilePath = FileOpen($sFilePath, $iFO_Style)
            If $hFilePath = -1 Then Return SetError(1, 0, 0)
        EndIf
        $aFileData = StringRegExpReplace($sINI_OPENFILE_EX & FileRead($hFilePath), '\r\n?', @LF)
        $iFileEncoding = FileGetEncoding($hFilePath)
        FileClose($hFilePath)
    EndIf
    $aErrorLine = StringRegExp($aFileData, '\n\K[\h\f\xb\x0]*\[[^\]\n]*(?:\n|$)', 1)
    If Not @Error Then
        Local $iErrorLine = @Extended - (StringLen($aErrorLine[0]) - 1)
        If Not BitAND($iFlags, $INI_REPAIR_ERROR) Then Return SetError(2, StringSplit(StringLeft($aFileData, $iErrorLine), @LF)[0] - 2, $aErrorLine[0])
        $aFileData = StringRegExpReplace($aFileData, '(\n[\h\f\xb\x0]*\[[^\]\n]*)(?=\n|$)', "$1]")
    EndIf
    $aFileData = StringRegExpReplace($aFileData & @LF & "[", '\n\K(?>[\n\h\f\xb\x0]*\n|\x0*)(?=[\h\f\xb\x0]*\[)', @CR & "${0}" & @CR)
    $aFileData = StringRegExp($aFileData & @CR, '\r([\h\f\xb\x0]*\[)([^\]\n]*)(\][^\n]*\n)((?>[\n\h\f\xb\x0]*\n)*)([^\r]*)\r([^\r]*)', 3)
    $aFileData[0] = UBound($aFileData) - 1
    If $aFileData[0] < 5 Then Return SetError(1, 0, 0) ; should not happen ever
    $aFileData[$aFileData[0]] = StringTrimRight($aFileData[$aFileData[0]], 1)
    For $iHINI = 1 To $_HINI[0][0]
        If Not $_HINI[$iHINI][0] Then ExitLoop
    Next
    If $iHINI > $_HINI[0][0] Then
        ReDim $_HINI[$iHINI + $iHINI][11]
        $_HINI[0][0] = $iHINI + $iHINI - 1
    EndIf
    $aFileData[2] = $iHINI
    $aFileData[3] = StringAddCR($aFileData[3])
    $aFileData[4] = StringAddCR($aFileData[4])
    $aFileData[5] = StringAddCR($aFileData[5])
    For $i = 7 To $aFileData[0] Step 6
        $_HINI[$iHINI][5] &= @LF & $aFileData[$i] & @CR & $i
        $aFileData[$i + 1] = StringAddCR($aFileData[$i + 1])
        $aFileData[$i + 2] = StringAddCR($aFileData[$i + 2])
        $aFileData[$i + 3] = StringAddCR($aFileData[$i + 3])
        $aFileData[$i + 4] = StringAddCR($aFileData[$i + 4])
    Next
    $_HINI[0][1] += 1    ;;($_HINI[0][1] < 1) ? 1 : $_HINI[0][1] + 1
    $_HINI[$iHINI][0] = $iHINI
    $_HINI[$iHINI][1] = $aFileData
    $_HINI[$iHINI][2] = $sFilePath
    $_HINI[$iHINI][3] = $iFileEncoding
    $_HINI[$iHINI][4] = ($aFileData[0] - 5) / 6
    $_HINI[$iHINI][5] = StringReplace($_HINI[$iHINI][5], "\E", "\e", 0, 1)
    $_HINI[$iHINI][7] = Null
    Return $iHINI
EndFunc   ;==>_IniOpenFileEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniCloseFileEx
; Description ...: The _IniCloseFileEx function closes the INI file opened by a call to _IniOpenFileEx.
; Syntax.........: _IniCloseFileEx($hIniFile[, $iFlags])
; Parameters ....: $hIniFile - Handle or INI Path to the INI file to be closed, This parameter can be NULL (use the $NULL_REF to set NULL this parameter)
;                    if $hIniFile is NULL Function Close All Open Handle or INI Path
;                   $iFlags  - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |Default - always Commits the changes that were made when the INI file was opened by _IniOpenFileEx()
;                  |$INI_DISCARDCHANGES (134217728) - Discards the changes that were made when the INI file was opened by _IniOpenFileEx()
; Return values .: NONE
; Author ........: DXRW4E
; Remarks .......:
; ===============================================================================================================================
Func _IniCloseFileEx($hIniFile, $iFlags = 0)
    If $hIniFile = $NULL_REF Then
        For $i = 1 To $_HINI[0][0]
            If Not BitAND($iFlags, $INI_DISCARDCHANGES) And $_HINI[$i][2] <> "FileQueue" Then _IniFileWriteEx($i, $iFlags)
            For $y = 0 To 10
                $_HINI[$i][$y] = ""
            Next
        Next
        $_HINI[0][1] = 0
    Else
        $hIniFile = _IniGetFileInformationEx($hIniFile)
        If @Error Then Return SetError(1, 0, 0)
        If Not BitAND($iFlags, $INI_DISCARDCHANGES) And $_HINI[$hIniFile][2] <> "FileQueue" Then _IniFileWriteEx($hIniFile, $iFlags)
        For $i = 0 To 10
            $_HINI[$hIniFile][$i] = ""
        Next
        $_HINI[0][1] -= 1
    EndIf
    Return 0
EndFunc   ;==>_IniCloseFileEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniDeleteEx
; Description ...: Delete\Remove - Section\KeyName in INI File.
; Syntax.........: _IniDeleteEx(ByRef $hIniFile, $sSectionName[, $sKeyName[, $iFlags[, $scKeyName]]])
; Parameters ....: $hIniFile     - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $sSectionName - The name of the section containing the Key\Value, This parameter can be NULL (use the $NULL_REF to set NULL this parameter)
;                    If $sSectionName is NULL, $hIniFile must be contain Section String\Key\Value\Data and $sKeyName the name of the key to delete
;                  $sKeyName     - The key name to delete, If $INI_OVERWRITEALL if set\used, $sKeyName will be writte exactly as in $sKeyName (without Edit\Formatting)
;                    This parameter can be NULL (use the $NULL_REF to set NULL this parameter), If $sKeyName is NULL, $hIniFile must be contain INI String\Text Data and $sSectionName the name of the section to delete
;                   $iFlags       - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_NOOCCURRENCE (512)       - Check only first section if there are more than one
;                  |$INI_IGNOREDUPLICATE (131072) - Proceed\Execute (Add\Delete\Replace\Edit ect ect) Once Only (Ignore all other Duplicate\Occurrences of KeyName\Value\Data)
;                  |$INI_DELETE (262144)          - Delete\Remove KeyName\Value\Data
;                  |$INI_REMOVE (1048576)         - Remove\Delete Section
;                   $scKeyName    - Optional, Key-Name separator character, Default is '=', This parameter can not be '"' or @CR or @LF
; Return values .: Returns a 0 (check @Extended for number of edit performed)
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName not found
; Remarks .......: $INI_MERGE (1024) - (Join section if more than one in INI file) is always set\used by default, to disable it just use the $INI_NOOCCURRENCE
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniDeleteEx(ByRef $hIniFile, $sSectionName, $sKeyName = "", $iFlags = 0, $scKeyName = "=")
    If Not $scKeyName Then $scKeyName = "="
    If $sSectionName = $NULL_REF Then
        Local $iOffSet = StringInStr($hIniFile, @LF, 1)
        If StringRegExp(StringLeft($hIniFile, $iOffSet), '^(?i)[\h\f\xb\x0]*(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*') Then
            If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $hIniFile = StringRegExpReplace($hIniFile, '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*', "")
            $hIniFile = StringTrimLeft($hIniFile, $iOffSet)
            SetExtended(1)
        Else
            $hIniFile = StringRegExpReplace($hIniFile, '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*', "", (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? 1 : 0))
        EndIf
    ElseIf $sKeyName = $NULL_REF Then
        ;Not Recommended (NOT SAFE), if the Section (contains) String\Text Data is greater than 4.5 MB, the Section will be ignored
        $hIniFile = StringTrimRight(StringRegExpReplace($hIniFile & @LF & "[", "(?is)\n[\h\f\xb\x0]*\[\Q" & StringReplace($sSectionName, "\E", "\e", 0, 1) & "\E\][^\n]*(?>\n?(?![\h\f\xb\x0]*\[))(.*?(?=\n[\h\f\xb\x0]*\[))", "", (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? 1 : 0)), 2)
    Else
        If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
        ;;;;If Not $sSectionName Then Return SetError(2, 0, "")    ;Invalid Section Name
        If StringInStr($sSectionName, "\E", 1) Then $sSectionName = StringReplace($sSectionName, "\E", "\e", 0, 1)
        If Not $sKeyName Or BitAND($iFlags, $INI_REMOVE_DELETE) = $INI_REMOVE Then
            $iFlags = BitOr($iFlags, $INI_REMOVE)
            __IniWriteSectionEx($hIniFile, $sSectionName, $INI_NULL_REF, $iFlags, $INI_NULL_REF, $_HINI[$hIniFile][1])
        Else
            $iFlags = BitOR(BitAND($iFlags, $INI_NOOCCURRENCE_IGNOREDUPLICATE), $INI_DELETE, $INI_MERGE)
            If $_HINI[$hIniFile][7] <> $sSectionName Or ($_HINI[$hIniFile][8] > 1 And BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) <> BitAND($_HINI[$hIniFile][9], $INI_MERGE_NOOCCURRENCE)) Then
                __IniReadSectionEx($hIniFile, $sSectionName, $iFlags, $_HINI[$hIniFile][1])
                If @Error Then Return SetError(3, 0, "")
            EndIf
            Local $aKeyValue[2][3] = [[1],[$sKeyName]]
            __IniWriteSectionEx($hIniFile, $sSectionName, $aKeyValue, $iFlags, $scKeyName, $_HINI[$hIniFile][1])
        EndIf
    EndIf
    Return SetError(0, @Extended, 0)
EndFunc


; #FUNCTION# ====================================================================================================================
; Name...........: _IniReadEx
; Description ...: The _IniReadEx Retrieves a string from the specified section in an Ini file
; Syntax.........: _IniReadEx($hIniFile, $sSectionName, $sKeyName[, $sDefault[, $iFlags[, $scKeyName]]])
; Parameters ....: $hIniFile      - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $sSectionName  - The name of the section containing the key name, This parameter can be NULL (use the $NULL_REF to set NULL this parameter)
;                    If $sSectionName is NULL, $hIniFile must be contain Section String\Key\Value\Data
;                   $sKeyName      - The name of the key whose associated string is to be retrieved
;                   $sDefault      - The default value to return if the requested KeyName is not found.
;                   $iFlags        - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_ARRAYDATA (4)         - Read All KeyName and Return Array of ValueString
;                  |$INI_ARRAYDATA_NOCOUNT (8) - Disable the return count in the first element, This Flags will be ignored if the $INI_ARRAYDATA is not set\used
;                  |$INI_NOOCCURRENCE (512)    - Read only first section if there are more than one
;                  |$INI_MERGE (1024)          - Join section if more than one in INI file, This Flag will be ignored if the $INI_NOOCCURRENCE is set\used
;                   $scKeyName - Optional, Key-Name separator character, Default is '=', This parameter can not be '"' or @CR or @LF
; Return values .: The first occurrence of requested key value as a string Or Array of Value String
;                  Failure - Returns $sDefault parameter
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName not found
;                  |5 = Invalid KeyName
;                  |6 = KeyName not found
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniReadEx(ByRef $hIniFile, $sSectionName, $sKeyName, $sDefault = "", $iFlags = 0, $scKeyName = "=")
    ;;If Not $sKeyName Then Return SetError(5, 0, "")
    If StringInStr($sKeyName, "\E", 1) Then $sKeyName = StringReplace($sKeyName, "\E", "\e", 0, 1)
    Local $aValueString, $sValueString, $iArray = BitAND($iFlags, $INI_ARRAYDATA)
    If $sSectionName = $NULL_REF Then
        $aValueString = StringRegExp(StringLeft($hIniFile, StringInStr($hIniFile, @LF, 1)), '^(?i)[\h\f\xb\x0]*(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)(?>[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*)(?|"([^\r\n]*)"|(.*?))[\h\f\xb\x0]*(?=[\r\n]|$)', 1)
    Else
        If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
        If StringInStr($sSectionName, "\E", 1) Then $sSectionName = StringReplace($sSectionName, "\E", "\e", 0, 1)
        If $_HINI[$hIniFile][7] <> $sSectionName Or ($_HINI[$hIniFile][8] > 1 And BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) <> BitAND($_HINI[$hIniFile][9], $INI_MERGE_NOOCCURRENCE)) Then
            _IniReadSectionEx($hIniFile, $sSectionName, BitOR($iFlags, $INI_STRIPLEADTRAILING))
            If @Error Then Return SetError(3, 0, "")
        EndIf
        $aValueString = StringRegExp(StringLeft(($_HINI[$hIniFile][1])[$_HINI[$hIniFile][10]], StringInStr(($_HINI[$hIniFile][1])[$_HINI[$hIniFile][10]], @LF, 1)), '^(?i)[\h\f\xb\x0]*(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)(?>[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*)(?|"([^\r\n]*)"|(.*?))[\h\f\xb\x0]*(?=[\r\n]|$)', 1)
        ;;;;$aValueString = StringRegExp(($sSectionName = $NULL_REF ? $hIniFile : ($_HINI[$hIniFile][1])[$_HINI[$hIniFile][10]]), '(?im)^[\h\f\xb\x0]*(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*(?|"([^\r\n]*)"|(.*?))[\h\f\xb\x0]*(?=[\r\n]|$)', 3)
    EndIf
    If Not @Error Then
        If Not $iArray Then Return $aValueString[0]
        $sValueString = $aValueString[0] & @LF
    EndIf
    $aValueString = StringRegExp(($sSectionName = $NULL_REF ? $hIniFile : ($_HINI[$hIniFile][1])[$_HINI[$hIniFile][10]]), '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)(?>[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*)(?|"([^\r\n]*)"|(.*?))[\h\f\xb\x0]*(?=[\r\n]|$)', ($iArray ? 3 : 1))
    If @Error Then Return SetError(6, 0, $sDefault)
    If Not $iArray Then Return $aValueString[0]
    For $i = 0 To UBound($aValueString) - 1
        $sValueString &= $aValueString[$i] & @LF
    Next
    Return StringSplit(StringTrimRight($sValueString, 1), @LF, (BitAND($iFlags, $INI_ARRAYDATA_NOCOUNT) ? 3 : 1))
EndFunc   ;==>_IniReadEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniReadSectionEx
; Description ...: The _IniReadSectionEx Retrieves all the lines for the specified section
; Syntax.........: _IniReadSectionEx(ByRef $hIniFile, $sSectionName[, $iFlags[, $scKeyName])
; Parameters ....: $hIniFile      - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $sSectionName  - The name of the section containing the Key\Value, This parameter can be NULL (use the $NULL_REF to set NULL this parameter)
;                    If $sSectionName is NULL, $hIniFile must be contain Section String\Key\Value\Data
;                   $iFlags        - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                    Default Return Section String\Text Data
;                  |$INI_NOOCCURRENCE (512)        - Read only first section if there are more than one
;                  |$INI_MERGE (1024)              - Join section if more than one in INI file, This Flag will be ignored if the $INI_NOOCCURRENCE is set\used
;                  |$INI_2DARRAYFIELD (1073741824) - Return 2DArray
;                     $aArray[0][0] = number of elements
;                     $aArray[0][1] = Key-Name separator character, Defaut is '='
;                     $aArray[1][0] = "KeyName"
;                     $aArray[1][1] = "Value"
;                     $aArray[1][2] = "Unmodified contents of a line (example '    KeyName  = Value')"
;                     $aArray[n][0] = "KeyName"
;                     $aArray[n][1] = "Value"
;                     $aArray[n][2] = "Unmodified contents of a line (example ' KeyName =  Value')"
;                   $scKeyName - Optional, Key-Name separator character, Default is '=', This parameter can not be '"' or @CR or @LF
; Return values .: String\Text Data Or 2D Array
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName's not found
;                  |4 = Array is invalid, Key\Value not found
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniReadSectionEx(ByRef $hIniFile, $sSectionName, $iFlags = 0, $scKeyName = "=")
    If Not $scKeyName Then $scKeyName = "="
    If $sSectionName = $NULL_REF Then
        Local $_aSectionData = StringRegExp($hIniFile, '(?m)^((?>[\h\f\xb\x0]*)((?>"[^"\r\n]+"|(?:[^"\s' & $scKeyName & '\x0]+|(?>[\h\f\xb\x0]+)(?!' & $scKeyName & '))*))(?>[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*)(?|"([^\r\n]*)"|(.*?))[\h\f\xb\x0]*(?=[\r\n]|$))', 3)
    Else
        If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
        If $_HINI[$hIniFile][7] <> $sSectionName Or ($_HINI[$hIniFile][8] > 1 And BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) <> BitAND($_HINI[$hIniFile][9], $INI_MERGE_NOOCCURRENCE)) Then
            $iFlags = BitOR($iFlags, $INI_NOCREATE)
            __IniReadSectionEx($hIniFile, $sSectionName, $iFlags, $_HINI[$hIniFile][1])
            If @Error Then Return SetError(3, 0, "")
        EndIf
        If Not BitAND($iFlags, $INI_2DARRAYFIELD) Then Return ($_HINI[$hIniFile][1])[$_HINI[$hIniFile][10]]
        Local $_aSectionData = StringRegExp(($_HINI[$hIniFile][1])[$_HINI[$hIniFile][10]], '(?m)^((?>[\h\f\xb\x0]*)((?>"[^"\r\n]+"|(?:[^"\s' & $scKeyName & '\x0]+|(?>[\h\f\xb\x0]+)(?!' & $scKeyName & '))*))(?>[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*)(?|"([^\r\n]*)"|(.*?))[\h\f\xb\x0]*(?=[\r\n]|$))', 3)
    EndIf
    If @Error Then Return SetError(4, 0, "")
    Local $iaSectionData = UBound($_aSectionData), $aSectionData[$iaSectionData / 3 + 1][3] = [[0,$scKeyName,$iaSectionData - 1]]
    For $i = 0 To $aSectionData[0][2] Step 3
        $aSectionData[0][0] += 1
        $aSectionData[$aSectionData[0][0]][0] = $_aSectionData[$i + 1]
        $aSectionData[$aSectionData[0][0]][1] = $_aSectionData[$i + 2]
        $aSectionData[$aSectionData[0][0]][2] = $_aSectionData[$i]
    Next
    Return SetError(0, $aSectionData[0][0], $aSectionData)
EndFunc   ;==>_IniReadSectionEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniReadSectionNamesEx
; Description ...: The _IniReadSectionNamesEx Retrieves the names of all sections in an INI file
; Syntax.........: _IniReadSectionNamesEx($hIniFile[, $iFlags])
; Parameters ....: $hIniFile - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $iFlags   - Optional, Flag to indicate the type of action that should be performed
;                  |$INI_ARRAYDATA_NOCOUNT (8) - disable the return count in the first element
;                  |$NULL_REF (NULL)           - $hIniFile must be contain INI String\Section\Key\Value\Data
; Return values .: Array of SectionNames String, and set @Extended = Number of Section's
;                  @Error  - 0 = No error.
;                  |1 = Array is invalid, Invalid IniHandle.
;                  |3 = Array is invalid, SectionName's not found
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniReadSectionNamesEx(ByRef $hIniFile, $iFlags = 0)
    If $iFlags = $NULL_REF Then
        Local $aSectionNames, $iANC = BitAND($iFlags, $INI_ARRAYDATA_NOCOUNT)
        $aSectionNames = StringRegExp(($iANC ? @LF : @LF & "[]" & @LF) & $hIniFile, "\n[\h\f\xb\x0]*\[([^\r\n]*)\]", 3)
        If @Error Then Return SetError(1, 0, "")
        If $iANC Then Return SetError(0, UBound($aSectionNames), $aSectionNames)
        $aSectionNames[0] = UBound($aSectionNames) - 1
        Return SetError(0, $aSectionNames[0], $aSectionNames)
    EndIf
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
    If Not $_HINI[$hIniFile][4] Then Return SetError(3, 0, "")
    If BitAND($iFlags, $INI_ARRAYDATA_NOCOUNT) Then Return SetError(0, $_HINI[$hIniFile][4], StringRegExp($_HINI[$hIniFile][5], "\n([^\r\n]*)", 3))
    Return SetError(0, $_HINI[$hIniFile][4], StringRegExp(@LF & $_HINI[$hIniFile][4] & $_HINI[$hIniFile][5], "\n([^\r\n]*)", 3))
EndFunc   ;==>_IniReadSectionNamesEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniRenameSectionEx
; Description ...: The _IniRenameSectionEx rename the sections in an INI file
; Syntax.........: _IniRenameSectionEx($hIniFile[, $iFlags])
; Parameters ....: $hIniFile      - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $iFlags        - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_NOOCCURRENCE (512) - Rename only first section if there are more than one
;                  |$INI_MERGE (1024)       - Join section if more than one in INI\INI file, This Flag will be ignored if the $INI_NOOCCURRENCE is set\used
;                  |$NULL_REF (NULL)        - $hIniFile must be contain INI String\Section\Key\Value\Data
; Return values .: Returns a 0 (check @Extended for number of edit performed)
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName's not found
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniRenameSectionEx(ByRef $hIniFile, $sSectionName, $sNewSectionName, $iFlags = 0)
    ;;;;If Not $sSectionName Or Not $sNewSectionName Then Return SetError(2, 0, "")    ;Invalid Section Name
    If $iFlags = $NULL_REF Then
        $hIniFile = StringRegExpReplace($hIniFile, "(?mi)^[\h\f\xb\x0]*\[\K\Q" & StringReplace($sSectionName, "\E", "\e", 0, 1) & "\E(?=\])", StringReplace($sNewSectionName, "\", "\\", 0, 1), (BitAND($iFlags, $INI_NOOCCURRENCE) ? 1 : 0))
    Else
        If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
        If StringInStr($sSectionName, "\E", 1) Then $sSectionName = StringReplace($sSectionName, "\E", "\e", 0, 1)
        $iFlags = BitXOR(BitOR($iFlags, $INI_REMOVE_RENAME), $INI_REMOVE)
        If BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) = $INI_MERGE And Not __IniReadSectionEx($hIniFile, $sSectionName, $iFlags, $_HINI[$hIniFile][1]) Then Return SetError(3, 0, 0)
        __IniWriteSectionEx($hIniFile, $sSectionName, $sNewSectionName, $iFlags, $INI_NULL_REF, $_HINI[$hIniFile][1])
    EndIf
    Return SetError(@Error, @Extended, 0)
EndFunc   ;==>_IniRenameSectionEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniWriteEx
; Description ...: Write\Add\Replace\Delete\Change\Edit a KeyName\Value\Data in INI File
; Syntax.........: _IniWriteEx(ByRef $hIniFile, $sSectionName, $sKeyName, $sValue[, $iFlags[, $scKeyName]])
; Parameters ....: $hIniFile     - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $sSectionName - The name of the section containing the Key\Value, This parameter can be NULL (use the $NULL_REF to set NULL this parameter)
;                    If $sSectionName is NULL, $hIniFile must be contain Section String\Key\Value\Data
;                  $sKeyName     - The key name in the in the .ini file.
;                  $sKeyName     - The value to write/change.
;                   $iFlags       - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_STRIPLEADING (1)         - strip leading white space Section, This Flag will be ignored if the $INI_OVERWRITEALL or $INI_APPENDDATA is set\used
;                  |$INI_STRIPTRAILING (2)        - trailing white space Section, This Flag will be ignored if the $INI_OVERWRITEALL or $INI_APPENDDATA is set\used
;                  |$INI_NOOCCURRENCE (512)       - Check only first section if there are more than one
;                  |$INI_NOCREATE (2048)          - Not Create New Section If Section Not Exist
;                  |$INI_APPENDDATA (4096)        - Add KeyName\Value\Data (Append Mod)
;                  |$INI_REPLACEONLY (8192)       - Add KeyName\Value\Data Only if Exist
;                  |$INI_NOOVERWRITE (32768)      - Add KeyName\Value\Data Only if Not Exist
;                  |$INI_OVERWRITEALL (65536)     - Overwrite All data in Section (Replaces all KeyName\Value\Data in the Section)
;                  |$INI_IGNOREDUPLICATE (131072) - Proceed\Execute (Add\Delete\Replace\Edit ect ect) Once Only (Ignore all other Duplicate\Occurrences of KeyName\Value\Data)
;                  |$INI_DELETE (262144)          - Delete\Remove KeyName\Value\Data
;                   $scKeyName     - Optional, Key-Name separator character, Default is '=', This parameter can not be '"' or @CR or @LF
; Return values .: Returns a 0 (check @Extended for number of edit performed)
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName's not found
;                  |5 = Invalid KeyName
; Author ........: DXRW4E
; Remarks .......: $INI_MERGE (1024) - (Join section if more than one in INI file) is always set\used by default, to disable it just use the $INI_NOOCCURRENCE
; ===============================================================================================================================
Func _IniWriteEx(ByRef $hIniFile, $sSectionName, $sKeyName, $sValue, $iFlags = 0, $scKeyName = "=")
    ;;If Not $sKeyName Then Return SetError(5, 0, "")
    If Not $scKeyName Then $scKeyName = "="
    If $sSectionName = $NULL_REF Then
        If BitAND($iFlags, $INI_OVERWRITEALL_APPENDDATA) Then
            If BitAND($iFlags, $INI_OVERWRITEALL) Then $hIniFile = ""
            $hIniFile &= $sKeyName & $scKeyName & $sValue & @CRLF
        Else
            Local $asKeyValue, $sKNPattern, $iOffSet = StringInStr($hIniFile, @LF, 1)
            $sKNPattern = '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*'
            If StringRegExp(StringLeft($hIniFile, $iOffSet), '^(?i)[\h\f\xb\x0]*(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*') Then
                If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $hIniFile = StringRegExpReplace($hIniFile, $sKNPattern, "")
                If BitAND($iFlags, $INI_DELETE) Then
                    $hIniFile = StringTrimLeft($hIniFile, $iOffSet)
                ElseIf Not BitAND($iFlags, $INI_NOOVERWRITE) Then
                    $hIniFile = $sKeyName & $scKeyName & $sValue & @CRLF & StringTrimLeft($hIniFile, $iOffSet)
                EndIf
            ElseIf BitAND($iFlags, $INI_DELETE) Then
                $hIniFile = StringRegExpReplace($hIniFile, $sKNPattern, "", (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? 1 : 0))
            Else
                $asKeyValue = StringRegExp($hIniFile, $sKNPattern, 1)
                $iOffSet = @Extended - 1
                If Not @Error Then
                    If BitAND($iFlags, $INI_NOOVERWRITE) Then
                        If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $hIniFile = StringLeft($hIniFile, $iOffSet) & StringRegExpReplace(StringTrimLeft($hIniFile, $iOffSet), $sKNPattern, "")
                    Else
                        $hIniFile = StringLeft($hIniFile, $iOffSet + 1 - StringLen($asKeyValue[0])) & $sKeyName & $scKeyName & $sValue & @CR & (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? StringTrimLeft($hIniFile, $iOffSet) : StringRegExpReplace(StringTrimLeft($hIniFile, $iOffSet), $sKNPattern, ""))
                    EndIf
                ElseIf Not BitAND($iFlags, $INI_REPLACEONLY) Then
                    $hIniFile &= $sKeyName & $scKeyName & $sValue & @CRLF
                Else
                    Return SetError(0, 0, 0)
                EndIf
            EndIf
        EndIf
        Return SetError(0, 1, 0)
    Else
        If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
        ;;;;If Not $sSectionName Then Return SetError(2, 0, "")    ;Invalid Section Name
        If StringInStr($sSectionName, "\E", 1) Then $sSectionName = StringReplace($sSectionName, "\E", "\e", 0, 1)
        Local $aKeyValue[2][3] = [[1],[$sKeyName,"",$sKeyName & $scKeyName & $sValue]]
        $iFlags = BitOR(BitXOR($iFlags, BitAND($iFlags, $INI_REMOVE_RENAME)), $INI_MERGE)
        If $_HINI[$hIniFile][7] <> $sSectionName Or ($_HINI[$hIniFile][8] > 1 And BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) <> BitAND($_HINI[$hIniFile][9], $INI_MERGE_NOOCCURRENCE)) Then
            __IniReadSectionEx($hIniFile, $sSectionName, $iFlags, $_HINI[$hIniFile][1])
            If @Error Then Return SetError(3, 0, "")
        EndIf
        __IniWriteSectionEx($hIniFile, $sSectionName, $aKeyValue, $iFlags, $scKeyName, $_HINI[$hIniFile][1])
    EndIf
    Return SetError(@Error, @Extended, 0)
EndFunc


; #FUNCTION# ====================================================================================================================
; Name...........: _IniWriteSectionEx
; Description ...: Add\Replace\Delete\Remove\Rename\Change\Edit a Section\KeyName\Value\Data in INI File.
; Syntax.........: _IniWriteSectionEx()
; Parameters ....: $hIniFile     - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $sSectionName - The name of the section containing the Key\Value\Data
;                  $aKeyValue    - String\Text Data (example 'KeyName=Value 7 @LF & KeyName2=Value2') or an 2DArray is passed as data, the return Array of IniReadSectionEx() can be used immediately.
;                    If $aKeyValue is String\Text Data and $INI_OVERWRITEALL or $INI_APPENDDATA if Set\Used, $aKeyValue will be writte exactly as in $aKeyValue (without Edit\Formatting)
;                   $iFlags       - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_STRIPLEADING (1)         - strip leading white space Section, This Flag will be ignored if the $INI_OVERWRITEALL or $INI_APPENDDATA is set\used
;                  |$INI_STRIPTRAILING (2)        - trailing white space Section, This Flag will be ignored if the $INI_OVERWRITEALL or $INI_APPENDDATA is set\used
;                  |$INI_NOOCCURRENCE (512)       - Check only first section if there are more than one
;                  |$INI_NOCREATE (2048)          - Not Create New Section If Section Not Exist
;                  |$INI_APPENDDATA (4096)        - Add KeyName\Value\Data (Append Mod)
;                  |$INI_REPLACEONLY (8192)       - Add KeyName\Value\Data Only if Exist
;                  |$INI_NOOVERWRITE (32768)      - Add KeyName\Value\Data Only if Not Exist
;                  |$INI_OVERWRITEALL (65536)     - Overwrite All data in Section (Replaces all KeyName\Value\Data in the Section)
;                  |$INI_IGNOREDUPLICATE (131072) - Proceed\Execute (Add\Delete\Replace\Edit ect ect) Once Only (Ignore all other Duplicate\Occurrences of KeyName\Value\Data)
;                  |$INI_DELETE (262144)          - Delete\Remove KeyName\Value\Data
;                  |$INI_RENAME (524288)          - Renames a section
;                  |$INI_REMOVE (1048576)         - Remove\Delete Section
;                   $scKeyName     - Optional, Key-Name separator character, Default is '=', This parameter can not be '"' or @CR or @LF
; Return values .: Returns a 0 (check @Extended for number of edit performed)
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName's not found
;                  |5 = Invalid KeyName
; Remarks .......:
; Author ........: DXRW4E
; Remarks .......: $INI_MERGE (1024) - (Join section if more than one in INI file) is always set\used by default, to disable it just use the $INI_NOOCCURRENCE
; ===============================================================================================================================
Func _IniWriteSectionEx(ByRef $hIniFile, $sSectionName, $aKeyValue, $iFlags = 0, $scKeyName = "=")
;~     If $sSectionName = $NULL_REF Then
;~         If Not $scKeyName Then $scKeyName = "="
;~         If IsArray($aKeyValue) Then
;~             Local $iCols = UBound($aKeyValue, 2)
;~             If UBound($aKeyValue, 0) <> 2 Or $iCols < 2 Then Return SetError(7, 0, "")
;~             If $iCols = 2 Then
;~                 ReDim $aKeyValue[$aKeyValue[0][0] + 1][3]
;~                 For $i = 1 To $aKeyValue[0][0]
;~                     $aKeyValue[$i][2] = $aKeyValue[$i][0] & $scKeyName & $aKeyValue[$i][1]
;~                 Next
;~             EndIf
;~         ElseIf Not BitAND($iFlags, $INI_OVERWRITEALL_APPENDDATA) Then
;~             $aKeyValue = _IniReadSectionEx($aKeyValue, Null, $INI_2DARRAYFIELD, $scKeyName)
;~             If @Error Then Return SetError(7, 0, "")
;~         EndIf
;~         If BitAND($iFlags, $INI_OVERWRITEALL_APPENDDATA) Then
;~             If BitAND($iFlags, $INI_OVERWRITEALL) Then $hIniFile = ""
;~             If IsArray($aKeyValue) Then
;~                 For $i = 1 To $aKeyValue[0][0]
;~                     $hIniFile &= $aKeyValue[$i][2] & @CRLF
;~                 Next
;~             Else
;~                 ;;    KeyName\Value\Text Data will be writte exactly as in $aKeyValue (without Edit\Formatting ect ect)
;~                 $hIniFile &= $aKeyValue & (StringRight($aKeyValue, 1) = @LF ? "" : @CRLF)
;~             EndIf
;~             Return SetError(0, 1, 0)
;~         Else
;~             Local $asKeyValue, $iKeyValue = 0, $sKNPattern, $iOffSet = StringInStr($hIniFile, @LF, 1)
;~             For $i = 1 To $aKeyValue[0][0]
;~                 $sKNPattern = '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $aKeyValue[$i][0] & '"\E|\Q' & $aKeyValue[$i][0] & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*'
;~                 If StringRegExp(StringLeft($hIniFile, $iOffSet), '^(?i)[\h\f\xb\x0]*(?>\Q"' & $aKeyValue[$i][0] & '"\E|\Q' & $aKeyValue[$i][0] & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*') Then
;~                     If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $hIniFile = StringRegExpReplace($hIniFile, $sKNPattern, "")
;~                     If BitAND($iFlags, $INI_DELETE) Then
;~                         $hIniFile = StringTrimLeft($hIniFile, $iOffSet)
;~                     ElseIf Not BitAND($iFlags, $INI_NOOVERWRITE) Then
;~                         $hIniFile = $aKeyValue[$i][2] & @CRLF & StringTrimLeft($hIniFile, $iOffSet)
;~                     EndIf
;~                 ElseIf BitAND($iFlags, $INI_DELETE) Then
;~                     $hIniFile = StringRegExpReplace($hIniFile, $sKNPattern, "", (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? 1 : 0))
;~                 Else
;~                     $asKeyValue = StringRegExp($hIniFile, $sKNPattern, 1)
;~                     $iOffSet = @Extended - 1
;~                     If Not @Error Then
;~                         If BitAND($iFlags, $INI_NOOVERWRITE) Then
;~                             If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $hIniFile = StringLeft($hIniFile, $iOffSet) & StringRegExpReplace(StringTrimLeft($hIniFile, $iOffSet), $sKNPattern, "")
;~                         Else
;~                             $hIniFile = StringLeft($hIniFile, $iOffSet + 1 - StringLen($asKeyValue[0])) & $aKeyValue[$i][2] & @CR & (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? StringTrimLeft($hIniFile, $iOffSet) : StringRegExpReplace(StringTrimLeft($hIniFile, $iOffSet), $sKNPattern, ""))
;~                         EndIf
;~                     ElseIf Not BitAND($iFlags, $INI_REPLACEONLY) Then
;~                         $hIniFile &= $aKeyValue[$i][2] & @CRLF
;~                     Else
;~                         $iKeyValue -= 1
;~                     EndIf
;~                 EndIf
;~                 $iKeyValue += 1
;~             Next
;~             Return SetError(0, $iKeyValue, 0)
;~         EndIf
;~     EndIf
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
    ;;;;If Not $sSectionName Then Return SetError(2, 0, "")    ;Invalid Section Name
    If StringInStr($sSectionName, "\E", 1) Then $sSectionName = StringReplace($sSectionName, "\E", "\e", 0, 1)
    If BitAND($iFlags, $INI_REMOVE) Then
        __IniWriteSectionEx($hIniFile, $sSectionName, $INI_NULL_REF, $iFlags, $INI_NULL_REF, $_HINI[$hIniFile][1])
    ElseIf BitAND($iFlags, $INI_RENAME) Then
        ;;;;    $aKeyValue is New Section Name
        ;;If Not $aKeyValue Then Return SetError(5, 0, "")
        If BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) = $INI_MERGE And Not __IniReadSectionEx($hIniFile, $sSectionName, $iFlags, $_HINI[$hIniFile][1]) Then Return SetError(3, 0, 0)
        __IniWriteSectionEx($hIniFile, $sSectionName, $aKeyValue, $iFlags, $INI_NULL_REF, $_HINI[$hIniFile][1])
    Else
        If Not $scKeyName Then $scKeyName = "="
        If IsArray($aKeyValue) Then
            Local $iCols = UBound($aKeyValue, 2)
            If UBound($aKeyValue, 0) <> 2 Or $iCols < 2 Then Return SetError(5, 0, "")
            If $iCols = 2 Then
                ReDim $aKeyValue[$aKeyValue[0][0] + 1][3]
                For $i = 1 To $aKeyValue[0][0]
                    $aKeyValue[$i][2] = $aKeyValue[$i][0] & $scKeyName & $aKeyValue[$i][1]
                Next
            EndIf
        ElseIf Not BitAND($iFlags, $INI_OVERWRITEALL_APPENDDATA) Then
            $aKeyValue = _IniReadSectionEx($aKeyValue, Null, $INI_2DARRAYFIELD, $scKeyName)
            If @Error Then Return SetError(5, 0, "")
        EndIf
        $iFlags = BitOR($iFlags, $INI_MERGE)
        If $_HINI[$hIniFile][7] <> $sSectionName Or ($_HINI[$hIniFile][8] > 1 And BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) <> BitAND($_HINI[$hIniFile][9], $INI_MERGE_NOOCCURRENCE)) Then
            __IniReadSectionEx($hIniFile, $sSectionName, $iFlags, $_HINI[$hIniFile][1])
            If @Error Then Return SetError(3, 0, "")
        EndIf
        __IniWriteSectionEx($hIniFile, $sSectionName, $aKeyValue, $iFlags, $scKeyName, $_HINI[$hIniFile][1])
    EndIf
    Return SetError(@Error, @Extended, 0)
EndFunc


; #FUNCTION# ====================================================================================================================
; Name...........: _IniGetSectionNumberEx
; Description ...: The _IniGetSectionNumberEx Retrieves the number of all sections in an INI file
; Syntax.........: _IniGetSectionNumberEx(Byref $hIniFile)
; Parameters ....: $hIniFile      - Handle to the INI file to query "see _IniOpenFileEx()"
; Return values .: Number of Section's
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
;                  |3 = SectionName's not found
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniGetSectionNumberEx(ByRef $hIniFile)
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then
        Local $aSectionNames = StringRegExp(@LF & $hIniFile, "\n[\h\f\xb\x0]*\[[^\r\n]*\K\]", 3)    ;StringRegExp($hIniFile, "(?m)^[\h\f\xb\x0]*\[[^\r\n]*\]", 3)
        Return SetError(@Error, 0, UBound($aSectionNames))
    EndIf
    Return SetError(($_HINI[$hIniFile][4] ? 0 : 3), 0, $_HINI[$hIniFile][4])
EndFunc   ;==>_IniGetSectionNumberEx


; #FUNCTION# ===========================================================================================================
; Name...........: _IniGetFileInformationEx
; Description ...: Returns information about an INI file
; Syntax.........: _IniGetFileInformationEx($hIniFile[, $iFlags])
; Parameters ....: $hIniFile    - Handle of INI file previously opened by _IniOpenFileEx, see _IniOpenFileEx()
;                  $iFlags - Optional
;                  |0  - Return INI Handle (Default)
;                  |1  - Return INI File Array Data (is array of arrays)
;                  |2  - Return INI File Path
;                  |3  - Return INI Encoding
;                  |4  - Return INI Section Number
; Return values .: See Flag parameter
; Author ........: DXRW4E
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _IniGetFileInformationEx($hIniFile, $iFlags = 0)
    If Not $hIniFile Then Return SetError(1, 0, "")
    If $_HINI[0][1] < 0 Then
        $_HINI[0][1] = 0
        Return SetError(1, 0, "")
    ElseIf IsString($hIniFile) Then
        ;;If StringIsDigit($hIniFile) And StringLeft($hIniFile, 1) <> "0" Then
        ;;    $hIniFile = Number($hIniFile)
        ;;Else
            For $i = 1 To $_HINI[0][0]
                If $_HINI[$i][2] = $hIniFile Then ExitLoop
            Next
            $hIniFile = $i
        ;;EndIf
    EndIf
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")    ; Or $hIniFile <> $_HINI[$hIniFile][0]
    If $iFlags < 1 Or $iFlags > 4 Then Return $hIniFile
    Return SetError(0, $hIniFile, $_HINI[$hIniFile][$iFlags])
EndFunc   ;==>_IniGetFileInformationEx


; #FUNCTION# ====================================================================================================================
; Name...........: _IniGetFileStringData
; Description ...: The _IniGetFileStringData Retrieves all INI Lines\String\Text Data
; Syntax.........: _IniGetFileStringData(ByRef $hIniFile[, $iFlags])
; Parameters ....: $hIniFile      - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $iFlags        - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_STRIPLEADING (1)          - strip leading white space Section
;                  |$INI_STRIPTRAILING (2)         - strip trailing white space Section
; Return values .: String\Text Data
;                  @Error  - 0 = No error.
;                  |1 = Invalid IniHandle.
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniGetFileStringData(ByRef $hIniFile, $iFlags = 0)
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
    ;;Local $sData, $iSL = BitAND($iFlags, $INI_STRIPLEADING), $iST = BitAND($iFlags, $INI_STRIPTRAILING)
    ;;$sData = ($iSL ? "" : ($_HINI[$hIniFile][1])[3]) & ($_HINI[$hIniFile][1])[4] & ($iST ? "" : ($_HINI[$hIniFile][1])[5])
    ;;For $i = 6 To ($_HINI[$hIniFile][1])[0] Step 6
    ;;    $sData &= ($_HINI[$hIniFile][1])[$i] & ($_HINI[$hIniFile][1])[$i + 1] & ($_HINI[$hIniFile][1])[$i + 2] & ($iSL ? "" : ($_HINI[$hIniFile][1])[$i + 3]) & ($_HINI[$hIniFile][1])[$i + 4] & ($iST ? "" : ($_HINI[$hIniFile][1])[$i + 5])
    ;;Next
    Local $sData = __IniGetFileStringData($hIniFile, $iFlags, $_HINI[$hIniFile][1])
    Return SetError(0, $_HINI[$hIniFile][3], $sData)
EndFunc   ;==>_IniGetFileStringData


; #FUNCTION# ====================================================================================================================
; Name...........: _IniClearCache
; Description ...: Clear INI File Processing Functions Cache
; Syntax.........: _IniClearCache(ByRef $aIniFile)
; Parameters ....: $hIniFile     - Handle to the INI file to query "see _IniOpenFileEx()"
; Return values .: None
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: This function is useful to Run after _IniRea*Ex Funcion's, only in the case when in the INI file are duplicated function
;                   and if the flag $INI_MERGE or $INI_NOOCCURRENCE is not set\used, because in this case the _IniReadEx\_IniReadSectionEx saves
;                   in cache the Function's\String\Data to be fast during the loop ect ect, so only in cases when you Get\Read Occurrence Function
;                   and the flag $INI_MERGE or $INI_NOOCCURRENCE is not set\used
;                   All other function as _IniDeleteEx or _IniWrite*Ex use by Default or Force the use of $INI_MERGE flag
;                   So in 99.9% of cases you do not Need\Have to run _IniClearCache(), because the INI File Processing Functions Work's only By Reference
; ===============================================================================================================================
Func _IniClearCache(ByRef $hIniFile)
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
    $_HINI[$hIniFile][6] = ""
    __IniSaveCache($hIniFile, $_HINI[$hIniFile][6], $INI_NULL_REF, $_HINI[$hIniFile][6], $_HINI[$hIniFile][6], $_HINI[$hIniFile][1])
    Return 0
EndFunc   ;==>_IniClearCache


; #FUNCTION# ====================================================================================================================
; Name...........: _IniFileWrite
; Description ...: Write a Ini File
; Syntax.........: _IniFileWriteEx(ByRef $hIniFile[, $iFlags[, $sFilePath[, $iFileEncoding]]])
; Parameters ....: $hIniFile      - Handle to the INI file to query "see _IniOpenFileEx()"
;                   $iFlags        - Optional, Flag to indicate the type of action that should be performed (add the flags together for multiple operations):
;                  |$INI_STRIPLEADING (1)     - strip leading white space Section
;                  |$INI_STRIPTRAILING (2)    - trailing white space Section
;                  |$INI_NOWRITEREADONLY (16) - Do not Write\Replace\Edit the ReadOnly file (Default Write\Replace\Edit the ReadOnly files)
;                   $sFilePath     - Optional, use alternative FilePath, By Default always is used (Default) PathFile
;                   $iFileEncoding - Optional, use alternative FileEncoding, By Default always is used (Default) FileEncoding
; Return values .: Returns a 0
;                  @Error  - 0 = No error.
;                  |1  =  Invalid IniHandle.
;                  |9  =  Invalid FilePath
;                  |10 = A file may fail to open due to access rights or attributes.
; Remarks .......:
; Author ........: DXRW4E
; ===============================================================================================================================
Func _IniFileWriteEx(ByRef $hIniFile, $iFlags = 0, $sFilePath = Default, $iFileEncoding = Default)
    If $hIniFile < 1 Or $hIniFile > $_HINI[0][0] Then Return SetError(1, 0, "")
    If $_HINI[$hIniFile][2] = "FileQueue" And Not $sFilePath Then Return SetError(9, 0, "")
    If $sFilePath = Default Then $sFilePath = $_HINI[$hIniFile][2]
    If $iFileEncoding = Default Then $iFileEncoding = $_HINI[$hIniFile][3] + 10
    ;;Local $hFileOpen, $iSL = BitAND($iFlags, $INI_STRIPLEADING), $iST = BitAND($iFlags, $INI_STRIPTRAILING)
    ;;$hFileOpen = FileOpen($_HINI[$hIniFile][2], $_HINI[$hIniFile][3] + 10)
    ;; ;; Check if file opened for writing OK
    ;;If $hFileOpen = -1 Then
    ;;    Return SetError(10, 0, 0)
    ;;EndIf
    ;;FileWrite($hFileOpen, ($iSL ? "" : ($_HINI[$hIniFile][1])[3]) & ($_HINI[$hIniFile][1])[4] & ($iST ? "" : ($_HINI[$hIniFile][1])[5]))
    ;;For $i = 6 To ($_HINI[$hIniFile][1])[0] Step 6
    ;;    FileWrite($hFileOpen, ($_HINI[$hIniFile][1])[$i] & ($_HINI[$hIniFile][1])[$i + 1] & ($_HINI[$hIniFile][1])[$i + 2] & ($iSL ? "" : ($_HINI[$hIniFile][1])[$i + 3]) & ($_HINI[$hIniFile][1])[$i + 4] & ($iST ? "" : ($_HINI[$hIniFile][1])[$i + 5]))
    ;;Next
    ;;FileClose($hFileOpen)
    __IniFileWriteEx($hIniFile, $iFlags, $sFilePath, $iFileEncoding, $_HINI[$hIniFile][1])
    Return SetError(@Error, @Extended, 0)
EndFunc   ;==>_IniFileWriteEx



; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __IniReadSectionEx
; Description ...: Support Function for _IniReadSectionEx
; Syntax.........: __IniReadSectionEx(ByRef $aIniFile, ByRef $sSectionName, ByRef $iFlags)
; Parameters ....: See _IniReadSectionEx()
; Return values .: See _IniReadSectionEx()
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: This function is used internally by _IniReadSectionEx
; ===============================================================================================================================
Func __IniReadSectionEx(ByRef $hIniFile, ByRef $sSectionName, ByRef $iFlags, ByRef $aIniFile)
    ;;;;If Not $sSectionName Then Return SetError(2, 0, "")    ;Invalid Section Name
    If StringInStr($sSectionName, "\E", 1) Then $sSectionName = StringReplace($sSectionName, "\E", "\e", 0, 1)
    Local $sSectionData, $aSectionName, $iSectionName = 1
    $aSectionName = StringRegExp($_HINI[$hIniFile][5], "\n(?is)\Q" & $sSectionName & "\E\r([^\n]+)", 3)
    If @Error Then
        If BitAND($iFlags, $INI_NOCREATE_REMOVE_DELETE) Then Return SetError(3, 0, "")
        $aIniFile[0] += 6
        Redim $aIniFile[$aIniFile[0] + 1]
        $aIniFile[$aIniFile[0] - 5] = "["
        $aIniFile[$aIniFile[0] - 4] = $sSectionName
        $aIniFile[$aIniFile[0] - 3] = "]" & @CRLF
        $_HINI[$hIniFile][4] += 1
        $_HINI[$hIniFile][5] &= @LF & $sSectionName & @CR & ($aIniFile[0] - 4)
        $_HINI[$hIniFile][6] = $aIniFile[0] - 1
    Else
        $_HINI[$hIniFile][6] = $aSectionName[0] + 3
        $iSectionName = UBound($aSectionName)
        ;;If BitAND($iFlags, $INI_STRIPLEADTRAILING) = $INI_STRIPLEADTRAILING Then    ;; BitOR($INI_STRIPLEADING,  $INI_STRIPTRAILING)
        ;;    $sSectionData = $aIniFile[$aSectionName[0] + 3]
        ;;ElseIf BitAND($iFlags, $INI_STRIPLEADING) Then
        ;;    $sSectionData = $aIniFile[$aSectionName[0] + 3] & $aIniFile[$aSectionName[0] + 4]
        ;;ElseIf BitAND($iFlags, $INI_STRIPTRAILING) Then
        ;;    $sSectionData = $aIniFile[$aSectionName[0] + 2] & $aIniFile[$aSectionName[0] + 3]
        ;;Else
        ;;    $sSectionData = $aIniFile[$aSectionName[0] + 2] & $aIniFile[$aSectionName[0] + 3] & $aIniFile[$aSectionName[0] + 4]
        ;;EndIf
        If Not BitAND($iFlags, $INI_NOOCCURRENCE) And $iSectionName > 1 Then
            $sSectionData = $aIniFile[$aSectionName[0] + 3]
            For $i = 1 To $iSectionName - 1
                $sSectionData &= $aIniFile[$aSectionName[$i] + 3]
                If BitAND($iFlags, $INI_MERGE) Then
                    For $y = $aSectionName[$i] - 1 To $aSectionName[$i] + 4
                        $aIniFile[$y] = ""
                    Next
                    $_HINI[$hIniFile][5] = StringRegExpReplace($_HINI[$hIniFile][5], '\n(?is)\Q' & $sSectionName & '\E\r' & $aSectionName[$i], "")
                EndIf
            Next
            If BitAND($iFlags, $INI_MERGE) Then $aIniFile[$aSectionName[0] + 3] = $sSectionData
        EndIf
    EndIf
    __IniSaveCache($hIniFile, $sSectionData, $sSectionName, $iFlags, $iSectionName, $aIniFile)
    Return $iSectionName    ;SetError(Not $iSectionName, $iSectionName, $sSectionData)
EndFunc   ;==>__IniReadSectionEx


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __IniWriteSectionEx
; Description ...: Support Function for _IniWriteSectionEx
; Syntax.........: __IniWriteSectionEx(ByRef $hIniFile, ByRef $sSectionName, ByRef $aKeyValue, ByRef $iFlags, ByRef $scKeyName, ByRef $aIniFile)
; Parameters ....: See _IniWriteSectionEx()
; Return values .: See _IniWriteSectionEx()
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: This function is used internally by _IniWriteSectionEx
; ===============================================================================================================================
Func __IniWriteSectionEx(ByRef $hIniFile, ByRef $sSectionName, ByRef $aKeyValue, ByRef $iFlags, ByRef $scKeyName, ByRef $aIniFile)
    If BitAND($iFlags, $INI_REMOVE) Then
        Local $iaSectionName, $aSectionName = StringRegExp($_HINI[$hIniFile][5], '\n(?is)\Q' & $sSectionName & '\E\r([^\n]+)', 3)
        If @Error Then Return SetError(3, 0, 0)
        $iaSectionName = UBound($aSectionName) - 1
        If BitAND($iFlags, $INI_NOOCCURRENCE) Then $iaSectionName = 0
        For $i = 0 To $iaSectionName
            For $y = $aSectionName[$i] - 1 To $aSectionName[$i] + 4
                $aIniFile[$y] = ""
            Next
        Next
        $_HINI[$hIniFile][4] -= $iaSectionName + 1
        $_HINI[$hIniFile][5] = StringRegExpReplace($_HINI[$hIniFile][5], '\n(?is)\Q' & $sSectionName & '\E\r[^\r\n]+', "", Int($iaSectionName = 0))
        Return SetError(0, @Extended, 0)
    ElseIf BitAND($iFlags, $INI_RENAME) Then
        Local $iaSectionName, $aSectionName = StringRegExp($_HINI[$hIniFile][5], '\n(?is)\Q' & $sSectionName & '\E\r([^\n]+)', 3)
        If @Error Then Return SetError(3, 0, 0)
        $iaSectionName = UBound($aSectionName) - 1
        If BitAND($iFlags, $INI_NOOCCURRENCE) Then $iaSectionName = 0
        ;; $aKeyValue is New Section Name
        For $i = 0 To $iaSectionName
            $aIniFile[$aSectionName[$i]] = $aKeyValue
        Next
        $_HINI[$hIniFile][5] = StringRegExpReplace($_HINI[$hIniFile][5], '\n\K(?is)\Q' & $sSectionName & '\E(?=\r)', StringReplace(StringReplace($aKeyValue, "\", "\\", 0, 1), "\E", "\e", 0, 1), Int($iaSectionName = 0))
        Return SetError(0, @Extended, 0)
    Else
        Local $iSN = $_HINI[$hIniFile][10]
        If BitAND($iFlags, $INI_OVERWRITEALL_APPENDDATA) Then
            If BitAND($iFlags, $INI_OVERWRITEALL) Then $aIniFile[$iSN] = ""
            If BitAND($iFlags, $INI_STRIPLEADING) Then $aIniFile[$iSN - 1] = ""
            If BitAND($iFlags, $INI_STRIPTRAILING) Then $aIniFile[$iSN + 1] = ""
            If IsArray($aKeyValue) Then
                For $i = 1 To $aKeyValue[0][0]
                    $aIniFile[$iSN] &= $aKeyValue[$i][2] & @CRLF
                Next
            Else
                ;;    KeyName\Value\Text Data will be writte exactly as in $aKeyValue (without Edit\Formatting ect ect)
                $aIniFile[$iSN] &= $aKeyValue & (StringRight($aKeyValue, 1) = @LF ? "" : @CRLF)
            EndIf
            Return SetError(0, 1, 0)
        Else
            Local $asKeyValue, $iKeyValue = 0, $sKNPattern, $iOffSet = StringInStr($aIniFile[$iSN], @LF, 1)
            For $i = 1 To $aKeyValue[0][0]
                $sKNPattern = '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $aKeyValue[$i][0] & '"\E|\Q' & $aKeyValue[$i][0] & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*'
                If StringRegExp(StringLeft($aIniFile[$iSN], $iOffSet), '^(?i)[\h\f\xb\x0]*(?>\Q"' & $aKeyValue[$i][0] & '"\E|\Q' & $aKeyValue[$i][0] & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*') Then
                    If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $aIniFile[$iSN] = StringRegExpReplace($aIniFile[$iSN], $sKNPattern, "")
                    If BitAND($iFlags, $INI_DELETE) Then
                        $aIniFile[$iSN] = StringTrimLeft($aIniFile[$iSN], $iOffSet)
                    ElseIf Not BitAND($iFlags, $INI_NOOVERWRITE) Then
                        $aIniFile[$iSN] = $aKeyValue[$i][2] & @CRLF & StringTrimLeft($aIniFile[$iSN], $iOffSet)
                    EndIf
                ElseIf BitAND($iFlags, $INI_DELETE) Then
                    $aIniFile[$iSN] = StringRegExpReplace($aIniFile[$iSN], $sKNPattern, "", (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? 1 : 0))
                Else
                    $asKeyValue = StringRegExp($aIniFile[$iSN], $sKNPattern, 1)
                    $iOffSet = @Extended - 1
                    If Not @Error Then
                        If BitAND($iFlags, $INI_NOOVERWRITE) Then
                            If Not BitAND($iFlags, $INI_IGNOREDUPLICATE) Then $aIniFile[$iSN] = StringLeft($aIniFile[$iSN], $iOffSet) & StringRegExpReplace(StringTrimLeft($aIniFile[$iSN], $iOffSet), $sKNPattern, "")
                        Else
                            $aIniFile[$iSN] = StringLeft($aIniFile[$iSN], $iOffSet + 1 - StringLen($asKeyValue[0])) & $aKeyValue[$i][2] & @CR & (BitAND($iFlags, $INI_IGNOREDUPLICATE) ? StringTrimLeft($aIniFile[$iSN], $iOffSet) : StringRegExpReplace(StringTrimLeft($aIniFile[$iSN], $iOffSet), $sKNPattern, ""))
                        EndIf
                    ElseIf Not BitAND($iFlags, $INI_REPLACEONLY) Then
                        $aIniFile[$iSN] &= $aKeyValue[$i][2] & @CRLF
                    Else
                        $iKeyValue -= 1
                    EndIf
                EndIf
                $iKeyValue += 1
            Next
            Return SetError(0, $iKeyValue, 0)
        EndIf
    EndIf
EndFunc


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __IniFileWriteEx
; Description ...: Support Function for _IniFileWriteEx
; Syntax.........: __IniFileWriteEx(ByRef $hIniFile, ByRef $iFlags, ByRef $sFilePath, ByRef $iFileEncoding, ByRef $aIniFile)
; Parameters ....: See _IniFileWriteEx()
; Return values .: See _IniFileWriteEx()
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: This function is used internally by _IniFileWriteEx
; ===============================================================================================================================
Func __IniFileWriteEx(ByRef $hIniFile, ByRef $iFlags, ByRef $sFilePath, ByRef $iFileEncoding, ByRef $aIniFile)
    Local $hFileOpen, $iSL = BitAND($iFlags, $INI_STRIPLEADING), $iST = BitAND($iFlags, $INI_STRIPTRAILING), $iReadOnly = 0
    $hFileOpen = FileOpen($sFilePath, $iFileEncoding)
    ; Check if file opened for writing OK
    If $hFileOpen = -1 Then
        If Not BitAND($iFlags, $INI_NOWRITEREADONLY) And StringInStr(FileGetAttrib($sFilePath), "R") Then
            FileSetAttrib($sFilePath, "-R")
            $iReadOnly = 1
            $hFileOpen = FileOpen($sFilePath, $iFileEncoding)
            If $hFileOpen = -1 Then Return SetError(10, 0, 0)
        Else
            Return SetError(10, 0, 0)
        EndIf
    EndIf
    FileWrite($hFileOpen, ($iSL ? "" : $aIniFile[3]) & $aIniFile[4] & ($iST ? "" : $aIniFile[5]))
    For $i = 6 To $aIniFile[0] Step 6
        FileWrite($hFileOpen, $aIniFile[$i] & $aIniFile[$i + 1] & $aIniFile[$i + 2] & ($iSL ? "" : $aIniFile[$i + 3]) & $aIniFile[$i + 4] & ($iST ? "" : $aIniFile[$i + 5]))
    Next
    FileClose($hFileOpen)
    If $iReadOnly Then FileSetAttrib($sFilePath, "+R")
    Return 0
EndFunc   ;==>__IniFileWriteEx


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __IniGetFileStringData
; Description ...: Support Function for _IniGetFileStringData
; Syntax.........: __IniGetFileStringData(ByRef $hIniFile, ByRef $iFlags, ByRef $aIniFile)
; Parameters ....: See _IniGetFileStringData()
; Return values .: See _IniGetFileStringData()
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: This function is used internally by _IniGetFileStringData
; ===============================================================================================================================
Func __IniGetFileStringData(ByRef $hIniFile, ByRef $iFlags, ByRef $aIniFile)
    Local $sData, $iSL = BitAND($iFlags, $INI_STRIPLEADING), $iST = BitAND($iFlags, $INI_STRIPTRAILING)
    Local $sData = ($iSL ? "" : $aIniFile[3]) & $aIniFile[4] & ($iST ? "" : $aIniFile[5])
    For $i = 6 To $aIniFile[0] Step 6
        $sData &= $aIniFile[$i] & $aIniFile[$i + 1] & $aIniFile[$i + 2] & ($iSL ? "" : $aIniFile[$i + 3]) & $aIniFile[$i + 4] & ($iST ? "" : $aIniFile[$i + 5])
    Next
    Return $sData
EndFunc   ;==>__IniGetFileStringData


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __IniSaveCache
; Description ...: Save in Cache last Read Section
; Syntax.........: __IniSaveCache(ByRef $hIniFile, ByRef $sSectionData, ByRef $sSectionName, ByRef $iFlags, ByRef $iSectionName, ByRef $aIniFile)
; Parameters ....: $hIniFile     - Handle to the INI file to query "see _IniOpenFileEx()"
;                  $sSectionData - Section Strings text/data
;                  $sSectionName - Section Name
;                  $iFlags       - Section Flags
;                  $iSectionName - Number of SectionName in INI File
;                  $aIniFile     - Array of INI File
; Return values .: None
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: This function is Internal Only
; ===============================================================================================================================
Func __IniSaveCache(ByRef $hIniFile, ByRef $sSectionData, ByRef $sSectionName, ByRef $iFlags, ByRef $iSectionName, ByRef $aIniFile)
    $_HINI[$hIniFile][7] = $sSectionName
    $_HINI[$hIniFile][8] = (BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) = $INI_MERGE) ? 1 : $iSectionName
    $_HINI[$hIniFile][9] = $iFlags
    If $iSectionName > 1 And Not BitAND($iFlags, $INI_MERGE_NOOCCURRENCE) Then
        $aIniFile[1] = $sSectionData
        $_HINI[$hIniFile][10] = 1
    Else
        $aIniFile[1] = ""
        $_HINI[$hIniFile][10] = $_HINI[$hIniFile][6]
    EndIf
    Return 0
EndFunc   ;==>__IniSaveCache


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GetSeparatorCharacter
; Description ...: Get Separator Character (non present character)
; Syntax.........: __GetSeparatorCharacter(ByRef $sData)
; Parameters ....: $sData  - INI String\Text Data
; Return values .: None
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: For Internal Use Only
; ===============================================================================================================================
Func __GetSeparatorCharacter(ByRef $sData)
    If Not StringInStr($sData, ChrW(8232), 1) Then Return ChrW(8232)
    If Not StringInStr($sData, ChrW(8233), 1) Then Return ChrW(8233)
    For $i = 1 To 31
        If $i > 8 And $i < 14 Then ContinueLoop
        If Not StringInStr($sData, Chr($i), 1) Then Return Chr($i)
    Next
    $sData = StringRegExpReplace($sData, '\r\n?', @LF)
    Return @CR
EndFunc   ;==>__GetSeparatorCharacter

example

#include <IniEx.au3>
#include <Array.au3>

Local $sData = @CRLF, $aData, $iData, $iTimerDiff, $hIniFile
FileDelete(@DesktopDir & "\Test.ini")
For $i = 1 To 10
    $sData &= "[SectionName_" & $i & "]" & @CRLF
    For $y = 1 to 100000
        $sData &= "KeyName" & $y & " = Value" & $y & @CRLF
    Next
Next
FileWrite(@DesktopDir & "\Test.ini", $sData)    ;25 MB - 1.000.000 Line, Key-Value
$sData = ""

$iTimerDiff = TimerInit()   ;;_IniOpenFileEx()
$hIniFile = _IniOpenFileEx(@DesktopDir & "\Test.ini")
If @Error Then
    ConsoleWrite("Error - " & @Error & @LF)
    Exit
EndIf
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("_IniOpenFileEx TimerDiff - " & $iTimerDiff & @LF)


$iTimerDiff = TimerInit()   ;;_IniGetSectionNumberEx()
$iData = _IniGetSectionNumberEx($hIniFile)
If @Error Then
    ConsoleWrite("Error - " & @Error & @LF)
    Exit
EndIf
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniGetSectionNumberEx TimerDiff - " & $iTimerDiff & @LF)
ConsoleWrite("SectionNumber - " & $iData & @LF & @LF)


$iTimerDiff = TimerInit()   ;;_IniRenameSectionEx()
_IniRenameSectionEx($hIniFile, "SectionName_10", "SectionName_111")
If @Error Then
    ConsoleWrite("Error - " & @Error & @LF)
    Exit
EndIf
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniRenameSectionEx TimerDiff - " & $iTimerDiff & @LF & @LF)


$iTimerDiff = TimerInit()   ;;_IniReadSectionNamesEx()
$aData = _IniReadSectionNamesEx($hIniFile)
If @Error Then
    ConsoleWrite("Error - " & @Error & @LF)
    Exit
EndIf
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniReadSectionNamesEx TimerDiff - " & $iTimerDiff & @LF & @LF)
_ArrayDisplay($aData)


$iTimerDiff = TimerInit()   ;;_IniReadSectionEx()
$sData = _IniReadSectionEx($hIniFile, "SectionName_8")
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniReadSectionEx TimerDiff - " & $iTimerDiff & @LF & @LF)
;;ConsoleWrite($sData & @LF & @LF)
;;MsgBox(0, "SectionName_8", $sData)

$iTimerDiff = TimerInit()   ;;_IniReadSectionEx()
$aData = _IniReadSectionEx($hIniFile, "SectionName_8", $INI_2DARRAYFIELD)   ;$INI_NOOCCURRENCE + $INI_MERGE + $INI_2DARRAYFIELD
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniReadSectionEx TimerDiff - " & $iTimerDiff & @LF & @LF)
_ArrayDisplay($aData, "IniReadSectionEx")


$iTimerDiff = TimerInit()   ;;_IniReadEx()
$sData = _IniReadEx($hIniFile, "SectionName_8", "KeyName99980")
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniReadEx TimerDiff - " & $iTimerDiff& @LF)
ConsoleWrite($sData & @LF & @LF)


$iTimerDiff = TimerInit()   ;;_IniReadEx()
$aData = _IniReadEx($hIniFile, "SectionName_8", "KeyName99988", "Default Return", $INI_ARRAYDATA)   ;$INI_NOOCCURRENCE + $INI_MERGE + $INI_ARRAYDATA
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniReadEx TimerDiff - " & $iTimerDiff & @LF)
ConsoleWrite($aData[1] & @LF & @LF)
_ArrayDisplay($aData, "IniReadEx")


$iTimerDiff = TimerInit()   ;;_IniDeleteEx()
_IniDeleteEx($hIniFile, "SectionName_8", "KeyName99988")    ;$INI_IGNOREDUPLICATE + $INI_NOOCCURRENCE + $INI_REMOVE
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniDeleteEx TimerDiff - " & $iTimerDiff & @LF & @LF)


$iTimerDiff = TimerInit()   ;;_IniWriteSectionEx()
_IniWriteSectionEx($hIniFile, "SectionName_8", "KeyNameX =  ValueX")    ; $INI_NOOCCURRENCE + $INI_IGNOREDUPLICATE + $INI_MERGE + $INI_REMOVE + $INI_OVERWRITEALL +  $INI_APPENDDATA
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniWriteSectionEx TimerDiff - " & $iTimerDiff & @LF & @LF)
ConsoleWrite(_IniReadEx($hIniFile, "SectionName_8", "KeyNameX") & @LF)


$iTimerDiff = TimerInit()
For $i = 1 To 5
    _IniWriteSectionEx($hIniFile, "SectionName_8", "KeyNameX" & $i & " =  ValueX" & $i)
Next
For $i = 6 To 10
    _IniWriteEx($hIniFile, "SectionName_8", "KeyNameX" & $i, "ValueX" & $i)
Next
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniWrite*Ex TimerDiff - " & $iTimerDiff & @LF)


$iTimerDiff = TimerInit()   ;;_IniReadEx()
For $i = 1 To 10
    ConsoleWrite(_IniReadEx($hIniFile, "SectionName_8", "KeyNameX" & $i) & @LF)
Next
$iTimerDiff = TimerDiff($iTimerDiff)
ConsoleWrite("IniReadEx TimerDiff - " & $iTimerDiff & @LF)

_IniCloseFileEx($hIniFile)

Exit


;~ >Running:(3.3.11.3):C:\Program Files (x86)\AutoIt3\Beta\autoit3.exe "C:\Users\DXRW4E\Desktop\New AutoIt v3 Script.au3"    
;~ --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop
;~ _IniOpenFileEx TimerDiff - 2656.48548057389
;~ IniGetSectionNumberEx TimerDiff - 0.0343594296492653
;~ SectionNumber - 10
;~  
;~ IniRenameSectionEx TimerDiff - 0.204971769976651
;~  
;~ IniReadSectionNamesEx TimerDiff - 0.0584505240010489
;~  
;~ IniReadSectionEx TimerDiff - 6.80316707055452
;~  
;~ IniReadSectionEx TimerDiff - 1831.04639075913
;~  
;~ IniReadEx TimerDiff - 24.1380917325683
;~ Value99980
;~  
;~ IniReadEx TimerDiff - 111.67841469541
;~ Value99988
;~  
;~ IniDeleteEx TimerDiff - 43.9488700091941
;~  
;~ IniWriteSectionEx TimerDiff - 28.2560891228314
;~  
;~ ValueX
;~ IniWrite*Ex TimerDiff - 261.353224415258
;~ ValueX1
;~ ValueX2
;~ ValueX3
;~ ValueX4
;~ ValueX5
;~ ValueX6
;~ ValueX7
;~ ValueX8
;~ ValueX9
;~ ValueX10
;~ IniReadEx TimerDiff - 261.622965684803
;~ +>00:07:21 AutoIt3.exe ended.rc:0
;~ >Exit code: 0    Time: 5.914
; $INI_OPEN_FILEQUEUE (268435456)       - Open INI file from Memory\Variable, $sFilePath must contain String Text Data of INI file

$hIniFile = _IniOpenFileEx(@DesktopDir & "\Test.ini")
;ect ect ect

;or

$hIniFile = _IniOpenFileEx($sData, $INI_OPEN_FILEQUEUE)
;ect ect ect



;Or direct mode, without load ini or using handles
; $sSectionName - The name of the section containing the Key\Value, This parameter can be NULL (use the $NULL_REF to set NULL this parameter)
;    If $sSectionName is NULL, $hIniFile must be contain Section String\Key\Value\Data

;;   _IniDeleteEx($hIniFile, $sSectionName, $sKeyName)
_IniDeleteEx($sData, $NULL_REF, $sKeyName)    ;$NULL_REF = NULL


;; _IniReadEx($hIniFile, $sSectionName, $sKeyName)
_IniDeleteEx($sData, $NULL_REF, $sKeyName)    ;$NULL_REF = NULL


;; _IniReadSectionEx($hIniFile, $sSectionName, $sKeyName)
_IniReadSectionEx($sData, $NULL_REF, $sKeyName)    ;$NULL_REF = NULL


;; _IniWriteEx($hIniFile, $sSectionName, $sKeyName, $sValue)
_IniWriteEx($sData, $NULL_REF, $sKeyName, $sValue) ;$NULL_REF = NULL

;;ect ect ect So for all other functions

 

IniEx.au3

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

  • 2 weeks later...
Posted

It sounds like a great script... but I am getting a lot of errors when I try to implement it into my script.

Syntax error: Global Const $NULL_REF = Null
 
Syntax Error: If Not BitAND($iFlags, $INI_REPAIR_ERROR) Then Return SetError(2, StringSplit(StringLeft($aFileData, $iErrorLine), @LF)[
 
Illegal Character: $hIniFile = StringRegExpReplace($hIniFile, '\n[\h\f\xb\x0]*(?i)(?>\Q"' & $sKeyName & '"\E|\Q' & $sKeyName & '\E)[\h\f\xb\x0]*' & $scKeyName & '[\h\f\xb\x0]*[^\n]*', "", (BitAND($iFlags, $INI_IGNOREDUPLICATE) ?
 
unbalanced paranthesis expression: $aValueString = StringRegExp(($sSectionName = $NULL_REF ? $hIniFile

 

Could you please help me?

Posted

The Null keyword isn't available in the current 3.3.8.1 version of AutoIt. Looks like you need one of the beta versions.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Posted (edited)

Hi all, IniEx.au3 already updated, Fixed a Bugin in _IniCloseFileEx()

need to use the last Beta that supports (Keyword) NULL + Ternary + Array access on expression

as you know  Au3Check does not accept (Const) $NULL_REF, for this is

Global Static $INI_NULL_REF = Null

need to always use the $INI_NULL_REF in Func Call (to set NULL in ByRef), need to be careful not ever editchange it

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

  • 2 months later...
Posted

Thanks for the UDF, quite useful.

A bit of an issue- commented lines, at start of lines (keys and sections) and after values, seem to get in the results when using _IniReadSectionEx and $INI_2DARRAYFIELD.

Attached is a zip file with a few of the files where that happens.

 

DPs.zip

Posted (edited)

Hi ilko, is not the INF File Processing Functions, but INI File Processing Functions, so do not ignore the comment line, however here (also check next line) attention is not 100% safe for Inf file, There are many scenarios regarding the INF file

#include <Array.au3>
#include <IniEx.au3>
$hIniFile = _IniOpenFileEx(@DesktopDir & "\DPs\ahcix64s.inf")
If Not @Error Then
    $IniReadSectionEx = _IniReadSectionEx($hIniFile, "ATI.ntamd64")
    If Not @Error Then
        ;;$IniReadSectionEx = StringRegExpReplace($IniReadSectionEx, '(?:[^;"\r\n]|"(?:[^"\r\n]|""(?!"))*"|"[^\r\n]*)*\K[^\r\n]+', "")
        ;;$IniReadSectionEx = StringRegExpReplace($IniReadSectionEx & @LF, '(?>:[^\\"\r\n]|"(?:[^"\r\n]|""(?!"))*"|"[^\r\n]*|\\(?!(?:[\\\h\f\xb\x0]|""(?!"))*\R))*\K\\(?:[\\\h\f\xb\x0]|""(?!"))*\R\h*', "")
        $IniReadSectionEx = StringRegExpReplace($IniReadSectionEx, '(?:[^;"\r\n]|"[^"\r\n]"|"[^\r\n]*)*\K[^\r\n]+', "")
        $IniReadSectionEx = StringRegExpReplace($IniReadSectionEx & @LF, '(?>:[^\\"\r\n]|"[^"\r\n]"|"[^\r\n]*|\\(?!(?:[\\\h\f\xb\x0]|""(?!"))*\R))*\K\\(?:[\\\h\f\xb\x0]|""(?!"))*\R\h*', "")
        $IniReadSectionEx = _IniReadSectionEx($IniReadSectionEx, $INI_NULL_REF, $INI_2DARRAYFIELD)
        _ArrayDisplay($IniReadSectionEx, "IniReadSectionEx")
    Else
        ;;ERROR
    EndIf
Else
    ;;ERROR
EndIf
also look >_FileReadToArrayEx to create an idea of fields

 

or here's an example SetupApiEx.au3 is old code, attention WinAPI INF Function are not tested

 

;;;;;;;;;;;;;;;;;;;;;; SetupApiEx.au3 ;;;;;;;;;;;;;;;;;;;;;;

#Region ;SetupAPI Constants
 If Not IsDeclared("arDllCall") Then
    Global Static $arDllCall
EndIf
Global Static $ProcessHeap[1]

Global Const $ERROR_INSUFFICIENT_BUFFER = 122 ;(0x7A) - The data area passed to a system call is too small.


;;////////////////////////////////////////////////////////////////////////////
;;
;; SetupAPI Constants
;;
;;////////////////////////////////////////////////////////////////////////////

;;
;; Define maximum string length constants
;;
Global Const $LINE_LEN                    = 256     ;; Windows 9x-compatible maximum for displayable strings coming from a device INF.
Global Const $MAX_INF_STRING_LENGTH       = 4096    ;; Actual maximum size of an INF string (including string substitutions).
Global Const $MAX_INF_SECTION_NAME_LENGTH = 255     ;; For Windows 9x compatibility, INF section names should be constrained to 32 characters.
Global Const $MAX_TITLE_LEN               = 60
Global Const $MAX_INSTRUCTION_LEN         = 256
Global Const $MAX_LABEL_LEN               = 30
Global Const $MAX_SERVICE_NAME_LEN        = 256
Global Const $MAX_SUBTITLE_LEN            = 256

;;
;; Define maximum length of a machine name in the format expected by ConfigMgr32
;; CM_Connect_Machine (i.e., "\\\\MachineName\0").
;;
Global Const $MAX_PATH = 260
Global Const $SP_MAX_MACHINENAME_LENGTH   = $MAX_PATH + 3

;;
;; the following flags are available to SP_ALTPLATFORM_INFO_V2
;;
Global Const $SP_ALTPLATFORM_FLAGS_VERSION_RANGE = 1    ;; 0x0001   -   FirstValidatedMajor/MinorVersion

Global Const $hSetupApiDll = DllOpen("SetupApi.dll")
Global Const $hKernel32DLL = DllOpen("Kernel32.dll")

;;
;; SP_INF_INFORMATION.InfStyle values
;;
Global Const $INF_STYLE_NONE           = 0      ;; 0x00000000   -   unrecognized or non-existent
Global Const $INF_STYLE_OLDNT          = 1      ;; 0x00000001   -   A legacy INF file format  - winnt 3.x
Global Const $INF_STYLE_WIN4           = 2      ;; 0x00000002   -   A Windows INF file format - Win95
Global Const $INF_STYLE_NULL           = NULL   ;;              -   or AutoIt v3.3.8 Global Const $INF_STYLE_NULL  = "Null"

;;
;; Additional InfStyle flags that may be specified when calling SetupOpenInfFile.
;;
;;
Global Const $INF_STYLE_CACHE_ENABLE   = 16 ;; 0x00000010   -   always cache INF, even outside of %windir%\Inf
Global Const $INF_STYLE_CACHE_DISABLE  = 32 ;; 0x00000020   -   delete cached INF information
;;  #if _SETUPAPI_VER >= _WIN32_WINNT_WS03
Global Const $INF_STYLE_CACHE_IGNORE   = 64 ;; 0x00000040   -   ignore any cached INF information
;;  #endif

;;
;; SearchControl flags for SetupGetInfInformation
;;
Global Const $INFINFO_INF_SPEC_IS_HINF        = 1   ;; InfSpec is an INF handle. A single INF handle may reference multiple INF files if they have been append-loaded together. If it does, the structure returned by this function contains multiple sets of information.
Global Const $INFINFO_INF_NAME_IS_ABSOLUTE    = 2   ;; The string specified for InfSpec is a full path. No further processing is performed on InfSpec.
Global Const $INFINFO_DEFAULT_SEARCH          = 3   ;; Search the default locations for the INF file specified for InfSpec, which is assumed to be a filename only. The default locations are %windir%\inf, followed by %windir%\system32.
Global Const $INFINFO_REVERSE_DEFAULT_SEARCH  = 4   ;; Same as INFINFO_DEFAULT_SEARCH, except the default locations are searched in reverse order.
Global Const $INFINFO_INF_PATH_LIST_SEARCH    = 5   ;; Search for the INF in each of the directories listed in the DevicePath value entry under the following:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion

;;
;; InfoDesired values for SetupGetSourceInfo
;;
Global Const $SRCINFO_PATH            = 1       ;; The path specified for the source. This is not a full path, but the path relative to the installation root.
Global Const $SRCINFO_TAGFILE         = 2       ;; The tag file that identifies the source media, or if cabinets are used, the name of the cabinet file.
Global Const $SRCINFO_DESCRIPTION     = 3       ;; A description for the media.
Global Const $SRCINFO_FLAGS           = 4       ;;


;; ect ect ect ect
;; ect ect ect ect
;; ect ect ect ect
;; ect ect ect ect
;; ect ect ect ect
#EndRegion


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupOpenInfFile
; Description ...: The SetupOpenInfFile function opens an INF file and returns a handle to it.
; Syntax.........: _SetupOpenInfFile($FileName, $InfClass, $InfStyle)
; Parameters ....: $FileName - Pointer to a null-terminated string containing the name (and optional path) of the INF file to be opened.
;                    If the filename does not contain path separator characters, it is searched for, first in the %windir%\inf directory,
;                    and then in the %windir%\system32 directory. If the filename contains path separator characters, it is assumed to be
;                    a full path specification and no further processing is performed on it.
;                  $InfClass - Optional pointer to a null-terminated string containing the class of INF file desired. This string must match
;                    the Class value of the Version section (for example, Class=Net). If there is no entry in the Class value, but there is an entry
;                    for ClassGUID in the Version section, the corresponding class name for that GUID is retrieved and used for the comparison.
;                   $InfStyle - Style of INF file to open or search for. This parameter can be a combination of the following flags.
;                  |Null - $INF_STYLE_NULL
;                  |0    - $INF_STYLE_NONE
;                  |1    - $INF_STYLE_OLDNT - A legacy INF file format.
;                  |2    - $INF_STYLE_WIN4 - A Windows INF file format.
; Return values .: The function returns a handle to the opened INF file if it is successful. Otherwise, the return value is INVALID_HANDLE_VALUE. (Extended error information retrieved by _WinAPI_GetLastErrorEx.)
; Remarks .......: If the load fails because the INF file type does not match InfClass, the function returns INVALID_HANDLE_VALUE and a call to
;                   _WinAPI_GetLastErrorEx returns ERROR_CLASS_MISMATCH.
;
;                   If multiple INF file styles are specified, the style of the INF file opened can be determined by calling the SetupGetInfInformation function.
;
;                   Because there may be more than one class GUID with the same class name, callers interested in INF files of a particular class
;                   (that is, a particular class GUID) should retrieve the ClassGUID value from the INF file by calling SetupQueryInfVersionInformation.
;
;                   For legacy INF files, the InfClass string must match the type specified in the OptionType value of the Identification section
;                   in the INF file (for example, OptionType=NetAdapter).
;
; Related .......: _SetupOpenAppendInfFile, _SetupCloseInfFile, _SetupGetInfInformationEx
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupOpenInfFile($FileName, $InfClass = NULL, $InfStyle = $INF_STYLE_WIN4)
    Local $arDllCall = DllCall($hSetupApiDll, "HANDLE", "SetupOpenInfFileW", "wstr", $FileName, "wstr", $InfClass, "dword", $InfStyle, "uint*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;If $arDllCall[0] = $ERROR_INVALID_HANDLE_VALUE Then Return SetError($arDllCall[0], $arDllCall[4], 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[4], $arDllCall[0])
EndFunc    ;==>_SetupOpenInfFile


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineCount
; Description ...: The SetupGetLineCount function returns the number of lines in a specified section of an INF file.
; Syntax.........: _SetupGetLineCount($InfHandle, $Section)
; Parameters ....: $InfHandle - Handle to the INF file.
;                  $Section   - Pointer to a null-terminated string that specifies the section in which you want to count the lines.
; Return values .: If InfHandle references multiple INF files that have been appended using _SetupOpenAppendInfFile, this function returns
;                    the sum of the lines in all of the INF files containing the specified section. A return value of 0 specifies an empty section.
;                    If the section does not exist, the function returns –1 Or Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......:
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineCount($InfHandle, $Section)
    $arDllCall = DllCall($hSetupApiDll, "long", "SetupGetLineCountW", "HANDLE", $InfHandle, "wstr", $Section)
    If @Error Then Return SetError(@Error, 0, 0)
    If $arDllCall[0] > 0 Then Return SetError(0, 0, $arDllCall[0])
    Return SetError(_WinAPI_GetLastErrorEx(), 0, -1)
EndFunc    ;==>_SetupGetLineCount


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineByIndex
; Description ...: The SetupGetLineByIndex function locates a line by its index value in the specified section in the INF file.
; Syntax.........: _SetupGetLineByIndex($InfHandle, $Section, $Index)
; Parameters ....: $InfHandle - Handle to the INF file.
;                  $Section   - Pointer to a null-terminated string specifying the section of the INF file to search.
;                   $Index     - Index of the line to be located. The total number of lines in a particular section can be found with a call to _SetupGetLineCount.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......: If InfHandle references multiple INF files that have been appended together using _SetupOpenAppendInfFile, this function searches across
;                    the specified section in all files referenced by the HINF to locate the indexed line.
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineByIndex($InfHandle, $Section, $Index)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($hKernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $Context = DllCall($hKernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetLineByIndexW", "HANDLE", $InfHandle, "wstr", $Section, "dword", $Index, "ptr", $Context[0])
    If @Error Or Not $arDllCall[0] Then SetError(_WinAPI_GetLastErrorEx(), DllCall($hKernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $Context[0]), 0)
    Return SetError(0, 0, $Context[0])
EndFunc    ;==>_SetupGetLineByIndex


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineText
; Description ...: The SetupGetLineText function returns the contents of a line in an INF file in a compact form. The line to retrieve can be specified by an
;                     INFCONTEXT structure returned from a SetupFindLineXXX function, or by explicitly passing in the INF handle, section, and key of the desired line.
; Syntax.........: _SetupGetLineText($Context, $InfHandle, $Section, $Key, $ReturnBufferSize)
; Parameters ....: $Context   - Context for a line in an INF file whose text is to be retrieved. This parameter can be NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $InfHandle - Handle to the INF file to query. This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                   $Section   - Pointer to a null-terminated string that specifies the section that contains the key name of the line whose text is to be retrieved.
;                     This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                   $Key       - Pointer to a null-terminated string that contains the key name whose associated string is to be retrieved. This parameter can be NULL.
;                     This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                   $ReturnBufferSize - Size of the buffer pointed to by the ReturnBuffer parameter, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value.
;                     If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size required to hold
;                   the specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value.
;                   Otherwise, the return value is zero and extended error information can be obtained by calling GetLastError.
;
;                   This function returns the contents of a line in a compact format. All extraneous white space is removed and multi-line values are converted
;                   into a single contiguous string. For example, this line:
;
;                       HKLM, , PointerClass0, 1 \
;                        ; This is a comment
;                        01, 02, 03
;
;                   would be returned as:
;
;                       HKLM,,PointerClass0,1,01,02,03
;
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineText($Context = 0, $InfHandle = 0, $Section = NULL, $Key = NULL, $ReturnBufferSize = 65535) ;;    4194303 = 4 MB
     ;;Local $RBuffer = DllStructCreate("wchar")
     ;;$arDllCall = DllCall($hSetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($hSetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $arDllCall[7], "dword*", 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[0], "")
    Return SetError(0, $arDllCall[7], $arDllCall[5])
EndFunc    ;==>_SetupGetLineText


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetTargetPath
; Description ...: The SetupGetTargetPath function determines the target directory for a file list section. The file list section can be a Copy Files section, a Delete Files section
;                    or a Rename Files section. All the files in the section must be in a single directory that is listed in a DestinationDirs section of the INF file.
; Syntax.........: _SetupGetTargetPath($InfHandle, $InfContext, $Section, $ReturnBufferSize)
; Parameters ....: $InfHandle  - Handle to the load INF file that contains a DestinationDirs section.
;                  $InfContext - Optional pointer to an INF context that specifies a line in a file list section whose destination directory is to be retrieved.
;                    If InfContext is NULL, then the Section parameter is used.
;                   $Section    - Optional parameter that specifies the name of a section of the INF file whose handle is InfHandle. SetupGetTargetPath retrieves the
;                    target directory for this section. The Section parameter is ignored if InfContext is specified. If neither InfContext nor Section is specified,
;                    the function retrieves the default target path from the INF file. You should use a null-terminated string.
;                   $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the specified
;                     data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise, the return value
;                     is zero and extended error information can be obtained by calling _WinAPI_GetLastErrorEx.
; Related .......: _SetupGetSourceFileLocation, _SetupGetSourceInfoEx, _SetupGetSourceFileSize
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetTargetPath($InfHandle, $InfContext = 0, $Section = NULL, $ReturnBufferSize = 32767) ;Or ASCII 260
     ;;Local $RBuffer = DllStructCreate("wchar[32767]")
     ;;$arDllCall = DllCall($hSetupApiDll, "int", "SetupGetTargetPathW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $Section, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($hSetupApiDll, "int", "SetupGetTargetPathW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $Section, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "int", "SetupGetTargetPathW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $Section, "wstr", "", "dword", $arDllCall[6], "dword*", 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[6], $arDllCall[4])
EndFunc    ;==>_SetupGetTargetPath


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupDecompressOrCopyFile
; Description ...: The SetupDecompressOrCopyFile function copies a file, decompressing it if necessary.
;                    If a file is copied, the caller of this function is required have privileges to write into the target directory.
; Syntax.........: _SetupDecompressOrCopyFile($SourceFileName, $TargetFileName, $CompressionType)
; Parameters ....: $SourceFileName  - File name of the file to be copied. You should use a null-terminated string. This parameter can be NULL. If CompressionType
;                    is notspecified and the SetupDecompressOrCopyFile function does not find the file specified in SourceFileName, the function searches for the
;                    file with up to two alternate, "compressed-form" names. For example, if the file is F:\x86\cmd.exe and it is not found, the function
;                    searches for F:\x86\cmd.ex_ and, if that is not found, F:\x86\cmd.ex$ is searched for. If CompressionType is specified, no additional
;                    processing is performed on the filename; the file must exist exactly as specified or the function fails.
;                  $TargetFileName  - Exact name of the target file that will be created by decompressing or copying the source file. You should use a null-terminated string.
;                   $CompressionType - Optional pointer to the compression type used on the source file. You can determine the compression type by calling
;                    SetupGetFileCompressionInfo. If this value is FILE_COMPRESSION_NONE, the file is copied (not decompressed) regardless of any
;                    compression in use on the source. If CompressionType is not specified, this routine determines the compression type automatically.
; Return values .: The SetupDecompressOrCopyFile function returns a system error code that indicates the outcome of the operation. or Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......:
; Related .......: _SetupGetFileCompressionInfoEx
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupDecompressOrCopyFile($SourceFileName, $TargetFileName, $CompressionType = 0)
    $arDllCall = DllCall($hSetupApiDll, "DWORD", "SetupDecompressOrCopyFileW", "wstr", $SourceFileName, "wstr", $TargetFileName, ($CompressionType ? "UINT*" : "ptr"), $CompressionType)
    If @Error Then Return SetError(@Error, 0, 0)
    If $arDllCall[0] Then Return SetError($arDllCall[0], 0, _WinAPI_GetLastErrorEx())
    Return SetError(0, 1, 0)
EndFunc    ;==>__SetupDecompressOrCopyFile


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetFileCompressionInfoEx
; Description ...: The SetupGetFileCompressionInfoEx function examines a potentially compressed file and gets the type of compression, the file's full path
;                    (including file name), the compressed size, and the size of the uncompressed target file. The caller of the function passes in the name of the file
;                    to be examined and pointers to locations for the buffer and buffer size to receive the returned file name and path.
;                  To determine the size of the buffer for the returned path and file name, you can call SetupGetFileCompressionInfoEx If a file is copied,
;                    with ActualSourceFileNameBuffer specified Null and ActualSourceFileNameLen containing 0. The function succeeds and on return fills in RequiredBufferLen.
; Syntax.........: _SetupGetFileCompressionInfoEx($SourceFileName)
; Parameters ....: $SourceFileName - File name of the potentially compressed file to be examined. If the file is not found on the source media exactly as named,
;                    Setup searches for up to two alternate names. For example; if Setup does not find F:\x86\cmd.exe, it searches for F:\mpis\cmd.ex_ and if that
;                    name is not found, it searches for F:\x86\cmd.ex$.
; Return values .: If the function succeeds, the return value is TRUE (nonzero).
;
;                  If the function fails, the return value is FALSE (zero). The function can also return one of the following system error codes.
;
;                  ERROR_FILE_NOT_FOUND
;                      The file cannot be found.
;
;                  NO_ERROR
;                      The file was located and the output parameters were filled in. Also returned if ActualSourceFileNameBuffer is Null.
;
;                  ERROR_INSUFFICIENT_BUFFER
;                     The file was located and the output parameters set except for ActualSourceFileNameBuffer.
;
; Return values .: The SetupDecompressOrCopyFile function returns a system error code that indicates the outcome of the operation. or Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......: Because SetupGetFileCompressionInfoEx determines the compression by examining the physical file, your setup application should ensure that the file is present before calling SetupGetFileCompressionInfoEx.
; Related .......: _SetupDecompressOrCopyFile
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetFileCompressionInfoEx($SourceFileName)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetFileCompressionInfoExW", "wstr", $SourceFileName, "wstr", "", "DWORD", 0, "dword*", 0, "dword*", 0, "dword*", 0, "UINT*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[4] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, $arDllCall[6], $arDllCall[7])
EndFunc    ;==>_SetupGetFileCompressionInfoEx


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupCloseInfFile
; Description ...: The SetupCloseInfFile function closes the INF file opened by a call to SetupOpenInfFile. This function closes any INF files appended to it by calling SetupOpenAppendInfFile.
; Syntax.........: _SetupCloseInfFile($InfHandle)
; Parameters ....: $InfHandle - Handle to the INF file to be closed.
; Return values .: This function does not return a value.
; Remarks .......: Because _SetupGetFileCompressionInfoEx determines the compression by examining the physical file, your setup application should ensure that the file is present before calling _SetupGetFileCompressionInfoEx.
; Related .......: _SetupOpenInfFile, _SetupOpenAppendInfFile
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupCloseInfFile($InfHandle)
    DllCall($hSetupApiDll, "none", "SetupCloseInfFile", "HANDLE", $InfHandle)
EndFunc    ;==>_SetupCloseInfFile


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindFirstLine
; Description ...: The SetupFindFirstLine function locates a line in the specified section of an INF file. If the Key parameter is NULL, _SetupFindFirstLine returns the first line of the section.dBufferLen.
; Syntax.........: _SetupFindFirstLine($InfHandle, $Section, $Key)
; Parameters ....: $InfHandle - Handle to the INF file to query.
;                  $Section   - Pointer to a null-terminated string specifying the section of the INF files to search in.
;                  $Key       - Optional pointer to a null-terminated string specifying the key to search for within the section. The null-terminated string should not
;                    exceed the size of the destination buffer. This parameter can be NULL. If Key is NULL, the first line in the section is returned.
; Return values .: If the function could not find a line, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If the InfHandle parameter references multiple INF files that have been appended together using _SetupOpenAppendInfFile,
;                    the _SetupFindFirstLine function searches across the specified section in all of the files referenced by the specified HINF.
; Related .......: _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindFirstLine($InfHandle, $Section, $Key = NULL)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($hKernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $Context = DllCall($hKernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupFindFirstLineW", "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "ptr", $Context[0])
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($hKernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $Context[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[4])
EndFunc    ;==>_SetupFindFirstLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindNextLine
; Description ...: The SetupFindNextLine returns the location of the next line in an INF file section relative to ContextIn.Line.
; Syntax.........: _SetupFindNextLine($ContextIn)
; Parameters ....: $ContextIn - Pointer to the INF file context retrieved by a call to the _SetupFindFirstLine function.
; Return values .: If this function finds the next line, the return value is a nonzero value. Otherwise, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If ContextIn.Line references multiple INF files that have been appended together using SetupOpenAppendInfFile, this function searches across
;                    the specified section in all files referenced by the HINF to locate the next line.
; Related .......: _SetupFindFirstLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindNextLine($ContextIn)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($hKernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $ContextOut = DllCall($hKernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupFindNextLine", "ptr", $ContextIn, "ptr", $ContextOut[0])
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($hKernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $ContextOut[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[2])
EndFunc    ;==>_SetupFindNextLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindNextMatchLine
; Description ...: The SetupFindNextMatchLine function returns the location of the next line in an INF file relative to ContextIn.Line that matches a specified key.
; Syntax.........: _SetupFindNextMatchLine($ContextIn, $Key)
; Parameters ....: $ContextIn - Pointer to the INF file context retrieved by a call to the _SetupFindFirstLine function.
;                  $Key       - If this optional parameter is specified, it supplies a key to match. This parameter should be a null-terminated string.
;                    This parameter can be Null. If Key is not specified, the SetupFindNextMatchLine function is equivalent to the SetupFindNextLine function.
; Return values .: The function returns a nonzero value if it finds a matching line. Otherwise, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If ContextIn.Inf references multiple INF files that have been appended together using _SetupOpenAppendInfFile, the _SetupFindNextMatchLine
;                    function searches across the specified section in all files referenced by the HINF to locate the next matching line.
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindNextMatchLine($ContextIn, $Key = NULL)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($hKernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $ContextOut = DllCall($hKernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupFindNextMatchLineW", "ptr", $ContextIn, "wstr", $Key, "ptr", $ContextOut[0])
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($hKernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $ContextOut[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[3])
EndFunc    ;==>_SetupFindNextMatchLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetBinaryField
; Description ...: The SetupGetBinaryField function returns the location of the next line in an INF file relative to ContextIn.Line that matches a specified key.
; Syntax.........: _SetupGetBinaryField($Context, $FieldIndex, $ReturnBufferSize)
; Parameters ....: $Context    - INF context for the line.
;                  $FieldIndex - The 1-based index of the starting field within the specified line from which the binary data should be retrieved. The binary data
;                    is built from each field, starting at this point to the end of the line. Each field corresponds to 1 byte and is in hexadecimal notation.
;                    A FieldIndex of zero is not valid with this function.
;                  $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This number includes the null terminator.
; Return values .: The function returns a nonzero value if it finds a matching line. Otherwise, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
;                    _WinAPI_GetLastErrorEx returns ERROR_INVALID_DATA if a field that _SetupGetBinaryField retrieves is not a valid hexadecimal number in the range 0-FF.
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the specified
;                    data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise, the return
;                    value is zero and extended error information can be obtained by calling _WinAPI_GetLastErrorEx.
;
;                  To better understand how this function works, consider the following line from an INF file.
;
;                    X=34,FF,00,13
;
;                  If SetupGetBinaryField was called on the preceding line, the binary values 34, FF, 00, and 13 would be put into the buffer specified by ReturnBuffer.
;
;                  For the Unicode version of this function, the buffer sizes ReturnBufferSize and RequiredSize are specified in number of characters.
;                    This number includes the null terminator. For the ANSI version of this function, the sizes are specified in number of bytes.
;
;                  If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the
;                    specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value.
;                    Otherwise, the return value is zero and extended error information can be obtained by calling _WinAPI_GetLastErrorEx.
;
;                  Thus, you can call the function once to get the required buffer size, allocate the necessary memory, and then call the function a second time to
;                    retrieve the data. Using this technique, you can avoid errors due to an insufficient buffer size.
;
; Related .......: _SetupGetIntField, _SetupGetMultiSzField, _SetupGetStringField
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetBinaryField($Context, $FieldIndex, $ReturnBufferSize = 0)
    If $FieldIndex < 1 Then Return SetError(1, 0, 0)
    If Not $ReturnBufferSize Then
        $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetBinaryField", "ptr", $Context, "dword", $FieldIndex, "BYTE", NULL, "BYTE", 0, "DWORD*", 0)
        If @Error Then Return SetError(@Error, 0, 0)
        $ReturnBufferSize = $arDllCall[5]
    EndIf
    Local $RBuffer = DllStructCreate("Byte[" & $ReturnBufferSize & "]")
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetBinaryField", "ptr", $Context, "dword", $FieldIndex, "ptr", DllStructGetPtr($RBuffer), "BYTE", $ReturnBufferSize, "DWORD*", 0)
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, $arDllCall[0], DllStructGetData($RBuffer, 1))
EndFunc    ;==>_SetupGetBinaryField


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetFieldCount
; Description ...: The SetupGetFieldCount function retrieves the number of fields in the specified line in an INF file.
; Syntax.........: _SetupGetFieldCount($Context)
; Parameters ....: $Context - Pointer to the context for a line in an INF file.
; Return values .: This function returns the number of fields on the line. If Context is invalid, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......:
; Related .......: _SetupGetLineCount
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetFieldCount($Context)
    $arDllCall = DllCall($hSetupApiDll, "DWORD", "SetupGetFieldCount", "ptr", $Context)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, 0, $arDllCall[0])
EndFunc    ;==>_SetupGetFieldCount


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetInfDriverStoreLocation
; Description ...: The _SetupGetInfDriverStoreLocation function retrieves the fully qualified file name (directory path and file name) of an INF file http://msdn.microsoft.com/en-us/library/windows/hardware/ff549520(v=vs.85).aspx
;                    in the driver store that corresponds to a specified INF file in the system INF file directory or a specified INF file in the driver store.
; Syntax.........: _SetupGetInfDriverStoreLocation($FileName, $ReturnBufferSize)
; Parameters ....: $FileName - A pointer to a NULL-terminated string that contains the name, and optionally the full directory path, of an INF file
;                    in the system INF file directory. Alternatively, this parameter is a pointer to a NULL-terminated string that contains the fully
;                    qualified file name (directory path and file name) of an INF file in the driver store.
;                                 For more information about how to specify the INF file, see the following Remarks section.
;                   $ReturnBufferSize - The size, in characters, of the buffer supplied by ReturnBuffer.
; Return values .: If _SetupGetInfDriverStoreLocation succeeds, the function returns Path; otherwise, the function returns (@Extendet = RequiredSize) & Extended error information retrieved by _WinAPI_GetLastErrorEx.
;                  If the size, in characters, of the fully qualified file name of the requested INF file, including a null-terminator,
;                    is greater than ReturnBufferSize, the function will fail, and a call to _WinAPI_GetLastErrorEx will return ERROR_INSUFFICIENT_BUFFER.
; Remarks .......: To determine the size of the return buffer that is required to contain the fully qualified file name of the specified INF file in the driver store,
;                    call SetupGetInfDriverStoreLocation and set ReturnBuffer to NULL, ReturnBufferSize to zero, and supply RequiredSize. SetupGetInfDriverStoreLocation will return the required buffer size in RequiredSize.
;
;                  When device installation preinstalls a driver package in the driver store, it creates two copies of the driver package INF file.
;                    Device installation installs one copy in the system INF directory and assigns that copy of the INF file a unique published file name of the
;                    form OEMnnn.inf. Device installation installs a second copy of the INF file in the driver store and assigns that copy the original INF file name.
;
;                  SetupGetInfDriverStoreLocation returns the fully qualified file name of the INF file in the driver store that matches the INF file, if any,
;                    that is supplied by FileName. Filename must specify the file name, and optionally the directory path, of an INF file in the system INF directory.
;                    Alternatively, Filename must specify the fully qualified file name of an INF file in the driver store.
;
;                  For example, assume that the INF file for a driver package is Myinf.inf, and that for this driver package, device installation installs the INF file
;                    OEM1.inf in the system INF directory C:\Windows\inf. Further assume that device installation installs the corresponding INF file copy
;                    C:\windows\system32\driverstore\filerepository\myinf_12345678\myinf.inf in the driver store. In this case, the function returns
;                    C:\windows\system32\driverstore\filerepository\myinf_12345678\myinf.inf if FileName supplies one of the following strings: OEM1.inf,
;                    C:\Windows\inf\OEM1.inf, or C:\windows\system32\driverstore\filerepository\myinf_12345678\myinf.inf.
;
;                    Class installers and co-installers can use _SetupGetInfDriverStoreLocation to access files in a driver package that is preinstalled in the
;                    driver store. To determine the path of the driver package in the driver store, the installer does the following:
;
;                          1. Call SetupDiGetDriverInfoDetail to retrieve a SP_DRVINFO_DETAIL_DATA structure for a driver. The InfFileName member of this structure
;                          contains the fully qualified file name of the driver INF file in the system INF directory.
;
;                          2. Call SetupGetInfDriverStoreLocation and supply the fully qualified file name of the driver INF file that was retrieved by calling
;                          SetupDiGetDriverInfoDetail. SetupGetInfDriverStoreLocation will return the fully qualified file name of the driver INF file in the driver
;                          store. The directory path part of the fully qualified file name of the INF file is the path of the driver package files.
;
;                  Note  SetupGetInfDriverStoreLocation does not process the contents of the INF file that is specified in FileName. You cannot use this function
;                    to perform a content-specific search for an INF file in the driver store.
;
;                  Call the SetupGetInfPublishedName function to retrieve the fully qualified file name of an INF file in the system INF file directory that
;                    corresponds to a specified INF file in the system INF file directory or a specified file in the driver store.
;
; Related .......: ;;;;;;;;;;;;; SetupDiGetDriverInfoDetail, SetupGetInfPublishedName
;
; C++ Syntax ....: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552194(v=vs.85).aspx
;                  ---------------------------------------------------------------------------------------------------
;                           WINSETUPAPI
;                           BOOL
;                           WINAPI
;                           SetupGetInfDriverStoreLocationW(
;                                   _In_ PCWSTR FileName,
;                               _In_opt_ PSP_ALTPLATFORM_INFO AlternatePlatformInfo,
;                               _In_opt_ PCWSTR LocaleName,
;                               _Out_writes_(ReturnBufferSize) PWSTR ReturnBuffer,
;                               _In_ DWORD ReturnBufferSize,
;                               _Out_opt_ PDWORD RequiredSize
;                               );
;                  ---------------------------------------------------------------------------------------------------
;                  Parameters
;                  FileName [in]                        - A pointer to a NULL-terminated string that contains the name, and optionally the full directory path,
;                       of an INF file in the system INF file directory. Alternatively, this parameter is a pointer to a NULL-terminated string that contains the
;                       fully qualified file name (directory path and file name) of an INF file in the driver store.
;                       For more information about how to specify the INF file, see the following Remarks section.
;                  AlternatePlatformInfo [in, optional] - Reserved for system use.
;                  LocaleName [in, optional]            - Reserved for system use.
;                  ReturnBuffer [out]                   - A pointer to a buffer in which the function returns a NULL-terminated string that contains the
;                       fully qualified file name of the specified INF file. This parameter can be set to NULL. The maximum supported path size is MAX_PATH.
;                       For information about how to determine the required size of the buffer, see the following Remarks section.
;                  ReturnBufferSize [in]                - The size, in characters, of the buffer supplied by ReturnBuffer.
;                  RequiredSize [out, optional]         - A pointer to a DWORD-typed variable that receives the size, in characters, of the ReturnBuffer buffer.
;                       This parameter is optional and can be set to NULL.
;
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetInfDriverStoreLocation($FileName, $ReturnBufferSize = 32767) ;Or ASCII 260
     ;;Local $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfDriverStoreLocationW", "wstr", $FileName, "ptr", 0, "ptr", 0, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfDriverStoreLocationW", "wstr", $FileName, "ptr", 0, "ptr", 0, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;;If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfDriverStoreLocationW", "wstr", $FileName, "ptr", 0, "ptr", 0, "wstr", "", "DWORD", $arDllCall[6], "dword*", 0)
    ;;If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then Return SetError($ERROR_INSUFFICIENT_BUFFER, $arDllCall[6], "")
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[6], $arDllCall[4])
EndFunc    ;==>_SetupGetInfDriverStoreLocation


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetInfFileList
; Description ...: The SetupGetInfFileList function returns a list of INF files located in a caller-specified directory to a call-supplied buffer.
; Syntax.........: _SetupGetInfFileList($DirectoryPath, $InfStyle)
; Parameters ....: $DirectoryPath - Optional pointer to a null-terminated string containing the path of the directory in which to search.
;                    If this value is NULL, the %windir%\inf directory is used.
;                  $InfStyle   - Type of INF file to search for. May be a combination of the following flags.
;                  |$INF_STYLE_OLDNT (1) - A legacy INF file format.
;                  |$INF_STYLE_WIN4 (2)  - A Windows INF file format.
; Return values .: If the function succeeds, the return value is a String Inf file List value.
; Remarks .......:
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetInfFileList($sDirectoryPath, $InfStyle = 2)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfFileListW", "WSTR", $sDirectoryPath, "DWORD", $InfStyle, "WSTR", "", "DWORD", Null, "DWORD*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfFileListW", "WSTR", $sDirectoryPath, "DWORD", $InfStyle, "WSTR", "", "DWORD", $arDllCall[5], "DWORD*", 0)
    ;If $arDllCall[0] Then Return SetError(0, $arDllCall[5], $arDllCall[3])
    Local $ReturnBuffer = DllStructCreate("BYTE[" & $arDllCall[5] * 2 & "]")
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfFileListW", "WSTR", $sDirectoryPath, "DWORD", $InfStyle, "STRUCT*", $ReturnBuffer, "DWORD", $arDllCall[5], "DWORD*", 0)
    If $arDllCall[0] Then Return SetError(0, $arDllCall[5], StringRegExpReplace(BinaryToString(DllStructGetData($ReturnBuffer, 1), 2), "\x00+", @LF))
    Return SetError(_WinAPI_GetLastErrorEx(), 0, -1)
EndFunc    ;==>_SetupGetInfFileList


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetInfInformation
; Description ...: The SetupGetInfInformation function returns a list of INF files located in a caller-specified directory to a call-supplied buffer.
; Syntax.........: _SetupGetInfInformation($DirectoryPath, $InfStyle)
; Parameters ....: $InfSpec       - Handle or a file name for an INF file, depending on the value of SearchControl.
;                   $SearchControl - This parameter can be one of the following constants.
;                   |1 = $INFINFO_INF_SPEC_IS_HINF - InfSpec is an INF handle. A single INF handle may reference multiple INF files if they have been append-loaded together. If it does, the structure returned by this function contains multiple sets of information.
;                   |2 = $INFINFO_INF_NAME_IS_ABSOLUTE - The string specified for InfSpec is a full path. No further processing is performed on InfSpec.
;                   |3 = $INFINFO_DEFAULT_SEARCH - Search the default locations for the INF file specified for InfSpec, which is assumed to be a filename only. The default locations are %windir%\inf, followed by %windir%\system32.
;                   |4 = $INFINFO_REVERSE_DEFAULT_SEARCH - Same as INFINFO_DEFAULT_SEARCH, except the default locations are searched in reverse order.
;                   |5 = $INFINFO_INF_PATH_LIST_SEARCH - Search for the INF in each of the directories listed in the DevicePath value entry under the following:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
;                   ;;; NOT USET - $ReturnBufferSize - Size of ReturnBuffer, in bytes.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of 0 (zero), the function puts the buffer size needed to hold the
;                     specified data into the variable pointed to by RequiredSize. If the function succeeds, the return value is a nonzero value. Otherwise, the return
;                     value is 0 (zero) & Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Related .......: _SetupQueryInfFileInformation, _SetupQueryInfVersionInformation
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetInfInformation($InfSpec, $SearchControl = $INFINFO_INF_NAME_IS_ABSOLUTE)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfInformationW", (IsString($InfSpec) ? "wstr" : "long"), $InfSpec, "dword", $SearchControl, "ptr", 0, "dword", 0, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    Local $SP_INF_INFORMATION = DllStructCreate("DWORD InfStyle;DWORD InfCount;BYTE  VersionData[" & $arDllCall[5] & "]")
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfInformationW", (IsString($InfSpec) ? "wstr" : "long"), $InfSpec, "dword", $SearchControl, "ptr", DllStructGetPtr($SP_INF_INFORMATION), "dword", $arDllCall[5], "dword*", 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, _WinAPI_GetLastErrorEx(), $arDllCall[3])
#cs
    Local $SP_INF_INFORMATION = DllStructCreate("DWORD InfStyle;DWORD InfCount;BYTE  VersionData[32767]"), $PSP_INF_INFORMATION = DllStructGetPtr($SP_INF_INFORMATION)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfInformationW", (IsString($InfSpec) ? "wstr" : "long"), $InfSpec, "dword", $SearchControl, "ptr", $PSP_INF_INFORMATION, "dword", 32767, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfInformationW", (IsString($InfSpec) ? "wstr" : "long"), $InfSpec, "dword", $SearchControl, "ptr", $PSP_INF_INFORMATION, "dword", $arDllCall[5], "dword*", 0)
    Return SetError(0, _WinAPI_GetLastErrorEx(), $arDllCall[3])
#CE
EndFunc    ;==>_SetupGetInfInformation


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetIntField
; Description ...: The SetupGetIntField function retrieves an integer value from the specified field of a line in an INF file.
; Syntax.........: _SetupGetIntField($Context, $FieldIndex)
; Parameters ....: $Context    - Pointer to the context for a line in an INF file.
;                   $FieldIndex - The 1-based index of the field within the specified line from which the integer should be retrieved.
;                     A FieldIndex of 0 can be used to retrieve an integer key (For example, consider the following INF line, 431 = 1, 2, 4. The value 431 would be
;                     put into the variable pointed at by IntegerValue if SetupGetIntField was called with a FieldIndex of 0).
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: The integer field may start with a positive (+) or negative (-) sign. It will be interpreted as a decimal number, unless prefixed in the file
;                     with 0x or 0X, in which case it is hexadecimal.
; Related .......: _SetupGetBinaryField, _SetupGetMultiSzField, _SetupGetStringField
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetIntField($Context, $FieldIndex)
    If $FieldIndex < 1 Then Return SetError(1, 0, 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetIntField", "ptr", $Context, "dword", $FieldIndex, "int*", "")
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, _WinAPI_GetLastErrorEx(), $arDllCall[3])
EndFunc    ;==>_SetupGetIntField


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetInfPublishedName
; Description ...: The SetupGetInfPublishedName function retrieves the fully qualified file name (directory path and file name) of an INF file in the system INF file http://msdn.microsoft.com/en-us/library/windows/hardware/ff549520(v=vs.85).aspx
;                    directory that corresponds to a specified INF file in the driver store or a specified INF file in the system INF file directory.
; Syntax.........: _SetupGetInfPublishedName($DriverStoreLocation, $ReturnBufferSize)
; Parameters ....: $DriverStoreLocation - A pointer to a NULL-terminated string that contains the fully qualified file name (directory path and file name) of an INF
;                     file in the driver store. Alternatively, this parameter is a pointer to a NULL-terminated string that contains the name, and optionally the full
;                     directory path, of an INF file in the system INF file directory. For more information about how to specify the INF file, see the following Remarks section.
;                   $ReturnBufferSize   - The size, in characters, of the buffer supplied by ReturnBuffer.
; Return values .: If SetupGetInfPublishedName succeeds, the function returns TRUE; otherwise, the function returns FALSE & Extended error information retrieved by _WinAPI_GetLastErrorEx.
;
;                   If the size, in characters, of the fully qualified file name of the requested INF file, including a null-terminator, is greater than ReturnBufferSize,
;                     the function will fail, and a call to _WinAPI_GetLastErrorEx will return ERROR_INSUFFICIENT_BUFFER.
; Remarks .......: To determine the size of the return buffer that is required to contain the fully qualified file name of the specified INF file in the system
;                     INF directory, call _SetupGetInfPublishedName and set ReturnBuffer to NULL, ReturnBufferSize to zero, and supply RequiredSize.
;                     _SetupGetInfPublishedName will return the required buffer size in RequiredSize.
;
;                   When device installation preinstalls a driver package in the driver store, it creates two copies of the driver package INF file. Device installation
;                     adds one copy to the system INF directory and assigns that copy of the INF file a unique published file name of the form OEMnnn.inf.
;                     Device installation adds a second copy of the INF file to the driver store and assigns that copy the original INF file name.
;
;                   SetupGetInfPublishedName returns the fully qualified file name of the INF file in the system INF file directory that matches the INF file, if any,
;                     that is supplied by DriverStoreLocation. DriverStoreLocation must specify the fully qualified file name of an INF file in the driver store or must
;                     specify the file name, and optionally the directory path, of an INF file in the system INF directory. For example, assume that the INF file for a
;                     driver package is myinf.inf, and that for this driver package, device installation installs the INF file OEM1.inf in the system INF directory
;                     C:\Windows\inf. Further assume that device installation installs the corresponding INF file copy
;                     C:\windows\system32\driverstore\filerepository\myinf_12345678\myinf.inf in the driver store. In this case, the function returns
;                     C:\Windows\inf\OEM1.inf if DriverStoreLocation supplies one of the following strings:
;                     C:\windows\system32\driverstore\filerepository\myinf_12345678\myinf.inf, OEM1.inf, or C:\Windows\inf\OEM1.inf.
;
;                   Call the _SetupGetInfDriverStoreLocation function to retrieve the fully qualified file name of an INF file in the driver store that corresponds to
;                     a specified INF file in the system INF file directory or a specified file in the driver store.
;
; Related .......: _SetupGetInfDriverStoreLocation
;
; C++ Syntax ....: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552194(v=vs.85).aspx
;                  ---------------------------------------------------------------------------------------------------
;                           WINSETUPAPI
;                           BOOL
;                           WINAPI
;                           SetupGetInfPublishedNameW(
;                                   _In_ PCWSTR DriverStoreLocation,
;                                   _Out_writes_(ReturnBufferSize) PWSTR ReturnBuffer,
;                                   _In_ DWORD ReturnBufferSize,
;                                   _Out_opt_ PDWORD RequiredSize
;                                   );
;                  ---------------------------------------------------------------------------------------------------
;                  Parameters
;                  DriverStoreLocation [in]     - A pointer to a NULL-terminated string that contains the fully qualified file name (directory path and file name)
;                       of an INF file in the driver store. Alternatively, this parameter is a pointer to a NULL-terminated string that contains the name,
;                       and optionally the full directory path, of an INF file in the system INF file directory. For more information about how to specify
;                       the INF file, see the following Remarks section.
;                  ReturnBuffer [out]           - A pointer to the buffer in which SetupGetInfPublishedName returns a NULL-terminated string that contains the
;                       fully qualified file name of the specified INF file in the system INF directory. The maximum path size is MAX_PATH. This pointer can be set
;                       to NULL. For information about how to determine the required size of the return buffer, see the following Remarks section.
;                  ReturnBufferSize [in]        - The size, in characters, of the buffer supplied by ReturnBuffer.
;                  RequiredSize [out, optional] - A pointer to a DWORD-typed variable that receives the size, in characters, of the ReturnBuffer buffer.
;                       This parameter is optional and can be set to NULL.
;
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetInfPublishedName($DriverStoreLocation, $ReturnBufferSize = 32767) ;Or ASCII 260
     ;;Local $RBuffer = DllStructCreate("wchar")
     ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfPublishedNameW", "wstr", $DriverStoreLocation, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfPublishedNameW", "wstr", $DriverStoreLocation, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;;If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetInfPublishedNameW", "wstr", $DriverStoreLocation, "wstr", "", "dword", $arDllCall[4], "dword*", 0)
    ;;If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then Return SetError($ERROR_INSUFFICIENT_BUFFER, $arDllCall[4], "")
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[4], $arDllCall[2])
EndFunc    ;==>_SetupGetInfPublishedName


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetMultiSzField
; Description ...: The SetupGetMultiSzField function retrieves multiple strings stored in a line of an INF file, from the specified field to the end of the line.
; Syntax.........: _SetupGetMultiSzField($Context, $FieldIndex)
; Parameters ....: $Context    - Pointer to the context for a line in an INF file.
;                   $FieldIndex - The 1-based index of the starting field within the specified line from which the strings should be retrieved. The string list is built
;                     from each field starting at this point to the end of the line. A FieldIndex of zero is not valid with this function.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the specified
;                     data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise, the return
;                     value is zero and extended error information can be obtained by calling _WinAPI_GetLastErrorEx.
;
;                   _SetupGetMultiSzField should not be used to iterate through string values on an INF line. Instead you should use _SetupGetStringField.
;                     _SetupGetMultiSzField returns a value in the format of REG_MULTI_SZ. This is an array of null-terminated strings terminated by an extra null
;                     character. This format does not allow zero-length strings. If the list of strings contains any zero-length strings, _SetupGetMultiSzField will
;                     return prematurely when it encounters the first blank string value.
;
; Related .......: _SetupGetBinaryField, _SetupGetIntField, _SetupGetStringField
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetMultiSzField($Context, $FieldIndex, $ReturnBufferSize = 32767) ;Or ASCII 260
     ;;Local $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetMultiSzFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    If $FieldIndex < 1 Then Return SetError(1, 0, 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetMultiSzFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetMultiSzFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $arDllCall[5], "dword*", 0)
    Return SetError(0, _WinAPI_GetLastErrorEx(), $arDllCall[3])
EndFunc    ;==>_SetupGetMultiSzField


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetSourceFileLocation
; Description ...: The _SetupGetSourceFileLocation function retrieves the location of a source file listed in an INF file.
; Syntax.........: _SetupGetSourceFileLocation($InfHandle, $InfContext, $FileName, $ReturnBufferSize)
; Parameters ....: $InfHandle  - Handle to the INF file that contains the SourceDisksNames and SourceDisksFiles sections. If platform-specific sections exist
;                     for the user's system (for example, SourceDisksNames.x86 and SourceDisksFiles.x86), the platform-specific section will be used.
;                   $InfContext - Optional pointer to the context of a line in a Copy Files section for which the full source path is to be retrieved.
;                     If this parameter is NULL, FileName is searched for in the SourceDisksFiles section of the INF file specified by InfHandle.
;                   $FileName   - Optional pointer to a null-terminated string containing the filename (no path) for which to return the full source location.
;                     This parameter can be NULL, but either FileName or InfContext must be specified.
;                   $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This number includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the
;                     specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise,
;                     the return value is zero and extended error information can be obtained by calling _WinAPI_GetLastErrorEx.
; Related .......: _SetupGetSourceInfo, _SetupGetSourceFileSize
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetSourceFileLocation($InfHandle, $InfContext = 0, $FileName = NULL, $ReturnBufferSize = 32767) ;Or ASCII 260
     ;;Local $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceFileLocationW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $FileName, "UINT*", 0, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    If Not $FileName And Not $InfContext Then Return SetError(@Error, 0, 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceFileLocationW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $FileName, "UINT*", 0, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceFileLocationW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $FileName, "UINT*", 0, "wstr", "", "dword", $arDllCall[7], "dword*", 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[4], $arDllCall[5])
EndFunc    ;==>_SetupGetSourceFileLocation


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetSourceFileSize
; Description ...: The _SetupGetSourceFileSize function reads the uncompressed size of a source file listed in an INF file.
; Syntax.........: _SetupGetSourceFileSize($InfHandle, $InfContext, $FileName, $Section, $RoundingFactor)
; Parameters ....: $InfHandle  - Handle to the loaded INF file that contains the SourceDisksNames and SourceDisksFiles sections. If platform-specific sections exist
;                     for the user's system (for example, SourceDisksNames.x86 and SourceDisksFiles.x86), the platform-specific section will be used.
;                   $InfContext - Optional pointer to a context for a line in a Copy Files section for which the size is to be retrieved. If InfContext is NULL,
;                     the FileName parameter is used.
;                   $FileName  - Optional pointer to a null-terminated string containing the filename (no path) for which to return the size. If this parameter is NULL
;                     as well as InfContext, then the Section parameter is used.
;                   $Section   - Optional pointer to a null-terminated string containing the name of a Copy Files section. If this parameter is specified, the total
;                     size of all files listed in the section is computed.
;                   $RoundingFactor - Optional value for rounding file sizes. All file sizes are rounded up to a multiple of this number before being added to the
;                     total size. Rounding is useful for more exact determinations of the space that a file will occupy on a given volume, because it allows the
;                     caller to have file sizes rounded up to a multiple of the cluster size. Rounding does not occur unless RoundingFactor is specified.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: One and only one of the optional parameters, InfContext, FileName, and Section, must be specified.
; Related .......: _SetupGetSourceFileLocation
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetSourceFileSize($InfHandle, $InfContext = 0, $FileName = NULL, $Section = NULL, $RoundingFactor = 0)
     ;;Local $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceFileSizeW", "ptr", $Context, "dword", $FieldIndex, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    If Not $FileName And Not $Section And Not $InfContext Then Return SetError(@Error, 0, 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceFileSizeW", "HANDLE", $InfHandle, "ptr", $InfContext, "wstr", $FileName, "wstr", $Section, "dword*", 0, "UINT", $RoundingFactor)
    If @Error Then Return SetError(@Error, 0, 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[6], $arDllCall[5])
EndFunc    ;==>_SetupGetSourceFileSize


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetSourceInfo
; Description ...: The _SetupGetSourceInfo function reads the uncompressed size of a source file listed in an INF file.
; Syntax.........: _SetupGetSourceInfo($InfHandle, $SourceId, $InfoDesired, $ReturnBufferSize)
; Parameters ....: $InfHandle   - Handle to an open INF file that contains a SourceDisksNames section. If platform-specific sections exist for the user's
;                     system (for example, SourceDisksNames.x86), the platform-specific section will be used.
;                   $SourceId - Identifier for a source media. This value is used to search by key in the SourceDisksNames section.
;                   $InfoDesired - Indicates what information is desired. Only one value may be specified per function call, and they cannot be combined.
;                     The following types of information can be retrieved from a SourceDisksNames section.
;                  |1 - $SRCINFO_PATH           The path specified for the source. This is not a full path, but the path relative to the installation root.
;                  |2 - $SRCINFO_TAGFILE        The tag file that identifies the source media, or if cabinets are used, the name of the cabinet file.
;                  |3 - $SRCINFO_DESCRIPTION     A description for the media.
;                   $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the specified
;                     data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise, the return value
;                     is zero and extended error information can be obtained by calling _WinAPI_GetLastErrorEx.; Related .......: _SetupGetSourceFileLocation, _SetupGetSourceFileSize, _SetupGetTargetPath
; Related .......: _SetupGetSourceFileLocation, _SetupGetSourceFileSize, _SetupGetTargetPath
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetSourceInfo($InfHandle, $SourceId = 0, $InfoDesired = $SRCINFO_PATH, $ReturnBufferSize = 32767) ;Or ASCII 260
     ;;Local $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceInfoW", "HANDLE", $InfHandle, "UINT", $SourceId, "UINT", $InfoDesired, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    If $InfoDesired < 1 Or $InfoDesired > 3 Then $InfoDesired = 1 ;; $SRCINFO_PATH
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceInfoW", "HANDLE", $InfHandle, "UINT", $SourceId, "UINT", $InfoDesired, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetSourceInfoW", "HANDLE", $InfHandle, "UINT", $SourceId, "UINT", $InfoDesired, "wstr", "", "dword", $arDllCall[6], "dword*", 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[5], $arDllCall[4])
EndFunc    ;==>_SetupGetSourceInfo

; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetStringField
; Description ...: The SetupGetStringField function retrieves a string from the specified field of a line in an INF file.
; Syntax.........: _SetupGetStringField($Context, $FieldIndex, $ReturnBufferSize)
; Parameters ....: $Context    - Pointer to the context for a line in an INF file.
;                  $FieldIndex - The 1-based index of the field within the specified line from which the string should be retrieved. Use a FieldIndex of 0 to retrieve a string key, if present.
;                  $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the
;                    specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise,
;                    the return value is zero and extended error information can be obtained by calling GetLastError. You can call the function once to get the
;                    required buffer size, allocate the necessary memory, and then call the function a second time to retrieve the data. Using this technique,
;                    you can avoid errors due to an insufficient buffer size.
;
;                  Note that the maximum length of any single string specified in an INF Strings section is 512 characters, including the terminating NULL. If the
;                    string length is greater than 512 it will be truncated and no error will be returned. The maximum length of any concatenated string created from
;                    one or more %strkey% tokens is 4096 characters.
;
; Related .......: _SetupGetIntField, _SetupGetBinaryField, _SetupGetMultiSzField
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetStringField($Context, $FieldIndex = 0, $ReturnBufferSize = 65535)
     ;;Local $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($hSetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $arDllCall[5], "dword*", 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[5], $arDllCall[3])
EndFunc    ;==>_SetupGetStringField


Func _WinAPI_GetLastErrorEx()
    Local $arDllCall = DllCall($hKernel32DLL, "long", "GetLastError")
    Return $arDllCall[0]
EndFunc ;==>_WinAPI_GetLastErrorEx


Func _HeapFree(ByRef $pMem)
    If Not $ProcessHeap[0] Or $pMem < 1 Then Return SetError(1, 0, 0)
    $arDllCall = DllCall($hKernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $pMem)
    If (@error) Or (Not $arDllCall[0]) Then Return SetError(2, 0, 0)
    $pMem = 0
    Return 1
EndFunc   ;==>_HeapFree
 

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Posted

Thanks for the quick reply.

 

I am figuring out a way to parse lots of inf files from driverpacks.net. I need an array with HardwareIDs and the corresponding inf filename. Due to their nature, all kind syntaxes and lots of comments are to be expected.

Internal IniReadSection fails with some of the files because of the 32767 characters limitation, hence looking for a already made similar function.

Ini or Inf, aren't comments or commented out lines to be ignored in either case?

Thanks for the WinApi inf functions, I can't see any relevant function for my needs. Am I missing something obvious?

Posted (edited)

the official way

 

; ahcix64s.INF
; Copyright 2009 Advanced Micro Devices, Inc.
;
[Version]
signature="$Windows NT$"
Class=SCSIAdapter
ClassGUID={4D36E97B-E325-11CE-BFC1-08002BE10318}
CatalogFile=ahcix64s.cat
Provider=%ATI%
DriverVer=07/01/2009, 3.1.1540.151
;

;ect ect ect

;ect ect ect

[strings]

;  *******Localizable Strings*******
ATI= "Advanced Micro Devices, Inc."
Desc_amd640= "AMD AHCI Compatible RAID Controller Driver"
NapaDesc= "AMD AHCI Compatible RAID Controller"
NapaDesc_DC5750= "AMD AHCI Compatible RAID Controller - DC5750"
ATI_Raid_ControllerDesc= "AMD RAID Console"

;  *******Non Localizable Strings*******
 

;ect ect ect

;ect ect ect

#Region ;SetupAPI Constants
Global Const $h_SetupApiDll = DllOpen("SetupApi.dll")
Global Const $h_Kernel32DLL = DllOpen("Kernel32.dll")

Global Const $ERROR_INSUFFICIENT_BUFFER = 122 ;(0x7A) - The data area passed to a system call is too small.

;;
;; SP_INF_INFORMATION.InfStyle values
;;
Global Const $INF_STYLE_NONE           = 0      ;; 0x00000000   -   unrecognized or non-existent
Global Const $INF_STYLE_OLDNT          = 1      ;; 0x00000001   -   A legacy INF file format  - winnt 3.x
Global Const $INF_STYLE_WIN4           = 2      ;; 0x00000002   -   A Windows INF file format - Win95
Global Const $INF_STYLE_NULL           = NULL   ;;              -   or AutoIt v3.3.8 Global Const $INF_STYLE_NULL  = "Null"

#EndRegion


Local $hInfFile, $sData, $fTimerDiff
$fTimerDiff = TimerInit()
$hInfFile = _SetupOpenInfFile(@DesktopDir & "\DPs\ahcix64s.inf")
If Not @Error Then
    $sData = _SetupGetLineText(0, $hInfFile, "Version", "Provider")
Else
    ;;Error
EndIf
_SetupCloseInfFile($hInfFile)
$fTimerDiff = TimerDiff($fTimerDiff)
ConsoleWrite($fTimerDiff & @LF)
ConsoleWrite($sData & @LF)

; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupOpenInfFile
; Description ...: The SetupOpenInfFile function opens an INF file and returns a handle to it.
; Syntax.........: _SetupOpenInfFile($FileName, $InfClass, $InfStyle)
; Parameters ....: $FileName - Pointer to a null-terminated string containing the name (and optional path) of the INF file to be opened.
;                    If the filename does not contain path separator characters, it is searched for, first in the %windir%\inf directory,
;                    and then in the %windir%\system32 directory. If the filename contains path separator characters, it is assumed to be
;                    a full path specification and no further processing is performed on it.
;                  $InfClass - Optional pointer to a null-terminated string containing the class of INF file desired. This string must match
;                    the Class value of the Version section (for example, Class=Net). If there is no entry in the Class value, but there is an entry
;                    for ClassGUID in the Version section, the corresponding class name for that GUID is retrieved and used for the comparison.
;                  $InfStyle - Style of INF file to open or search for. This parameter can be a combination of the following flags.
;                  |Null - $INF_STYLE_NULL
;                  |0    - $INF_STYLE_NONE
;                  |1    - $INF_STYLE_OLDNT - A legacy INF file format.
;                  |2    - $INF_STYLE_WIN4 - A Windows INF file format.
; Return values .: The function returns a handle to the opened INF file if it is successful. Otherwise, the return value is INVALID_HANDLE_VALUE. (Extended error information retrieved by _WinAPI_GetLastErrorEx.)
; Remarks .......: If the load fails because the INF file type does not match InfClass, the function returns INVALID_HANDLE_VALUE and a call to
;                   _WinAPI_GetLastErrorEx returns ERROR_CLASS_MISMATCH.
;
;                   If multiple INF file styles are specified, the style of the INF file opened can be determined by calling the SetupGetInfInformation function.
;
;                   Because there may be more than one class GUID with the same class name, callers interested in INF files of a particular class
;                   (that is, a particular class GUID) should retrieve the ClassGUID value from the INF file by calling SetupQueryInfVersionInformation.
;
;                   For legacy INF files, the InfClass string must match the type specified in the OptionType value of the Identification section
;                   in the INF file (for example, OptionType=NetAdapter).
;
; Related .......: _SetupOpenAppendInfFile, _SetupCloseInfFile, _SetupGetInfInformationEx
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupOpenInfFile($FileName, $InfClass = NULL, $InfStyle = $INF_STYLE_WIN4)
    Local $HINF = DllCall($h_SetupApiDll, "long", "SetupOpenInfFileW", "wstr", $FileName, "wstr", $InfClass, "dword", $InfStyle, "uint*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;If $HINF[0] = $ERROR_INVALID_HANDLE_VALUE Then Return SetError($HINF[0], $HINF[4], 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $HINF[4], $HINF[0])
EndFunc ;==>_SetupOpenInfFile


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineText
; Description ...: The SetupGetLineText function returns the contents of a line in an INF file in a compact form. The line to retrieve can be specified by an
;                    INFCONTEXT structure returned from a SetupFindLineXXX function, or by explicitly passing in the INF handle, section, and key of the desired line.
; Syntax.........: _SetupGetLineText($Context, $InfHandle, $Section, $Key, $ReturnBufferSize)
; Parameters ....: $Context   - Context for a line in an INF file whose text is to be retrieved. This parameter can be NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $InfHandle - Handle to the INF file to query. This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $Section   - Pointer to a null-terminated string that specifies the section that contains the key name of the line whose text is to be retrieved.
;                    This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                  $Key       - Pointer to a null-terminated string that contains the key name whose associated string is to be retrieved. This parameter can be NULL.
;                    This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                  $ReturnBufferSize - Size of the buffer pointed to by the ReturnBuffer parameter, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value.
;                    If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size required to hold
;                  the specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value.
;                  Otherwise, the return value is zero and extended error information can be obtained by calling GetLastError.
;
;                  This function returns the contents of a line in a compact format. All extraneous white space is removed and multi-line values are converted
;                  into a single contiguous string. For example, this line:
;
;                    HKLM, , PointerClass0, 1 \
;                    ; This is a comment
;                    01, 02, 03
;
;                  would be returned as:
;
;                   HKLM,,PointerClass0,1,01,02,03
;
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineText($Context = 0, $InfHandle = 0, $Section = NULL, $Key = NULL, $ReturnBufferSize = 65535) ;;    4194303 = 4 MB
    Local $GetLineText = DllCall($h_SetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "long", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $GetLineText[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $GetLineText = DllCall($h_SetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "long", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $GetLineText[7], "dword*", 0)
    If Not $GetLineText[0] Then Return SetError(_WinAPI_GetLastErrorEx(), $GetLineText[0], "")
    Return SetError(0, $GetLineText[7], $GetLineText[5])
EndFunc ;==>_SetupGetLineText


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupCloseInfFile
; Description ...: The SetupCloseInfFile function closes the INF file opened by a call to SetupOpenInfFile. This function closes any INF files appended to it by calling SetupOpenAppendInfFile.
; Syntax.........: _SetupCloseInfFile($InfHandle)
; Parameters ....: $InfHandle - Handle to the INF file to be closed.
; Return values .: This function does not return a value.
; Remarks .......: Because _SetupGetFileCompressionInfoEx determines the compression by examining the physical file, your setup application should ensure that the file is present before calling _SetupGetFileCompressionInfoEx.
; Related .......: _SetupOpenInfFile, _SetupOpenAppendInfFile
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupCloseInfFile($InfHandle)
    DllCall($h_SetupApiDll, "none", "SetupCloseInfFile", "long", $InfHandle)
EndFunc    ;==>_SetupCloseInfFile


Func _WinAPI_GetLastErrorEx()
    Local $GetLastError = DllCall($h_Kernel32DLL, "long", "GetLastError")
    Return $GetLastError[0]
EndFunc ;==>_WinAPI_GetLastErrorEx
;~ >Running:(3.3.11.3):C:\Program Files (x86)\AutoIt3\Beta\autoit3.exe "C:\Users\DXRW4E\Desktop\test.au3"    
;~ --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop
;~ 3.6460546623845
;~ Advanced Micro Devices, Inc.
;~ +>01:04:33 AutoIt3.exe ended.rc:0
;~ +>01:04:33 AutoIt3Wrapper Finished..
;~ >Exit code: 0    Time: 0.3137

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Posted (edited)

Got it, thanks.

Overlooked the _SetupGetLineText function and its parameters.

Does the 32767 characters limit apply to SetupGetLineText WinApi? I can't see such remarks in the msdn article.

Edit: Never mind, silly question.

Edited by ilko
Posted (edited)

Or

#include <Array.au3>

#Region ;SetupAPI Constants
If Not IsDeclared("arDllCall") Then
    Global Static $arDllCall
EndIf
Global Static $ProcessHeap[1]

Global Const $h_SetupApiDll = DllOpen("SetupApi.dll")
Global Const $h_Kernel32DLL = DllOpen("Kernel32.dll")

Global Const $ERROR_INSUFFICIENT_BUFFER = 122 ;(0x7A) - The data area passed to a system call is too small.

;;
;; SP_INF_INFORMATION.InfStyle values
;;
Global Const $INF_STYLE_NONE           = 0      ;; 0x00000000   -   unrecognized or non-existent
Global Const $INF_STYLE_OLDNT          = 1      ;; 0x00000001   -   A legacy INF file format  - winnt 3.x
Global Const $INF_STYLE_WIN4           = 2      ;; 0x00000002   -   A Windows INF file format - Win95
Global Const $INF_STYLE_NULL           = NULL   ;;              -   or AutoIt v3.3.8 Global Const $INF_STYLE_NULL  = "Null"

#EndRegion


Local $hInfFile, $sData, $aData, $iLineCount, $iContext, $_iContext, $fTimerDiff
$fTimerDiff = TimerInit()
$hInfFile = _SetupOpenInfFile(@DesktopDir & "\iaAHCI.inf")
If @Error Then
    ;;error
    Exit
Else
    $fTimerDiff = TimerDiff($fTimerDiff)
    ConsoleWrite($fTimerDiff & @LF)
    ConsoleWrite($sData & @LF)

    $fTimerDiff = TimerInit()
    $iLineCount = _SetupGetLineCount($hInfFile, "Version")
    For $i = 0 To $iLineCount - 1
        $iContext = _SetupGetLineByIndex($hInfFile, "Version", $i)
        If @Error Then ExitLoop
        $sData &= _SetupGetLineText($iContext) & @LF
        _HeapFree($iContext)
    Next
    $aData = StringSplit($sData, @LF)
    _ArrayDisplay($aData)
EndIf
;;_SetupCloseInfFile($hInfFile)

$fTimerDiff = TimerInit()
$iLineCount = _SetupGetLineCount($hInfFile, "Version")
If $iLineCount > 0 Then
    Local $aData[$iLineCount + 1][3] = [[1]]
    $iContext = _SetupFindFirstLine($hInfFile, "Version")
    ;; $iFieldCount = _SetupGetFieldCount($iContext)
    ;;For $i = 1 To $iFieldCount
    ;;    $sData &= _SetupGetStringField($iContext, $i - 1)
    ;;Next
    $aData[$aData[0][0]][0] = _SetupGetStringField($iContext, 0)
    $aData[$aData[0][0]][1] = _SetupGetStringField($iContext, 1)
    $aData[$aData[0][0]][2] = _SetupGetStringField($iContext, 2)
    While 1
        $iContext = _SetupFindNextLine($iContext)
        If @Error Then ExitLoop
        ;; $iFieldCount = _SetupGetFieldCount($iContext)
        ;;For $i = 1 To $iFieldCount
        ;;    $sData &= _SetupGetStringField($iContext, $i - 1)
        ;;Next
        $aData[0][0] += 1
        $aData[$aData[0][0]][0] = _SetupGetStringField($iContext, 0)
        $aData[$aData[0][0]][1] = _SetupGetStringField($iContext, 1)
        $aData[$aData[0][0]][2] = _SetupGetStringField($iContext, 2)
    WEnd
    _HeapFree($iContext)
    _HeapFree($_iContext)
EndIf
_SetupCloseInfFile($hInfFile)
$fTimerDiff = TimerDiff($fTimerDiff)
ConsoleWrite($fTimerDiff & @LF)
_ArrayDisplay($aData)

; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupOpenInfFile
; Description ...: The SetupOpenInfFile function opens an INF file and returns a handle to it.
; Syntax.........: _SetupOpenInfFile($FileName, $InfClass, $InfStyle)
; Parameters ....: $FileName - Pointer to a null-terminated string containing the name (and optional path) of the INF file to be opened.
;                    If the filename does not contain path separator characters, it is searched for, first in the %windir%\inf directory,
;                    and then in the %windir%\system32 directory. If the filename contains path separator characters, it is assumed to be
;                    a full path specification and no further processing is performed on it.
;                  $InfClass - Optional pointer to a null-terminated string containing the class of INF file desired. This string must match
;                    the Class value of the Version section (for example, Class=Net). If there is no entry in the Class value, but there is an entry
;                    for ClassGUID in the Version section, the corresponding class name for that GUID is retrieved and used for the comparison.
;                  $InfStyle - Style of INF file to open or search for. This parameter can be a combination of the following flags.
;                  |Null - $INF_STYLE_NULL
;                  |0    - $INF_STYLE_NONE
;                  |1    - $INF_STYLE_OLDNT - A legacy INF file format.
;                  |2    - $INF_STYLE_WIN4 - A Windows INF file format.
; Return values .: The function returns a handle to the opened INF file if it is successful. Otherwise, the return value is INVALID_HANDLE_VALUE. (Extended error information retrieved by _WinAPI_GetLastErrorEx.)
; Remarks .......: If the load fails because the INF file type does not match InfClass, the function returns INVALID_HANDLE_VALUE and a call to
;                   _WinAPI_GetLastErrorEx returns ERROR_CLASS_MISMATCH.
;
;                   If multiple INF file styles are specified, the style of the INF file opened can be determined by calling the SetupGetInfInformation function.
;
;                   Because there may be more than one class GUID with the same class name, callers interested in INF files of a particular class
;                   (that is, a particular class GUID) should retrieve the ClassGUID value from the INF file by calling SetupQueryInfVersionInformation.
;
;                   For legacy INF files, the InfClass string must match the type specified in the OptionType value of the Identification section
;                   in the INF file (for example, OptionType=NetAdapter).
;
; Related .......: _SetupOpenAppendInfFile, _SetupCloseInfFile, _SetupGetInfInformationEx
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupOpenInfFile($FileName, $InfClass = NULL, $InfStyle = $INF_STYLE_WIN4)
    $arDllCall = DllCall($h_SetupApiDll, "HANDLE", "SetupOpenInfFileW", "wstr", $FileName, "wstr", $InfClass, "dword", $InfStyle, "uint*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;If $arDllCall[0] = $ERROR_INVALID_HANDLE_VALUE Then Return SetError($arDllCall[0], $arDllCall[4], 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[4], $arDllCall[0])
EndFunc ;==>_SetupOpenInfFile


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineCount
; Description ...: The SetupGetLineCount function returns the number of lines in a specified section of an INF file.
; Syntax.........: _SetupGetLineCount($InfHandle, $Section)
; Parameters ....: $InfHandle - Handle to the INF file.
;                  $Section   - Pointer to a null-terminated string that specifies the section in which you want to count the lines.
; Return values .: If InfHandle references multiple INF files that have been appended using _SetupOpenAppendInfFile, this function returns
;                    the sum of the lines in all of the INF files containing the specified section. A return value of 0 specifies an empty section.
;                    If the section does not exist, the function returns –1 Or Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......:
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineCount($InfHandle, $Section)
    $arDllCall = DllCall($h_SetupApiDll, "long", "SetupGetLineCountW", "HANDLE", $InfHandle, "wstr", $Section)
    If @Error Then Return SetError(@Error, 0, 0)
    If $arDllCall[0] > 0 Then Return SetError(0, 0, $arDllCall[0])
    Return SetError(_WinAPI_GetLastErrorEx(), 0, -1)
EndFunc    ;==>_SetupGetLineCount


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindFirstLine
; Description ...: The SetupFindFirstLine function locates a line in the specified section of an INF file. If the Key parameter is NULL, _SetupFindFirstLine returns the first line of the section.dBufferLen.
; Syntax.........: _SetupFindFirstLine($InfHandle, $Section, $Key)
; Parameters ....: $InfHandle - Handle to the INF file to query.
;                  $Section   - Pointer to a null-terminated string specifying the section of the INF files to search in.
;                  $Key       - Optional pointer to a null-terminated string specifying the key to search for within the section. The null-terminated string should not
;                    exceed the size of the destination buffer. This parameter can be NULL. If Key is NULL, the first line in the section is returned.
; Return values .: If the function could not find a line, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If the InfHandle parameter references multiple INF files that have been appended together using _SetupOpenAppendInfFile,
;                    the _SetupFindFirstLine function searches across the specified section in all of the files referenced by the specified HINF.
; Related .......: _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindFirstLine($InfHandle, $Section, $Key = NULL)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $Context = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupFindFirstLineW", "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "ptr", $Context[0])
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $Context[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[4])
EndFunc    ;==>_SetupFindFirstLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindNextLine
; Description ...: The SetupFindNextLine returns the location of the next line in an INF file section relative to ContextIn.Line.
; Syntax.........: _SetupFindNextLine($ContextIn)
; Parameters ....: $ContextIn - Pointer to the INF file context retrieved by a call to the _SetupFindFirstLine function.
; Return values .: If this function finds the next line, the return value is a nonzero value. Otherwise, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If ContextIn.Line references multiple INF files that have been appended together using SetupOpenAppendInfFile, this function searches across
;                    the specified section in all files referenced by the HINF to locate the next line.
; Related .......: _SetupFindFirstLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindNextLine($ContextIn)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $ContextOut = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupFindNextLine", "ptr", $ContextIn, "ptr", $ContextOut[0])
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $ContextOut[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[2])
EndFunc    ;==>_SetupFindNextLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineByIndex
; Description ...: The SetupGetLineByIndex function locates a line by its index value in the specified section in the INF file.
; Syntax.........: _SetupGetLineByIndex($InfHandle, $Section, $Index)
; Parameters ....: $InfHandle - Handle to the INF file.
;                  $Section   - Pointer to a null-terminated string specifying the section of the INF file to search.
;                   $Index     - Index of the line to be located. The total number of lines in a particular section can be found with a call to _SetupGetLineCount.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......: If InfHandle references multiple INF files that have been appended together using _SetupOpenAppendInfFile, this function searches across
;                    the specified section in all files referenced by the HINF to locate the indexed line.
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineByIndex($InfHandle, $Section, $Index)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    $Context = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetLineByIndexW", "HANDLE", $InfHandle, "wstr", $Section, "dword", $Index, "ptr", $Context[0])
    If @Error Or Not $arDllCall[0] Then SetError(_WinAPI_GetLastErrorEx(), DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $Context[0]), 0)
    Return SetError(0, 0, $Context[0])
EndFunc    ;==>_SetupGetLineByIndex


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetStringField
; Description ...: The SetupGetStringField function retrieves a string from the specified field of a line in an INF file.
; Syntax.........: _SetupGetStringField($Context, $FieldIndex, $ReturnBufferSize)
; Parameters ....: $Context    - Pointer to the context for a line in an INF file.
;                  $FieldIndex - The 1-based index of the field within the specified line from which the string should be retrieved. Use a FieldIndex of 0 to retrieve a string key, if present.
;                  $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the
;                    specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise,
;                    the return value is zero and extended error information can be obtained by calling GetLastError. You can call the function once to get the
;                    required buffer size, allocate the necessary memory, and then call the function a second time to retrieve the data. Using this technique,
;                    you can avoid errors due to an insufficient buffer size.
;
;                  Note that the maximum length of any single string specified in an INF Strings section is 512 characters, including the terminating NULL. If the
;                    string length is greater than 512 it will be truncated and no error will be returned. The maximum length of any concatenated string created from
;                    one or more %strkey% tokens is 4096 characters.
;
; Related .......: _SetupGetIntField, _SetupGetBinaryField, _SetupGetMultiSzField
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetStringField($Context, $FieldIndex = 0, $ReturnBufferSize = 65535)
     ;;Local $arDllCall, $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $arDllCall[5], "dword*", 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[5], $arDllCall[3])
EndFunc    ;==>_SetupGetStringField


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineText
; Description ...: The SetupGetLineText function returns the contents of a line in an INF file in a compact form. The line to retrieve can be specified by an
;                    INFCONTEXT structure returned from a SetupFindLineXXX function, or by explicitly passing in the INF handle, section, and key of the desired line.
; Syntax.........: _SetupGetLineText($Context, $InfHandle, $Section, $Key, $ReturnBufferSize)
; Parameters ....: $Context   - Context for a line in an INF file whose text is to be retrieved. This parameter can be NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $InfHandle - Handle to the INF file to query. This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $Section   - Pointer to a null-terminated string that specifies the section that contains the key name of the line whose text is to be retrieved.
;                    This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                  $Key       - Pointer to a null-terminated string that contains the key name whose associated string is to be retrieved. This parameter can be NULL.
;                    This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                  $ReturnBufferSize - Size of the buffer pointed to by the ReturnBuffer parameter, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value.
;                    If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size required to hold
;                  the specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value.
;                  Otherwise, the return value is zero and extended error information can be obtained by calling GetLastError.
;
;                  This function returns the contents of a line in a compact format. All extraneous white space is removed and multi-line values are converted
;                  into a single contiguous string. For example, this line:
;
;                    HKLM, , PointerClass0, 1 \
;                    ; This is a comment
;                    01, 02, 03
;
;                  would be returned as:
;
;                   HKLM,,PointerClass0,1,01,02,03
;
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineText($Context = 0, $InfHandle = 0, $Section = NULL, $Key = NULL, $ReturnBufferSize = 65535) ;;    4194303 = 4 MB
    $arDllCall = DllCall($h_SetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($h_SetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "long", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $arDllCall[7], "dword*", 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[0], "")
    Return SetError(0, $arDllCall[7], $arDllCall[5])
EndFunc ;==>_SetupGetLineText


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetFieldCount
; Description ...: The SetupGetFieldCount function retrieves the number of fields in the specified line in an INF file.
; Syntax.........: _SetupGetFieldCount($Context)
; Parameters ....: $Context - Pointer to the context for a line in an INF file.
; Return values .: This function returns the number of fields on the line. If Context is invalid, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......:
; Related .......: _SetupGetLineCount
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetFieldCount($Context)
    $arDllCall = DllCall($h_SetupApiDll, "DWORD", "SetupGetFieldCount", "ptr", $Context)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, 0, $arDllCall[0])
EndFunc ;==>_SetupGetFieldCount


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupCloseInfFile
; Description ...: The SetupCloseInfFile function closes the INF file opened by a call to SetupOpenInfFile. This function closes any INF files appended to it by calling SetupOpenAppendInfFile.
; Syntax.........: _SetupCloseInfFile($InfHandle)
; Parameters ....: $InfHandle - Handle to the INF file to be closed.
; Return values .: This function does not return a value.
; Remarks .......: Because _SetupGetFileCompressionInfoEx determines the compression by examining the physical file, your setup application should ensure that the file is present before calling _SetupGetFileCompressionInfoEx.
; Related .......: _SetupOpenInfFile, _SetupOpenAppendInfFile
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupCloseInfFile($InfHandle)
    DllCall($h_SetupApiDll, "none", "SetupCloseInfFile", "HANDLE", $InfHandle)
EndFunc    ;==>_SetupCloseInfFile


Func _WinAPI_GetLastErrorEx()
    Local $arDllCall = DllCall($h_Kernel32DLL, "long", "GetLastError")
    Return $arDllCall[0]
EndFunc ;==>_WinAPI_GetLastErrorEx

Func _HeapFree(ByRef $pMem)
    If Not $ProcessHeap[0] Or $pMem < 1 Then Return SetError(1, 0, 0)
    $arDllCall = DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $pMem)
    If (@error) Or (Not $arDllCall[0]) Then Return SetError(2, 0, 0)
    $pMem = 0
    Return 1
EndFunc   ;==>_HeapFree

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Posted (edited)

A bit of help please :)

Got all working fine during WinPE stage of Vista x32, 7 x64 and 8 x32 setup.

On Windows 8 x64 (Enterprise Eval) _SetupGetLineCount fails with error 6, "The handle is invalid". _SetupOpenInfFile seems ok, returning different handles for each inf file processed. Script and inf files are all the same.

Do you have any hints?

Edited by ilko
Posted

6

ERROR_INVALID_HANDLE
The handle is invalid.

Mind you, I am testing in WinPE environment.

Currently installing the same Win8 x64 to test same script in normal environment.

 

8x64test.zip

Posted (edited)

this is Ok ???

#include <Array.au3>

#Region ;SetupAPI Constants
If Not IsDeclared("arDllCall") Then
    Global Static $arDllCall
EndIf
Global Static $ProcessHeap[1]

Global Const $h_SetupApiDll = DllOpen("SetupApi.dll")
Global Const $h_Kernel32DLL = DllOpen("Kernel32.dll")

Global Const $ERROR_INSUFFICIENT_BUFFER = 122 ;(0x7A) - The data area passed to a system call is too small.

;;
;; SP_INF_INFORMATION.InfStyle values
;;
Global Const $INF_STYLE_NONE           = 0      ;; 0x00000000   -   unrecognized or non-existent
Global Const $INF_STYLE_OLDNT          = 1      ;; 0x00000001   -   A legacy INF file format  - winnt 3.x
Global Const $INF_STYLE_WIN4           = 2      ;; 0x00000002   -   A Windows INF file format - Win95
Global Const $INF_STYLE_NULL           = NULL   ;;              -   or AutoIt v3.3.8 Global Const $INF_STYLE_NULL  = "Null"

#EndRegion


Local $hInfFile, $sData, $aData, $iLineCount, $iContext, $_iContext, $fTimerDiff
$fTimerDiff = TimerInit()
$hInfFile = _SetupOpenInfFile(@DesktopDir & "\iaAHCI.inf")
If @Error Then
    ;;error
    Exit
Else
    $fTimerDiff = TimerDiff($fTimerDiff)
    ConsoleWrite($fTimerDiff & @LF)
    ConsoleWrite($sData & @LF)

    $fTimerDiff = TimerInit()
    $iLineCount = _SetupGetLineCount($hInfFile, "Version")
    For $i = 0 To $iLineCount - 1
        $iContext = _SetupGetLineByIndex($hInfFile, "Version", $i)
        If @Error Then ExitLoop
        $sData &= _SetupGetLineText($iContext) & @LF
        _HeapFree($iContext)
    Next
    $aData = StringSplit($sData, @LF)
    _ArrayDisplay($aData)
EndIf
;;_SetupCloseInfFile($hInfFile)

$fTimerDiff = TimerInit()
$iLineCount = _SetupGetLineCount($hInfFile, "Version")
If $iLineCount > 0 Then
    Local $aData[$iLineCount + 1][3] = [[1]]
    $iContext = _SetupFindFirstLine($hInfFile, "Version")
    ;; $iFieldCount = _SetupGetFieldCount($iContext)
    ;;For $i = 1 To $iFieldCount
    ;;    $sData &= _SetupGetStringField($iContext, $i - 1)
    ;;Next
    $aData[$aData[0][0]][0] = _SetupGetStringField($iContext, 0)
    $aData[$aData[0][0]][1] = _SetupGetStringField($iContext, 1)
    $aData[$aData[0][0]][2] = _SetupGetStringField($iContext, 2)
    While 1
        $iContext = _SetupFindNextLine($iContext)
        If @Error Then ExitLoop
        ;; $iFieldCount = _SetupGetFieldCount($iContext)
        ;;For $i = 1 To $iFieldCount
        ;;    $sData &= _SetupGetStringField($iContext, $i - 1)
        ;;Next
        $aData[0][0] += 1
        $aData[$aData[0][0]][0] = _SetupGetStringField($iContext, 0)
        $aData[$aData[0][0]][1] = _SetupGetStringField($iContext, 1)
        $aData[$aData[0][0]][2] = _SetupGetStringField($iContext, 2)
    WEnd
    _HeapFree($iContext)
    _HeapFree($_iContext)
EndIf
_SetupCloseInfFile($hInfFile)
$fTimerDiff = TimerDiff($fTimerDiff)
ConsoleWrite($fTimerDiff & @LF)
_ArrayDisplay($aData)

; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupOpenInfFile
; Description ...: The SetupOpenInfFile function opens an INF file and returns a handle to it.
; Syntax.........: _SetupOpenInfFile($FileName, $InfClass, $InfStyle)
; Parameters ....: $FileName - Pointer to a null-terminated string containing the name (and optional path) of the INF file to be opened.
;                    If the filename does not contain path separator characters, it is searched for, first in the %windir%\inf directory,
;                    and then in the %windir%\system32 directory. If the filename contains path separator characters, it is assumed to be
;                    a full path specification and no further processing is performed on it.
;                  $InfClass - Optional pointer to a null-terminated string containing the class of INF file desired. This string must match
;                    the Class value of the Version section (for example, Class=Net). If there is no entry in the Class value, but there is an entry
;                    for ClassGUID in the Version section, the corresponding class name for that GUID is retrieved and used for the comparison.
;                  $InfStyle - Style of INF file to open or search for. This parameter can be a combination of the following flags.
;                  |Null - $INF_STYLE_NULL
;                  |0    - $INF_STYLE_NONE
;                  |1    - $INF_STYLE_OLDNT - A legacy INF file format.
;                  |2    - $INF_STYLE_WIN4 - A Windows INF file format.
; Return values .: The function returns a handle to the opened INF file if it is successful. Otherwise, the return value is INVALID_HANDLE_VALUE. (Extended error information retrieved by _WinAPI_GetLastErrorEx.)
; Remarks .......: If the load fails because the INF file type does not match InfClass, the function returns INVALID_HANDLE_VALUE and a call to
;                   _WinAPI_GetLastErrorEx returns ERROR_CLASS_MISMATCH.
;
;                   If multiple INF file styles are specified, the style of the INF file opened can be determined by calling the SetupGetInfInformation function.
;
;                   Because there may be more than one class GUID with the same class name, callers interested in INF files of a particular class
;                   (that is, a particular class GUID) should retrieve the ClassGUID value from the INF file by calling SetupQueryInfVersionInformation.
;
;                   For legacy INF files, the InfClass string must match the type specified in the OptionType value of the Identification section
;                   in the INF file (for example, OptionType=NetAdapter).
;
; Related .......: _SetupOpenAppendInfFile, _SetupCloseInfFile, _SetupGetInfInformationEx
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupOpenInfFile($FileName, $InfClass = NULL, $InfStyle = $INF_STYLE_WIN4)
    $arDllCall = DllCall($h_SetupApiDll, "HANDLE", "SetupOpenInfFileW", "wstr", $FileName, "wstr", $InfClass, "dword", $InfStyle, "uint*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    ;If $arDllCall[0] = $ERROR_INVALID_HANDLE_VALUE Then Return SetError($arDllCall[0], $arDllCall[4], 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[4], $arDllCall[0])
EndFunc ;==>_SetupOpenInfFile


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineCount
; Description ...: The SetupGetLineCount function returns the number of lines in a specified section of an INF file.
; Syntax.........: _SetupGetLineCount($InfHandle, $Section)
; Parameters ....: $InfHandle - Handle to the INF file.
;                  $Section   - Pointer to a null-terminated string that specifies the section in which you want to count the lines.
; Return values .: If InfHandle references multiple INF files that have been appended using _SetupOpenAppendInfFile, this function returns
;                    the sum of the lines in all of the INF files containing the specified section. A return value of 0 specifies an empty section.
;                    If the section does not exist, the function returns –1 Or Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......:
; Related .......:
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineCount($InfHandle, $Section)
    $arDllCall = DllCall($h_SetupApiDll, "long", "SetupGetLineCountW", "HANDLE", $InfHandle, "wstr", $Section)
    If @Error Then Return SetError(@Error, 0, 0)
    If $arDllCall[0] > 0 Then Return SetError(0, 0, $arDllCall[0])
    Return SetError(_WinAPI_GetLastErrorEx(), 0, -1)
EndFunc    ;==>_SetupGetLineCount


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindFirstLine
; Description ...: The SetupFindFirstLine function locates a line in the specified section of an INF file. If the Key parameter is NULL, _SetupFindFirstLine returns the first line of the section.dBufferLen.
; Syntax.........: _SetupFindFirstLine($InfHandle, $Section, $Key)
; Parameters ....: $InfHandle - Handle to the INF file to query.
;                  $Section   - Pointer to a null-terminated string specifying the section of the INF files to search in.
;                  $Key       - Optional pointer to a null-terminated string specifying the key to search for within the section. The null-terminated string should not
;                    exceed the size of the destination buffer. This parameter can be NULL. If Key is NULL, the first line in the section is returned.
; Return values .: If the function could not find a line, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If the InfHandle parameter references multiple INF files that have been appended together using _SetupOpenAppendInfFile,
;                    the _SetupFindFirstLine function searches across the specified section in all of the files referenced by the specified HINF.
; Related .......: _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindFirstLine($InfHandle, $Section, $Key = NULL)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $Context = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupFindFirstLineW", "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "ptr", $Context[0])
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $Context[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[4])
EndFunc    ;==>_SetupFindFirstLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupFindNextLine
; Description ...: The SetupFindNextLine returns the location of the next line in an INF file section relative to ContextIn.Line.
; Syntax.........: _SetupFindNextLine($ContextIn)
; Parameters ....: $ContextIn - Pointer to the INF file context retrieved by a call to the _SetupFindFirstLine function.
; Return values .: If this function finds the next line, the return value is a nonzero value. Otherwise, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If ContextIn.Line references multiple INF files that have been appended together using SetupOpenAppendInfFile, this function searches across
;                    the specified section in all files referenced by the HINF to locate the next line.
; Related .......: _SetupFindFirstLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupFindNextLine($ContextIn)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    Local $ContextOut = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupFindNextLine", "ptr", $ContextIn, "ptr", $ContextOut[0])
    If @Error Or Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $ContextOut[0]), 0)
    Return SetError(0, $arDllCall[0], $arDllCall[2])
EndFunc    ;==>_SetupFindNextLine


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineByIndex
; Description ...: The SetupGetLineByIndex function locates a line by its index value in the specified section in the INF file.
; Syntax.........: _SetupGetLineByIndex($InfHandle, $Section, $Index)
; Parameters ....: $InfHandle - Handle to the INF file.
;                  $Section   - Pointer to a null-terminated string specifying the section of the INF file to search.
;                   $Index     - Index of the line to be located. The total number of lines in a particular section can be found with a call to _SetupGetLineCount.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx.
; Remarks .......: If InfHandle references multiple INF files that have been appended together using _SetupOpenAppendInfFile, this function searches across
;                    the specified section in all files referenced by the HINF to locate the indexed line.
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineByIndex($InfHandle, $Section, $Index)
    If Not $ProcessHeap[0] Then $ProcessHeap = DllCall($h_Kernel32DLL, "HANDLE", "GetProcessHeap")    ;;;    $ProcessHeap = DllCall('kernel32.dll', 'ptr', 'HeapCreate', 'dword', 0, 'ulong_ptr', 0, 'ulong_ptr', 0)
    $Context = DllCall($h_Kernel32DLL, "ptr", "HeapAlloc", "hWnd", $ProcessHeap[0], "dword", 8, "dword", 16)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetLineByIndexW", "HANDLE", $InfHandle, "wstr", $Section, "dword", $Index, "ptr", $Context[0])
    If @Error Or Not $arDllCall[0] Then SetError(_WinAPI_GetLastErrorEx(), DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $Context[0]), 0)
    Return SetError(0, 0, $Context[0])
EndFunc    ;==>_SetupGetLineByIndex


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetStringField
; Description ...: The SetupGetStringField function retrieves a string from the specified field of a line in an INF file.
; Syntax.........: _SetupGetStringField($Context, $FieldIndex, $ReturnBufferSize)
; Parameters ....: $Context    - Pointer to the context for a line in an INF file.
;                  $FieldIndex - The 1-based index of the field within the specified line from which the string should be retrieved. Use a FieldIndex of 0 to retrieve a string key, if present.
;                  $ReturnBufferSize - Size of the buffer pointed to by ReturnBuffer, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size needed to hold the
;                    specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value. Otherwise,
;                    the return value is zero and extended error information can be obtained by calling GetLastError. You can call the function once to get the
;                    required buffer size, allocate the necessary memory, and then call the function a second time to retrieve the data. Using this technique,
;                    you can avoid errors due to an insufficient buffer size.
;
;                  Note that the maximum length of any single string specified in an INF Strings section is 512 characters, including the terminating NULL. If the
;                    string length is greater than 512 it will be truncated and no error will be returned. The maximum length of any concatenated string created from
;                    one or more %strkey% tokens is 4096 characters.
;
; Related .......: _SetupGetIntField, _SetupGetBinaryField, _SetupGetMultiSzField
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetStringField($Context, $FieldIndex = 0, $ReturnBufferSize = 65535)
     ;;Local $arDllCall, $RBuffer = DllStructCreate("wchar")
    ;;$arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", DllStructGetPtr($RBuffer), "dword", $ReturnBufferSize, "dword*", 0)
    $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($h_SetupApiDll, "BOOL", "SetupGetStringFieldW", "ptr", $Context, "dword", $FieldIndex, "wstr", "", "dword", $arDllCall[5], "dword*", 0)
    Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[5], $arDllCall[3])
EndFunc    ;==>_SetupGetStringField


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetLineText
; Description ...: The SetupGetLineText function returns the contents of a line in an INF file in a compact form. The line to retrieve can be specified by an
;                    INFCONTEXT structure returned from a SetupFindLineXXX function, or by explicitly passing in the INF handle, section, and key of the desired line.
; Syntax.........: _SetupGetLineText($Context, $InfHandle, $Section, $Key, $ReturnBufferSize)
; Parameters ....: $Context   - Context for a line in an INF file whose text is to be retrieved. This parameter can be NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $InfHandle - Handle to the INF file to query. This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must all be specified.
;                  $Section   - Pointer to a null-terminated string that specifies the section that contains the key name of the line whose text is to be retrieved.
;                    This parameter can be NULL. This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                  $Key       - Pointer to a null-terminated string that contains the key name whose associated string is to be retrieved. This parameter can be NULL.
;                    This parameter is used only if Context is NULL. If Context is NULL, InfHandle, Section, and Key must be specified.
;                  $ReturnBufferSize - Size of the buffer pointed to by the ReturnBuffer parameter, in characters. This includes the null terminator.
; Return values .: If the function succeeds, the return value is a nonzero value.
;                    If the function fails, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......: If this function is called with a ReturnBuffer of NULL and a ReturnBufferSize of zero, the function puts the buffer size required to hold
;                  the specified data into the variable pointed to by RequiredSize. If the function succeeds in this, the return value is a nonzero value.
;                  Otherwise, the return value is zero and extended error information can be obtained by calling GetLastError.
;
;                  This function returns the contents of a line in a compact format. All extraneous white space is removed and multi-line values are converted
;                  into a single contiguous string. For example, this line:
;
;                    HKLM, , PointerClass0, 1 \
;                    ; This is a comment
;                    01, 02, 03
;
;                  would be returned as:
;
;                   HKLM,,PointerClass0,1,01,02,03
;
; Related .......: _SetupFindFirstLine, _SetupFindNextLine, _SetupFindNextMatchLine, _SetupGetLineByIndex
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetLineText($Context = 0, $InfHandle = 0, $Section = NULL, $Key = NULL, $ReturnBufferSize = 65535) ;;    4194303 = 4 MB
    $arDllCall = DllCall($h_SetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "HANDLE", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $ReturnBufferSize, "dword*", 0)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] And _WinAPI_GetLastErrorEx() = $ERROR_INSUFFICIENT_BUFFER Then $arDllCall = DllCall($h_SetupApiDll, "int", "SetupGetLineTextW", "ptr", $Context, "long", $InfHandle, "wstr", $Section, "wstr", $Key, "wstr", "", "dword", $arDllCall[7], "dword*", 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), $arDllCall[0], "")
    Return SetError(0, $arDllCall[7], $arDllCall[5])
EndFunc ;==>_SetupGetLineText


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupGetFieldCount
; Description ...: The SetupGetFieldCount function retrieves the number of fields in the specified line in an INF file.
; Syntax.........: _SetupGetFieldCount($Context)
; Parameters ....: $Context - Pointer to the context for a line in an INF file.
; Return values .: This function returns the number of fields on the line. If Context is invalid, the return value is zero & Extended error information retrieved by _WinAPI_GetLastErrorEx
; Remarks .......:
; Related .......: _SetupGetLineCount
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupGetFieldCount($Context)
    $arDllCall = DllCall($h_SetupApiDll, "DWORD", "SetupGetFieldCount", "ptr", $Context)
    If @Error Then Return SetError(@Error, 0, 0)
    If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 0, 0)
    Return SetError(0, 0, $arDllCall[0])
EndFunc ;==>_SetupGetFieldCount


; #FUNCTION# ==============================================================================================================================================
; Name...........: _SetupCloseInfFile
; Description ...: The SetupCloseInfFile function closes the INF file opened by a call to SetupOpenInfFile. This function closes any INF files appended to it by calling SetupOpenAppendInfFile.
; Syntax.........: _SetupCloseInfFile($InfHandle)
; Parameters ....: $InfHandle - Handle to the INF file to be closed.
; Return values .: This function does not return a value.
; Remarks .......: Because _SetupGetFileCompressionInfoEx determines the compression by examining the physical file, your setup application should ensure that the file is present before calling _SetupGetFileCompressionInfoEx.
; Related .......: _SetupOpenInfFile, _SetupOpenAppendInfFile
; Author ........: DXRW4E
; =========================================================================================================================================================
Func _SetupCloseInfFile($InfHandle)
    DllCall($h_SetupApiDll, "none", "SetupCloseInfFile", "HANDLE", $InfHandle)
EndFunc    ;==>_SetupCloseInfFile


Func _WinAPI_GetLastErrorEx()
    Local $arDllCall = DllCall($h_Kernel32DLL, "long", "GetLastError")
    Return $arDllCall[0]
EndFunc ;==>_WinAPI_GetLastErrorEx

Func _HeapFree(ByRef $pMem)
    If Not $ProcessHeap[0] Or $pMem < 1 Then Return SetError(1, 0, 0)
    $arDllCall = DllCall($h_Kernel32DLL, "int", "HeapFree", "hWnd", $ProcessHeap[0], "dword", 0, "ptr", $pMem)
    If (@error) Or (Not $arDllCall[0]) Then Return SetError(2, 0, 0)
    $pMem = 0
    Return 1
EndFunc   ;==>_HeapFree

Ciao.

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Posted (edited)

Got it installed. Compiled the last script in post #19, 32 and 64 bits, AutoIt 3.3.10.2.

32 bits binary work as expected, the 64 bits returns empty array...

The 64 bits version does the same when run under WinPE environment.

Windows is 8.1 x64 Enterprise Eval.

Installing AutoIt on this test virtual machine, will get back later when have more results.

Any ideas are welcome.

post-36197-0-67830400-1394416879_thumb.j

Script in post #18 does the same- ok in 32 bit mode, error 6 in 64 bits in _SetupGetLineCount.

Edit:

It seems in 32 bit mode the handle returned by SetupOpenInfFile is 8 digits, in 64 bits it's 9, maybe helps.

Edited by ilko

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...