benners Posted May 2, 2009 Share Posted May 2, 2009 I have converted a vbs script to AutoIt for a program that I have written. I am having a problem where some users encounter an AutoIt error which I myself cannot reproduce. The code works for other users and myself but for some reason exits with the error "Line -1: Error: Error in expression" with a small percentage of users.I with the logging function of the program I have tracked the problem to the line $session = $Installer.OpenPackage($DB). I would appreciate if someone could explain where I am going wrong or how to improve the code. With the vbs there is a call to an error checking function (: CheckError) after the command but I don't know how to replicate this. What I have done is add the line Global $oMyError = ObjEvent('AutoIt.Error', 'ComErrorHandler') which just sets $COM_Err = 1 and then a check is done for the value. I don't know if this is the best way (It obviously doesn't help with the current error) or if works for all of the code but as I have said previously I have no problems so I cannot track it down.My function is below. It is not a complete conversion as some features are not required.expandcollapse popupFunc DI_UpdateCabs10($iembedCab = 0, $imakeCab = 1, $iupdateMsi = 1, $isequenceFile = 0, $scompressType = 'LZX') Local $Installer, $DB, $View, $Record, $updateMode, $SumInfo, $sequence, $lastSequence, $session, $shortNames, $sorderBy, $COM_Err = 0 Local $fileKey, $fileName, $sequence, $folder, $delim, $attributes, $sourcePath Local $sOldFile, $sFile, $sNum, $iwCount, $oldPT, $msg Local $msiOpenDatabaseModeReadOnly = 0 Local $msiOpenDatabaseModeTransact = 1 Local $msiViewModifyInsert = 1 Local $msiViewModifyUpdate = 2 Local $msiViewModifyAssign = 3 Local $msiUILevelNone = 2 Local $msiRunModeSourceShortNames = 9 Local $msidbFileAttributesNoncompressed = 8192 $oldPT = $Proc_Title; Save the previous function process title. $Proc_Title = 'Rebuilding Cabinet File'; Set the process title. Log_Progress(0); Reset the progress bar. Log_Banner(0, $Proc_Title); Create a header for the process Log_Labels_Update('', 'Processing...', 'Retrieving cabinet info') $ssourceFolder = $Destination; Use the default destination. If DirGetSize($ssourceFolder) > 0 Then; If the Dir is not empty. If StringRight($ssourceFolder, 1) <> '\' Then $ssourceFolder &= '\'; Check for and add a '\' $session.Property("OriginalDatabase") = $ssourceFolder & '\'; Set the path to the MSI file. Else; Folder is empty. Log_Fatal('There are no files in the Source Folder: ' & $ssourceFolder, '', '', $ssourceFolder & ' is empty', $Proc_Title) Return 1 EndIf $sdatabasePath = $ssourceFolder & $MSI; Set the location of the MSI. Local $cabFile = Msi_GetProperty($sdatabasePath, 'Cabinet', 'Media', 'DiskId', 1, 1); Get the cabinet name from the MSI. If $COM_Err Then Return 1; Error returned from getting cabfile. If StringLeft($cabFile, 1) = '#' Then $cabFile = StringReplace($cabFile, '#', ''); Trim the hash if cab file is embedded' Local $baseName = StringTrimRight($cabFile, 4) Local $DDF = $ssourceFolder & $baseName & '.ddf' Local $scabName = $cabFile If $iembedCab Then $scabName = '#' & $scabName; Add the # for embedded cabs. If $iupdateMsi Or $isequenceFile Then; If updating the MSI or re sequencing the file order. $iopenMode = $msiOpenDatabaseModeTransact; Open in write mode. Else $iopenMode = $msiOpenDatabaseModeReadOnly; Open in read mode. EndIf Log_Update('Database Path: ' & $sdatabasePath & '¦Source Folder: ' & $ssourceFolder & '¦Cabinet File : ' & $cabFile & '¦Base Name : ' & $baseName & '¦DDF File name: ' & $baseName & '.ddf' & '¦¦Compress Type: ' & $scompressType & '¦MakeCab : ' & _ $imakeCab & '¦Embed Cab : ' & $iembedCab & '¦Update MSI : ' & $iupdateMsi & '¦Sequence File: ' & $isequenceFile & '¦¦Working Hard' & '...¦') $iwCount = MSI_SummaryInfo($sdatabasePath, 15); Get the compressed bit of the package (Expecting 2 (Compressed source files using long file name) or 3 (Compressed source files using short file names). Log_Update('Retrieving Compressed Bit: ' & $iwCount) Log_Update('Updating Compressed Bit : ' & ($iwCount + 2)) If MSI_SummaryInfo($sdatabasePath, 15, ($iwCount + 2), 1) = 1 Then Return; Change the compressed bit to the correct type of source file (Administrative image + long or short file names) Log_Update('Creating COM object : 1') $Installer = ObjCreate("WindowsInstaller.Installer"); Create a reference to the Windows Installer COM. If Not IsObj($Installer) Then; Problem creating the COM object. $msg = 'Unable to create the WindowsInstaller COM object' $COM_Err = 1; Manually set the COM_Err. Else Log_Update('Opening database : 1') $DB = $Installer.OpenDatabase($sdatabasePath, $iopenMode); Open database. If $COM_Err Then; Problem opening the MSI $msg = 'Unable to open file (' & $sdatabasePath & ') in Read mode' Else; Create an install session and execute actions in order to perform directory resolution Log_Update('Setting UILevel : Silent') $Installer.UILevel = $msiUILevelNone; Set UI level of the installer to silent (msiUILevelNone). Log_Update('Opening installer package: 1') $session = $Installer.OpenPackage($DB) If $COM_Err Then; Problem starting a session. $msg = 'Database: ' & $sdatabasePath & ' Invalid installer package format' Else Log_Update('Setting Source files : Short Names') $shortNames = $session.Mode($msiRunModeSourceShortNames); Set the mode property of the the session to Source files use only short file names (msiRunModeSourceShortNames). $session.Property("OriginalDatabase") = $ssourceFolder $stat = $session.DoAction("CostInitialize"); Run the CostInitialize action for the MSI. Log_Update('Running CostInitialize : ' & $stat) If ($COM_Err) Or ($stat <> 1) Then $msg = 'A problem occurred during CostInitialize' $COM_Err = 1; Manually set the COM_Err. Else $lastSequence = 0 If $isequenceFile Then; If re sequencing check for non-cabinet files to avoid sequence number collisions $sorderBy = 'Directory_'; Order by Directory. Log_Update('Resequencing by : Directory') $View = $DB.OpenView('SELECT Sequence, Attributes FROM File') If $COM_Err Then; Error occured opening the view. $msg = 'Unable to query the File Table' Else $View.Execute; Execute the query. If $COM_Err Then; Error occured opening the view. $msg = 'Unable to execute the view' Else While 1 $Record = $View.fetch If Not IsObj($Record) Then ExitLoop; No more records. $sequence = $Record.IntegerData(1); Set the sequence number. If BitAND($Record.IntegerData(2), $msidbFileAttributesNoncompressed) <> 0 And $sequence > $lastSequence Then $lastSequence = $sequence WEnd EndIf EndIf Else; Not resequencing. Log_Update('Resequencing by : Sequence') $sorderBy = 'Sequence'; Order by Sequence. EndIf $View.Close; Close the view. $View = $DB.OpenView("SELECT File, FileName, Directory_, Sequence, File.Attributes FROM File, Component WHERE Component_= Component ORDER BY " & $sorderBy) If $COM_Err Then; Error occured opening the view. $msg = 'Unable to query the File Table' Else $View.Execute; Execute the query. If $COM_Err Then; Error occured opening the view. $msg = 'Unable to execute the view' Else Log_Update('Creating DDF File : ' & $DDF) Log_Labels_Update('', 'Creating DDF file', $DDF); 'Direct Integration' & 'Creating DDF file' | 'DDF file name' If Not FileExists($DDF) Then; Create DDF file and write header properties $file = FileOpen($DDF, 1); Open in write mode and append text. If $file = -1 Then; Unable to create and open file. $COM_Err += 1 $msg = 'Unable to open ' & $DDF & ' in write mode' Log_Fatal($msg, '', '', $msg, $Proc_Title); If COM error stop the process. Return $COM_Err Else; Opened OK Write DDF header information. FileWriteLine($file, '; Generated from ' & $sdatabasePath & ' on ' & @YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC) FileWriteLine($file, '.Set CabinetNameTemplate=' & $baseName & '*.CAB') FileWriteLine($file, '.Set CabinetName1=' & $cabFile) FileWriteLine($file, '.Set ReservePerCabinetSize=8') FileWriteLine($file, '.Set MaxDiskSize=CDROM') FileWriteLine($file, '.Set CompressionType=' & $scompressType) FileWriteLine($file, '.Set InfFileLineFormat=(*disk#*) *file#*: *file* = *Size*') FileWriteLine($file, '.Set InfFileName=' & $baseName & '.INF') FileWriteLine($file, '.Set RptFileName=' & $baseName & '.RPT') FileWriteLine($file, '.Set InfHeader=') FileWriteLine($file, '.Set InfFooter=') FileWriteLine($file, '.Set DiskDirectoryTemplate=.') FileWriteLine($file, '.Set Compress=ON') FileWriteLine($file, '.Set Cabinet=ON') EndIf Else $file = FileOpen($DDF, 1); Open in write mode and append text. EndIf While 1; Fetch each file and request the source path, then verify the source path $Record = $View.Fetch If Not IsObj($Record) Then ExitLoop $fileKey = $Record.StringData(1); Info from File Column. $fileName = $Record.StringData(2); info from FileName column. $folder = $Record.StringData(3); Folder location of the file. $sequence = $Record.IntegerData(4); Sequence number of the file. $attributes = $Record.IntegerData(5); Files attributes. If BitAND($attributes, $msidbFileAttributesNoncompressed) = 0 Then If $sequence <= $lastSequence Then If Not $isequenceFile Then; Files need resequencing. Log_Fatal('Files exist with same sequence numbers. Select to sequence files', '', '', 'Files need resequencing but its not selected', $Proc_Title) Return 1 Else; Files don't need resequencing. $sequence = $lastSequence + 1 $Record.IntegerData(4) = $sequence $View.Modify($msiViewModifyUpdate, $Record) EndIf EndIf $lastSequence = $sequence; Set the last sequence. $delim = StringInStr($fileName, "|"); Check for pipe delimiter in filename. If $delim Then If $shortNames Then $fileName = StringLeft($fileName, $delim - 1) ;Log_update('shortnames ' & $fileName) Else $fileName = StringRight($fileName, StringLen($fileName) - $delim) ;Log_update('longnames ' & $fileName) EndIf EndIf $sourcePath = $session.SourcePath($folder) & $fileName; Get the session folder ;Log_update('source path ' & $sourcePath) If Not FileExists($sourcePath) Then; Check for file. Log_Fatal($sourcePath & ' does not exist', '', '', $sourcePath & ' was not found') FileClose($file); Close the DDF file. Return 1 EndIf FileWriteLine($file, """" & $sourcePath & """" & " " & $fileKey); Write the file to the ddf file. EndIf WEnd FileClose($file); Close the DDF file. If $imakeCab Then; If selected for recabbing. Log_Update('Rebuilding cabinet file : ' & $cabFile) Log_Labels_Update('Rebuilding ' & $cabFile, '(?/?)', 'Current File:'); 'Direct Integration' & 'Updating Cabs' | 'Recompressing Cabinet Files' $Runstring = 'MakeCab.exe /f ' & $baseName & '.DDF' Log_Update('Command Line : ' & $Runstring & '¦') ;$Run = Run(@ComSpec & ' /c ' & $Runstring, $ssourceFolder, @SW_HIDE, $STDOUT_CHILD); Generate compressed file cabinet. $Run = Run($Runstring, $ssourceFolder, @SW_HIDE, $STDOUT_CHILD); Generate compressed file cabinet. $sOldFile = '' While ProcessExists($Run) $line1 = StdoutRead($Run); Read the output stream. If $line1 <> '' Then; If the output is not blank. $newLine = StringSplit($line1, @CR); Split the returned stream. $sStr = $newLine[(UBound($newLine) - 1) - 1]; Get the 2nd to last line. #cs If StringInStr($sStr, 'flushing current folder') Then GUICtrlSetData($Log_msg_lbl, 'Flushing current folder') GUICtrlSetData($Log_Action_lbl, 'Cleaning Up...') EndIf #ce $sFile = _StringBetween($sStr, '- ', ' ('); Split to get the file name. Log_Progress(StringMid($sStr, 1, (StringInStr($sStr, '%')) - 1)); Update the progress bar. If Not IsArray($sFile) Or ($sFile[0] = $sOldFile) Then; File name is the same. Else; Different file name. $sNum = _StringBetween($sStr, '(', ')'); Get the file count from the string. If IsArray($sNum) Then GUICtrlSetData($Log_Action_lbl, '(' & $sNum[0] & ')'); If found then update the actions label. GUICtrlSetData($Log_msg_lbl, 'Current File: ' & $sFile[0]); Update the log message label. $sOldFile = $sFile[0]; Set the old file name to the new one. EndIf EndIf Sleep(1) WEnd Log_Progress(100) EndIf If $iupdateMsi Then; Update MSI is selected. $View = $DB.OpenView("SELECT DiskId, LastSequence, Cabinet FROM Media ORDER BY DiskId") If $COM_Err Then $msg = 'Update MSI: Unable to query the database ' & $sdatabasePath Else $View.Execute; Execute the SQL query. If $COM_Err Then $msg = 'Update MSI: Unable to execute the query on database ' & $sdatabasePath Else $updateMode = $msiViewModifyUpdate $Record = $View.Fetch If Not IsObj($Record) Then; Media table empty $Record = $Installer.CreateRecord(3); Create a new record with 3 fields. $Record.IntegerData(1) = 1; Set the number of cabinets. $updateMode = $msiViewModifyInsert EndIf $Record.IntegerData(2) = $lastSequence; Update the Media table LastSequence column with the cabinet name. $Record.StringData(3) = $scabName; Update the Media table Cabinet column with the cabinet name. $View.Modify($updateMode, $Record); Modify the media $SumInfo = $DB.SummaryInformation(3); Set the max number of proerties to be modified. ;$sumInfo.Property(11) = @YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC ;$sumInfo.Property(13) = @YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC $SumInfo.Property(15) = BitAND($shortNames, 1) + 2; Reset Word Count summary to "Compressed source files using short\long file names" setup will error if not. $SumInfo.Persist(); Formats and writes the previously stored properties into the standard summary information stream. $DB.Commit; Commit database in case updates performed EndIf EndIf EndIf If $iembedCab Then; Embed the cabinet $View = $DB.OpenView("SELECT `Name`,`Data` FROM _Streams") If $COM_Err Then; Error occured openi $msg = 'Embed Cab: Unable to retrieve a view object from the database ' & $sdatabasePath Else $Record = $Installer.CreateRecord(2) $Record.StringData(1) = $cabFile $Record.SetStream(2, $ssourceFolder & $cabFile); Copy the cab into the stream. If $COM_Err Then $msg = 'Embed Cab: Unable to copy the cab file into the record stream' Else $View.Modify($msiViewModifyAssign, $Record) EndIf EndIf EndIf $DB.Commit; Commit database in case updates performed EndIf $View.Close; Close the view. EndIf EndIf EndIf EndIf EndIf If $COM_Err Then Log_Fatal($msg, '', '', $msg); If COM error stop the process. Return $COM_Err; Return 1. EndIf Log_Update('Done: PHEW!!!, Having a Beer¦') Log_Banner(1, $Proc_Title) $Proc_Title = $oldPT; Set the process title as previous functions. EndFunc ;==>DI_UpdateCabs10The original vbs is:expandcollapse popup' Windows Installer utility to generate file cabinets from MSI database ' For use with Windows Scripting Host, CScript.exe or WScript.exe ' Copyright (c) 1999-2001, Microsoft Corporation ' Demonstrates the access to install engine and actions ' Option Explicit ' FileSystemObject.CreateTextFile and FileSystemObject.OpenTextFile Const OpenAsASCII = 0 Const OpenAsUnicode = -1 ' FileSystemObject.CreateTextFile Const OverwriteIfExist = -1 Const FailIfExist = 0 ' FileSystemObject.OpenTextFile Const OpenAsDefault = -2 Const CreateIfNotExist = -1 Const FailIfNotExist = 0 Const ForReading = 1 Const ForWriting = 2 Const ForAppending = 8 Const msiOpenDatabaseModeReadOnly = 0 Const msiOpenDatabaseModeTransact = 1 Const msiViewModifyInsert = 1 Const msiViewModifyUpdate = 2 Const msiViewModifyAssign = 3 Const msiViewModifyReplace = 4 Const msiViewModifyDelete = 6 Const msiUILevelNone = 2 Const msiRunModeSourceShortNames = 9 Const msidbFileAttributesNoncompressed = &h00002000 Dim argCount:argCount = Wscript.Arguments.Count Dim iArg:iArg = 0 If argCount > 0 Then If InStr(1, Wscript.Arguments(0), "?", vbTextCompare) > 0 Then argCount = 0 If (argCount < 2) Then Wscript.Echo "Windows Installer utility to generate compressed file cabinets from MSI database" &_ vbNewLine & " The 1st argument is the path to MSI database, at the source file root" &_ vbNewLine & " The 2nd argument is the base name used for the generated files (DDF, INF, RPT)" &_ vbNewLine & " The 3rd argument can optionally specify separate source location from the MSI" &_ vbNewLine & " The following options may be specified at any point on the command line" &_ vbNewLine & " /L to use LZX compression instead of MSZIP" &_ vbNewLine & " /F to limit cabinet size to 1.44 MB floppy size rather than CD" &_ vbNewLine & " /C to run compression, else only generates the .DDF file" &_ vbNewLine & " /U to update the MSI database to reference the generated cabinet" &_ vbNewLine & " /E to embed the cabinet file in the installer package as a stream" &_ vbNewLine & " /S to sequence number file table, ordered by directories" &_ vbNewLine & " /R to revert to non-cabinet install, removes cabinet if /E specified" &_ vbNewLine & " Notes:" &_ vbNewLine & " In order to generate a cabinet, MAKECAB.EXE must be on the PATH" &_ vbNewLine & " base name used for files and cabinet stream is case-sensitive" &_ vbNewLine & " If source type set to compressed, all files will be opened at the root" &_ vbNewLine & " (The /R option removes the compressed bit - SummaryInfo property 15 & 2)" &_ vbNewLine & " To replace an embedded cabinet, include the options: /R /C /U /E" &_ vbNewLine & " Does not handle updating of Media table to handle multiple cabinets" &_ vbNewLine &_ vbNewLine & "Copyright (C) Microsoft Corporation, 1999-2001. All rights reserved." Wscript.Quit 1 End If ' Get argument values, processing any option flags Dim compressType : compressType = "MSZIP" Dim cabSize : cabSize = "CDROM" Dim makeCab : makeCab = False Dim embedCab : embedCab = False Dim updateMsi : updateMsi = False Dim sequenceFile : sequenceFile = False Dim removeCab : removeCab = False Dim databasePath : databasePath = NextArgument Dim baseName : baseName = NextArgument Dim sourceFolder : sourceFolder = NextArgument If Not IsEmpty(NextArgument) Then Fail "More than 3 arguments supplied" ' process any trailing options If Len(baseName) < 1 Or Len(baseName) > 8 Then Fail "Base file name must be from 1 to 8 characters" If Not IsEmpty(sourceFolder) And Right(sourceFolder, 1) <> "\" Then sourceFolder = sourceFolder & "\" Dim cabFile : cabFile = baseName & ".CAB" Dim cabName : cabName = cabFile : If embedCab Then cabName = "#" & cabName ' Connect to Windows Installer object On Error Resume Next Dim installer : Set installer = Nothing Set installer = Wscript.CreateObject("WindowsInstaller.Installer") : CheckError ' Open database Dim database, openMode, view, record, updateMode, sumInfo, sequence, lastSequence If updateMsi Or sequenceFile Or removeCab Then openMode = msiOpenDatabaseModeTransact Else openMode = msiOpenDatabaseModeReadOnly Set database = installer.OpenDatabase(databasePath, openMode) : CheckError ' Remove existing cabinet(s) and revert to source tree install if options specified If removeCab Then Set view = database.OpenView("SELECT DiskId, LastSequence, Cabinet FROM Media ORDER BY DiskId") : CheckError view.Execute : CheckError updateMode = msiViewModifyUpdate Set record = view.Fetch : CheckError If Not record Is Nothing Then ' Media table not empty If Not record.IsNull(3) Then If record.StringData(3) <> cabName Then Wscript.Echo "Warning, cabinet name in media table, " & record.StringData(3) & " does not match " & cabName record.StringData(3) = Empty End If record.IntegerData(2) = 9999 ' in case of multiple cabinets, force all files from 1st media view.Modify msiViewModifyUpdate, record : CheckError Do Set record = view.Fetch : CheckError If record Is Nothing Then Exit Do view.Modify msiViewModifyDelete, record : CheckError 'remove other cabinet records Loop End If Set sumInfo = database.SummaryInformation(3) : CheckError sumInfo.Property(11) = Now sumInfo.Property(13) = Now sumInfo.Property(15) = sumInfo.Property(15) And Not 2 sumInfo.Persist Set view = database.OpenView("SELECT `Name`,`Data` FROM _Streams WHERE `Name`= '" & cabFile & "'") : CheckError view.Execute : CheckError Set record = view.Fetch If record Is Nothing Then Wscript.Echo "Warning, cabinet stream not found in package: " & cabFile Else view.Modify msiViewModifyDelete, record : CheckError End If Set sumInfo = Nothing ' must release stream database.Commit : CheckError If Not updateMsi Then Wscript.Quit 0 End If ' Create an install session and execute actions in order to perform directory resolution installer.UILevel = msiUILevelNone Dim session : Set session = installer.OpenPackage(database) : If Err <> 0 Then Fail "Database: " & databasePath & ". Invalid installer package format" Dim shortNames : shortNames = session.Mode(msiRunModeSourceShortNames) : CheckError If Not IsEmpty(sourceFolder) Then session.Property("OriginalDatabase") = sourceFolder : CheckError Dim stat : stat = session.DoAction("CostInitialize") : CheckError If stat <> 1 Then Fail "CostInitialize failed, returned " & stat ' Check for non-cabinet files to avoid sequence number collisions lastSequence = 0 If sequenceFile Then Set view = database.OpenView("SELECT Sequence,Attributes FROM File") : CheckError view.Execute : CheckError Do Set record = view.Fetch : CheckError If record Is Nothing Then Exit Do sequence = record.IntegerData(1) If (record.IntegerData(2) And msidbFileAttributesNoncompressed) <> 0 And sequence > lastSequence Then lastSequence = sequence Loop End If ' Join File table to Component table in order to find directories Dim orderBy : If sequenceFile Then orderBy = "Directory_" Else orderBy = "Sequence" Set view = database.OpenView("SELECT File,FileName,Directory_,Sequence,File.Attributes FROM File,Component WHERE Component_=Component ORDER BY " & orderBy) : CheckError view.Execute : CheckError ' Create DDF file and write header properties Dim FileSys : Set FileSys = CreateObject("Scripting.FileSystemObject") : CheckError Dim outStream : Set outStream = FileSys.CreateTextFile(baseName & ".DDF", OverwriteIfExist, OpenAsASCII) : CheckError outStream.WriteLine "; Generated from " & databasePath & " on " & Now outStream.WriteLine ".Set CabinetNameTemplate=" & baseName & "*.CAB" outStream.WriteLine ".Set CabinetName1=" & cabFile outStream.WriteLine ".Set ReservePerCabinetSize=8" outStream.WriteLine ".Set MaxDiskSize=" & cabSize outStream.WriteLine ".Set CompressionType=" & compressType outStream.WriteLine ".Set InfFileLineFormat=(*disk#*) *file#*: *file* = *Size*" outStream.WriteLine ".Set InfFileName=" & baseName & ".INF" outStream.WriteLine ".Set RptFileName=" & baseName & ".RPT" outStream.WriteLine ".Set InfHeader=" outStream.WriteLine ".Set InfFooter=" outStream.WriteLine ".Set DiskDirectoryTemplate=." outStream.WriteLine ".Set Compress=ON" outStream.WriteLine ".Set Cabinet=ON" ' Fetch each file and request the source path, then verify the source path Dim fileKey, fileName, folder, sourcePath, delim, message, attributes Do Set record = view.Fetch : CheckError If record Is Nothing Then Exit Do fileKey = record.StringData(1) fileName = record.StringData(2) folder = record.StringData(3) sequence = record.IntegerData(4) attributes = record.IntegerData(5) If (attributes And msidbFileAttributesNoncompressed) = 0 Then If sequence <= lastSequence Then If Not sequenceFile Then Fail "Duplicate sequence numbers in File table, use /S option" sequence = lastSequence + 1 record.IntegerData(4) = sequence view.Modify msiViewModifyUpdate, record End If lastSequence = sequence delim = InStr(1, fileName, "|", vbTextCompare) If delim <> 0 Then If shortNames Then fileName = Left(fileName, delim-1) Else fileName = Right(fileName, Len(fileName) - delim) End If sourcePath = session.SourcePath(folder) & fileName outStream.WriteLine """" & sourcePath & """" & " " & fileKey If installer.FileAttributes(sourcePath) = -1 Then message = message & vbNewLine & sourcePath End If Loop outStream.Close REM Wscript.Echo "SourceDir = " & session.Property("SourceDir") If Not IsEmpty(message) Then Fail "The following files were not available:" & message ' Generate compressed file cabinet If makeCab Then Dim WshShell : Set WshShell = Wscript.CreateObject("Wscript.Shell") : CheckError Dim cabStat : cabStat = WshShell.Run("MakeCab.exe /f " & baseName & ".DDF", 1, True) : CheckError If cabStat <> 0 Then Fail "MAKECAB.EXE failed, possibly could not find source files, or invalid DDF format" End If ' Update Media table and SummaryInformation if requested If updateMsi Then Set view = database.OpenView("SELECT DiskId, LastSequence, Cabinet FROM Media ORDER BY DiskId") : CheckError view.Execute : CheckError updateMode = msiViewModifyUpdate Set record = view.Fetch : CheckError If record Is Nothing Then ' Media table empty Set record = Installer.CreateRecord(3) record.IntegerData(1) = 1 updateMode = msiViewModifyInsert End If record.IntegerData(2) = lastSequence record.StringData(3) = cabName view.Modify updateMode, record Set sumInfo = database.SummaryInformation(3) : CheckError sumInfo.Property(11) = Now sumInfo.Property(13) = Now sumInfo.Property(15) = (shortNames And 1) + 2 sumInfo.Persist End If ' Embed cabinet if requested If embedCab Then Set view = database.OpenView("SELECT `Name`,`Data` FROM _Streams") : CheckError view.Execute : CheckError Set record = Installer.CreateRecord(2) record.StringData(1) = cabFile record.SetStream 2, cabFile : CheckError view.Modify msiViewModifyAssign, record : CheckError 'replace any existing stream of that name End If ' Commit database in case updates performed database.Commit : CheckError Wscript.Quit 0 ' Extract argument value from command line, processing any option flags Function NextArgument Dim arg Do ' loop to pull in option flags until an argument value is found If iArg >= argCount Then Exit Function arg = Wscript.Arguments(iArg) iArg = iArg + 1 If (AscW(arg) <> AscW("/")) And (AscW(arg) <> AscW("-")) Then Exit Do Select Case UCase(Right(arg, Len(arg)-1)) Case "C" : makeCab = True Case "E" : embedCab = True Case "F" : cabSize = "1.44M" Case "L" : compressType = "LZX" Case "R" : removeCab = True Case "S" : sequenceFile = True Case "U" : updateMsi = True Case Else: Wscript.Echo "Invalid option flag:", arg : Wscript.Quit 1 End Select Loop NextArgument = arg End Function Sub CheckError Dim message, errRec If Err = 0 Then Exit Sub message = Err.Source & " " & Hex(Err) & ": " & Err.Description If Not installer Is Nothing Then Set errRec = installer.LastErrorRecord If Not errRec Is Nothing Then message = message & vbNewLine & errRec.FormatText End If Fail message End Sub Sub Fail(message) Wscript.Echo message Wscript.Quit 2 End Sub Link to comment Share on other sites More sharing options...
John117 Posted May 2, 2009 Share Posted May 2, 2009 (edited) have you tried adding something like this to debug? Func ComErrorHandler() Local $sHexNumber = Hex($oMyError.number,8) Local $sDesc = StringStripWS($oMyError.windescription, 2) Msgbox(0,"AutoItCOM Test","We intercepted a COM Error !" & @CRLF & @CRLF & _ "err.description is: " & @TAB & $oMyError.description & @CRLF & _ "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _ "err.number is: " & @TAB & $sHexNumber & @CRLF & _ "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF) $g_eventerror = 1 ; something to check for when this function returns $oMyError.clear Endfunc Edit: If they run it from sciTE it should help . . . Read the console for error info . . . Edited May 2, 2009 by John117 Link to comment Share on other sites More sharing options...
benners Posted May 2, 2009 Author Share Posted May 2, 2009 (edited) have you tried adding something like this to debug? Func ComErrorHandler() Local $sHexNumber = Hex($oMyError.number,8) Local $sDesc = StringStripWS($oMyError.windescription, 2) Msgbox(0,"AutoItCOM Test","We intercepted a COM Error !" & @CRLF & @CRLF & _ "err.description is: " & @TAB & $oMyError.description & @CRLF & _ "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _ "err.number is: " & @TAB & $sHexNumber & @CRLF & _ "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF) $g_eventerror = 1 ; something to check for when this function returns $oMyError.clear Endfunc Edit: If they run it from sciTE it should help . . . Read the console for error info . . . Yes I have the same function for the error handler but I have commented out the code and just set the $COM_Err to 1. I don't always want the program to stop on an error and prefer to have error messages relevant to what action is being performed. My next action is to log the error information as well as setting the $COM_Err to see if anything obvious is happening. I thought I would post to try and find out why some users have no problem and for others the "error in expression problem", surely the code should work for all and just not return a value if an action cannot be performed. The code is compiled so running from sciTe is not an option. Thanks Edited May 2, 2009 by benners Link to comment Share on other sites More sharing options...
John117 Posted May 2, 2009 Share Posted May 2, 2009 Yes I have the same function for the error handler but I have commented out the code and just set the $COM_Err to 1. I don't always want the program to stop on an error and prefer to have error messages relevant to what action is being performed. My next action is to log the error information as well as setting the $COM_Err to see if anything obvious is happening. I thought I would post to try and find out why some users have no problem and for others the "error in expression problem", surely the code should work for all and just not return a value if an action cannot be performed.The code is compiled so running from sciTe is not an option.ThanksWere I on my home pc I could give you a better one.Try keeping the entire code given before. convert it to Console write. Then do a console read and dump everything to a txt file in the @ScriptDir.May help. -They could then email you that . . . Link to comment Share on other sites More sharing options...
benners Posted May 2, 2009 Author Share Posted May 2, 2009 Were I on my home pc I could give you a better one.Try keeping the entire code given before. convert it to Console write. Then do a console read and dump everything to a txt file in the @ScriptDir.May help. -They could then email you that . . .With the program, I have a logging function so I can just write the "$oMyError.description" etc to the log file. The problem is the error function is not triggered (if an error occurs) because the command is not run due to the "error with the expression" problem. I just don't know why the code is wrong for some people and not always wrong. Link to comment Share on other sites More sharing options...
Quual Posted May 3, 2009 Share Posted May 3, 2009 (edited) I'm clueless when it comes to the installer object, might be a dumb suggestion. Have you tried changing the line to $session = $Installer.OpenPackage($DB,1) 'When options is 1, the OpenPackage Method ignores the current computer state when opening the package. Edited May 3, 2009 by Quual Link to comment Share on other sites More sharing options...
benners Posted May 8, 2009 Author Share Posted May 8, 2009 I'm clueless when it comes to the installer object, might be a dumb suggestion.Have you tried changing the line to $session = $Installer.OpenPackage($DB,1)'When options is 1, the OpenPackage Method ignores the current computer state when opening the package.Hi Quual Thanks for the reply. I had tried the 1 option in other parts of the code and it didn't seem to have any effect. I altered the code to use the vbs and the users had the same problem. The script reported an "invalid installer package". I added the 1 as you suggested and have received feedback that the solution worked. I don't understand what could cause the problem if the same package is already installed, maybe it looks for the installer in a cached folder? but it seems to work.Thanks Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now