diff --git a/PanelSwCustomActions/ExecOnComponent.cpp b/PanelSwCustomActions/ExecOnComponent.cpp
index 4d3b34d3..50a30ab5 100644
--- a/PanelSwCustomActions/ExecOnComponent.cpp
+++ b/PanelSwCustomActions/ExecOnComponent.cpp
@@ -117,8 +117,8 @@ extern "C" UINT __stdcall ExecuteCommand(MSIHANDLE hInstall)
hr = cad.AddExec(szCommand, (LPCWSTR)szWorkingFolder, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, isAsync ? Flags::ASync : 0, errorHandling);
ExitOnFailure(hr, "Failed to create command");
- hr = cad.DoDeferredAction((LPCWSTR)szId);
- ExitOnFailure(hr, "Failed to schedule deferred custom action");
+ hr = cad.SetCustomActionData((LPCWSTR)szId);
+ ExitOnFailure(hr, "Failed to set CustomActionData");
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
diff --git a/PanelSwWixExtension/MessageResources.Designer.cs b/PanelSwWixExtension/MessageResources.Designer.cs
new file mode 100644
index 00000000..48994282
--- /dev/null
+++ b/PanelSwWixExtension/MessageResources.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace PanelSw.Wix.Extensions {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class MessageResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal MessageResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PanelSw.Wix.Extensions.MessageResources", typeof(MessageResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The InstallExecuteSequence table contains action '{1}' in between actions required for ExecuteCommand action '{0}'. Please schedule commands to execute after '{0}' or before 'Prepare{0}'.
+ ///
+ internal static string ExecuteCommandSequence {
+ get {
+ return ResourceManager.GetString("ExecuteCommandSequence", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/PanelSwWixExtension/MessageResources.resx b/PanelSwWixExtension/MessageResources.resx
new file mode 100644
index 00000000..824c9431
--- /dev/null
+++ b/PanelSwWixExtension/MessageResources.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ The InstallExecuteSequence table contains action '{1}' in between actions required for ExecuteCommand action '{0}'. Please schedule commands to execute after '{0}' or before 'Prepare{0}'
+
+
\ No newline at end of file
diff --git a/PanelSwWixExtension/PanelSwWiBackendBinder.cs b/PanelSwWixExtension/PanelSwWiBackendBinder.cs
index 88a99264..d998bc15 100644
--- a/PanelSwWixExtension/PanelSwWiBackendBinder.cs
+++ b/PanelSwWixExtension/PanelSwWiBackendBinder.cs
@@ -485,6 +485,7 @@ public override IReadOnlyCollection TableDefinitions
new TableDefinition(nameof(PSW_ExecOnComponent), PSW_ExecOnComponent.SymbolDefinition, PSW_ExecOnComponent.ColumnDefinitions, symbolIdIsPrimaryKey: true),
new TableDefinition(nameof(PSW_ExecOnComponent_Environment), PSW_ExecOnComponent_Environment.SymbolDefinition, PSW_ExecOnComponent_Environment.ColumnDefinitions, symbolIdIsPrimaryKey: false),
new TableDefinition(nameof(PSW_ExecOnComponent_ExitCode), PSW_ExecOnComponent_ExitCode.SymbolDefinition, PSW_ExecOnComponent_ExitCode.ColumnDefinitions, symbolIdIsPrimaryKey: false),
+ new TableDefinition(nameof(PSW_ExecuteCommand), PSW_ExecuteCommand.SymbolDefinition, PSW_ExecuteCommand.ColumnDefinitions, symbolIdIsPrimaryKey: true, unreal: true),
new TableDefinition(nameof(PSW_FileRegex), PSW_FileRegex.SymbolDefinition, PSW_FileRegex.ColumnDefinitions, symbolIdIsPrimaryKey: true),
new TableDefinition(nameof(PSW_ForceVersion), PSW_ForceVersion.SymbolDefinition, PSW_ForceVersion.ColumnDefinitions, symbolIdIsPrimaryKey: false),
new TableDefinition(nameof(PSW_InstallUtil), PSW_InstallUtil.SymbolDefinition, PSW_InstallUtil.ColumnDefinitions, symbolIdIsPrimaryKey: false),
@@ -547,8 +548,49 @@ public override void SymbolsFinalized(IntermediateSection section)
GetSplitFiles();
ResolveTaskScheduler();
DuplicateFolder(section);
+ CheckExecuteCommandSequences();
}
+ private void CheckExecuteCommandSequences()
+ {
+ List executeCommands = new List();
+ List wixActions = new List();
+ foreach (IntermediateSection intermediate in base.Context.IntermediateRepresentation.Sections)
+ {
+ foreach (IntermediateSymbol symbol in intermediate.Symbols)
+ {
+ if (symbol is PSW_ExecuteCommand exc)
+ {
+ executeCommands.Add(exc);
+ }
+ if (symbol is WixActionSymbol act)
+ {
+ wixActions.Add(act);
+ }
+ }
+ }
+
+ foreach (PSW_ExecuteCommand executeCommand in executeCommands)
+ {
+ string prepareId = $"Prepare{executeCommand.Id.Id}";
+ string schedId = $"Sched{executeCommand.Id.Id}";
+ string prepareFullId = $"InstallExecuteSequence/{prepareId}";
+ string schedFullId = $"InstallExecuteSequence/{schedId}";
+
+ IEnumerable actionRows = wixActions.Where(action => action.SequenceTable.Equals(SequenceTable.InstallExecuteSequence) && (
+ executeCommand.Id.Id.Equals(action.Before) && !schedFullId.Equals(action.Id.Id)) /* Actions that might be sequnced before PSW_ExecuteCommand */
+ || (schedId.Equals(action.Before) && !prepareFullId.Equals(action.Id.Id)) /* Before Sched, but not Prepare*/
+ || (schedId.Equals(action.After) && !executeCommand.Id.Id.Equals(action.Id.Id)) /* After Sched, but not PSW_ExecuteCommand*/
+ || (prepareId.Equals(action.After) && !schedFullId.Equals(action.Id.Id)) /* After Prepare, but not Sched*/
+ );
+ foreach (WixActionSymbol action in actionRows)
+ {
+ string otherId = action.Id.Id.Remove(0, "InstallExecuteSequence/".Length);
+ Messaging.Write(PanelSwWixErrorMessages.ExecuteCommandSequence(action.SourceLineNumbers, executeCommand.Id.Id, otherId));
+ }
+ }
+ }
+
private void DuplicateFolder(IntermediateSection section)
{
List duplicateFolders = new List();
diff --git a/PanelSwWixExtension/PanelSwWixCompiler.cs b/PanelSwWixExtension/PanelSwWixCompiler.cs
index c3781ede..17a4cd79 100644
--- a/PanelSwWixExtension/PanelSwWixCompiler.cs
+++ b/PanelSwWixExtension/PanelSwWixCompiler.cs
@@ -1043,6 +1043,8 @@ private void ParseExecuteCommand(IntermediateSection section, XElement element)
string cad = json.ToString();
cad = Regex.Replace(cad, "([\\[\\]\\{\\}])", "[\\$1]");
+ section.AddSymbol(new PSW_ExecuteCommand(sourceLineNumbers, new Identifier(AccessModifier.Global, id)));
+
CustomActionSymbol prepareCA = section.AddSymbol(new CustomActionSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, $"Prepare{id}")));
prepareCA.ExecutionType = CustomActionExecutionType.Immediate;
prepareCA.Source = "PSW_ExecuteCommand";
@@ -1070,8 +1072,8 @@ private void ParseExecuteCommand(IntermediateSection section, XElement element)
schedCadSched.Action = schedCAD.Id.Id;
schedCadSched.SequenceTable = SequenceTable.InstallExecuteSequence;
schedCadSched.Condition = condition;
- schedCadSched.Before = before;
- schedCadSched.After = after;
+ schedCadSched.Before = id;
+ schedCadSched.After = null;
schedCadSched.Overridable = false;
// 3. PanelSwCustomActions::CommonDeferred
@@ -1083,6 +1085,14 @@ private void ParseExecuteCommand(IntermediateSection section, XElement element)
deferredCA.TargetType = CustomActionTargetType.Dll;
deferredCA.Impersonate = impersonate;
deferredCA.Hidden = true;
+
+ WixActionSymbol deferredCASched = section.AddSymbol(new WixActionSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, $"InstallExecuteSequence/{id}")));
+ deferredCASched.Action = deferredCA.Id.Id;
+ deferredCASched.SequenceTable = SequenceTable.InstallExecuteSequence;
+ deferredCASched.Condition = condition;
+ deferredCASched.Before = before;
+ deferredCASched.After = after;
+ deferredCASched.Overridable = false;
}
private void ParseWebsiteConfigElement(IntermediateSection section, XElement element, string component)
diff --git a/PanelSwWixExtension/PanelSwWixExtension.csproj b/PanelSwWixExtension/PanelSwWixExtension.csproj
index 75561ea3..5929bda8 100644
--- a/PanelSwWixExtension/PanelSwWixExtension.csproj
+++ b/PanelSwWixExtension/PanelSwWixExtension.csproj
@@ -37,25 +37,25 @@
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -68,9 +68,24 @@
-
-
-
+
+
+
+
+
+
+
+ True
+ True
+ MessageResources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ MessageResources.Designer.cs
+
diff --git a/PanelSwWixExtension/PanelSwWixExtensionMessage.cs b/PanelSwWixExtension/PanelSwWixExtensionMessage.cs
new file mode 100644
index 00000000..3785cf45
--- /dev/null
+++ b/PanelSwWixExtension/PanelSwWixExtensionMessage.cs
@@ -0,0 +1,17 @@
+using WixToolset.Data;
+
+namespace PanelSw.Wix.Extensions
+{
+ public static class PanelSwWixErrorMessages
+ {
+ public static Message ExecuteCommandSequence(SourceLineNumber sourceLineNumber, string executeCommandId, string otherActionId)
+ {
+ return new Message(sourceLineNumber, MessageLevel.Error, (int)PswErrorId.ExecuteCommandSequence, MessageResources.ExecuteCommandSequence, executeCommandId, otherActionId);
+ }
+ }
+
+ public enum PswErrorId
+ {
+ ExecuteCommandSequence = 9000,
+ }
+}
diff --git a/PanelSwWixExtension/Symbols/PSW_ExecuteCommand.cs b/PanelSwWixExtension/Symbols/PSW_ExecuteCommand.cs
new file mode 100644
index 00000000..ddbbc4c0
--- /dev/null
+++ b/PanelSwWixExtension/Symbols/PSW_ExecuteCommand.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using WixToolset.Data;
+using WixToolset.Data.WindowsInstaller;
+
+namespace PanelSw.Wix.Extensions.Symbols
+{
+ internal class PSW_ExecuteCommand : BaseSymbol
+ {
+ public static IntermediateSymbolDefinition SymbolDefinition
+ {
+ get
+ {
+ return new IntermediateSymbolDefinition(nameof(PSW_ExecuteCommand), CreateFieldDefinitions(ColumnDefinitions), typeof(PSW_ExecuteCommand));
+ }
+ }
+ public static IEnumerable ColumnDefinitions
+ {
+ get
+ {
+ return new ColumnDefinition[]
+ {
+ new ColumnDefinition(nameof(Id), ColumnType.String, 72, true, false, ColumnCategory.Identifier, modularizeType: ColumnModularizeType.Column),
+ };
+ }
+ }
+
+ public PSW_ExecuteCommand() : base(SymbolDefinition)
+ { }
+
+ public PSW_ExecuteCommand(SourceLineNumber lineNumber, Identifier id) : base(SymbolDefinition, lineNumber, id)
+ { }
+ }
+}
diff --git a/TidyBuild.custom.props b/TidyBuild.custom.props
index 9cff40a6..88e916c0 100644
--- a/TidyBuild.custom.props
+++ b/TidyBuild.custom.props
@@ -2,7 +2,7 @@
- 3.15.0
+ 3.15.1
$(FullVersion).$(GITHUB_RUN_NUMBER)
PanelSwWixExtension
Panel::Software
diff --git a/UnitTests/ExecuteCommandUT/ExecuteCommandUT.wxs b/UnitTests/ExecuteCommandUT/ExecuteCommandUT.wxs
index 1c8f7fe2..600c74af 100644
--- a/UnitTests/ExecuteCommandUT/ExecuteCommandUT.wxs
+++ b/UnitTests/ExecuteCommandUT/ExecuteCommandUT.wxs
@@ -10,6 +10,7 @@
+