Introduction:
***************************
I am using the MSI API to extract MSI embedded files, I do this by iterating
through all of the records in the ‘_Streams’ table and dumping each to a
local directory on the disk, the following illustrate this:
01)MsiDatabaseOpenView(m_hMSI,
L"SELECT `Name`,`Data` FROM `_Streams`",
&hStreamsView)
02)MsiViewExecute(hStreamsView, NULL);
for each record in the _Streams table
03)MsiViewFetch(hStreamsView, &hStreamRecord)
04) MsiRecordGetString(hStreamRecord, 1,
pPackedFileName, &dwBufSize)
05)CreateFile
While there is still data in the stream
06)MsiRecordReadStream(hStreamRecord, 2,
(char*)pbtStream, &dwBufSize);
07)WriteFile
The problem:
****************************
Some MSI installation has the files embedded in a CAB file named as a GUIDs,
this CAB contain the installation files, the files are named as GUIDs
resembling the data held in the ‘File’ field of the ‘File’ table…
My Question:
****************************
Is it possible to use the MSI API to extract the ‘real’ file directly from
the MSI? Is there a method for extracting embedded files according to the
‘FileName’ column of the ‘File’ table?
My alternative is to manually dump the ‘_Streams’ table ( as I do today ),
then to identify the CAB file according to it’s signature ( I have to
identify the file according to it’s signature as the name of the CAB is a
GUID… ), extract it and to rename the extracted files according to the
File->FileName mapping provided by the ‘File’ table.
I AM SURE THERE IS AN ELEGANTH WAY TO DO THAT… What it is?
--
Nadav
http://www.ddevel.com
"Nadav" <Na...@discussions.microsoft.com> wrote in message news:<A87141DB-6324-4810...@microsoft.com>...
> Is it possible to use the MSI API to extract the ‘real’ file directly from
> the MSI?
You need to do an "adminsitrative install" (the "/a" switch on
MSIEXEC.EXE for example).
Bye,
Dennis
this should extract all your embedded files.
--
Please reply to NG only. This email is not monitored.
Alex.
"Suraj Nair" <Suraj Na...@discussions.microsoft.com> wrote in message
news:4A330879-9130-4283...@microsoft.com...
>> resembling the data held in the 'File' field of the 'File' table.
>>
>> My Question:
>> ****************************
>> Is it possible to use the MSI API to extract the 'real' file directly
>> from
>> the MSI? Is there a method for extracting embedded files according to the
>> 'FileName' column of the 'File' table?
>> My alternative is to manually dump the '_Streams' table ( as I do
>> today ),
>> then to identify the CAB file according to it's signature ( I have to
>> identify the file according to it's signature as the name of the CAB is a
>> GUID. ), extract it and to rename the extracted files according to the
>> File->FileName mapping provided by the 'File' table.
>> I AM SURE THERE IS AN ELEGANTH WAY TO DO THAT. What it is?
>> --
>> Nadav
>> http://www.ddevel.com
Thanks for your immediate responce, Is there any alternative solution for
extracting the MSI using the /a option? ( something to do with the MSI API )
--
Please reply to NG only. This email is not monitored.
Alex.
"Nadav" <Na...@discussions.microsoft.com> wrote in message
news:45C052A7-CAD4-4B1F...@microsoft.com...
"Alex Ivanov" <con...@collegeclub.com> wrote in message news:<OX9PmcR...@TK2MSFTNGP14.phx.gbl>...
> This works if the msi has the AdminExecute sequence, but what if it hasn't?
Then you could add it...
from the doco (Suggested AdminExecuteSequence):
Action Condition Sequence
CostInitialize 800
FileCost 900
CostFinalize 1000
InstallValidate 1400
InstallInitialize 1500
InstallAdminPackage 3900
InstallFiles 4000
InstallFinalize 6600
Bye,
Dennis
Why can't you just use the real file name here?
Notice, however, that you also need to build the directory hierarchy,
as file names might be duplicated (in different directories).
Regards,
Martin
Why don't you try and see for yourself, or read the documentation on
what precisely an administrative install does?
Regards,
Martin
Here is a python script that will extract all .CAB files and hidden streams.
#
# ExtractMsiFiles.py
#
# Copyright (c) 2004, Algin Technology
# Author: Alan Klietz, al...@algintechN0SPAM.com
#
# Extract MSI files and streams
#
# Works similar to MSIEXEC.EXE /a <foo>.msi, except it also extracts
'hidden'
# installer Custom Action DLLs and hidden streams (e.g., the Authenticode
# signature stream.)
#
# To unpack the extracted .CAB files, use cabarc.exe X foo.cab
#
import pythoncom
import win32com.client
from win32com.client import constants
from win32com.server.exception import COMException
szMsiFile = ".\\UMove.msi"
szExtractDir = "."
#
# Load the "WindowsInstaller.Installer" Type Library from
#
# \python\win32all146\com\win32com\client\gen_py
# 000C1092-0000-0000-C000-000000000046x1033x1x0.py
#
# TypeLib name via OLEVIEW.EXE:
# "Microsoft Windows Installer Object Library"
#
from win32com.client import gencache
gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}', 1033, 1, 0)
def doit(szDatabaseFileName, method):
#
# BUG: msi.GetTypeInfo() wrongly fails instead of returning
# an ITypeInfo interface.
#
# WORKAROUND: Must specify the CLSID explicitly to coax gen_py into
# loading the typelib from the gen_py cache.
#
msi = win32com.client.Dispatch("WindowsInstaller.Installer",
resultCLSID="{000C1090-0000-0000-C000-000000000046}")
db = msi.OpenDatabase(szDatabaseFileName,
constants.msiOpenDatabaseModeReadOnly)
#
# Dig into the virtual _Streams table
#
view = db.OpenView("SELECT `Name`,`Data` FROM `_Streams`")
#
# BUG: The "Microsoft Windows Installer Object Library" typelib
# wrongly declares that Execute takes a default parameter of 0
# for the Record parameter, when it really is VT_EMPTY (None)
#
view.Execute(None) # otherwise InvokeTypes throws not-an-object on arg
while 1:
rst = view.Fetch()
if rst is None:
break
szFile = rst.StringData(1) # column 1 = Name
#
# pseudoStreams are prefixed with a \005 byte.
#
# Skip SummaryInformation -- it is actually a translation
# of the OLE property table and is not a stream.
#
# Useful for extracting DigitalSignature
#
if szFile[0:1] == chr(5):
szFile=szFile[1:] # skip leading \005 byte
if szFile.find("Summary") >= 0:
print "Skipping the pseudo-stream \"%s\"." % (szFile[1:],)
continue
print "Extracting the stream \"%s\"." % (szFile,)
f = open(szExtractDir + "\\" + szFile, "wb")
while 1:
col = 2
buflen = 4096
usz = rst.ReadStream(col, buflen, constants.msiReadStreamBytes)
if usz == 'None':
break # EOF
f.write(usz)
f.close()
del rst, view
#
# Now print the file name-to-cab-item mappings from the File table
#
view = db.OpenView("SELECT `File`, `FileName`, `Version`, `FileSize` FROM
`File`")
view.Execute(None)
szCatalog = szExtractDir + "\\FILELIST.TXT"
f = open(szCatalog, "w")
while 1:
rst = view.Fetch()
if rst is None:
break
szCabItem = rst.StringData(1)
szFile = rst.StringData(2)
szVersion = rst.StringData(3)
szSize = rst.StringData(4)
#
# Change "FOO.TXT|foo.txt" to just "foo.txt"
#
pos = szFile.find("|")
if pos >= 0:
szFile = szFile[pos+1:]
szLine = "Cab item %s: \"%s\"" % (szCabItem, szFile)
if len(szVersion) > 0:
szLine = szLine + " version %s" % (szVersion,)
szLine = szLine + ", %s bytes.\n" % (szSize,)
f.write(szLine)
f = open(szCatalog, "r")
print f.read()
f.close()
del rst, view
del db
def ExtractMsiFile():
doit(szMsiFile, 1)
print 'Done.'
ExtractMsiFile()