home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 June
/
Chip_2001-06_cd1.bin
/
zkuste
/
vbasic
/
Data
/
Utility
/
MSISDK15.msi
/
WiFeatur.vbs
< prev
next >
Wrap
Text File
|
2000-10-05
|
8KB
|
192 lines
' Windows Installer utility to list feature composition in an MSI database
' For use with Windows Scripting Host, CScript.exe or WScript.exe
' Copyright (c) 1999-2000, Microsoft Corporation
' Demonstrates the use of adding temporary columns to a read-only database
'
Option Explicit
Public isGUI, installer, database, message, featureParam, nextSequence 'global variables accessed across functions
Const msiOpenDatabaseModeReadOnly = 0
Const msiDbNullInteger = &h80000000
Const msiViewModifyUpdate = 2
' Check if run from GUI script host, in order to modify display
If UCase(Mid(Wscript.FullName, Len(Wscript.Path) + 2, 1)) = "W" Then isGUI = True
' Show help if no arguments or if argument contains ?
Dim argCount:argCount = Wscript.Arguments.Count
If argCount > 0 Then If InStr(1, Wscript.Arguments(0), "?", vbTextCompare) > 0 Then argCount = 0
If argCount = 0 Then
Wscript.Echo "Windows Installer utility to list feature composition in an installer database." &_
vbLf & " The 1st argument is the path to an install database, relative or complete path" &_
vbLf & " The 2nd argument is the name of the feature (the primary key of Feature table)" &_
vbLf & " If the 2nd argument is not present, all feature names will be listed as a tree" &_
vbLf & " If the 2nd argument is ""*"" then the composition of all features will be listed" &_
vbLf & " Large databases or features are better displayed by using CScript than WScript" &_
vbNewLine &_
vbNewLine & "Copyright (C) Microsoft Corporation, 1999-2000. All rights reserved."
Wscript.Quit 1
End If
' Connect to Windows Installer object
REM On Error Resume Next
Set installer = Nothing
Set installer = Wscript.CreateObject("WindowsInstaller.Installer") : CheckError
' Open database
Dim databasePath:databasePath = Wscript.Arguments(0)
Set database = installer.OpenDatabase(databasePath, msiOpenDatabaseModeReadOnly) : CheckError
REM Set database = installer.OpenDatabase(databasePath, 1) : CheckError
If argCount = 1 Then 'If no feature specified, then simply list features
ListFeatures False
ShowOutput "Features for " & databasePath, message
ElseIf Left(Wscript.Arguments(1), 1) = "*" Then 'List all features
ListFeatures True
Else
QueryFeature Wscript.Arguments(1)
End If
Wscript.Quit 0
' List all table rows referencing a given feature
Function QueryFeature(feature)
' Get feature info and format output header
Dim view, record, header, parent
Set view = database.OpenView("SELECT `Feature_Parent` FROM `Feature` WHERE `Feature` = ?") : CheckError
Set featureParam = installer.CreateRecord(1)
featureParam.StringData(1) = feature
view.Execute featureParam : CheckError
Set record = view.Fetch : CheckError
Set view = Nothing
If record Is Nothing Then Fail "Feature not in database: " & feature
parent = record.StringData(1)
header = "Feature: "& feature & " Parent: " & parent
' List of tables with foreign keys to Feature table - with subsets of columns to display
DoQuery "FeatureComponents","Component_" '
DoQuery "Condition", "Level,Condition" '
DoQuery "Billboard", "Billboard,Action" 'Ordering
QueryFeature = ShowOutput(header, message)
message = Empty
End Function
' Query used for sorting and corresponding record field indices
const irecParent = 1 'put first in order to use as query parameter
const irecChild = 2 'primary key of Feature table
const irecSequence = 3 'temporary column added for sorting
const sqlSort = "SELECT `Feature_Parent`,`Feature`,`Sequence` FROM `Feature`"
' Recursive function to resolve parent feature chain, return tree level (low order 8 bits of sequence number)
Function LinkParent(childView)
Dim view, record, level
On Error Resume Next
Set record = childView.Fetch
If record Is Nothing Then Exit Function 'return Empty if no record found
If Not record.IsNull(irecSequence) Then LinkParent = (record.IntegerData(irecSequence) And 255) + 1 : Exit Function 'Already resolved
If record.IsNull(irecParent) Or record.StringData(irecParent) = record.StringData(irecChild) Then 'Root node
level = 0
Else 'child node, need to get level from parent
Set view = database.OpenView(sqlSort & " WHERE `Feature` = ?") : CheckError
view.Execute record : CheckError '1st param is parent feature
level = LinkParent(view)
If IsEmpty(level) Then Fail "Feature parent does not exist: " & record.StringData(irecParent)
End If
record.IntegerData(irecSequence) = nextSequence + level
nextSequence = nextSequence + 256
childView.Modify msiViewModifyUpdate, record : CheckError
LinkParent = level + 1
End Function
' List all features in database, sorted hierarchically
Sub ListFeatures(queryAll)
Dim viewSchema, view, record, feature, level
On Error Resume Next
Set viewSchema = database.OpenView("ALTER TABLE Feature ADD Sequence LONG TEMPORARY") : CheckError
viewSchema.Execute : CheckError 'Add ordering column, keep view open to hold temp columns
Set view = database.OpenView(sqlSort) : CheckError
view.Execute : CheckError
nextSequence = 0
While LinkParent(view) : Wend 'Loop to link rows hierachically
Set view = database.OpenView("SELECT `Feature`,`Title`, `Sequence` FROM `Feature` ORDER BY Sequence") : CheckError
view.Execute : CheckError
Do
Set record = view.Fetch : CheckError
If record Is Nothing Then Exit Do
feature = record.StringData(1)
level = record.IntegerData(3) And 255
If queryAll Then
If QueryFeature(feature) = vbCancel Then Exit Sub
Else
If Not IsEmpty(message) Then message = message & vbLf
message = message & Space(level * 2) & feature & " (" & record.StringData(2) & ")"
End If
Loop
End Sub
' Perform a join to query table rows linked to a given feature, delimiting and qualifying names to prevent conflicts
Sub DoQuery(table, columns)
Dim view, record, columnCount, column, output, header, delim, columnList, tableList, tableDelim, query, joinTable, primaryKey, foreignKey, columnDelim
On Error Resume Next
tableList = Replace(table, ",", "`,`")
tableDelim = InStr(1, table, ",", vbTextCompare)
If tableDelim Then ' need a 3-table join
joinTable = Right(table, Len(table)-tableDelim)
table = Left(table, tableDelim-1)
foreignKey = columns
Set record = database.PrimaryKeys(joinTable)
primaryKey = record.StringData(1)
columnDelim = InStr(1, columns, ",", vbTextCompare)
If columnDelim Then foreignKey = Left(columns, columnDelim - 1)
query = " AND `" & foreignKey & "` = `" & primaryKey & "`"
End If
columnList = table & "`." & Replace(columns, ",", "`,`" & table & "`.`")
query = "SELECT `" & columnList & "` FROM `" & tableList & "` WHERE `Feature_` = ?" & query
If database.TablePersistent(table) <> 1 Then Exit Sub
Set view = database.OpenView(query) : CheckError
view.Execute featureParam : CheckError
Do
Set record = view.Fetch : CheckError
If record Is Nothing Then Exit Do
If IsEmpty(output) Then
If Not IsEmpty(message) Then message = message & vbLf
message = message & "----" & table & " Table---- (" & columns & ")" & vbLf
End If
output = Empty
columnCount = record.FieldCount
delim = " "
For column = 1 To columnCount
If column = columnCount Then delim = vbLf
output = output & record.StringData(column) & delim
Next
message = message & output
Loop
End Sub
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 & vbLf & errRec.FormatText
End If
Fail message
End Sub
Function ShowOutput(header, message)
ShowOutput = vbOK
If IsEmpty(message) Then Exit Function
If isGUI Then
ShowOutput = MsgBox(message, vbOKCancel, header)
Else
Wscript.Echo "> " & header
Wscript.Echo message
End If
End Function
Sub Fail(message)
Wscript.Echo message
Wscript.Quit 2
End Sub