Drivercab Helper (AutoIT3 example)

May 3, 2008 at 9:23 pm | Posted in AutoIT3 | 1 Comment

This is a utility I wrote that works in conjunction with HFSLIP to slipstream additional drivers into a Windows 2000 or XP install. My announcement thread on MSFN has instructions and a screen shot. It is written in AutoIT3, which is similar to modern BASIC. The GUI work was done in Koda form designer.

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
; Drivercab Helper
; Version 1.2
; by David Eason

; Thanks to (in no order)
; TommyP and Tomcat76 for HFSLIP
; Tim Fehlman for sample code described in "Folder Recursion in Autoit" at http://dailycupoftech.com/folder-recursion-in-autoit/
; Lookfar, LazyCat, and JosBe for Koda Form Designer for AutoIt
; Jon Bennett for Autoit3 and adding Unicode support for version v3.2.4.0

; Requires Autoit v3.2.4.0 build to compile due to Unicode support

; History
; 1.1 First  version ;)
; 1.2 Added support for Unicode .INF files

#include <guiconstants .au3>
#include <file .au3>

If @AutoItVersion < "3.2.4.0" Then
	MsgBox(0, "Version Check", "This AutoIt script requires v.3.2.4.0 or later")
	Exit 1
EndIf

If @Unicode <> 1 Then
	MsgBox(0, "Unicode Check", "This AutoIt script requires the Unicode build")
	Exit 2
EndIf

; Globals
Dim $SourceFolder, $DestFolder, $StopProcessingFiles, $dir

#Region ### START Koda GUI section ### Form=d:\drivercabhelper\aform1.kxf
$Form1_1 = GUICreate("Drivercab Helper 1.1 for HFSLIP", 591, 507, 229, 78)
$Group1 = GUICtrlCreateGroup("Log", 13, 189, 560, 299)
$Edit1 = GUICtrlCreateEdit("", 26, 209, 534, 267, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $ES_READONLY, $ES_WANTRETURN, $WS_HSCROLL, $WS_VSCROLL))
GUICtrlSetData(-1, "")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group2 = GUICtrlCreateGroup("&Folders", 13, 20, 560, 117)
$Input1 = GUICtrlCreateInput("", 137, 40, 361, 21)
GUICtrlSetTip(-1, "Specify the folder containing existing INF files and driver files")
$Button1 = GUICtrlCreateButton("...", 512, 40, 36, 20, 0)
$Label1 = GUICtrlCreateLabel("&Source folder:", 33, 46, 76, 17)
$Input2 = GUICtrlCreateInput("", 137, 85, 361, 21)
GUICtrlSetTip(-1, "Specify the folder to be deleted and populated with modified INF files and existing driver files")
$Button2 = GUICtrlCreateButton("...", 512, 85, 36, 20, 0)
$Label2 = GUICtrlCreateLabel("&Destination folder:", 33, 85, 95, 17)
$Label3 = GUICtrlCreateLabel("Destination folder will be deleted and overwritten", 137, 111, 282, 17)
GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Button3 = GUICtrlCreateButton("Delete and &regenerate destination folder now!", 253, 150, 297, 20, 0)
$Label4 = GUICtrlCreateLabel("&ISOTITLE", 32, 152, 58, 17)
$Input3 = GUICtrlCreateInput("HFSLIPCD", 88, 152, 121, 21)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

If $CmdLine[0] > 0 Then
	GUICtrlSetData($Input1, $CmdLine[1])
EndIf

If $CmdLine[0] > 1 Then
	GUICtrlSetData($Input2, $CmdLine[2])
EndIf

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $Button1
			$dir = FileSelectFolder("Source folder", "", 6)
			If @error = 0 Then
				GUICtrlSetData($Input1, $dir)
			EndIf
		Case $Button2
			$dir = FileSelectFolder("Destination folder (will be overwritten)", "", 7)
			If @error = 0 Then
				GUICtrlSetData($Input2, $dir)
			EndIf
		Case $Button3
			If StringStripWS(GUICtrlRead($Input3), 1) = "" Then
				GUICtrlSetData($Input3, "HFSLIPCD")
			EndIf
			$IsoTitle = GUICtrlRead($Input3)
			$CabLine = '1 = "' & $IsoTitle & '",driver.cab,,"\I386"'
			$SourceFolder = GUICtrlRead($Input1)
			$DestFolder = GUICtrlRead($Input2)
			If ValidateFolders($SourceFolder, $DestFolder) Then
				$StopProcessingFiles = False
				DirRemove($DestFolder, 1)
				ScanFolder($SourceFolder, $DestFolder)
				If Not $StopProcessingFiles Then
					LogToWindow('Completed reading "' & $SourceFolder & '" and writing "' & $DestFolder & '".')
					MsgBox(262144, "Drivercab Helper", "Drivercab Helper has finished.")
				EndIf
			EndIf
	EndSwitch
WEnd


Func ValidateFolders($SourceFolder, $DestFolder)

	If StringRight($SourceFolder, 1) = "\" Or StringRight($SourceFolder, 1) = "/" Then
		$SourceFolder = StringLeft($SourceFolder, StringLen($SourceFolder) - 1)
		GUICtrlSetData($Input1, $SourceFolder)
	EndIf

	If StringRight($DestFolder, 1) = "\" Or StringRight($SourceFolder, 1) = "/" Then
		$SourceFolder = StringLeft($DestFolder, StringLen($DestFolder) - 1)
		GUICtrlSetData($Input2, $DestFolder)
	EndIf

	If $SourceFolder = "" Then
		ShowError('Please specify a source folder.')
		Return False
	EndIf

	If _PathFull($SourceFolder) <> $SourceFolder Then
		ShowError('Source folder "' & $SourceFolder & '" cannot be a relative path.')
		Return False
	EndIf

	; Source folder must exist
	If DirGetSize($SourceFolder) = -1 Then
		ShowError('Source folder "' & $SourceFolder & '"does not exist.')
		Return False
	EndIf


	If $DestFolder = "" Then
		ShowError('Please specify a destination folder.')
		Return False
	EndIf

	If _PathFull($DestFolder) <> $DestFolder Then
		ShowError('Destination folder "' & $DestFolder & '" cannot be a relative path.')
		Return False
	EndIf

	If DirGetSize($DestFolder) <> -1 Then
		LogToWindow('Destination folder "' & $DestFolder & '"exists and will be overwritten.')
		; not an error
	EndIf

	If StringInStr($SourceFolder, $DestFolder) > 0 Then
		ShowError('Destination folder "' & $DestFolder & '" must not contain source folder "' & $SourceFolder & '".')
		Return False
	EndIf


	Return True
EndFunc   ;==>ValidateFolders

Func LogToWindow($s)
	GUICtrlSetData($Edit1, $s & @CRLF, 1)
EndFunc   ;==>LogToWindow

Func ModifyInfFile($SourceFileName, $DestFileName)

	Local $line, $comment, $in_sourcedisksfiles, $section_name_this_line
	Local $comment_pos, $equals_pos, $left_bracket_pos, $right_bracket_pos
	Local $BOMCheck

	$BOMCheck = _BOMCheck($SourceFileName)

	If $BOMCheck = -1 Then
		ShowError('Unable to determine if "' & $SourceFileName & '" is ANSI or Unicode.')
		Return False
	EndIf

	$SourceInfFile = FileOpen($SourceFileName, 0) ;Read

	If $SourceInfFile = -1 Then
		ShowError('Unable to open file "' & $SourceFileName & '" for reading.')
		Return False
	EndIf


	$DestInfFile = FileOpen($DestFileName, 10 + $BOMCheck)  ; Erase + Write + Unicode Mode

	If $DestInfFile = -1 Then
		ShowError('Unable to open file "' & $DestFileName & '" for writing.')
		FileClose($SourceInfFile)
		Return False
	EndIf

	LogToWindow('Reading ' & '"' & $SourceFileName & '",' & @CRLF & 'Writing "' & $DestFileName & '".')

	$in_sourcedisksfiles = False
	$line_num = 0
	While 1
		$line = FileReadLine($SourceInfFile)
		If @error = -1 Then ExitLoop
		$line_num = $line_num + 1
		$comment_pos = StringInStr($line, ";")
		If $comment_pos > 0 Then
			$comment = StringMid($line, $comment_pos, StringLen($line))
			$line = StringLeft($line, $comment_pos - 1)
		Else
			$comment = ""
		EndIf

		StringStripWS($line, 8)
		$left_bracket_pos = StringInStr($line, "[")
		If $left_bracket_pos > 0 Then
			$right_bracket_pos = StringInStr($line, "]")
			$section_name_this_line = StringMid($line, $left_bracket_pos, $right_bracket_pos)
			$section_name = $section_name_this_line;
			Switch StringUpper($section_name_this_line)
				Case "[SOURCEDISKSNAMES]", "[SOURCEDISKSNAMES.X86]", "[SOURCEDISKSNAMES.X64]"
					FileWriteLine($DestInfFile, $line & $comment)
					FileWriteLine($DestInfFile, $CabLine)
					LogToWindow($SourceFileName & '(' & $line_num & '): Inserted "' & $CabLine & '" in section "' & $section_name & '".')
					$in_sourcedisksfiles = False
				Case "[SOURCEDISKSFILES]"
					FileWriteLine($DestInfFile, $line & $comment)
					$in_sourcedisksfiles = True
				Case Else
					;Still a section header
					FileWriteLine($DestInfFile, $line & $comment)
					$in_sourcedisksfiles = False
			EndSwitch
		Else
			;Not a section header
			If $in_sourcedisksfiles = True Then
				$equals_pos = StringInStr($line, "=", 0, -1)
				If $equals_pos > 0 Then
					$old_line = $line
					$line = StringLeft($line, $equals_pos) & "1"
					LogToWindow($SourceFileName & '(' & $line_num & '):  Changed "' & $old_line & '" to "' & $line & '" in section "' & $section_name & '".')
				EndIf
			EndIf
			FileWriteLine($DestInfFile, $line & $comment)
		EndIf
		$section_name_this_line = "";
	WEnd

	
	FileClose($SourceInfFile)
	FileClose($DestInfFile)
	Return True
EndFunc   ;==>ModifyInfFile

Func ScanFolder($SourceFolder, $DestFolder)

	If $StopProcessingFiles Then
		Return
	EndIf

	Local $Search
	Local $File
	Local $FileAttributes
	Local $SourceFullFilePath
	Local $DestFullFilePath

	$Search = FileFindFirstFile($SourceFolder & "\*.*")

	While Not $StopProcessingFiles
		If $Search = -1 Then
			ExitLoop
		EndIf

		$File = FileFindNextFile($Search)
		If @error Then ExitLoop

		$SourceFullFilePath = $SourceFolder & "\" & $File
		$DestFullFilePath = $DestFolder & "\" & $File
		$FileAttributes = FileGetAttrib($SourceFullFilePath)

		If StringInStr($FileAttributes, "D") Then
			ScanFolder($SourceFullFilePath, $DestFullFilePath)
		Else
			LogFile($SourceFullFilePath, $DestFullFilePath)
		EndIf

	WEnd

	FileClose($Search)
EndFunc   ;==>ScanFolder

Func LogFile($SourceFileName, $DestFileName)
	If StringLen($SourceFileName) >= 4 And StringUpper(StringRight($SourceFileName, 4)) = ".INF" Then
		If Not ModifyInfFile($SourceFileName, $DestFileName) Then
			$StopProcessingFiles = True
		EndIf
	Else
		$FCStatus = FileCopy($SourceFileName, $DestFileName, 8)
		If $FCStatus = 1 Then
			LogToWindow('Copied "' & $SourceFileName & '" to "' & $DestFileName & '".')
		Else
			ShowError('Unable to copy "' & $SourceFileName & '" to "' & $DestFileName & '".')
			$StopProcessingFiles = True
		EndIf
	EndIf
EndFunc   ;==>LogFile

Func ShowError($ErrStr)
	MsgBox(16, "Error", $ErrStr)
EndFunc   ;==>ShowError




; Function Name:   _BOMCheck()
;
; Description:     Determines whether a given file is ANSI,
;                  UTF-16 Little Endian, UTF-16 Big Endian, or UTF-8
;
; Syntax:          _BOMCheck ( $filename )
;
; Parameter(s):    $filename   = The file to check

;
; Requirement(s):  Must be Unicode build of AutoIt v3.2.4.0 or later.
;
; Return Value(s): ANSI or Unsupported:    Returns 0
;                  UTF-16 Little Endian:   Returns 32
;                  UTF-16 Big Endian:      Returns 64
;                  UTF-8:                  Returns 128
;                  Problem opening file:   Returns -1
;                  The general idea with the return value is that it can
;                  be used in the calculation of the FileOpen mode


; Author:          David Eason

; Sample usage:
; While 1
;     Local $file = FileOpenDialog("Choose file", @DesktopDir & "\", "Text files (*.txt;*.inf)", 3)
;     if @error = 1 Then ExitLoop
;     MsgBox(0,"", _BOMCheck($file))
; Wend



Func _BOMCheck(ByRef $filename)

	; Supported Byte Order Markers for non-ANSI
	Local $BOMS[3]
	$BOMS[0] = Binary("0xFFFE")     ;UTF-16 Little Endian
	$BOMS[1] = Binary("0xFEFF")     ;UTF-16 Big Endian
	$BOMS[2] = Binary("0xEFBBBF")   ;UTF-8

	; Corresponding mode bit for FileOpen
	Local $FileModes[3]
	$FileModes[0] = 32
	$FileModes[1] = 64
	$FileModes[2] = 128

	Local $FH = FileOpen($filename, 4)

	If $FH = -1 Then
		Return -1
	EndIf
	Local $FirstBytes = FileRead($FH, 3)

	If @error = -1 Then
		FileClose($FH)
		Return -1
	EndIf

	Local $I
	For $I = 0 To 2
		If BinaryMid($FirstBytes, 1, BinaryLen($BOMS[$I])) = BinaryMid($BOMS[$I], 1, BinaryLen($BOMS[$I])) Then
			FileClose($FH)
			Return $FileModes[$I]
		EndIf
	Next

	; If still here, then it is presumed ANSI
	FileClose($FH)
	Return 0

EndFunc   ;==>_BOMCheck

Create a free website or blog at WordPress.com.
Entries and comments feeds.