
Ящик для предложений: sales@blogslov.ru
Send Wix-commits mailing list submissions to
wix-commits@lists.sourceforge.net
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.sourceforge.net/lists/listinfo/wix-commits
or, via email, send a message with subject or body 'help' to
wix-commits-request@lists.sourceforge.net
You can reach the person managing the list at
wix-commits-owner@lists.sourceforge.net
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Wix-commits digest..."
Today's Topics:
1. wix/src/wix Melter.cs, NONE, 1.1 MelterCore.cs, NONE, 1.1
Patch.cs, NONE, 1.1 PatchTransform.cs, NONE, 1.1
ValidatorExtension.cs, NONE, 1.1 AppCommon.cs, 1.3, 1.4
Binder.cs, 1.49, 1.50 BinderExtension.cs, 1.13, 1.14
CabinetBuilder.cs, 1.3, 1.4 ColumnDefinition.cs, 1.16, 1.17
Compiler.cs, 1.63, 1.64 CompilerCore.cs, 1.30, 1.31
Decompiler.cs, 1.48, 1.49 Differ.cs, 1.2, 1.3 Field.cs, 1.19,
1.20 FileRow.cs, 1.16, 1.17 Linker.cs, 1.46, 1.47 ObjectField.cs,
1.5, 1.6 Output.cs, 1.25, 1.26 Preprocessor.cs, 1.30, 1.31
Row.cs, 1.17, 1.18 Validator.cs, 1.8, 1.9 WixExtension.cs, 1.5,
1.6 WixFileRow.cs, 1.2, 1.3 wix.csproj, 1.29, 1.30 wixdll.build,
1.18, 1.19 (Rob Mensching)
----------------------------------------------------------------------
Message: 1
Date: Wed, 27 Jun 2007 05:39:09 +0000
From: Rob Mensching
Subject: [WiX-commits] wix/src/wix Melter.cs, NONE, 1.1 MelterCore.cs,
NONE, 1.1 Patch.cs, NONE, 1.1 PatchTransform.cs, NONE, 1.1
ValidatorExtension.cs, NONE, 1.1 AppCommon.cs, 1.3, 1.4 Binder.cs,
1.49, 1.50 BinderExtension.cs, 1.13, 1.14 CabinetBuilder.cs, 1.3, 1.4
ColumnDefinition.cs, 1.16, 1.17 Compiler.cs, 1.63, 1.64
CompilerCore.cs, 1.30, 1.31 Decompiler.cs, 1.48, 1.49 Differ.cs, 1.2,
1.3 Field.cs, 1.19, 1.20 FileRow.cs, 1.16, 1.17 Linker.cs, 1.46, 1.47
ObjectField.cs, 1.5, 1.6 Output.cs, 1.25, 1.26 Preprocessor.cs, 1.30,
1.31 Row.cs, 1.17, 1.18 Validator.cs, 1.8, 1.9 WixExtension.cs, 1.5,
1.6 WixFileRow.cs, 1.2, 1.3 wix.csproj, 1.29, 1.30 wixdll.build, 1.18,
1.19
To: wix-commits@lists.sourceforge.net
Message-ID:
Update of /cvsroot/wix/wix/src/wix
In directory sc8-pr-cvs9.sourceforge.net:/tmp/cvs-serv1332/src/wix
Modified Files:
AppCommon.cs Binder.cs BinderExtension.cs CabinetBuilder.cs
ColumnDefinition.cs Compiler.cs CompilerCore.cs Decompiler.cs
Differ.cs Field.cs FileRow.cs Linker.cs ObjectField.cs
Output.cs Preprocessor.cs Row.cs Validator.cs WixExtension.cs
WixFileRow.cs wix.csproj wixdll.build
Added Files:
Melter.cs MelterCore.cs Patch.cs PatchTransform.cs
ValidatorExtension.cs
Log Message:
Benxing: Number of patch related bug fix
*Update FeatureComponent table when ComponentRef in the selected PatchFamily
*File Sequence problem
PMarcu: Allowing extension attributes on DirectoryRef and PropertyRef
Adding extension attributes to the VSExtension Refs
PMarcu: Adding UIRef and DirectoryRef to possible PatchFamily Children
Allowing extension attributes on CustomAction elements.
JRock: Added support for setting pre- and post-build event command lines via a
property page in Votive. This gets me one step closer to restoring the
inter-project variables that we had in V2 but had to pull in V3 to get
it out the door (e.g. $(var.MyProject.TargetPath)).
JRock: Added support for SolutionX variables in the wix.targets file. So, you
can now use $(var.SolutionDir) in your .wxs files and have the variables
automatically added to the preprocessor definitions when building with
wix.targets and MSBuild.
Benxing: Regardless of differences in the MST, we will compare underlying files before
copying data into the patch. Extensions can override CompareFiles to provide
custom file diffing behavior.
AaronSte: Updating Heat to use HKCU instead of HKLM when harvesting registry
information on Windows Vista to avoid UAC issues
PMarcu: Making XsdStitch only output a single prefix for each extension namespace.
Benxing: Fixing null reference exception in the binder when the file table is empty.
RobMen: Default File/@Name to File/@Id.
MikeHo: Fix bug with Setup.exe when trying to install and TEMP and AppData
folders are not on same drive, setup fails
MikeHo: Add fallback to Caching the MSI.
RobMen: SFBUG:1680666 - Correctly modularize RemoveIniFile.DirProperites.
PMarcu: Removing FragmentRef's
AaronSte: SFBUG:1675664 - Marking ComboBox value attribute as localizable.
PMarcu: Adding BinaryRef as a child of PatchFamily.
Benxing: Give warning when removing component from feature during the patch build.
PMarcu: Changing namespace keys in the VSExtension help tables to not be modularized.
PMarcu: Adding some targeted checks to patch transforms to catch possible error
conditions as early as possible.
AaronSte: Adding Visual Studio Codename Orcas detection properties.
AaronSte: SFBUG:1687207 - Update Heat so DllRegisterServer captures will work
on Windows Vista from an elevated cmd prompt.
PMarcu: Fix for DocCompiler to handle ref attributes in attribute definitions under
elements.
BobArnso: Resize and combine some controls to better fit localized strings
(affects all UI sets, dialogs UserExit, OutOfRbDiskDlg, OutOfDiskDlg)
Benxing: Skipping unreal tables when binding transforms to improve patch build
perfomance.
Adding active substorage into binder extension to give the ability to
access corresponding transform information.
JRock: SFBUG:1673425 - Cannot access the VS menu using the alt key
SFBUG:1576283 - Unable to enter 'c' or 'm' in proj properties screen fields
SFBUG:1570392 - Project Designer - Index was outside the bounds of the array
SFBUG:1566296 - Setting 'Cultures' field in project properties has no effect
SFBUG:1576287 - Modifying project properties does not force rebuild
Benxing: Ignore rows without section id in ReduceTransform.
MikeHo: Allow for multiple files to be extracted from chainer.
AaronSte: Adding Visual Studio Team Test project system detection properties.
FGrohn: Support for PubCA in WiX v3.
HeathS: Added extension support to the Validator.
Exposed extension support for the Validator through light.exe.
Exposed extension support for the Validator through smoke.exe.
Exposed multiple .cub file support through smoke.exe.
HeathS: Exposed multiple .cub file support through light.exe.
Added a test for the Validator and multiple .cub support in light.exe.
MikeHo: Add error messages for Windows Installer service can't start or Install
blocked by system policy
BobArnso: Add WixQueryOsInfo CA to detect system suite info and "special
folders" as properties over and above the MSI set
BobArnso: Default to removing library rows from decompiled output in
WixUtilExtension
PMarcu: Refactoring patch buld system to use Pyro instead of Light for filtering
and binding. Other target patch specific bug fixes are in the mix as well.
PMarcu: Adding more command line options to Pyro, specifically the ones that
provide settings for the binder.
PMarcu: Adding error and warning preprocessor instructions.
PMarcu: Fixing an exception thrown when Dark is run and no extensions are defined
in the config file or the config file is absent.
Also, bug where Customtable columns that are not foreign keys have the
keytable attribute defined on the column as keytable="". This results in
an invalid table reference to "".
PMarcu: Switching order on Pyro commandline.
Jordanf: Adding support to WixUnit for Pyro. Fixing the qtest patch.minorupgrade
to use Pyro.
BrianRe: Added code to detect a namespace prefix that is already in use and if
so it will append it with its' position within the "duplicates" for
that specific prefix; eg. sql, sql2, sql3, and so on.
RobMen: Add support for PerformanceCounters (including managed code).
FGrohn: Added COM+ and MSMQ extensions to the zip file.
FGrohn: Move to Windows Vista SDK.
JRock: SFBUG:1566807 - Display full version in about dialog.
SFBUG:1697089 - MSBuild WiX taskscannot resolve WiX tool paths automatically
SFBUG:1689830 - Error when using Wix3 when not installed on C drive
Benxing: Handle Sequence tables when building the patch.
Don't allow empty patch.
HeathS: Added an extension for installing PowerShell snap-ins.
PMarcu: Adding Melt as a tool to decompile MSM's to ComponentGroups.
PMarcu: Adding warning for when a non keypath file is updated and the keypath file
of that component is not.
Benxing: Adding information into _SummaryInformation table for patch build.
PMarcu: Adding a check to assure no duplicate fragment Id's exist.
JKuhne: Fixing a GC issue with the Validator. (Locals are rooted until last reference, not
end of scope.)
BobArnso: Add DiskId attribute to Directory and DirectoryRef to provide default
DiskId for contained components and files.
MikeHo: Fix language matching in Setup.exe
PMarcu: Making sdut and tsa defaults when passing xo to light.exe
AaronSte: Adding more CSIDL values to WixQueryOsDirs custom action
RobMen: Reverse integrate WiX v2 CustomAction fixes.
BobArnso: Add element-extensibility points to Directory and DirectoryRef.
Jordanf: Add a new test for preprocessor .
Mikeho: Add NewFolder UIText element.
AaronSte: Adding custom actions to run devenv.exe /InstallVSTemplates to the
WixVSExtension
BobArnso: Pass directory ID to Directory and DirectoryRef extension elements.
RobMen: Introducing smart-cabbing.
RobMen: SFBUG:1707259 - fix nasty memory violation
HeathS: Added patch-specific property to identify client patches and
if they can be removed.
Mikeho: Fix manifests for setupbld.exe/setup.exe
JordanF: Add the -update option to automatically update a test. Make MSI/MSI
validation explicit in the tests.
JRock: Adding back project references to Votive V3! Actually, I'm adding them
to the wix.targets MSBuild file to be exact. Votive uses it, but you get
the goodness without using Votive also. Basically, this is the feature
where if you reference other projects in your Visual Studio solution,
you can reference the output of those projects from within your wixproj
project. For example, $(var.MyCSharpApp.TargetPath). This will work for
any managed project in Visual Studio (at least it does for VC#, VB, and
VC++ managed). You have to build from within Visual Studio or from the
command line. If you build just the .wixproj, then you won't get the
project variables defined.
SFBUG:1585281 - Add solution and project variables back to Votive v3
MikeHo: Fix support for more than 10 MSIs/MSTs
JRock: SFBUG:1588291 - Support response files for MSBuild candle/light/lit
tasks
BobArnso: Have heat generate a default ComponentGroup when harvesting
directories in a fragment.
JRock: SFBUG:1717966 - Solution Build Issues (build 2911)
When a wixproj is the only thing in the solution, the SolutionX
variables aren't defined when building within Visual Studio. This
is because normally C#/VB define these variables for us. The fix
is to define them ourself.
HeathS: SFBUG:1716160 - ICE03 string overflow error, xmlFile
RobMen: SFBUG:1716160 - fix string overflow error for XmlConfig
BrianRe: Fixing wix.xsd to use W3C recognized regular expressions.
PMarcu: Defaulting Media\@Source to a form of the patchId if not specified
when Media is a child of a patch.
RobMen: SFBUG:1724535 - correctly integrate a few more fixes from WiX v2 to
WiX v3.
JordanF: WixUnit now compares the transforms inside a patch when it is diffing
two patches. Previously, only the tables in the patch were compared.
AaronSte: Added documentation for properties and custom actions in the
WixVSExtension.
PMarcu: Fix for ServiceConfig CA's to call correct rollback entrypoint.
BMurri: Add support for bound wixouts/wixmsts to torch and pyro.
PMarcu: Fix for ServiceConfig CA's to call correct rollback entrypoint.
RobMen: Schema tweaks to enable simple references on FeatureRef and
FeatureGroupRef plus tweaks to enable floating Components.
AaronSte: Added documentation for Votive functionality.
AaronSte: Fixing variable resolution problem in WiX Product item template
in Votive.
PMarcu: Updating flags in XmlConfig to match with CA after the 2.0 to
3.0 integration.
JRock: Integrated the VS SDK 4.0 into Votive.
AaronSte: Merged WiX 2.0 documentation changes into 3.0. Updated instances
of deprecated src attributes in examples in the docs.
MikeHo: Add reinstall support & logging to Chainer + fix bug when using
transforms other than Chinese.
HeathS: SFBUG:1739868 - Pyro does not find .AllowRemoval property
PMarcu: Removing primary key from EnsureTable to support patching.
Fixing documentation for XmlConfig.
RobMen: SFBUG:1739194 - Preserve whitespace when using XmlFile or XmlConfig
JKuhne: Fix a GC related bug in the cab enumeration callback. (Cab.WixEnumerateCab.Enumerate)
Index: FileRow.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/FileRow.cs,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -d -r1.16 -r1.17
*** FileRow.cs 16 Feb 2007 09:35:13 -0000 1.16
--- FileRow.cs 27 Jun 2007 05:39:06 -0000 1.17
***************
*** 57,60 ****
--- 57,62 ----
private Row hashRow;
private RowCollection assemblyNameRows;
+ private string[] previousSource;
+ private PatchAttributeType patchAttributes;
///
***************
*** 67,70 ****
--- 69,73 ----
{
this.assemblyType = FileAssemblyType.NotAnAssembly;
+ this.previousSource = new string[1];
}
***************
*** 78,81 ****
--- 81,85 ----
{
this.assemblyType = FileAssemblyType.NotAnAssembly;
+ this.previousSource = new string[1];
}
***************
*** 265,268 ****
--- 269,291 ----
///
+ /// Gets or sets the source location to the previous file.
+ ///
+ /// Source location to the previous file.
+ public string PreviousSource
+ {
+ get { return this.previousSource[0]; }
+ set { this.previousSource[0] = value; }
+ }
+
+ ///
+ /// Gets the source location to the previous files.
+ ///
+ /// Source location to the previous files.
+ public string[] PreviousSourceArray
+ {
+ get { return this.previousSource; }
+ }
+
+ ///
/// Gets or sets the architecture the file executes on.
///
***************
*** 326,329 ****
--- 349,362 ----
///
+ /// Gets or sets the patching attributes to the file.
+ ///
+ /// Patching attributes of the file.
+ public PatchAttributeType PatchAttributes
+ {
+ get { return this.patchAttributes; }
+ set { this.patchAttributes = value; }
+ }
+
+ ///
/// Compares the current FileRow with another object of the same type.
///
***************
*** 376,379 ****
--- 409,436 ----
this.processorArchitecture = src.processorArchitecture;
this.source = src.source;
+ this.PreviousSource = src.PreviousSource;
+ this.patchAttributes = src.patchAttributes;
+ }
+
+ ///
+ /// Appends previous data from another FileRow object.
+ ///
+ /// An row to get data from.
+ public void AppendPreviousDataFrom(FileRow src)
+ {
+ AppendStringToArray(ref this.previousSource, src.previousSource[0]);
+ }
+
+ ///
+ /// Helper method for AppendPreviousDataFrom.
+ ///
+ /// Destination array.
+ /// Source string.
+ private static void AppendStringToArray(ref string[] destination, string source)
+ {
+ string[] result = new string[destination.Length + 1];
+ destination.CopyTo(result, 0);
+ result[destination.Length] = source;
+ destination = result;
}
}
Index: Output.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Output.cs,v
retrieving revision 1.25
retrieving revision 1.26
diff -C2 -d -r1.25 -r1.26
*** Output.cs 2 Mar 2007 12:22:59 -0000 1.25
--- Output.cs 27 Jun 2007 05:39:06 -0000 1.26
***************
*** 225,292 ****
else
{
Hashtable cabinets = new Hashtable();
StringCollection fileIds = new StringCollection();
StringCollection files = new StringCollection();
- int index = 0;
! // resolve paths to files and create the output cabinet file
! foreach (Section section in this.sections)
{
! foreach (Table table in section.Tables)
{
! foreach (Row row in table.Rows)
{
! foreach (Field field in row.Fields)
! {
! ObjectField objectField = field as ObjectField;
!
! if (null != objectField && null != objectField.Data)
! {
! string file = null;
! bool isDefault = true;
!
! // resolve localization and wix variables
! objectField.Data = wixVariableResolver.ResolveVariables(null, row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault);
!
! // do not save the output if errors were found while resolving object paths
! if (wixVariableResolver.EncounteredError)
! {
! return;
! }
!
! // file is compressed in a cabinet (and not modified above)
! if (null != objectField.CabinetFileId && isDefault)
! {
! // index cabinets that have not been previously encountered
! if (!cabinets.ContainsKey(objectField.BaseUri))
! {
! Uri baseUri = new Uri(objectField.BaseUri);
! string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath);
! string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension);
!
! // index the cabinet file's base URI (source location) and extracted directory
! cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName));
! }
!
! // set the path to the file once its extracted from the cabinet
! file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId);
! }
! else if (null != binderExtension)
! {
! file = binderExtension.ResolveFile((string)objectField.Data);
! }
!
! // add the file to the list of files to go in the cabinet
! if (null != file)
! {
! string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture);
!
! objectField.CabinetFileId = cabinetFileId;
! fileIds.Add(cabinetFileId);
!
! files.Add(file);
! }
! }
! }
}
}
--- 225,245 ----
else
{
+ int index = 0;
Hashtable cabinets = new Hashtable();
StringCollection fileIds = new StringCollection();
StringCollection files = new StringCollection();
! if (null != tempFilesLocation)
{
! // resolve paths to files and create the output cabinet file
! if (0 == this.sections.Count)
{
! ResolveSectionFiles(this.tables, binderExtension, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index);
! }
! else
! {
! foreach (Section section in this.sections)
{
! ResolveSectionFiles(section.Tables, binderExtension, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index);
}
}
***************
*** 391,394 ****
--- 344,463 ----
///
+ /// Resolves paths to files.
+ ///
+ /// TableCollection of tables to process
+ /// If provided, the binder extension is used to bind files into the output.
+ /// The Wix variable resolver.
+ /// Location for temporary files.
+ /// Hash of source cabinets.
+ /// Collection of CabinetFileIds.
+ /// Collection of file paths from compressed files.
+ /// CabinetFileId generator.
+ public void ResolveSectionFiles(TableCollection tables, BinderExtension binderExtension, WixVariableResolver wixVariableResolver, string tempFilesLocation, Hashtable cabinets, StringCollection fileIds, StringCollection files, ref int index)
+ {
+ foreach (Table table in tables)
+ {
+ foreach (Row row in table.Rows)
+ {
+ foreach (Field field in row.Fields)
+ {
+ ObjectField objectField = field as ObjectField;
+
+ if (null != objectField && null != objectField.Data)
+ {
+ string file = null;
+ string previousFile = null;
+ bool isDefault = true;
+ bool isPreviousDefault = true;
+
+ // resolve localization and wix variables
+ if (null != wixVariableResolver)
+ {
+ objectField.Data = wixVariableResolver.ResolveVariables(null, row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault);
+
+ if (null != objectField.PreviousData)
+ {
+ objectField.PreviousData = wixVariableResolver.ResolveVariables(null, row.SourceLineNumbers, objectField.PreviousData, false, ref isPreviousDefault);
+ }
+
+ // do not save the output if errors were found while resolving object paths
+ if (wixVariableResolver.EncounteredError)
+ {
+ return;
+ }
+ }
+
+ // file is compressed in a cabinet (and not modified above)
+ if (null != objectField.CabinetFileId && isDefault)
+ {
+ // index cabinets that have not been previously encountered
+ if (!cabinets.ContainsKey(objectField.BaseUri))
+ {
+ Uri baseUri = new Uri(objectField.BaseUri);
+ string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath);
+ string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension);
+
+ // index the cabinet file's base URI (source location) and extracted directory
+ cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName));
+ }
+
+ // set the path to the file once its extracted from the cabinet
+ file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId);
+ }
+ else if (null != binderExtension)
+ {
+ file = binderExtension.ResolveFile((string)objectField.Data);
+ }
+
+ // add the file to the list of files to go in the cabinet
+ if (null != file)
+ {
+ string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture);
+
+ objectField.CabinetFileId = cabinetFileId;
+ fileIds.Add(cabinetFileId);
+
+ files.Add(file);
+ }
+
+ // previous file is compressed in a cabinet (and not modified above)
+ if (null != objectField.PreviousCabinetFileId && isPreviousDefault)
+ {
+ // index cabinets that have not been previously encountered
+ if (!cabinets.ContainsKey(objectField.PreviousBaseUri))
+ {
+ Uri baseUri = new Uri(objectField.PreviousBaseUri);
+ string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath);
+ string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension);
+
+ // index the cabinet file's base URI (source location) and extracted directory
+ cabinets.Add(objectField.PreviousBaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName));
+ }
+
+ // set the path to the file once its extracted from the cabinet
+ previousFile = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId);
+ }
+ else if (null != objectField.PreviousData && null != binderExtension)
+ {
+ previousFile = binderExtension.ResolveFile((string)objectField.PreviousData);
+ }
+
+ // add the file to the list of files to go in the cabinet
+ if (null != previousFile)
+ {
+ string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture);
+
+ objectField.PreviousCabinetFileId = cabinetFileId;
+ fileIds.Add(cabinetFileId);
+
+ files.Add(previousFile);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
/// Loads an output from a path on disk.
///
--- NEW FILE: Patch.cs ---
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using Microsoft.Tools.WindowsInstallerXml.Msi;
using Microsoft.Tools.WindowsInstallerXml.Msi.Interop;
namespace Microsoft.Tools.WindowsInstallerXml
{
public class Patch
{
private Output patch;
private TableDefinitionCollection tableDefinitions;
public Output PatchOutput
{
get { return this.patch; }
}
public Patch()
{
this.tableDefinitions = Installer.GetTableDefinitions();
}
public void Load(string patchPath)
{
this.patch = Output.Load(patchPath, false, false);
}
///
/// Include transforms in a patch.
///
/// List of transforms to attach.
public void AttachTransforms(ArrayList transforms)
{
int emptyTransform = 0;
if (transforms == null || transforms.Count == 0)
{
throw new WixException(WixErrors.PatchWithoutTransforms());
}
// Get the patch id from the WixPatchId table.
string patchId = null;
Table wixPatchIdTable = this.patch.Tables["WixPatchId"];
if (null != wixPatchIdTable && 0 < wixPatchIdTable.Rows.Count)
{
Row patchIdRow = wixPatchIdTable.Rows[0];
if (null != patchIdRow)
{
patchId = patchIdRow[0].ToString();
}
}
if (null == patchId)
{
throw new WixException(WixErrors.ExpectedPatchIdInWixMsp());
}
// enumerate patch.Media to map diskId to Media row
Hashtable mediaRows = new Hashtable();
Table patchMediaTable = patch.Tables["Media"];
if (patchMediaTable != null)
{
foreach (MediaRow row in patchMediaTable.Rows)
{
int media = row.DiskId;
mediaRows[media] = row;
}
}
if (0 == mediaRows.Count)
{
throw new WixException(WixErrors.ExpectedMediaRowsInWixMsp());
}
// enumerate patch.WixPatchBaseline to map baseline to diskId
Hashtable baselineMedia = new Hashtable();
Table patchBaselineTable = patch.Tables["WixPatchBaseline"];
if (patchBaselineTable != null)
{
foreach (Row row in patchBaselineTable.Rows)
{
string baseline = (string)row[0];
int media = (int)row[1];
if (baselineMedia.Contains(baseline))
{
throw new InvalidOperationException(String.Format("PatchBaseline '{0}' authored into multiple Media.", baseline));
}
baselineMedia[baseline] = media;
}
}
// enumerate transforms
ArrayList productCodes = new ArrayList();
ArrayList transformNames = new ArrayList();
int transformCount = 0;
foreach (PatchTransform mainTransform in transforms)
{
string baseline = null;
int media = -1;
if (baselineMedia.Contains(mainTransform.Baseline))
{
int newMedia = (int)baselineMedia[mainTransform.Baseline];
if (media != -1 && media != newMedia)
{
throw new InvalidOperationException(String.Format("Transform authored into multiple Media '{0}' and '{1}'.", media, newMedia));
}
baseline = mainTransform.Baseline;
media = newMedia;
}
if (media == -1)
{
// transform's baseline not attached to any Media
continue;
}
Table patchRefTable = patch.Tables["WixPatchRef"];
if (patchRefTable != null && patchRefTable.Rows.Count > 0)
{
if (!this.ReduceTransform(mainTransform.Transform, patchRefTable))
{
// transform has none of the content authored into this patch
emptyTransform++;
continue;
}
}
// ensure consistent File.Sequence within each Media
MediaRow mediaRow = (MediaRow)mediaRows[media];
// TODO: should this be authored rather than inferring it from DiskId?
mediaRow.LastSequence = mediaRow.DiskId;
// ignore media table from transform.
mainTransform.Transform.Tables.Remove("Media");
mainTransform.Transform.Tables.Remove("WixMedia");
mainTransform.Transform.Tables.Remove("MsiDigitalSignature");
string productCode;
Output pairedTransform = this.BuildPairedTransform(patchId, mainTransform.Transform, mediaRow, out productCode);
productCodes.Add(productCode);
// attach these transforms to the patch object
// TODO: is this an acceptable way to auto-generate transform stream names?
string transformName = baseline + "." + (++transformCount).ToString();
patch.SubStorages.Add(new SubStorage(transformName, mainTransform.Transform));
patch.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform));
transformNames.Add(":" + transformName);
transformNames.Add(":#" + transformName);
}
if (emptyTransform == transforms.Count)
{
throw new WixException(WixErrors.PatchWithoutValidTransforms());
}
// populate MSP summary information
Table patchSummaryInfo = patch.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
// remove any existing data for these fields
for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--)
{
Row row = patchSummaryInfo.Rows[i];
switch ((SummaryInformation.Patch)row[0])
{
case SummaryInformation.Patch.ProductCodes:
case SummaryInformation.Patch.TransformNames:
case SummaryInformation.Patch.PatchCode:
case SummaryInformation.Patch.InstallerRequirement:
patchSummaryInfo.Rows.RemoveAt(i);
break;
}
}
// Semicolon delimited list of the product codes that can accept the patch.
Row templateRow = patchSummaryInfo.CreateRow(null);
templateRow[0] = (int)SummaryInformation.Patch.ProductCodes;
templateRow[1] = String.Join(";", (string[])productCodes.ToArray(typeof(string)));
// Semicolon delimited list of transform substorage names in the order they are applied.
Row savedbyRow = patchSummaryInfo.CreateRow(null);
savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames;
savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string)));
// GUID patch code for the patch.
Row revisionRow = patchSummaryInfo.CreateRow(null);
revisionRow[0] = (int)SummaryInformation.Patch.PatchCode;
revisionRow[1] = patchId;
// Indicates the minimum Windows Installer version that is required to install the patch.
Row wordsRow = patchSummaryInfo.CreateRow(null);
wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement;
wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString();
Row security = patchSummaryInfo.CreateRow(null);
security[0] = 19; //PID_SECURITY
security[1] = "4"; // Read-only enforced
Table msiPatchMetadataTable = patch.Tables["MsiPatchMetadata"];
if (null != msiPatchMetadataTable)
{
Hashtable metadataTable = new Hashtable();
foreach (Row row in msiPatchMetadataTable.Rows)
{
metadataTable.Add(row.Fields[1].Data.ToString(), row.Fields[2].Data.ToString());
}
if (metadataTable.Contains("DisplayName"))
{
string comment = String.Concat("This patch contains the logic and data required to install ", metadataTable["DisplayName"]);
Row title = patchSummaryInfo.CreateRow(null);
title[0] = 2; //PID_TITLE
title[1] = metadataTable["DisplayName"];
Row comments = patchSummaryInfo.CreateRow(null);
comments[0] = 6; //PID_COMMENTS
comments[1] = comment;
}
if (metadataTable.Contains("CodePage"))
{
Row codePage = patchSummaryInfo.CreateRow(null);
codePage[0] = 1; //PID_CODEPAGE
codePage[1] = metadataTable["CodePage"];
}
if (metadataTable.Contains("Description"))
{
Row subject = patchSummaryInfo.CreateRow(null);
subject[0] = 3; //PID_SUBJECT
subject[1] = metadataTable["Description"];
}
if (metadataTable.Contains("ManufacturerName"))
{
Row author = patchSummaryInfo.CreateRow(null);
author[0] = 4; //PID_AUTHOR
author[1] = metadataTable["ManufacturerName"];
}
}
}
///
/// Reduce the transform according to the patch references.
///
/// transform generated by torch.
/// Table contains patch family filter.
/// true if the transform is not empty
public bool ReduceTransform(Output transform, Table patchRefTable)
{
// identify sections to keep
Hashtable oldSections = new Hashtable();
Hashtable newSections = new Hashtable();
Hashtable tableKeyRows = new Hashtable();
ArrayList sequenceList = new ArrayList();
Hashtable customActionTable = new Hashtable();
foreach (Row patchRefRow in patchRefTable.Rows)
{
string tableName = (string)patchRefRow[0];
string key = (string)patchRefRow[1];
Table table = transform.Tables[tableName];
if (table == null)
{
// table not found
continue;
}
// index this table
if (!tableKeyRows.Contains(tableName))
{
Hashtable newKeyRows = new Hashtable();
foreach (Row newRow in table.Rows)
{
newKeyRows[newRow.GetPrimaryKey('/')] = newRow;
}
tableKeyRows[tableName] = newKeyRows;
}
Hashtable keyRows = (Hashtable)tableKeyRows[tableName];
Row row = (Row)keyRows[key];
if (row == null)
{
// row not found
continue;
}
// Differ.sectionDelimiter
string[] sections = row.SectionId.Split('/');
oldSections[sections[0]] = row;
newSections[sections[1]] = row;
}
// throw away sections not referenced
int keptRows = 0;
ArrayList tablesToDelete = new ArrayList();
foreach (Table table in transform.Tables)
{
if (table.Name == "_SummaryInformation")
{
continue;
}
if (table.Name == "AdminExcuteSequence"
|| table.Name == "AdminUISequence"
|| table.Name == "AdvtExecuteSequence"
|| table.Name == "InstallUISequence"
|| table.Name == "InstallExecuteSequence")
{
sequenceList.Add(table);
continue;
}
for (int i = 0; i < table.Rows.Count; i++)
{
Row row = table.Rows[i];
if (table.Name == "CustomAction")
{
customActionTable.Add(row[0], row);
}
if (null == row.SectionId)
{
table.Rows.RemoveAt(i);
i--;
}
else
{
string[] sections = row.SectionId.Split('/');
// ignore the row without section id.
if (sections[0] == string.Empty && sections[1] == string.Empty)
{
table.Rows.RemoveAt(i);
i--;
}
else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
{
keptRows++;
}
else
{
table.Rows.RemoveAt(i);
i--;
}
}
}
if (table.Rows.Count == 0)
{
tablesToDelete.Add(table.Name);
}
}
keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable, tablesToDelete);
// delete separately to avoid messing up enumeration
foreach (string tableName in tablesToDelete)
{
transform.Tables.Remove(tableName);
}
return keptRows > 0;
}
///
/// Check if the section is in a PatchFamily.
///
/// Section id in target wixout
/// Section id in upgrade wixout
/// Hashtable contains section id should be kept in the baseline wixout.
/// Hashtable contains section id should be kept in the upgrade wixout.
/// true if section in patch family
private bool IsInPatchFamily(string oldSection, string newSection, Hashtable oldSections, Hashtable newSections)
{
bool result = false;
if ((oldSection == string.Empty && newSections.Contains(newSection)) || (newSection == string.Empty && oldSections.Contains(oldSection)))
{
result = true;
}
else if (oldSection != string.Empty && newSection != string.Empty && (oldSections.Contains(oldSection) || newSections.Contains(newSection)))
{
result = true;
}
return result;
}
///
/// Reduce the transform sequence tables.
///
/// ArrayList of tables to be reduced
/// Hashtable contains section id should be kept in the baseline wixout.
/// Hashtable contains section id should be kept in the target wixout.
/// Hashtable contains all the rows in the CustomAction table.
/// ArrayList contains tables that should be deleted.
/// Number of rows left
private int ReduceTransformSequenceTable(ArrayList sequenceList, Hashtable oldSections, Hashtable newSections, Hashtable customAction, ArrayList tablesToDelete)
{
int keptRows = 0;
foreach (Table currentTable in sequenceList)
{
for (int i = 0; i < currentTable.Rows.Count; i++)
{
Row row = currentTable.Rows[i];
string actionName = row.Fields[0].Data.ToString();
string[] sections = row.SectionId.Split('/');
bool isSectionIdEmpty = (sections[0] == string.Empty && sections[1] == string.Empty);
if (row.Operation == RowOperation.None)
{
// ignore the rows without section id.
if (isSectionIdEmpty)
{
currentTable.Rows.RemoveAt(i);
i--;
}
else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
{
keptRows++;
}
else
{
currentTable.Rows.RemoveAt(i);
i--;
}
}
else if (row.Operation == RowOperation.Modify)
{
bool sequenceChanged = row.Fields[2].Modified;
bool conditionChanged = row.Fields[1].Modified;
if (sequenceChanged && !conditionChanged)
{
keptRows++;
}
else if (!sequenceChanged && conditionChanged)
{
if (isSectionIdEmpty)
{
currentTable.Rows.RemoveAt(i);
i--;
}
else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
{
keptRows++;
}
else
{
currentTable.Rows.RemoveAt(i);
i--;
}
}
else if (sequenceChanged && conditionChanged )
{
if (isSectionIdEmpty)
{
row.Fields[1].Modified = false;
keptRows++;
}
else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
{
keptRows++;
}
else
{
row.Fields[1].Modified = false;
keptRows++;
}
}
}
else if (row.Operation == RowOperation.Delete)
{
if (isSectionIdEmpty)
{
// it is a stardard action which is added by wix, we should keep this action.
row.Operation = RowOperation.None;
keptRows++;
}
else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
{
keptRows++;
}
else
{
if (customAction.ContainsKey(actionName))
{
currentTable.Rows.RemoveAt(i);
i--;
}
else
{
// it is a stardard action, we should keep this action.
row.Operation = RowOperation.None;
keptRows++;
}
}
}
else if (row.Operation == RowOperation.Add)
{
if (isSectionIdEmpty)
{
keptRows++;
}
else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
{
keptRows++;
}
else
{
if (customAction.ContainsKey(actionName))
{
currentTable.Rows.RemoveAt(i);
i--;
}
else
{
keptRows++;
}
}
}
}
if (currentTable.Rows.Count == 0)
{
tablesToDelete.Add(currentTable.Name);
}
}
return keptRows;
}
///
/// Create the #transform for the given main transform.
///
/// patch GUID from patch authoring.
/// transform generated by torch.
/// media authored into patch.
/// output string to receive ProductCode.
public Output BuildPairedTransform(string patchId, Output mainTransform, MediaRow mediaRow, out string productCode)
{
productCode = null;
Output pairedTransform = new Output(null);
pairedTransform.Type = OutputType.Transform;
pairedTransform.Codepage = mainTransform.Codepage;
// lookup productVersion property to correct summaryInformation
string newProductVersion = null;
Table mainPropertyTable = mainTransform.Tables["Property"];
if (mainPropertyTable != null)
{
foreach (Row row in mainPropertyTable.Rows)
{
if ("ProductVersion" == (string)row[0])
{
newProductVersion = (string)row[1];
}
}
}
// TODO: build class for manipulating SummaryInformation table
Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"];
// add required properties
Hashtable mainSummaryRows = new Hashtable();
foreach (Row mainSummaryRow in mainSummaryTable.Rows)
{
mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow;
}
if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
{
Row mainSummaryRow = mainSummaryTable.CreateRow(null);
mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
mainSummaryRow[1] = "0";
}
// copy summary information from core transform
Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
foreach (Row mainSummaryRow in mainSummaryTable.Rows)
{
string value = (string)mainSummaryRow[1];
switch ((SummaryInformation.Transform)mainSummaryRow[0])
{
case SummaryInformation.Transform.ProductCodes:
string[] propertyData = value.Split(';');
string oldProductVersion = propertyData[0].Substring(38);
string upgradeCode = propertyData[2];
productCode = propertyData[0].Substring(0, 38);
if (newProductVersion == null)
{
newProductVersion = oldProductVersion;
}
// force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade
mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
break;
case SummaryInformation.Transform.ValidationFlags:
// TODO: ensure this row exists in mainSummaryTable!!!!
// TODO: author these settings in patch XML or set in torch.exe
int i = Convert.ToInt32(value);
i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingRow;
i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingRow;
i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingTable;
i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingTable;
i |= (int)SummaryInformation.TransformFlags.ErrorUpdateMissingRow;
i |= (int)SummaryInformation.TransformFlags.ValidateProduct;
mainSummaryRow[1] = value = i.ToString();
break;
}
Row pairedSummaryRow = pairedSummaryTable.CreateRow(null);
pairedSummaryRow[0] = mainSummaryRow[0];
pairedSummaryRow[1] = value;
}
if (productCode == null)
{
throw new InvalidOperationException("Could not determine ProductCode from transform summary information");
}
// copy File table
Table mainFileTable = mainTransform.Tables["File"];
Table mainWixFileTable = mainTransform.Tables["WixFile"];
if (mainFileTable != null)
{
FileRowCollection mainFileRows = new FileRowCollection();
mainFileRows.AddRange(mainFileTable.Rows);
Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition);
foreach (WixFileRow mainWixFileRow in mainWixFileTable.Rows)
{
FileRow mainFileRow = mainFileRows[mainWixFileRow.File];
// set File.Sequence to non null to satisfy transform bind
mainFileRow.Sequence = 1;
// delete's don't need rows in the paired transform
if (mainFileRow.Operation == RowOperation.Delete)
{
continue;
}
FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null);
pairedFileRow.Operation = RowOperation.Modify;
for (int i = 0; i < mainFileRow.Fields.Length; i++)
{
pairedFileRow[i] = mainFileRow[i];
}
// override authored media for patch bind
// TODO: consider using File/@DiskId for patch media
mainFileRow.DiskId = mediaRow.DiskId;
mainWixFileRow.DiskId = mediaRow.DiskId;
// suppress any change to File.Sequence to avoid bloat
mainFileRow.Fields[7].Modified = false;
// force File row to appear in the transform
switch(mainFileRow.Operation)
{
case RowOperation.Modify:
case RowOperation.Add:
// set msidbFileAttributesPatchAdded
pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded;
pairedFileRow.Fields[6].Modified = true;
pairedFileRow.Operation = mainFileRow.Operation;
break;
default:
pairedFileRow.Fields[6].Modified = false;
break;
}
}
}
// add Media row to pairedTransform
Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]);
Row pairedMediaRow = pairedMediaTable.CreateRow(null);
pairedMediaRow.Operation = RowOperation.Add;
for (int i = 0; i < mediaRow.Fields.Length; i++)
{
pairedMediaRow[i] = mediaRow[i];
}
// add PatchPackage for this Media
Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]);
pairedPackageTable.Operation = TableOperation.Add;
Row pairedPackageRow = pairedPackageTable.CreateRow(null);
pairedPackageRow.Operation = RowOperation.Add;
pairedPackageRow[0] = patchId;
pairedPackageRow[1] = mediaRow.DiskId;
// add property to both identify client patches and whether those patches are removable or not
string patchPropertyId = new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper();
int allowRemoval = 0;
Table msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"];
if (null != msiPatchMetadataTable)
{
foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows)
{
// get the value of the standard AllowRemoval property, if present
string company = (string)msiPatchMetadataRow[0];
if ((null == company || 0 == company.Length) && "AllowRemoval" == (string)msiPatchMetadataRow[1])
{
allowRemoval = Convert.ToInt32((string)msiPatchMetadataRow[2]);
}
}
}
// add the property to the patch transform's Property table
Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]);
pairedPropertyTable.Operation = TableOperation.Add;
Row pairedPropertyRow = pairedPropertyTable.CreateRow(null);
pairedPropertyRow.Operation = RowOperation.Add;
pairedPropertyRow[0] = string.Format(CultureInfo.InvariantCulture, "_{0}.AllowRemoval", patchPropertyId);
pairedPropertyRow[1] = allowRemoval.ToString();
return pairedTransform;
}
}
}
Index: wix.csproj
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/wix.csproj,v
retrieving revision 1.29
retrieving revision 1.30
diff -C2 -d -r1.29 -r1.30
*** wix.csproj 29 Nov 2006 20:55:18 -0000 1.29
--- wix.csproj 27 Jun 2007 05:39:07 -0000 1.30
***************
*** 101,105 ****
!
Code
--- 101,105 ----
!
Code
***************
*** 110,114 ****
Code
!
Code
--- 110,114 ----
Code
!
Code
***************
*** 137,140 ****
--- 137,142 ----
Code
+
+
***************
*** 245,248 ****
--- 247,256 ----
Code
+
+ Code
+
+
+ Code
+
Code
***************
*** 340,343 ****
--- 348,352 ----
+
Code
***************
*** 393,395 ****
!
\ No newline at end of file
--- 402,404 ----
!
Index: BinderExtension.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/BinderExtension.cs,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** BinderExtension.cs 16 Feb 2007 09:35:12 -0000 1.13
--- BinderExtension.cs 27 Jun 2007 05:39:04 -0000 1.14
***************
*** 56,59 ****
--- 56,60 ----
private bool reuseCabinets;
private StringCollection sourcePaths;
+ private SubStorage activeSubstorage = null;
///
***************
*** 115,118 ****
--- 116,129 ----
///
+ /// Gets or sets the active subStorage used for binding.
+ ///
+ /// The subStorage object.
+ public SubStorage ActiveSubStorage
+ {
+ get { return this.activeSubstorage; }
+ set { this.activeSubstorage = value; }
+ }
+
+ ///
/// Compares two files to determine if they are equivalent.
///
Index: Linker.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Linker.cs,v
retrieving revision 1.46
retrieving revision 1.47
diff -C2 -d -r1.46 -r1.47
*** Linker.cs 2 Mar 2007 12:22:59 -0000 1.46
--- Linker.cs 27 Jun 2007 05:39:06 -0000 1.47
***************
*** 28,31 ****
--- 28,32 ----
using Microsoft.Tools.WindowsInstallerXml.Msi;
+ using Microsoft.Tools.WindowsInstallerXml.Msi.Interop;
///
***************
*** 577,580 ****
--- 578,588 ----
case "WixAction":
+ if (this.sectionIdOnRows)
+ {
+ foreach (Row row in table.Rows)
+ {
+ row.SectionId = sectionId;
+ }
+ }
actionRows.AddRange(table.Rows);
break;
***************
*** 814,817 ****
--- 822,829 ----
break;
+ case "WixFragment":
+ copyRows = true;
+ break;
+
case "WixMedia":
copyRows = true;
***************
*** 873,876 ****
--- 885,889 ----
case "WixPatchRef":
case "WixPatchBaseline":
+ case "WixPatchId":
copyRows = true;
break;
***************
*** 885,888 ****
--- 898,924 ----
}
+ // Verify that there were no duplicate fragment Id's.
+ Table wixFragmentTable = this.activeOutput.Tables["WixFragment"];
+ Hashtable fragmentIdIndex = new Hashtable();
+ if (null != wixFragmentTable)
+ {
+ foreach (Row row in wixFragmentTable.Rows)
+ {
+ string fragmentId = row.Fields[0].Data.ToString();
+ if (!fragmentIdIndex.ContainsKey(fragmentId))
+ {
+ fragmentIdIndex.Add(fragmentId, row.SourceLineNumbers);
+ }
+ else
+ {
+ this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, fragmentId));
+ if (null != fragmentIdIndex[fragmentId])
+ {
+ this.OnMessage(WixErrors.DuplicateSymbol2((SourceLineNumberCollection)fragmentIdIndex[fragmentId]));
+ }
+ }
+ }
+ }
+
// copy the module to feature connections into the output
if (0 < modulesToFeatures.Count)
***************
*** 928,932 ****
suppressActionTable.Rows.AddRange(suppressActionRows);
}
!
// sequence all the actions
this.SequenceActions(actionRows, suppressActionRows);
--- 964,968 ----
suppressActionTable.Rows.AddRange(suppressActionRows);
}
!
// sequence all the actions
this.SequenceActions(actionRows, suppressActionRows);
***************
*** 1106,1109 ****
--- 1142,1173 ----
}
+ //correct the section Id in FeatureComponents table
+ if (this.sectionIdOnRows)
+ {
+ Hashtable componentSectionIds = new Hashtable();
+ Table componentTable = output.Tables["Component"];
+
+ if (null != componentTable)
+ {
+ foreach (Row componentRow in componentTable.Rows)
+ {
+ componentSectionIds.Add(componentRow.Fields[0].Data.ToString(), componentRow.SectionId);
+ }
+ }
+
+ Table featureComponentsTable = output.Tables["FeatureComponents"];
+
+ if (null != featureComponentsTable)
+ {
+ foreach (Row featureComponentsRow in featureComponentsTable.Rows)
+ {
+ if (componentSectionIds.Contains(featureComponentsRow.Fields[1].Data.ToString()))
+ {
+ featureComponentsRow.SectionId = (string)componentSectionIds[featureComponentsRow.Fields[1].Data.ToString()];
+ }
+ }
+ }
+ }
+
// update the special properties
if (0 < adminProperties.Count)
***************
*** 1211,1219 ****
}
}
-
- if (this.activeOutput.Type == OutputType.Patch)
- {
- this.AttachPatchTransforms(transforms);
- }
}
finally
--- 1275,1278 ----
***************
*** 1509,1513 ****
if (ComplexReferenceParentType.Group == wixComplexReferenceRow.ParentType ||
ComplexReferenceParentType.Feature == wixComplexReferenceRow.ParentType ||
! ComplexReferenceParentType.Module == wixComplexReferenceRow.ParentType)
{
// Group all complex references with a common parent
--- 1568,1573 ----
if (ComplexReferenceParentType.Group == wixComplexReferenceRow.ParentType ||
ComplexReferenceParentType.Feature == wixComplexReferenceRow.ParentType ||
! ComplexReferenceParentType.Module == wixComplexReferenceRow.ParentType ||
! ComplexReferenceParentType.Product == wixComplexReferenceRow.ParentType)
{
// Group all complex references with a common parent
***************
*** 1611,1615 ****
foreach (WixComplexReferenceRow wixComplexReferenceRow in referencesToParent)
{
! Debug.Assert(ComplexReferenceParentType.Group == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Feature == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Module == wixComplexReferenceRow.ParentType);
Debug.Assert(parentId == wixComplexReferenceRow.ParentId);
--- 1671,1675 ----
foreach (WixComplexReferenceRow wixComplexReferenceRow in referencesToParent)
{
! Debug.Assert(ComplexReferenceParentType.Group == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Feature == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Module == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Product == wixComplexReferenceRow.ParentType);
Debug.Assert(parentId == wixComplexReferenceRow.ParentId);
***************
*** 2394,2397 ****
--- 2454,2462 ----
Table sequenceTable = this.activeOutput.EnsureTable(sequenceTableDefinition);
Row row = sequenceTable.CreateRow(actionRow.SourceLineNumbers);
+ if (this.sectionIdOnRows)
+ {
+ row.SectionId = actionRow.SectionId;
+ }
+
if (OutputType.Module == this.activeOutput.Type)
{
***************
*** 2479,2868 ****
}
}
-
- ///
- /// Include transforms in a patch.
- ///
- /// List of transforms to attach.
- public void AttachPatchTransforms(ArrayList transforms)
- {
- if (transforms == null || transforms.Count == 0)
- {
- throw new ArgumentException("Expected WIXMSTs to link with.", "wixmst");
- }
-
- Output output = this.activeOutput;
- string patchId = output.EntrySection.Id;
-
- // enumerate patch.Media to map diskId to Media row
- Hashtable mediaRows = new Hashtable();
- Table patchMediaTable = output.Tables["Media"];
- if (patchMediaTable != null)
- {
- foreach (MediaRow row in patchMediaTable.Rows)
- {
- int media = row.DiskId;
- mediaRows[media] = row;
- }
- }
-
- // enumerate patch.WixPatchBaseline to map baseline to diskId
- Hashtable baselineMedia = new Hashtable();
- Table patchBaselineTable = output.Tables["WixPatchBaseline"];
- if (patchBaselineTable != null)
- {
- foreach (Row row in patchBaselineTable.Rows)
- {
- string baseline = (string) row[0];
- int media = (int)row[1];
- if (baselineMedia.Contains(baseline))
- {
- throw new InvalidOperationException(String.Format("PatchBaseline '{0}' authored into multiple Media.", baseline));
- }
- baselineMedia[baseline] = media;
- }
- }
-
- Table patchRefTable = output.Tables["WixPatchRef"];
-
- // enumerate transforms
- ArrayList productCodes = new ArrayList();
- ArrayList transformNames = new ArrayList();
- int transformCount = 0;
- foreach (Output mainTransform in transforms)
- {
- string baseline = null;
- int media = -1;
- Table transformBaselineTable = mainTransform.Tables["WixPatchBaseline"];
- if (transformBaselineTable != null)
- {
- foreach (Row row in transformBaselineTable.Rows)
- {
- string newBaseline = (string) row[0];
- if (baselineMedia.Contains(newBaseline))
- {
- int newMedia = (int)baselineMedia[newBaseline];
- if (media != -1 && media != newMedia)
- {
- throw new InvalidOperationException(String.Format("Transform authored into multiple Media '{0}' and '{1}'.", media, newMedia));
- }
- baseline = newBaseline;
- media = newMedia;
- }
- }
-
- // for some reason, this unreal table does not get removed prior to binding the transform
- mainTransform.Tables.Remove("WixPatchBaseline");
- }
- if (media == -1)
- {
- // transform's baseline not attached to any Media
- continue;
- }
-
- if (patchRefTable != null && patchRefTable.Rows.Count > 0)
- {
- if (!this.ReduceTransform(mainTransform, patchRefTable))
- {
- // transform has none of the content authored into this patch
- continue;
- }
- }
-
- // ensure consistent File.Sequence within each Media
- MediaRow mediaRow = (MediaRow)mediaRows[media];
- // TODO: should this be authored rather than inferring it from DiskId?
- mediaRow.LastSequence = mediaRow.DiskId;
-
- string productCode = null;
- Output pairedTransform = this.BuildPairedTransform(patchId, mainTransform, mediaRow, ref productCode);
- productCodes.Add(productCode);
-
- // attach these transforms to the patch object
- // TODO: is this an acceptable way to auto-generate transform stream names?
- string transformName = baseline + "." + (++transformCount).ToString();
- output.SubStorages.Add(new SubStorage(transformName, mainTransform));
- output.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform));
- transformNames.Add(":" + transformName);
- transformNames.Add(":#" + transformName);
- }
-
- // populate MSP summary information
- Table patchSummaryInfo = output.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
- // remove any existing data for these fields
- for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--)
- {
- Row row = patchSummaryInfo.Rows[i];
- switch ((SummaryInformation.Patch)row[0])
- {
- case SummaryInformation.Patch.ProductCodes:
- case SummaryInformation.Patch.TransformNames:
- case SummaryInformation.Patch.PatchCode:
- case SummaryInformation.Patch.InstallerRequirement:
- patchSummaryInfo.Rows.RemoveAt(i);
- break;
- }
- }
-
- // Semicolon delimited list of the product codes that can accept the patch.
- Row templateRow = patchSummaryInfo.CreateRow(null);
- templateRow[0] = (int)SummaryInformation.Patch.ProductCodes;
- templateRow[1] = String.Join(";", (string[])productCodes.ToArray(typeof(string)));
-
- // Semicolon delimited list of transform substorage names in the order they are applied.
- Row savedbyRow = patchSummaryInfo.CreateRow(null);
- savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames;
- savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string)));
-
- // GUID patch code for the patch.
- Row revisionRow = patchSummaryInfo.CreateRow(null);
- revisionRow[0] = (int)SummaryInformation.Patch.PatchCode;
- revisionRow[1] = patchId;
-
- // Indicates the minimum Windows Installer version that is required to install the patch.
- Row wordsRow = patchSummaryInfo.CreateRow(null);
- wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement;
- wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString();
- }
-
- ///
- /// Reduce the transform according to the patch references.
- ///
- /// transform generated by torch.
- /// output string to receive ProductCode.
- /// true if the transform is not empty
- public bool ReduceTransform(Output transform, Table patchRefTable)
- {
- // identify sections to keep
- Hashtable oldSections = new Hashtable();
- Hashtable newSections = new Hashtable();
- Hashtable tableKeyRows = new Hashtable();
- foreach (Row patchRefRow in patchRefTable.Rows)
- {
- string tableName = (string)patchRefRow[0];
- string key = (string)patchRefRow[1];
-
- Table table = transform.Tables[tableName];
- if (table == null)
- {
- // table not found
- continue;
- }
-
- // index this table
- if (!tableKeyRows.Contains(tableName))
- {
- Hashtable newKeyRows = new Hashtable();
- foreach (Row newRow in table.Rows)
- {
- newKeyRows[newRow.GetPrimaryKey('/')] = newRow;
- }
- tableKeyRows[tableName] = newKeyRows;
- }
- Hashtable keyRows = (Hashtable)tableKeyRows[tableName];
-
- Row row = (Row)keyRows[key];
- if (row == null)
- {
- // row not found
- continue;
- }
-
- // Differ.sectionDelimiter
- string[] sections = row.SectionId.Split('/');
- oldSections[sections[0]] = row;
- newSections[sections[1]] = row;
- }
-
- // throw away sections not referenced
- int keptRows = 0;
- ArrayList tablesToDelete = new ArrayList();
- foreach (Table table in transform.Tables)
- {
- if (table.Name == "_SummaryInformation")
- {
- continue;
- }
-
- for (int i = 0; i < table.Rows.Count; i++)
- {
- Row row = table.Rows[i];
- string[] sections = row.SectionId.Split('/');
- if (oldSections.Contains(sections[0]) || newSections.Contains(sections[1]))
- {
- keptRows++;
- }
- else
- {
- table.Rows.RemoveAt(i);
- i--;
- }
- }
-
- if (table.Rows.Count == 0 && table.Operation == TableOperation.None)
- {
- tablesToDelete.Add(table.Name);
- }
- }
-
- // delete separately to avoid messing up enumeration
- foreach (string tableName in tablesToDelete)
- {
- transform.Tables.Remove(tableName);
- }
-
- return keptRows > 0;
- }
-
- ///
- /// Create the #transform for the given main transform.
- ///
- /// patch GUID from patch authoring.
- /// transform generated by torch.
- /// media authored into patch.
- /// output string to receive ProductCode.
- public Output BuildPairedTransform(string patchId, Output mainTransform, MediaRow mediaRow, ref string productCode)
- {
- Output pairedTransform = new Output(null);
- pairedTransform.Type = OutputType.Transform;
- pairedTransform.Codepage = mainTransform.Codepage;
-
- // lookup productVersion property to correct summaryInformation
- string newProductVersion = null;
- Table mainPropertyTable = mainTransform.Tables["Property"];
- if (mainPropertyTable != null)
- {
- foreach (Row row in mainPropertyTable.Rows)
- {
- if ("ProductVersion" == (string)row[0])
- {
- newProductVersion = (string)row[1];
- }
- }
- }
-
- // TODO: build class for manipulating SummaryInformation table
- Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"];
- // add required properties
- Hashtable mainSummaryRows = new Hashtable();
- foreach (Row mainSummaryRow in mainSummaryTable.Rows)
- {
- mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow;
- }
- if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
- {
- Row mainSummaryRow = mainSummaryTable.CreateRow(null);
- mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
- mainSummaryRow[1] = "0";
- }
-
- // copy summary information from core transform
- Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
- foreach (Row mainSummaryRow in mainSummaryTable.Rows)
- {
- string value = (string)mainSummaryRow[1];
- switch ((SummaryInformation.Transform)mainSummaryRow[0])
- {
- case SummaryInformation.Transform.ProductCodes:
- string[] propertyData = value.Split(';');
- string oldProductVersion = propertyData[0].Substring(38);
- string upgradeCode = propertyData[2];
- productCode = propertyData[0].Substring(0, 38);
- if (newProductVersion == null)
- {
- newProductVersion = oldProductVersion;
- }
-
- // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade
- mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
- value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
- break;
- case SummaryInformation.Transform.ValidationFlags:
- // TODO: ensure this row exists in mainSummaryTable!!!!
- // TODO: author these settings in patch XML or set in torch.exe
- int i = Convert.ToInt32(value);
- i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingRow;
- i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingRow;
- i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingTable;
- i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingTable;
- i |= (int)SummaryInformation.TransformFlags.ErrorUpdateMissingRow;
- i |= (int)SummaryInformation.TransformFlags.ValidateProduct;
- mainSummaryRow[1] = value = i.ToString();
- break;
- }
- Row pairedSummaryRow = pairedSummaryTable.CreateRow(null);
- pairedSummaryRow[0] = mainSummaryRow[0];
- pairedSummaryRow[1] = value;
- }
-
- if (productCode == null)
- {
- throw new InvalidOperationException("Could not determine ProductCode from transform summary information");
- }
-
- // copy File table
- Table mainFileTable = mainTransform.Tables["File"];
- Table mainWixFileTable = mainTransform.Tables["WixFile"];
- if (mainFileTable != null)
- {
- FileRowCollection mainFileRows = new FileRowCollection();
- mainFileRows.AddRange(mainFileTable.Rows);
-
- Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition);
- foreach (Row mainWixFileRow in mainWixFileTable.Rows)
- {
- FileRow mainFileRow = mainFileRows[(string)mainWixFileRow[0]];
-
- // set File.Sequence to non null to satisfy transform bind
- mainFileRow.Sequence = 1;
-
- // delete's don't need rows in the paired transform
- if (mainFileRow.Operation == RowOperation.Delete)
- {
- continue;
- }
-
- FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null);
- pairedFileRow.Operation = RowOperation.Modify;
- for (int i = 0; i < mainFileRow.Fields.Length; i++)
- {
- object value = mainFileRow[i];
- pairedFileRow[i] = value;
- }
-
- // override authored media for patch bind
- // TODO: consider using File/@DiskId for patch media
- mainFileRow.DiskId = mediaRow.DiskId;
- mainWixFileRow[5] = mediaRow.DiskId;
- // suppress any change to File.Sequence to avoid bloat
- mainFileRow.Fields[7].Modified = false;
- // force File row to appear in the transform
- mainFileRow.Operation = RowOperation.Modify;
-
- // set msidbFileAttributesPatchAdded
- pairedFileRow.Attributes |= 0x001000;
- pairedFileRow.Fields[6].Modified = true;
- pairedFileRow.Operation = RowOperation.Modify;
- }
- }
-
- // add Media row to pairedTransform
- Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]);
- Row pairedMediaRow = pairedMediaTable.CreateRow(null);
- pairedMediaRow.Operation = RowOperation.Add;
- for (int i = 0; i < mediaRow.Fields.Length; i++)
- {
- pairedMediaRow[i] = mediaRow[i];
- }
-
- // add PatchPackage for this Media
- Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]);
- pairedPackageTable.Operation = TableOperation.Add;
- Row pairedPackageRow = pairedPackageTable.CreateRow(null);
- pairedPackageRow.Operation = RowOperation.Add;
- pairedPackageRow[0] = patchId;
- pairedPackageRow[1] = mediaRow.DiskId;
-
- return pairedTransform;
- }
}
}
--- 2544,2547 ----
Index: wixdll.build
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/wixdll.build,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -d -r1.18 -r1.19
*** wixdll.build 29 Nov 2006 20:55:18 -0000 1.18
--- wixdll.build 27 Jun 2007 05:39:07 -0000 1.19
***************
*** 180,183 ****
--- 180,185 ----
+
+
***************
*** 187,190 ****
--- 189,194 ----
+
+
***************
*** 207,210 ****
--- 211,215 ----
+
Index: Differ.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Differ.cs,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** Differ.cs 16 Feb 2007 09:35:12 -0000 1.2
--- Differ.cs 27 Jun 2007 05:39:06 -0000 1.3
***************
*** 31,35 ****
{
private bool suppressKeepingSpecialRows;
! private string patchBaseline;
private const char sectionDelimiter = '/';
--- 31,35 ----
{
private bool suppressKeepingSpecialRows;
! private bool preserveUnchangedRows;
private const char sectionDelimiter = '/';
***************
*** 57,67 ****
///
! /// Gets or sets the baseline for a patch transform.
///
! /// The baseline identifier for this transform.
! public string PatchBaseline
{
! get { return this.patchBaseline; }
! set { this.patchBaseline = value; }
}
--- 57,67 ----
///
! /// Gets or sets the flag to determine if all rows, even unchanged ones will be persisted in the output.
///
! /// The option to keep all rows including unchanged rows.
! public bool PreserveUnchangedRows
{
! get { return this.preserveUnchangedRows; }
! set { this.preserveUnchangedRows = value; }
}
***************
*** 74,77 ****
--- 74,78 ----
public Output Diff(Output targetOutput, Output updatedOutput)
{
+ Hashtable cabinets = new Hashtable();
Output transform = new Output(null);
transform.Type = OutputType.Transform;
***************
*** 200,203 ****
--- 201,205 ----
else // possibly modified
{
+ updatedRow.Operation = RowOperation.None;
if (!this.suppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name)
{
***************
*** 210,214 ****
bool keepRow = false;
! if (null != this.patchBaseline)
{
keepRow = true;
--- 212,216 ----
bool keepRow = false;
! if (this.preserveUnchangedRows)
{
keepRow = true;
***************
*** 234,237 ****
--- 236,246 ----
}
}
+ else if (ColumnType.Preserved == columnDefinition.Type)
+ {
+ updatedRow.Fields[i].PreviousData = (string)targetRow.Fields[i].Data;
+
+ // keep rows containing preserved fields so the historical data is available to the binder
+ keepRow = !this.suppressKeepingSpecialRows;
+ }
else if (ColumnType.Object == columnDefinition.Type)
{
***************
*** 239,246 ****
ObjectField updatedObjectField = (ObjectField)updatedRow.Fields[i];
! if (null != targetObjectField.CabinetFileId)
! {
! // TODO: handle this
! }
if ((string)targetObjectField.Data != (string)updatedObjectField.Data)
--- 248,253 ----
ObjectField updatedObjectField = (ObjectField)updatedRow.Fields[i];
! updatedObjectField.PreviousCabinetFileId = targetObjectField.CabinetFileId;
! updatedObjectField.PreviousBaseUri = targetObjectField.BaseUri;
if ((string)targetObjectField.Data != (string)updatedObjectField.Data)
***************
*** 269,273 ****
{
Table modifiedTable = transform.EnsureTable(updatedTable.Definition);
- updatedRow.Operation = RowOperation.Modify;
updatedRow.SectionId = targetRow.SectionId + sectionDelimiter + updatedRow.SectionId;
modifiedTable.Rows.Add(updatedRow);
--- 276,279 ----
***************
*** 324,336 ****
}
- // save the baseline in the transform
- if (null != this.patchBaseline)
- {
- TableDefinitionCollection tableDefinitions = Installer.GetTableDefinitions();
- Table baselineTable = transform.EnsureTable(tableDefinitions["WixPatchBaseline"]);
- Row baselineRow = baselineTable.CreateRow(null);
- baselineRow[0] = this.patchBaseline;
- }
-
return transform;
}
--- 330,333 ----
Index: Validator.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Validator.cs,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** Validator.cs 16 Aug 2006 05:18:19 -0000 1.8
--- Validator.cs 27 Jun 2007 05:39:07 -0000 1.9
***************
*** 36,43 ****
private StringCollection cubeFiles;
private bool encounteredError;
! private Hashtable indexedSourceLineNumbers;
private Output output;
private string[] suppressedICEs;
- private SourceLineNumberCollection sourceLineNumbers;
private TempFileCollection tempFiles;
--- 36,42 ----
private StringCollection cubeFiles;
private bool encounteredError;
! private ValidatorExtension extension;
private Output output;
private string[] suppressedICEs;
private TempFileCollection tempFiles;
***************
*** 48,57 ****
{
this.cubeFiles = new StringCollection();
}
///
! /// Event for messages.
///
! public event MessageEventHandler Message;
///
--- 47,62 ----
{
this.cubeFiles = new StringCollection();
+ this.extension = new ValidatorExtension();
}
///
! /// Gets or sets a that directs messages from the validator.
///
! /// A that directs messages from the validator.
! public ValidatorExtension Extension
! {
! get { return this.extension; }
! set { this.extension = value; }
! }
///
***************
*** 61,64 ****
--- 66,70 ----
public Output Output
{
+ // cache Output object until validation for changes in extension
get { return this.output; }
set { this.output = value; }
***************
*** 127,131 ****
}
! this.sourceLineNumbers = SourceLineNumberCollection.FromFileName(databaseFile);
// if we don't have the temporary files object yet, get one
--- 133,140 ----
}
! // initialize the validator extension
! this.extension.DatabaseFile = databaseFile;
! this.extension.Output = this.output;
! this.extension.InitializeValidator();
// if we don't have the temporary files object yet, get one
***************
*** 248,252 ****
// disable the internal UI handler and set an external UI handler
previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd);
! currentUIHandler = new InstallUIHandler(this.ValidationUIHandler); // very important - this prevents the external UI delegate from being garbage collected too early
previousUIHandler = Installer.SetExternalUI(currentUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero);
--- 257,261 ----
// disable the internal UI handler and set an external UI handler
previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd);
! currentUIHandler = new InstallUIHandler(this.ValidationUIHandler);
previousUIHandler = Installer.SetExternalUI(currentUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero);
***************
*** 282,289 ****
Installer.SetInternalUI(previousUILevel, ref previousHwnd);
this.cubeFiles.Clear();
! this.indexedSourceLineNumbers = null;
! this.output = null;
! this.sourceLineNumbers = null;
}
--- 291,299 ----
Installer.SetInternalUI(previousUILevel, ref previousHwnd);
+ // very important - this prevents the external UI delegate from being garbage collected too early
+ GC.KeepAlive(currentUIHandler);
+
this.cubeFiles.Clear();
! this.extension.FinalizeValidator();
}
***************
*** 327,338 ****
}
! if (null != this.Message)
! {
! this.Message(this, mea);
! }
! else if (null != errorEventArgs)
! {
! throw new WixException(errorEventArgs);
! }
}
--- 337,341 ----
}
! this.extension.OnMessage(mea);
}
***************
*** 348,443 ****
private int ValidationUIHandler(IntPtr context, uint messageType, string message)
{
! string[] messageParts = message.Split('\t');
!
! if (3 > messageParts.Length)
! {
! this.OnMessage(WixErrors.UnexpectedExternalUIMessage(message));
! return -1;
! }
!
! SourceLineNumberCollection messageSourceLineNumbers = null;
! if (6 < messageParts.Length)
! {
! string[] primaryKeys = new string[messageParts.Length - 6];
!
! Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length);
!
! messageSourceLineNumbers = this.GetSourceLineNumbers(messageParts[4], primaryKeys);
! }
! else // use the file name as the source line information
! {
! messageSourceLineNumbers = this.sourceLineNumbers;
! }
!
! switch (messageParts[1])
! {
! case "1":
! this.OnMessage(WixErrors.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2]));
! break;
! case "2":
! this.OnMessage(WixWarnings.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2]));
! break;
! case "3":
! this.OnMessage(WixVerboses.ValidationInfo(messageParts[0], messageParts[2]));
! break;
! default:
! throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Unknown validation message type '{0}'.", messageParts[1]));
! }
!
return 1;
}
-
- ///
- /// Gets the source line information (if available) for a row by its table name and primary key.
- ///
- /// The table name of the row.
- /// The primary keys of the row.
- /// The source line number information if found; null otherwise.
- private SourceLineNumberCollection GetSourceLineNumbers(string tableName, string[] primaryKeys)
- {
- // source line information only exists if an output file was supplied
- if (null != this.output)
- {
- // index the source line information if it hasn't been indexed already
- if (null == this.indexedSourceLineNumbers)
- {
- this.indexedSourceLineNumbers = new Hashtable();
-
- // index each real table
- foreach (Table table in this.output.Tables)
- {
- // skip unreal tables
- if (table.Definition.IsUnreal)
- {
- continue;
- }
-
- // index each row
- foreach (Row row in table.Rows)
- {
- // skip rows that don't contain source line information
- if (null == row.SourceLineNumbers)
- {
- continue;
- }
-
- // index the row using its table name and primary key
- string primaryKey = row.GetPrimaryKey(';');
- if (null != primaryKey)
- {
- string key = String.Concat(table.Name, ":", primaryKey);
-
- this.indexedSourceLineNumbers.Add(key, row.SourceLineNumbers);
- }
- }
- }
- }
-
- return (SourceLineNumberCollection)this.indexedSourceLineNumbers[String.Concat(tableName, ":", String.Join(";", primaryKeys))];
- }
-
- // use the file name as the source line information
- return this.sourceLineNumbers;
- }
}
}
--- 351,357 ----
private int ValidationUIHandler(IntPtr context, uint messageType, string message)
{
! this.extension.Log(message);
return 1;
}
}
}
Index: Preprocessor.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Preprocessor.cs,v
retrieving revision 1.30
retrieving revision 1.31
diff -C2 -d -r1.30 -r1.31
*** Preprocessor.cs 2 Mar 2007 12:22:59 -0000 1.30
--- Preprocessor.cs 27 Jun 2007 05:39:06 -0000 1.31
***************
*** 482,485 ****
--- 482,491 ----
this.PreprocessDefine(reader.Value);
break;
+ case "error":
+ this.PreprocessError(reader.Value);
+ break;
+ case "warning":
+ this.PreprocessWarning(reader.Value);
+ break;
case "undef":
this.PreprocessUndef(reader.Value);
***************
*** 697,700 ****
--- 703,726 ----
///
+ /// Processes an error processing instruction.
+ ///
+ /// Text from source.
+ private void PreprocessError(string errorMessage)
+ {
+ SourceLineNumberCollection sourceLineNumbers = this.GetCurrentSourceLineNumbers();
+ throw new WixException(WixErrors.PreprocessorError(sourceLineNumbers, errorMessage));
+ }
+
+ ///
+ /// Processes a warning processing instruction.
+ ///
+ /// Text from source.
+ private void PreprocessWarning(string warningMessage)
+ {
+ SourceLineNumberCollection sourceLineNumbers = this.GetCurrentSourceLineNumbers();
+ this.core.OnMessage(WixWarnings.PreprocessorWarning(sourceLineNumbers, warningMessage));
+ }
+
+ ///
/// Processes a define processing instruction and creates the appropriate parameter.
///
Index: Compiler.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Compiler.cs,v
retrieving revision 1.63
retrieving revision 1.64
diff -C2 -d -r1.63 -r1.64
*** Compiler.cs 2 Mar 2007 12:22:57 -0000 1.63
--- Compiler.cs 27 Jun 2007 05:39:04 -0000 1.64
***************
*** 274,344 ****
///
- /// Generates a short file/directory name using an identifier and long file/directory name as input.
- ///
- /// The long file/directory name.
- /// The option to keep the extension on generated short names.
- /// true if wildcards are allowed in the filename.
- /// Any additional information to include in the hash for the generated short name.
- /// The generated 8.3-compliant short file/directory name.
- private string GenerateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args)
[...1080 lines suppressed...]
}
--- 13862,13866 ----
if (null == shortName)
{
! shortName = CompilerCore.GenerateShortName(name, true, false, node.LocalName, componentId, directory);
}
}
***************
*** 15307,15311 ****
disabled = true;
! this.EnsureTable(sourceLineNumbers, "Billboard");
break;
case "Bitmap":
--- 15328,15332 ----
disabled = true;
! this.core.EnsureTable(sourceLineNumbers, "Billboard");
break;
case "Bitmap":
Index: AppCommon.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/AppCommon.cs,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** AppCommon.cs 24 May 2006 09:21:43 -0000 1.3
--- AppCommon.cs 27 Jun 2007 05:39:04 -0000 1.4
***************
*** 100,108 ****
{
// find extensions
! AppSettingsReader appSettingsReader = new AppSettingsReader();
! string extensionTypes = (string)appSettingsReader.GetValue("extensions", typeof(string));
! foreach (string extensionType in extensionTypes.Split(";".ToCharArray()))
{
! extensions.Add(extensionType);
}
}
--- 100,115 ----
{
// find extensions
! try
{
! AppSettingsReader appSettingsReader = new AppSettingsReader();
! string extensionTypes = (string)appSettingsReader.GetValue("extensions", typeof(string));
! foreach (string extensionType in extensionTypes.Split(";".ToCharArray()))
! {
! extensions.Add(extensionType);
! }
! }
! catch (InvalidOperationException)
! {
! // This exception is thrown if there is no extensions key in the appSettings configuration section.
}
}
Index: CabinetBuilder.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/CabinetBuilder.cs,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** CabinetBuilder.cs 16 Aug 2006 05:18:18 -0000 1.3
--- CabinetBuilder.cs 27 Jun 2007 05:39:04 -0000 1.4
***************
*** 36,39 ****
--- 36,40 ----
private object lockObject;
private int threadCount;
+ private int threadError;
///
***************
*** 71,76 ****
/// Create the queued cabinets.
///
! public void CreateQueuedCabinets()
{
// don't create more threads than the number of cabinets to build
if (this.cabinetWorkItems.Count < this.threadCount)
--- 72,79 ----
/// Create the queued cabinets.
///
! /// error message number (zero if no error)
! public int CreateQueuedCabinets()
{
+ this.threadError = 0;
// don't create more threads than the number of cabinets to build
if (this.cabinetWorkItems.Count < this.threadCount)
***************
*** 95,98 ****
--- 98,102 ----
}
}
+ return this.threadError;
}
***************
*** 164,168 ****
///
! /// Sends a message to the message delegate if there is one.
///
/// Message event arguments.
--- 168,172 ----
///
! /// Sends a message to the message delegate if there is one. WARNING: if warnings-as-errors is turned on, this won't stop the build on a warning.
///
/// Message event arguments.
***************
*** 175,178 ****
--- 179,186 ----
lock (this.lockObject)
{
+ if (null != errorEventArgs)
+ {
+ this.threadError = errorEventArgs.Id;
+ }
this.Message(this, mea);
}
***************
*** 180,183 ****
--- 188,195 ----
else if (null != errorEventArgs)
{
+ lock (this.lockObject)
+ {
+ this.threadError = errorEventArgs.Id;
+ }
throw new WixException(errorEventArgs);
}
Index: Field.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Field.cs,v
retrieving revision 1.19
retrieving revision 1.20
diff -C2 -d -r1.19 -r1.20
*** Field.cs 13 Sep 2006 08:13:36 -0000 1.19
--- Field.cs 27 Jun 2007 05:39:06 -0000 1.20
***************
*** 34,37 ****
--- 34,38 ----
private object data;
private bool modified;
+ private string previousData;
///
***************
*** 85,88 ****
--- 86,99 ----
///
+ /// Gets or sets the previous data.
+ ///
+ /// The previous data.
+ public string PreviousData
+ {
+ get { return this.previousData; }
+ set { this.previousData = value; }
+ }
+
+ ///
/// Instantiate a new Field object of the correct type.
///
***************
*** 129,132 ****
--- 140,146 ----
this.modified = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "field", reader.Name, reader.Value);
break;
+ case "previousData":
+ this.previousData = reader.Value;
+ break;
default:
if (!reader.NamespaceURI.StartsWith("http://www.w3.org/"))
***************
*** 204,207 ****
--- 218,226 ----
}
+ if (null != this.previousData)
+ {
+ writer.WriteAttributeString("previousData", this.previousData);
+ }
+
if (this.columnDefinition.UseCData)
{
Index: WixFileRow.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/WixFileRow.cs,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** WixFileRow.cs 6 Dec 2006 10:18:53 -0000 1.2
--- WixFileRow.cs 27 Jun 2007 05:39:07 -0000 1.3
***************
*** 25,28 ****
--- 25,43 ----
///
+ /// PatchAttribute values
+ ///
+ [Flags]
+ public enum PatchAttributeType
+ {
+ None = 0,
+
+ /// Prevents the updating of the file that is in fact changed in the upgraded image relative to the target images.
+ Ignore = 1,
+
+ /// Allowed bits.
+ Defined = Ignore
+ }
+
+ ///
/// Specialization of a row for the WixFile table.
///
***************
*** 148,151 ****
--- 163,186 ----
set { this.Fields[6].Data = value; }
}
+
+ ///
+ /// Gets or sets the source location to the file.
+ ///
+ /// Source location to the file.
+ public string PreviousSource
+ {
+ get { return (string)this.Fields[6].PreviousData; }
+ set { this.Fields[6].PreviousData = value; }
+ }
+
+ ///
+ /// Gets or sets the patching attributes to the file.
+ ///
+ /// Patching attributes of the file.
+ public PatchAttributeType PatchAttributes
+ {
+ get { return (PatchAttributeType) Convert.ToInt32(this.Fields[10].Data, CultureInfo.InvariantCulture); }
+ set { this.Fields[10].Data = (int) value; }
+ }
}
}
Index: WixExtension.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/WixExtension.cs,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** WixExtension.cs 13 Sep 2006 08:13:36 -0000 1.5
--- WixExtension.cs 27 Jun 2007 05:39:07 -0000 1.6
***************
*** 75,78 ****
--- 75,87 ----
///
+ /// Gets the optional validator extension.
+ ///
+ /// The optional validator extension.
+ public virtual ValidatorExtension ValidatorExtension
+ {
+ get { return null; }
+ }
+
+ ///
/// Loads a WixExtension from a type description string.
///
Index: ObjectField.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/ObjectField.cs,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** ObjectField.cs 13 Sep 2006 08:13:36 -0000 1.5
--- ObjectField.cs 27 Jun 2007 05:39:06 -0000 1.6
***************
*** 30,34 ****
private string baseUri;
private string cabinetFileId;
! private string previousData;
///
--- 30,35 ----
private string baseUri;
private string cabinetFileId;
! private string previousCabinetFileId;
! private string previousBaseUri;
///
***************
*** 52,62 ****
///
! /// Gets or sets the previous data.
///
! /// The previous data.
! public string PreviousData
{
! get { return this.previousData; }
! set { this.previousData = value; }
}
--- 53,73 ----
///
! /// Gets or sets the previous identifier of the file in the cabinet.
///
! /// The identifier of the file in the cabinet.
! public string PreviousCabinetFileId
{
! get { return this.previousCabinetFileId; }
! set { this.previousCabinetFileId = value; }
! }
!
! ///
! /// Gets or sets the path to the embedded cabinet of the previous file.
! ///
! /// The path of the cabinet containing the previous file.
! public string PreviousBaseUri
! {
! get { return this.previousBaseUri; }
! set { this.previousBaseUri = value; }
}
***************
*** 93,97 ****
break;
case "previousData":
! this.previousData = reader.Value;
break;
default:
--- 104,111 ----
break;
case "previousData":
! this.PreviousData = reader.Value;
! break;
! case "previousCabinetFileId":
! this.previousCabinetFileId = reader.Value;
break;
default:
***************
*** 164,170 ****
}
! if (null != this.previousData)
{
! writer.WriteAttributeString("previousData", this.previousData);
}
--- 178,189 ----
}
! if (null != this.PreviousData)
{
! writer.WriteAttributeString("previousData", this.PreviousData);
! }
!
! if (null != this.previousCabinetFileId)
! {
! writer.WriteAttributeString("previousCabinetFileId", this.previousCabinetFileId);
}
Index: Binder.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Binder.cs,v
retrieving revision 1.49
retrieving revision 1.50
diff -C2 -d -r1.49 -r1.50
*** Binder.cs 2 Mar 2007 12:22:57 -0000 1.49
--- Binder.cs 27 Jun 2007 05:39:04 -0000 1.50
***************
*** 436,439 ****
--- 436,440 ----
{
case ColumnType.Localized:
+ case ColumnType.Preserved:
case ColumnType.String:
if (columnDefinition.IsPrimaryKey)
***************
*** 736,746 ****
}
! foreach (Row row in wixFileTable.Rows)
{
! FileRow fileRow = (FileRow)indexedFileRows[row[0]];
if (null != row[1])
{
! fileRow.AssemblyType = (FileAssemblyType)Enum.ToObject(typeof(FileAssemblyType), (int)row[1]);
}
else
--- 737,747 ----
}
! foreach (WixFileRow row in wixFileTable.Rows)
{
! FileRow fileRow = (FileRow)indexedFileRows[row.File];
if (null != row[1])
{
! fileRow.AssemblyType = (FileAssemblyType)Enum.ToObject(typeof(FileAssemblyType), row.AssemblyAttributes);
}
else
***************
*** 748,757 ****
fileRow.AssemblyType = FileAssemblyType.NotAnAssembly;
}
! fileRow.AssemblyManifest = (string)row[2];
! fileRow.Directory = (string)row[4];
! fileRow.DiskId = (int)row[5];
! fileRow.Source = (string)row[6];
! fileRow.ProcessorArchitecture = (string)row[7];
! fileRow.PatchGroup = (int)row[8];
}
}
--- 749,760 ----
fileRow.AssemblyType = FileAssemblyType.NotAnAssembly;
}
! fileRow.AssemblyManifest = row.AssemblyManifest;
! fileRow.Directory = row.Directory;
! fileRow.DiskId = row.DiskId;
! fileRow.Source = row.Source;
! fileRow.PreviousSource = row.PreviousSource;
! fileRow.ProcessorArchitecture = row.ProcessorArchitecture;
! fileRow.PatchGroup = row.PatchGroup;
! fileRow.PatchAttributes = row.PatchAttributes;
}
}
***************
*** 926,988 ****
// localize fields, resolve wix variables, and resolve file paths
! foreach (Table table in output.Tables)
! {
! foreach (Row row in table.Rows)
! {
! foreach (Field field in row.Fields)
! {
! bool isDefault = true;
!
! // resolve localization and wix variables
! if (field.Data is string)
! {
! field.Data = this.wixVariableResolver.ResolveVariables(this.localizer, row.SourceLineNumbers, (string)field.Data, false, ref isDefault);
! }
!
! // resolve file paths
! if (!this.wixVariableResolver.EncounteredError && ColumnType.Object == field.Column.Type)
! {
! ObjectField objectField = (ObjectField)field;
!
! // file is compressed in a cabinet (and not modified above)
! if (null != objectField.CabinetFileId && isDefault)
! {
! // index cabinets that have not been previously encountered
! if (!cabinets.ContainsKey(objectField.BaseUri))
! {
! Uri baseUri = new Uri(objectField.BaseUri);
! string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath);
! string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension);
!
! // index the cabinet file's base URI (source location) and extracted directory
! cabinets.Add(objectField.BaseUri, Path.Combine(this.TempFilesLocation, extractedDirectoryName));
! }
!
! // set the path to the file once its extracted from the cabinet
! objectField.Data = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId);
! }
! else if (null != objectField.Data) // non-compressed file (or localized value)
! {
! try
! {
! // resolve the path to the file
! objectField.Data = this.extension.ResolveFile((string)objectField.Data);
! }
! catch (WixFileNotFoundException)
! {
! // display the error with source line information
! this.OnMessage(WixErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.Data));
! }
! }
! }
! }
! }
! }
!
! // remember if the variable resolver found an error
! if (this.wixVariableResolver.EncounteredError)
! {
! this.encounteredError = true;
! }
// stop processing if an error previously occurred
--- 929,933 ----
// localize fields, resolve wix variables, and resolve file paths
! this.ResolveFields(output.Tables, cabinets);
// stop processing if an error previously occurred
***************
*** 997,1004 ****
// modularize identifiers and add tables with real streams to the import tables
! foreach (Table table in output.Tables)
{
! // modularize the output if this is a merge module
! if (OutputType.Module == output.Type)
{
table.Modularize(modularizationGuid, suppressModularizationIdentifiers);
--- 942,948 ----
// modularize identifiers and add tables with real streams to the import tables
! if (OutputType.Module == output.Type)
{
! foreach (Table table in output.Tables)
{
table.Modularize(modularizationGuid, suppressModularizationIdentifiers);
***************
*** 1014,1021 ****
--- 958,972 ----
{
Output transform = (Output)substorage.Data;
+ this.ResolveFields(transform.Tables, cabinets);
MergeUnrealTables(transform.Tables);
}
}
+ // stop processing if an error previously occurred
+ if (this.encounteredError)
+ {
+ return false;
+ }
+
// index the File table for quicker access later
// this must occur after the unreal data has been merged in
***************
*** 1193,1196 ****
--- 1144,1148 ----
this.validator.Output = output;
+ this.OnMessage(WixVerboses.ValidatingDatabase());
this.encounteredError = !this.validator.Validate(tempDatabaseFile);
***************
*** 1216,1219 ****
--- 1168,1296 ----
///
+ /// Resolve source fields in the tables included in the output
+ ///
+ /// The tables to resolve.
+ /// Cabinets containing files that need to be patched.
+ private void ResolveFields(TableCollection tables, Hashtable cabinets)
+ {
+ foreach (Table table in tables)
+ {
+ foreach (Row row in table.Rows)
+ {
+ foreach (Field field in row.Fields)
+ {
+ bool isDefault = true;
+
+ // resolve localization and wix variables
+ if (field.Data is string)
+ {
+ field.Data = this.wixVariableResolver.ResolveVariables(this.localizer, row.SourceLineNumbers, (string)field.Data, false, ref isDefault);
+ }
+
+ // resolve file paths
+ if (!this.wixVariableResolver.EncounteredError && ColumnType.Object == field.Column.Type)
+ {
+ ObjectField objectField = (ObjectField)field;
+
+ // file is compressed in a cabinet (and not modified above)
+ if (null != objectField.CabinetFileId && isDefault)
+ {
+ // index cabinets that have not been previously encountered
+ if (!cabinets.ContainsKey(objectField.BaseUri))
+ {
+ Uri baseUri = new Uri(objectField.BaseUri);
+ string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath);
+ string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension);
+
+ // index the cabinet file's base URI (source location) and extracted directory
+ cabinets.Add(objectField.BaseUri, Path.Combine(this.TempFilesLocation, extractedDirectoryName));
+ }
+
+ // set the path to the file once its extracted from the cabinet
+ objectField.Data = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId);
+ }
+ else if (null != objectField.Data) // non-compressed file (or localized value)
+ {
+ // when SuppressFileHasAndInfo is true do not resolve file paths
+ if (this.SuppressFileHashAndInfo && table.Name == "WixFile")
+ {
+ continue;
+ }
+
+ try
+ {
+ // resolve the path to the file
+ objectField.Data = this.extension.ResolveFile((string)objectField.Data);
+ }
+ catch (WixFileNotFoundException)
+ {
+ // display the error with source line information
+ this.OnMessage(WixErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.Data));
+ }
+ }
+ isDefault = true;
+ if (null != objectField.PreviousData)
+ {
+ objectField.PreviousData = this.wixVariableResolver.ResolveVariables(this.localizer, row.SourceLineNumbers, objectField.PreviousData, false, ref isDefault);
+ if (!this.wixVariableResolver.EncounteredError)
+ {
+ // file is compressed in a cabinet (and not modified above)
+ if (null != objectField.PreviousCabinetFileId && isDefault)
+ {
+ // when loading transforms from disk, PreviousBaseUri may not have been set
+ if (null == objectField.PreviousBaseUri)
+ {
+ objectField.PreviousBaseUri = objectField.BaseUri;
+ }
+
+ // index cabinets that have not been previously encountered
+ if (!cabinets.ContainsKey(objectField.PreviousBaseUri))
+ {
+ Uri baseUri = new Uri(objectField.PreviousBaseUri);
+ string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath);
+ string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension);
+
+ // index the cabinet file's base URI (source location) and extracted directory
+ cabinets.Add(objectField.PreviousBaseUri, Path.Combine(this.TempFilesLocation, extractedDirectoryName));
+ }
+
+ // set the path to the file once its extracted from the cabinet
+ objectField.PreviousData = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId);
+ }
+ else if (null != objectField.PreviousData) // non-compressed file (or localized value)
+ {
+ // when SuppressFileHasAndInfo is true do not resolve file paths
+ if (this.SuppressFileHashAndInfo && table.Name == "WixFile")
+ {
+ continue;
+ }
+
+ try
+ {
+ // resolve the path to the file
+ objectField.PreviousData = this.extension.ResolveFile((string)objectField.PreviousData);
+ }
+ catch (WixFileNotFoundException)
+ {
+ // display the error with source line information
+ this.OnMessage(WixErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.PreviousData));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // remember if the variable resolver found an error
+ if (this.wixVariableResolver.EncounteredError)
+ {
+ this.encounteredError = true;
+ }
+ }
+
+
+ ///
/// Copy file data between transform substorages and the patch output object
///
***************
*** 1264,1510 ****
}
! // copy File bind data into substorages
! foreach (SubStorage substorage in output.SubStorages)
{
! if ("#" == substorage.Name.Substring(0, 1))
! {
! // no changes necessary for paired transforms
! continue;
! }
!
! Output mainTransform = (Output)substorage.Data;
! Table mainFileTable = mainTransform.Tables["File"];
! Output pairedTransform = (Output)pairedTransforms[substorage.Name];
!
! // copy Media.LastSequence
! if (copyFromPatch)
{
! Table pairedMediaTable = pairedTransform.Tables["Media"];
! foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
{
! MediaRow patchMediaRow = (MediaRow)patchMediaRows[pairedMediaRow.DiskId];
! pairedMediaRow.Fields[1] = patchMediaRow.Fields[1];
}
- }
! // index File table of pairedTransform
! FileRowCollection pairedFileRows = new FileRowCollection();
! Table pairedFileTable = pairedTransform.Tables["File"];
! if (null != pairedFileTable)
! {
! pairedFileRows.AddRange(pairedFileTable.Rows);
! }
! foreach (FileRow mainFileRow in mainFileTable.Rows)
! {
! if (mainFileRow.Operation == RowOperation.Delete)
{
! continue;
}
! // index patch files by diskId+fileId
! int diskId = mainFileRow.DiskId;
! if (!patchMediaFileRows.Contains(diskId))
{
! patchMediaFileRows[diskId] = new FileRowCollection();
}
- FileRowCollection mediaFileRows = (FileRowCollection)patchMediaFileRows[diskId];
! string fileId = mainFileRow.File;
! FileRow patchFileRow = mediaFileRows[fileId];
! if (copyToPatch)
{
! if (patchFileRow == null)
! {
! patchFileRow = (FileRow)patchFileTable.CreateRow(null);
! patchFileRow.CopyFrom(mainFileRow);
! mediaFileRows.Add(patchFileRow);
! allFileRows.Add(patchFileRow);
! }
! else
! {
! // TODO: confirm the data is identical?
! }
}
! else
{
! // copy data from the patch back to the transform
! if (null != patchFileRow)
{
! FileRow pairedFileRow = (FileRow)pairedFileRows[fileId];
! for (int i = 0; i < patchFileRow.Fields.Length; i++)
{
! string patchValue = patchFileRow[i] == null ? "" : patchFileRow[i].ToString();
! string mainValue = mainFileRow[i] == null ? "" : mainFileRow[i].ToString();
! if (7 == i)
! {
! // File.Sequence is updated in pairedTransform, not mainTransform
! pairedFileRow[i] = patchFileRow[i];
! pairedFileRow.Fields[i].Modified = true;
! mainFileRow.Fields[i].Modified = false;
! }
! else if (patchValue != mainValue)
! {
! mainFileRow[i] = patchFileRow[i];
! mainFileRow.Fields[i].Modified = true;
! if (mainFileRow.Operation == RowOperation.None)
! {
! mainFileRow.Operation = RowOperation.Modify;
! }
! }
}
! // copy MsiFileHash row for this File
! Row patchHashRow = patchFileRow.HashRow;
! if (null != patchHashRow)
{
! Table mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]);
! Row mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
! for (int i = 0; i < patchHashRow.Fields.Length; i++)
{
! mainHashRow[i] = patchHashRow[i];
! if (i > 1)
{
! // assume all hash fields have been modified
! mainHashRow.Fields[i].Modified = true;
}
}
! // assume the MsiFileHash operation follows the File one
! mainHashRow.Operation = mainFileRow.Operation;
}
! // copy MsiAssemblyName rows for this File
! RowCollection patchAssemblyNameRows = patchFileRow.AssemblyNameRows;
! if (null != patchAssemblyNameRows)
{
! Table mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]);
! foreach (Row patchAssemblyNameRow in patchAssemblyNameRows)
{
! Row mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
! for (int i = 0; i < patchAssemblyNameRow.Fields.Length; i++)
! {
! mainAssemblyNameRow[i] = patchAssemblyNameRow[i];
! }
! // assume value field has been modified
! mainAssemblyNameRow.Fields[2].Modified = true;
! mainAssemblyNameRow.Operation = mainFileRow.Operation;
}
}
! }
! else
! {
! // TODO: throw because all transform rows should have made it into the patch
! }
! }
! }
!
! if (copyFromPatch)
! {
! output.Tables.Remove("Media");
! output.Tables.Remove("File");
! output.Tables.Remove("MsiFileHash");
! output.Tables.Remove("MsiAssemblyName");
! }
! }
!
! return true;
! }
! ///
! /// Binds a databse.
! ///
! /// The output to bind.
! /// Cabinet data.
! /// The database file to create.
! /// The database file to create.
! /// The database file to create.
! /// The database file to create.
! /// The database file to create.
! /// The database file to create.
! /// The database file to create.
! /// The database file to create.
! /// true if binding completed successfully; false otherwise
! private bool BindPackage(Output output, Hashtable cabinets, bool compressed, bool longNames, ArrayList fileTransfers, FileRowCollection fileRows, FileRowCollection uncompressedFileRows, MediaRowCollection mediaRows, string databaseFile, string layoutDirectory)
! {
! StringCollection suppressedTableNames = new StringCollection();
! // add back suppressed tables which must be present prior to merging in modules
! if (OutputType.Product == output.Type)
! {
! Table wixMergeTable = output.Tables["WixMerge"];
! if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count)
! {
! foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable)))
! {
! string sequenceTableName = sequence.ToString();
! Table sequenceTable = output.Tables[sequenceTableName];
! if (null == sequenceTable)
! {
! sequenceTable = output.EnsureTable(this.tableDefinitions[sequenceTableName]);
! }
! if (0 == sequenceTable.Rows.Count)
! {
! suppressedTableNames.Add(sequenceTableName);
}
}
- }
- }
-
- // generate database file
- this.OnMessage(WixVerboses.GeneratingDatabase());
- string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile));
- this.GenerateDatabase(output, tempDatabaseFile);
- fileTransfers.Add(new FileTransfer(tempDatabaseFile, databaseFile, true)); // note where this database needs to move in the future
-
- // stop processing if an error previously occurred
- if (this.encounteredError)
- {
- return false;
- }
-
- // merge modules
- if (OutputType.Product == output.Type)
- {
- this.OnMessage(WixVerboses.MergingModules());
- this.MergeModules(tempDatabaseFile, output, fileRows, suppressedTableNames);
! // stop processing if an error previously occurred
! if (this.encounteredError)
! {
! return false;
! }
! }
!
! // validate the output if there is an MSI validator
! if (null != this.validator)
! {
! // set the output file for source line information
! this.validator.Output = output;
!
! this.encounteredError = !this.validator.Validate(tempDatabaseFile);
!
! // stop processing if an error previously occurred
! if (this.encounteredError)
! {
! return false;
}
}
!
! // process uncompressed files
! if (!this.suppressLayout)
{
! this.ProcessUncompressedFiles(tempDatabaseFile, uncompressedFileRows, fileTransfers, mediaRows, layoutDirectory, compressed, longNames);
}
! // layout media
! this.OnMessage(WixVerboses.LayingOutMedia());
! this.LayoutMedia(fileTransfers);
!
! return !this.encounteredError;
}
--- 1341,1577 ----
}
! try
{
! // copy File bind data into substorages
! foreach (SubStorage substorage in output.SubStorages)
{
! if ("#" == substorage.Name.Substring(0, 1))
{
! // no changes necessary for paired transforms
! continue;
}
! this.extension.ActiveSubStorage = substorage;
! Hashtable wixFiles = new Hashtable();
! Output mainTransform = (Output)substorage.Data;
! Table mainFileTable = mainTransform.Tables["File"];
! Output pairedTransform = (Output)pairedTransforms[substorage.Name];
! Table mainWixFileTable = mainTransform.Tables["WixFile"];
! if (null != mainWixFileTable)
{
! // Index the WixFile table for later use.
! foreach (WixFileRow row in mainWixFileTable.Rows)
! {
! wixFiles.Add(row.Fields[0].Data.ToString(), row);
! }
}
! // copy Media.LastSequence
! if (copyFromPatch)
{
! Table pairedMediaTable = pairedTransform.Tables["Media"];
! foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
! {
! MediaRow patchMediaRow = (MediaRow)patchMediaRows[pairedMediaRow.DiskId];
! pairedMediaRow.Fields[1] = patchMediaRow.Fields[1];
! }
}
! // index File table of pairedTransform
! FileRowCollection pairedFileRows = new FileRowCollection();
! Table pairedFileTable = pairedTransform.Tables["File"];
! if (null != pairedFileTable)
{
! pairedFileRows.AddRange(pairedFileTable.Rows);
}
!
! if (null != mainFileTable)
{
! foreach (FileRow mainFileRow in mainFileTable.Rows)
{
! if (mainFileRow.Operation == RowOperation.Delete)
{
! continue;
}
! if (!copyToPatch && mainFileRow.Operation == RowOperation.None)
{
! continue;
! }
! // When copying to the patch, we need compare the underlying files and include all file changes.
! else if (copyToPatch)
! {
! // If the file is new, we always need to add it to the patch.
! if (mainFileRow.Operation != RowOperation.Add)
{
! WixFileRow wixFileRow = (WixFileRow)wixFiles[mainFileRow.Fields[0].Data.ToString()];
! ObjectField objectField = (ObjectField)wixFileRow.Fields[6];
! FileRow pairedFileRow = pairedFileRows[mainFileRow.Fields[0].Data.ToString()];
!
! // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare.
! if (null == objectField.PreviousData)
{
! if (mainFileRow.Operation == RowOperation.None)
! {
! continue;
! }
! }
! else
! {
! // TODO: should this entire condition be placed in the binder extension?
! if ((0 == (PatchAttributeType.Ignore & wixFileRow.PatchAttributes)) &&
! !this.extension.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString()))
! {
! // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified.
! mainFileRow.Operation = RowOperation.Modify;
! if (null != pairedFileRow)
! {
! pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded;
! pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
! pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesCompressed;
! pairedFileRow.Fields[6].Modified = true;
! pairedFileRow.Operation = RowOperation.Modify;
! }
! }
! else
! {
! // The File is same. We need mark all the attributes as unchanged.
! mainFileRow.Operation = RowOperation.None;
! foreach (Field field in mainFileRow.Fields)
! {
! field.Modified = false;
! }
!
! if (null != pairedFileRow)
! {
! pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesPatchAdded;
! pairedFileRow.Fields[6].Modified = false;
! pairedFileRow.Operation = RowOperation.None;
! }
! continue;
! }
}
}
+ }
! // index patch files by diskId+fileId
! int diskId = mainFileRow.DiskId;
! if (!patchMediaFileRows.Contains(diskId))
! {
! patchMediaFileRows[diskId] = new FileRowCollection();
}
+ FileRowCollection mediaFileRows = (FileRowCollection)patchMediaFileRows[diskId];
! string fileId = mainFileRow.File;
! FileRow patchFileRow = mediaFileRows[fileId];
! if (copyToPatch)
{
! if (patchFileRow == null)
{
! patchFileRow = (FileRow)patchFileTable.CreateRow(null);
! patchFileRow.CopyFrom(mainFileRow);
! mediaFileRows.Add(patchFileRow);
! allFileRows.Add(patchFileRow);
! }
! else
! {
! // TODO: confirm the data is identical?
! // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
! patchFileRow.AppendPreviousDataFrom(mainFileRow);
}
}
! else
! {
! // copy data from the patch back to the transform
! if (null != patchFileRow)
! {
! FileRow pairedFileRow = (FileRow)pairedFileRows[fileId];
! for (int i = 0; i < patchFileRow.Fields.Length; i++)
! {
! string patchValue = patchFileRow[i] == null ? "" : patchFileRow[i].ToString();
! string mainValue = mainFileRow[i] == null ? "" : mainFileRow[i].ToString();
! // File.Sequence is updated in pairedTransform, not mainTransform
! if (7 == i)
! {
! pairedFileRow[i] = patchFileRow[i];
! pairedFileRow.Fields[i].Modified = true;
! mainFileRow.Fields[i].Modified = false;
! }
! else if (patchValue != mainValue)
! {
! mainFileRow[i] = patchFileRow[i];
! mainFileRow.Fields[i].Modified = true;
! if (mainFileRow.Operation == RowOperation.None)
! {
! mainFileRow.Operation = RowOperation.Modify;
! }
! }
! }
! // copy MsiFileHash row for this File
! Row patchHashRow = patchFileRow.HashRow;
! if (null != patchHashRow)
! {
! Table mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]);
! Row mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
! for (int i = 0; i < patchHashRow.Fields.Length; i++)
! {
! mainHashRow[i] = patchHashRow[i];
! if (i > 1)
! {
! // assume all hash fields have been modified
! mainHashRow.Fields[i].Modified = true;
! }
! }
! // assume the MsiFileHash operation follows the File one
! mainHashRow.Operation = mainFileRow.Operation;
! }
! // copy MsiAssemblyName rows for this File
! RowCollection patchAssemblyNameRows = patchFileRow.AssemblyNameRows;
! if (null != patchAssemblyNameRows)
! {
! Table mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]);
! foreach (Row patchAssemblyNameRow in patchAssemblyNameRows)
! {
! Row mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
! for (int i = 0; i < patchAssemblyNameRow.Fields.Length; i++)
! {
! mainAssemblyNameRow[i] = patchAssemblyNameRow[i];
! }
! // assume value field has been modified
! mainAssemblyNameRow.Fields[2].Modified = true;
! mainAssemblyNameRow.Operation = mainFileRow.Operation;
! }
! }
! }
! else
! {
! // TODO: throw because all transform rows should have made it into the patch
! }
! }
}
}
! if (copyFromPatch)
! {
! output.Tables.Remove("Media");
! output.Tables.Remove("File");
! output.Tables.Remove("MsiFileHash");
! output.Tables.Remove("MsiAssemblyName");
! }
}
}
! finally
{
! this.extension.ActiveSubStorage = null;
}
! return true;
}
***************
*** 1594,1597 ****
--- 1661,1672 ----
foreach (Table table in transform.Tables)
{
+ // Ignore unreal tables when building transforms except the _Stream table.
+ // These tables are ignored when generating the database so there is no reason
+ // to process them here.
+ if (table.Definition.IsUnreal && "_Streams" != table.Name)
+ {
+ continue;
+ }
+
// process table operations
switch (table.Operation)
***************
*** 1629,1633 ****
if (ColumnType.Number == field.Column.Type && !field.Column.IsLocalizable)
{
! field.Data = 0;
}
else if (ColumnType.Object == field.Column.Type)
--- 1704,1708 ----
if (ColumnType.Number == field.Column.Type && !field.Column.IsLocalizable)
{
! field.Data = field.Column.MinValue;
}
else if (ColumnType.Object == field.Column.Type)
***************
*** 2604,2607 ****
--- 2679,2683 ----
}
+ this.OnMessage(WixVerboses.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage));
merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
moduleOpen = true;
***************
*** 2615,2618 ****
--- 2691,2695 ----
// merge the module into the database that's being built
+ this.OnMessage(WixVerboses.MergingMergeModule(wixMergeRow.SourceFile));
merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback);
***************
*** 2624,2627 ****
--- 2701,2705 ----
if (wixMergeRow.Id == (string)row[1])
{
+ this.OnMessage(WixVerboses.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0]));
merge.Connect((string)row[0]);
}
***************
*** 2787,2790 ****
--- 2865,2869 ----
// now update the Attributes column for the files from the Merge Modules
+ this.OnMessage(WixVerboses.ResequencingMergeModuleFiles());
using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?"))
{
***************
*** 2946,2950 ****
// create queued cabinets with multiple threads
! cabinetBuilder.CreateQueuedCabinets();
return uncompressedFileRows;
--- 3025,3034 ----
// create queued cabinets with multiple threads
! int cabError = cabinetBuilder.CreateQueuedCabinets();
! if (0 != cabError)
! {
! this.encounteredError = true;
! return null;
! }
return uncompressedFileRows;
--- NEW FILE: PatchTransform.cs ---
using System;
using System.Collections;
using System.Text;
namespace Microsoft.Tools.WindowsInstallerXml
{
public class PatchTransform : IMessageHandler
{
private string baseline;
private Output transform;
public string Baseline
{
get { return this.baseline; }
}
public Output Transform
{
get { return this.transform; }
}
public PatchTransform(Output transform, string baseline)
{
this.transform = transform;
this.baseline = baseline;
this.Validate();
}
///
/// Event for messages.
///
public event MessageEventHandler Message;
///
/// Validates that the differences in the transform are valid for patch transforms.
///
public void Validate()
{
Table componentTable = this.transform.Tables["Component"];
Hashtable deletedComponent = new Hashtable();
Hashtable componentKeyPath = new Hashtable();
if (null != componentTable)
{
// Index Component table and check for keypath modifications
foreach (Row row in componentTable.Rows)
{
string keypath = (null == row.Fields[5].Data) ? String.Empty : row.Fields[5].Data.ToString();
componentKeyPath.Add(row.Fields[0].Data.ToString(), keypath);
if (RowOperation.Delete == row.Operation)
{
deletedComponent.Add(row.Fields[0].Data.ToString(), row);
}
else if (RowOperation.Modify == row.Operation)
{
// If the keypath is modified its an error
if (row.Fields[5].Modified)
{
this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, row.Fields[0].Data.ToString()));
}
}
}
// Verify changes in the file table
Table fileTable = this.transform.Tables["File"];
if (null != fileTable)
{
Hashtable componentWithChangedKeyPath = new Hashtable();
Hashtable componentWithNonKeyPathChanged = new Hashtable();
foreach (Row row in fileTable.Rows)
{
if (RowOperation.None != row.Operation)
{
string fileId = row.Fields[0].Data.ToString();
string componentId = row.Fields[1].Data.ToString();
if (0 != String.Compare((string)componentKeyPath[componentId], fileId, false))
{
if (!componentWithNonKeyPathChanged.ContainsKey(componentId))
{
componentWithNonKeyPathChanged.Add(componentId, fileId);
}
}
else
{
if (!componentWithChangedKeyPath.ContainsKey(componentId))
{
componentWithChangedKeyPath.Add(componentId, fileId);
}
}
if (RowOperation.Delete == row.Operation)
{
// If the file is removed from a component that is not deleted.
if (!deletedComponent.ContainsKey(componentId))
{
this.OnMessage(WixWarnings.InvalidRemoveFile(row.SourceLineNumbers, fileId, componentId));
}
}
}
}
foreach (DictionaryEntry componentFile in componentWithNonKeyPathChanged)
{
// Make sure all changes to non keypaths also had a change in the keypath.
if (!componentWithChangedKeyPath.ContainsKey(componentFile.Key))
{
this.OnMessage(WixWarnings.RemovalOfNonKeyPathFile((string)componentFile.Value, (string)componentFile.Key, (string)componentKeyPath[componentFile.Key]));
}
}
}
if (0 < deletedComponent.Count)
{
// Index feature table
Table featureTable = this.transform.Tables["Feature"];
Hashtable deletedFeature = new Hashtable();
if (null != featureTable)
{
foreach (Row row in featureTable.Rows)
{
if (RowOperation.Delete == row.Operation)
{
deletedFeature.Add(row.Fields[0].Data.ToString(), row);
}
}
}
// Index FeatureComponents table.
Table featureComponentsTable = this.transform.Tables["FeatureComponents"];
Hashtable featureComponents = new Hashtable();
if (null != featureComponentsTable)
{
foreach (Row row in featureComponentsTable.Rows)
{
ArrayList features;
string componentId = row.Fields[1].Data.ToString();
if (featureComponents.Contains(componentId))
{
features = (ArrayList)featureComponents[componentId];
}
else
{
features = new ArrayList();
featureComponents.Add(row.Fields[1].Data.ToString(), features);
}
features.Add(row.Fields[0].Data.ToString());
}
}
// Check to make sure if a component was deleted, the feature was too.
foreach (DictionaryEntry entry in deletedComponent)
{
if (featureComponents.Contains(entry.Key.ToString()))
{
ArrayList features = (ArrayList)featureComponents[entry.Key.ToString()];
foreach (string featureId in features)
{
if (deletedFeature.Contains(featureId))
{
//The feature has also been deleted.
continue;
}
else
{
this.OnMessage(WixWarnings.InvalidRemoveComponent(((Row)entry.Value).SourceLineNumbers, entry.Key.ToString(), featureId));
}
}
}
}
}
}
}
///
/// Sends a message to the message delegate if there is one.
///
/// Message event arguments.
public void OnMessage(MessageEventArgs mea)
{
WixErrorEventArgs errorEventArgs = mea as WixErrorEventArgs;
if (null != this.Message)
{
this.Message(this, mea);
}
else if (null != errorEventArgs)
{
throw new WixException(errorEventArgs);
}
}
}
}
Index: CompilerCore.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/CompilerCore.cs,v
retrieving revision 1.30
retrieving revision 1.31
diff -C2 -d -r1.30 -r1.31
*** CompilerCore.cs 2 Mar 2007 12:22:59 -0000 1.30
--- CompilerCore.cs 27 Jun 2007 05:39:05 -0000 1.31
***************
*** 24,27 ****
--- 24,28 ----
using System.Diagnostics;
using System.Globalization;
+ using System.IO;
using System.Security.Cryptography;
using System.Text;
***************
*** 127,131 ****
///
! /// Gets whether the compiler core encoutered an error while processing.
///
/// Flag if core encountered and error during processing.
--- 128,132 ----
///
! /// Gets whether the compiler core encountered an error while processing.
///
/// Flag if core encountered and error during processing.
***************
*** 335,338 ****
--- 336,401 ----
///
+ /// Generates a short file/directory name using an identifier and long file/directory name as input.
+ ///
+ /// The long file/directory name.
+ /// The option to keep the extension on generated short names.
+ /// true if wildcards are allowed in the filename.
+ /// Any additional information to include in the hash for the generated short name.
+ /// The generated 8.3-compliant short file/directory name.
+ public static string GenerateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args)
+ {
+ Debug.Assert(null != longName);
+
+ // canonicalize the long name if its not a localization identifier (they are case-sensitive)
+ if (!CompilerCore.IsValidLocIdentifier(longName))
+ {
+ longName = longName.ToLower(CultureInfo.InvariantCulture);
+ }
+
+ // collect all the data
+ ArrayList strings = new ArrayList();
+ strings.Add(longName);
+ strings.AddRange(args);
+
+ // prepare for hashing
+ string stringData = String.Join("|", (string[])strings.ToArray(typeof(string)));
+ byte[] data = Encoding.Unicode.GetBytes(stringData);
+
+ // hash the data
+ byte[] hash;
+ using (MD5 md5 = new MD5CryptoServiceProvider())
+ {
+ hash = md5.ComputeHash(data);
+ }
+
+ // generate the short file/directory name without an extension
+ StringBuilder shortName = new StringBuilder(Convert.ToBase64String(hash));
+ shortName.Remove(8, shortName.Length - 8);
+ shortName.Replace('/', '_');
+ shortName.Replace('+', '-');
+
+ if (keepExtension)
+ {
+ string extension = Path.GetExtension(longName);
+
+ if (4 < extension.Length)
+ {
+ extension = extension.Substring(0, 4);
+ }
+
+ shortName.Append(extension);
+
+ // check the generated short name to ensure its still legal (the extension may not be legal)
+ if (!CompilerCore.IsValidShortFilename(shortName.ToString(), allowWildcards))
+ {
+ // remove the extension (by truncating the generated file name back to the generated characters)
+ shortName.Length -= extension.Length;
+ }
+ }
+
+ return shortName.ToString().ToLower(CultureInfo.InvariantCulture);
+ }
+
+ ///
/// Verifies the given string is a valid product version.
///
***************
*** 353,365 ****
/// The module version to verify.
/// True if version is a valid module version
! public static bool IsValidModuleVersion(string version)
{
! Regex moduleVersion = new Regex(@"^(?[0-9])\.(?[0-9])$", RegexOptions.Compiled);
! Match moduleMatch = moduleVersion.Match(version);
! if (moduleMatch.Success)
{
! return true;
}
! return false;
}
--- 416,426 ----
/// The module version to verify.
/// True if version is a valid module version
! public static bool IsValidModuleVersion(Version version)
{
! if (65535 < version.Major || 65535 < version.Minor || 65535 < version.Build || 65535 < version.Revision)
{
! return false;
}
! return true;
}
***************
*** 498,501 ****
--- 559,585 ----
///
+ /// Add the appropriate rows to make sure that the given table shows up
+ /// in the resulting output.
+ ///
+ /// Source line numbers.
+ /// Name of the table to ensure existance of.
+ public void EnsureTable(SourceLineNumberCollection sourceLineNumbers, string tableName)
+ {
+ if (!this.encounteredError)
+ {
+ Row row = this.CreateRow(sourceLineNumbers, "WixEnsureTable");
+ row[0] = tableName;
+
+ // We don't add custom table definitions to the tableDefinitions collection,
+ // so if it's not in there, it better be a custom table. If the Id is just wrong,
+ // instead of a custom table, we get an unresolved reference at link time.
+ if (!this.tableDefinitions.Contains(tableName))
+ {
+ this.CreateWixSimpleReferenceRow(sourceLineNumbers, "WixCustomTable", tableName);
+ }
+ }
+ }
+
+ ///
/// Get an attribute value and displays an error if the value is empty.
///
Index: Decompiler.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Decompiler.cs,v
retrieving revision 1.48
retrieving revision 1.49
diff -C2 -d -r1.48 -r1.49
*** Decompiler.cs 13 Sep 2006 08:13:35 -0000 1.48
--- Decompiler.cs 27 Jun 2007 05:39:05 -0000 1.49
***************
*** 5489,5492 ****
--- 5489,5493 ----
column.Type = Wix.Column.TypeType.binary;
break;
+ case ColumnType.Preserved:
case ColumnType.String:
column.Type = Wix.Column.TypeType.@string;
***************
*** 8051,8069 ****
if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id)
{
! foreach (string propertyId in value.Split(';'))
{
! Wix.Property specialProperty = this.EnsureProperty(propertyId);
!
! switch (id)
{
! case "AdminProperties":
! specialProperty.Admin = Wix.YesNoType.yes;
! break;
! case "MsiHiddenProperties":
! specialProperty.Hidden = Wix.YesNoType.yes;
! break;
! case "SecureCustomProperties":
! specialProperty.Secure = Wix.YesNoType.yes;
! break;
}
}
--- 8052,8073 ----
if ("AdminProperties" == id || "MsiHiddenProperties" == id || "SecureCustomProperties" == id)
{
! if (0 < value.Length)
{
! foreach (string propertyId in value.Split(';'))
{
! Wix.Property specialProperty = this.EnsureProperty(propertyId);
!
! switch (id)
! {
! case "AdminProperties":
! specialProperty.Admin = Wix.YesNoType.yes;
! break;
! case "MsiHiddenProperties":
! specialProperty.Hidden = Wix.YesNoType.yes;
! break;
! case "SecureCustomProperties":
! specialProperty.Secure = Wix.YesNoType.yes;
! break;
! }
}
}
Index: Row.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/Row.cs,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -d -r1.17 -r1.18
*** Row.cs 13 Sep 2006 08:13:36 -0000 1.17
--- Row.cs 27 Jun 2007 05:39:07 -0000 1.18
***************
*** 513,517 ****
if (ColumnModularizeType.Property == modularizeType)
{
! regex = new Regex(@"\[(?[#$!]?[a-zA-Z_][a-zA-Z0-9_\.]*)]", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
}
else
--- 513,517 ----
if (ColumnModularizeType.Property == modularizeType)
{
! regex = new Regex(@"\[(?[#$!]?[a-zA-Z_][a-zA-Z0-9_\.]*)]", RegexOptions.Singleline | RegexOptions.ExplicitCapture);
}
else
***************
*** 533,540 ****
// 4. Match all identifiers that are things that need to be modularized. Note
// the special characters (!, $, ?, &) that denote Component and Feature states.
! regex = new Regex(@"NOT|EQV|XOR|OR|AND|IMP|"".*?""|%[a-zA-Z_][a-zA-Z0-9_\.]*|(?[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
// less performant version of the above with captures showing where everything lives
! // regex = new Regex(@"(?NOT|EQV|XOR|OR|AND|IMP)|(?"".*?"")|(?%[a-zA-Z_][a-zA-Z0-9_\.]*)|(?[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
}
--- 533,540 ----
// 4. Match all identifiers that are things that need to be modularized. Note
// the special characters (!, $, ?, &) that denote Component and Feature states.
! regex = new Regex(@"NOT|EQV|XOR|OR|AND|IMP|"".*?""|%[a-zA-Z_][a-zA-Z0-9_\.]*|(?[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
// less performant version of the above with captures showing where everything lives
! // regex = new Regex(@"(?NOT|EQV|XOR|OR|AND|IMP)|(?"".*?"")|(?%[a-zA-Z_][a-zA-Z0-9_\.]*)|(?[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)",RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
}
--- NEW FILE: Melter.cs ---
//-------------------------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
//
// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source.
//
//-------------------------------------------------------------------------------------------------
namespace Microsoft.Tools.WindowsInstallerXml
{
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Wix = Microsoft.Tools.WindowsInstallerXml.Serialize;
using Installer = Microsoft.Tools.WindowsInstallerXml.Msi;
///
/// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source.
///
public sealed class Melter
{
private MelterCore core;
private Decompiler decompiler;
private Wix.ComponentGroup componentGroup;
private Wix.DirectoryRef primaryDirectoryRef;
private Wix.Fragment fragment;
private string id;
private const string nullGuid = "{00000000-0000-0000-0000-000000000000}";
public string Id
{
get { return this.id; }
set { this.id = value; }
}
public Decompiler Decompiler
{
get { return this.decompiler; }
set { this.decompiler = value; }
}
///
/// Event for messages.
///
public event MessageEventHandler Message;
///
/// Creates a new melter object.
///
/// The decompiler to use during the melting process.
/// The Id to use for the ComponentGroup, DirectoryRef, and WixVariables. If null, defaults to the Module's Id
public Melter(Decompiler decompiler, string id)
{
this.core = new MelterCore(this.Message);
this.componentGroup = new Wix.ComponentGroup();
this.fragment = new Wix.Fragment();
this.primaryDirectoryRef = new Wix.DirectoryRef();
this.decompiler = decompiler;
this.id = id;
if (null == this.decompiler)
{
this.core.OnMessage(WixErrors.ExpectedDecompiler("The melting process"));
}
}
///
/// Converts a Module wixout into a ComponentGroup.
///
/// The output object representing the unbound merge module to melt.
/// The converted Module as a ComponentGroup.
public Wix.Wix Melt(Output wixout)
{
string moduleId = GetModuleId(wixout);
// Assign the default componentGroupId if none was specified
if (null == this.id)
{
this.id = moduleId;
}
this.componentGroup.Id = this.id;
this.primaryDirectoryRef.Id = this.id;
PreDecompile(wixout);
Wix.Wix wix = decompiler.Decompile(wixout);
if (null == wix)
{
return wix;
}
ConvertModule(wix);
return wix;
}
///
/// Converts a Module to a ComponentGroup and adds all of its relevant elements to the main fragment.
///
/// The output object representing an unbound merge module.
private void ConvertModule(Wix.Wix wix)
{
Wix.Module module = GetModule(wix);
foreach (Wix.ISchemaElement child in module.Children)
{
if (child is Wix.Directory)
{
bool isTargetDir = WalkDirectory((Wix.Directory)child);
if (isTargetDir)
{
continue;
}
}
else if (child is Wix.Dependency)
{
AddPropertyRef(((Wix.Dependency)child).RequiredId);
continue;
}
else if (child is Wix.Package)
{
continue;
}
this.fragment.AddChild(child);
}
AddProperty(module.Id, this.id);
wix.RemoveChild(module);
wix.AddChild(this.fragment);
this.fragment.AddChild(this.componentGroup);
this.fragment.AddChild(this.primaryDirectoryRef);
}
///
/// Gets the module from the Wix object.
///
/// The Wix object.
/// The Module in the Wix object, null if no Module was found
private Wix.Module GetModule(Wix.Wix wix)
{
foreach (Wix.ISchemaElement element in wix.Children)
{
if (element is Wix.Module)
{
return (Wix.Module)element;
}
}
return null;
}
///
/// Adds a PropertyRef to the main Fragment.
///
/// Id of the PropertyRef.
private void AddPropertyRef(string id)
{
Wix.PropertyRef propertyRef = new Wix.PropertyRef();
propertyRef.Id = id;
this.fragment.AddChild(propertyRef);
}
///
/// Adds a Property to the main Fragment.
///
/// Id of the Property.
/// Value of the Property.
private void AddProperty(string id, string value)
{
Wix.Property property = new Wix.Property();
property.Id = id;
property.Value = value;
this.fragment.AddChild(property);
}
///
/// Walks a directory structure obtaining Component Id's and Standard Directory Id's.
///
/// The Directory to walk.
/// true if the directory is TARGETDIR.
private bool WalkDirectory(Wix.Directory directory)
{
bool isTargetDir = false;
if ("TARGETDIR" == directory.Id)
{
isTargetDir = true;
}
string standardDirectoryId = null;
if (StartsWithStandardDirectoryId(directory.Id, out standardDirectoryId) && !isTargetDir)
{
AddSetPropertyCustomAction(directory.Id, String.Format("[{0}]", standardDirectoryId));
}
foreach (Wix.ISchemaElement child in directory.Children)
{
if (child is Wix.Directory)
{
if (isTargetDir)
{
this.primaryDirectoryRef.AddChild(child);
}
WalkDirectory((Wix.Directory)child);
}
else if (child is Wix.Component)
{
if (isTargetDir)
{
this.primaryDirectoryRef.AddChild(child);
}
AddComponentRef((Wix.Component)child);
}
}
return isTargetDir;
}
///
/// Gets the module Id out of the Output object.
///
/// The output object.
/// The module Id from the Output object.
private string GetModuleId(Output wixout)
{
// get the moduleId from the wixout
Table moduleSignatureTable = wixout.Tables["ModuleSignature"];
if (null == moduleSignatureTable || 0 >= moduleSignatureTable.Rows.Count)
{
this.core.OnMessage(WixErrors.ExpectedTableInMergeModule("ModuleSignature"));
}
return moduleSignatureTable.Rows[0].Fields[0].Data.ToString();
}
///
/// Determines if the directory Id starts with a standard directory id.
///
/// The directory id.
/// The standard directory id.
/// true if the directory starts with a standard directory id.
private bool StartsWithStandardDirectoryId(string directoryId, out string standardDirectoryId)
{
standardDirectoryId = null;
foreach (string id in Installer.Installer.StandardDirectories.Keys)
{
if (directoryId.StartsWith(id))
{
standardDirectoryId = id;
return true;
}
}
return false;
}
///
/// Adds a ComponentRef to the main ComponentGroup.
///
/// The component to add.
private void AddComponentRef(Wix.Component component)
{
Wix.ComponentRef componentRef = new Wix.ComponentRef();
componentRef.Id = component.Id;
this.componentGroup.AddChild(componentRef);
}
///
/// Adds a SetProperty CA for a Directory.
///
/// The Id of the Property to set.
/// The value to set the Property to.
private void AddSetPropertyCustomAction(String id, string value)
{
// Add the action
Wix.CustomAction customAction = new Wix.CustomAction();
customAction.Id = id;
customAction.Property = id;
customAction.Value = value;
this.fragment.AddChild(customAction);
// Schedule the action
Wix.InstallExecuteSequence installExecuteSequence = new Wix.InstallExecuteSequence();
Wix.Custom custom = new Wix.Custom();
custom.Action = customAction.Id;
custom.Before = "CostInitialize";
installExecuteSequence.AddChild(custom);
this.fragment.AddChild(installExecuteSequence);
}
///
/// Does any operations to the wixout that would need to be done before decompiling.
///
/// The output object representing the unbound merge module.
private void PreDecompile(Output wixout)
{
string wixVariable = String.Format("!(wix.{0}", this.id);
foreach (Table table in wixout.Tables)
{
// Determine if the table has a feature foreign key
bool hasFeatureForeignKey = false;
foreach (ColumnDefinition columnDef in table.Definition.Columns)
{
if (null != columnDef.KeyTable)
{
string[] keyTables = columnDef.KeyTable.Split(';');
foreach (string keyTable in keyTables)
{
if ("Feature" == keyTable)
{
hasFeatureForeignKey = true;
break;
}
}
}
}
// If this table has no foreign keys to the feature table, skip it.
if (!hasFeatureForeignKey)
{
continue;
}
// Go through all the rows and replace the null guid with the wix variable
// for columns that are foreign keys into the feature table.
foreach (Row row in table.Rows)
{
foreach (Field field in row.Fields)
{
if (null != field.Column.KeyTable)
{
string[] keyTables = field.Column.KeyTable.Split(';');
foreach (string keyTable in keyTables)
{
if ("Feature" == keyTable)
{
field.Data = field.Data.ToString().Replace(nullGuid, wixVariable);
break;
}
}
}
}
}
}
}
}
}
Index: ColumnDefinition.cs
===================================================================
RCS file: /cvsroot/wix/wix/src/wix/ColumnDefinition.cs,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -d -r1.16 -r1.17
*** ColumnDefinition.cs 13 Sep 2006 08:13:35 -0000 1.16
--- ColumnDefinition.cs 27 Jun 2007 05:39:04 -0000 1.17
***************
*** 43,46 ****
--- 43,49 ----
/// Column is a binary stream.
Object,
+
+ /// Column is a string that is preserved in transforms (like Object).
+ Preserved,
}
***************
*** 428,431 ****
--- 431,435 ----
typeCharacter = this.nullable ? 'I' : 'i';
break;
+ case ColumnType.Preserved:
case ColumnType.String:
typeCharacter = this.nullable ? 'S' : 's';
***************
*** 663,666 ****
--- 667,673 ----
type = ColumnType.String;
break;
+ case "preserved":
+ type = ColumnType.Preserved;
+ break;
default:
throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value, "localized", "number", "object", "string"));
***************
*** 732,735 ****
--- 739,745 ----
writer.WriteAttributeString("type", "string");
break;
+ case ColumnType.Preserved:
+ writer.WriteAttributeString("type", "preserved");
+ break;
}
***************
*** 797,801 ****
}
! if (null != this.keyTable)
{
writer.WriteAttributeString("keyTable", this.keyTable);
--- 807,811 ----
}
! if (null != this.keyTable && String.Empty != this.keyTable)
{
writer.WriteAttributeString("keyTable", this.keyTable);
--- NEW FILE: MelterCore.cs ---
//-------------------------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
//
// Decompiles an msi database into WiX source.
//
//-------------------------------------------------------------------------------------------------
namespace Microsoft.Tools.WindowsInstallerXml
{
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Wix = Microsoft.Tools.WindowsInstallerXml.Serialize;
///
/// Melts a Module Wix document into a ComponentGroup representation.
///
public sealed class MelterCore : IMessageHandler
{
private bool encounteredError;
///
/// Instantiate a new melter core.
///
/// The message handler.
public MelterCore(MessageEventHandler messageHandler)
{
this.MessageHandler = messageHandler;
}
///
/// Gets whether the melter core encoutered an error while processing.
///
/// Flag if core encountered and error during processing.
public bool EncounteredError
{
get { return this.encounteredError; }
}
///
/// Event for messages.
///
private event MessageEventHandler MessageHandler;
///
/// Sends a message to the message delegate if there is one.
///
/// Message event arguments.
public void OnMessage(MessageEventArgs mea)
{
WixErrorEventArgs errorEventArgs = mea as WixErrorEventArgs;
if (null != errorEventArgs)
{
this.encounteredError = true;
}
if (null != this.MessageHandler)
{
this.MessageHandler(this, mea);
}
else if (null != errorEventArgs)
{
throw new WixException(errorEventArgs);
}
}
}
}
--- NEW FILE: ValidatorExtension.cs ---
//-------------------------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
//
// The base validator extension. Any of these methods can be overridden to
// change the behavior of the validator. The default implementation fires
// an event with the ICE name and description.
//
//-------------------------------------------------------------------------------------------------
namespace Microsoft.Tools.WindowsInstallerXml
{
using System;
using System.Collections;
using System.ComponentModel;
using Microsoft.Tools.WindowsInstallerXml.Msi;
using Microsoft.Tools.WindowsInstallerXml.Msi.Interop;
///
/// Base class for creating a validator extension. This default implementation
/// will fire and event with the ICE name and description.
///
public class ValidatorExtension : IMessageHandler
{
private string databaseFile;
private Hashtable indexedSourceLineNumbers;
private Output output;
private SourceLineNumberCollection sourceLineNumbers;
///
/// Instantiate a new .
///
public ValidatorExtension()
{
}
///
/// Event for messages.
///
public event MessageEventHandler Message;
///
/// Gets or sets the path to the database to validate.
///
/// The path to the database to validate.
public string DatabaseFile
{
get { return this.databaseFile; }
set { this.databaseFile = value; }
}
///
/// Gets or sets the for inding source line information.
///
/// The for finding source line information.
public Output Output
{
get { return this.output; }
set { this.output = value; }
}
///
/// Called at the beginning of the validation of a database file.
///
///
/// The will set
/// before calling InitializeValidator.
/// Notes to Inheritors: When overriding
/// InitializeValidator in a derived class, be sure to call
/// the base class's InitializeValidator to thoroughly
/// initialize the extension.
///
public virtual void InitializeValidator()
{
if (this.databaseFile != null)
{
this.sourceLineNumbers = SourceLineNumberCollection.FromFileName(databaseFile);
}
}
///
/// Called at the end of the validation of a database file.
///
///
/// The default implementation will nullify source lines.
/// Notes to Inheritors: When overriding
/// FinalizeValidator in a derived class, be sure to call
/// the base class's FinalizeValidator to thoroughly
/// finalize the extension.
///
public virtual void FinalizeValidator()
{
this.sourceLineNumbers = null;
}
///
/// Logs a message from the .
///
/// A of tab-delmited tokens
/// in the validation message.
///
/// a tab-delimited set of tokens,
/// formatted according to Windows Installer guidelines for ICE
/// message. The following table lists what each token by index
/// should mean.
///
///
/// Index
/// Description
///
///
/// 0
/// Name of the ICE.
///
///
/// 1
/// Message type. See the following list.
///
///
/// 2
/// Detailed description.
///
///
/// 3
/// Help URL or location.
///
///
/// 4
/// Table name.
///
///
/// 5
/// Column name.
///
///
/// 6
/// This and remaining fields are primary keys
/// to identify a row.
///
///
/// The message types are one of the following value.
///
///
/// Value
/// Message Type
///
///
/// 0
/// Failure message reporting the failure of the
/// ICE custom action.
///
///
/// 1
/// Error message reporting database authoring that
/// case incorrect behavior.
///
///
/// 2
/// Warning message reporting database authoring that
/// causes incorrect behavior in certain cases. Warnings can also
/// report unexpected side-effects of database authoring.
///
///
///
/// 3
/// Informational message.
///
///
///
public virtual void Log(string message)
{
if (message == null)
{
throw new ArgumentNullException("message");
}
string[] messageParts = message.Split('\t');
if (3 > messageParts.Length)
{
throw new WixException(WixErrors.UnexpectedExternalUIMessage(message));
}
SourceLineNumberCollection messageSourceLineNumbers = null;
if (6 < messageParts.Length)
{
string[] primaryKeys = new string[messageParts.Length - 6];
Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length);
messageSourceLineNumbers = this.GetSourceLineNumbers(messageParts[4], primaryKeys);
}
else // use the file name as the source line information
{
messageSourceLineNumbers = this.sourceLineNumbers;
}
switch (messageParts[1])
{
case "1":
this.OnMessage(WixErrors.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2]));
break;
case "2":
this.OnMessage(WixWarnings.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2]));
break;
case "3":
this.OnMessage(WixVerboses.ValidationInfo(messageParts[0], messageParts[2]));
break;
default:
throw new WixException(WixErrors.InvalidValidatorMessageType(messageParts[1]));
}
}
///
/// Gets the source line information (if available) for a row by its table name and primary key.
///
/// The table name of the row.
/// The primary keys of the row.
/// The source line number information if found; null otherwise.
protected SourceLineNumberCollection GetSourceLineNumbers(string tableName, string[] primaryKeys)
{
// source line information only exists if an output file was supplied
if (null != this.output)
{
// index the source line information if it hasn't been indexed already
if (null == this.indexedSourceLineNumbers)
{
this.indexedSourceLineNumbers = new Hashtable();
// index each real table
foreach (Table table in this.output.Tables)
{
// skip unreal tables
if (table.Definition.IsUnreal)
{
continue;
}
// index each row
foreach (Row row in table.Rows)
{
// skip rows that don't contain source line information
if (null == row.SourceLineNumbers)
{
continue;
}
// index the row using its table name and primary key
string primaryKey = row.GetPrimaryKey(';');
if (null != primaryKey)
{
string key = String.Concat(table.Name, ":", primaryKey);
this.indexedSourceLineNumbers.Add(key, row.SourceLineNumbers);
}
}
}
}
return (SourceLineNumberCollection)this.indexedSourceLineNumbers[String.Concat(tableName, ":", String.Join(";", primaryKeys))];
}
// use the file name as the source line information
return this.sourceLineNumbers;
}
///
/// Sends a message to the delegate if there is one.
///
/// Message event arguments.
///
/// Notes to Inheritors: When overriding OnMessage
/// in a derived class, be sure to call the base class's
/// OnMessage method so that registered delegates recieve
/// the event.
///
public virtual void OnMessage(MessageEventArgs e)
{
WixErrorEventArgs errorEventArgs = e as WixErrorEventArgs;
if (null != this.Message)
{
this.Message(this, e);
}
else if (null != errorEventArgs)
{
throw new WixException(errorEventArgs);
}
}
}
}
------------------------------
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
------------------------------
_______________________________________________
Wix-commits mailing list
Wix-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wix-commits
End of Wix-commits Digest, Vol 11, Issue 27
*******************************************
P.S. И не забудьте послать роботу вашу рекламу :)
Обработано объявлений: 11776
Стас Давыдов & Outcorp © 2007