diff options
Diffstat (limited to 'src/samples/Dtf/EmbeddedUI/InstallProgressCounter.cs')
-rw-r--r-- | src/samples/Dtf/EmbeddedUI/InstallProgressCounter.cs | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/samples/Dtf/EmbeddedUI/InstallProgressCounter.cs b/src/samples/Dtf/EmbeddedUI/InstallProgressCounter.cs new file mode 100644 index 00000000..df77e106 --- /dev/null +++ b/src/samples/Dtf/EmbeddedUI/InstallProgressCounter.cs | |||
@@ -0,0 +1,176 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixToolset.Dtf.Samples.EmbeddedUI | ||
4 | { | ||
5 | using System; | ||
6 | using WixToolset.Dtf.WindowsInstaller; | ||
7 | |||
8 | /// <summary> | ||
9 | /// Tracks MSI progress messages and converts them to usable progress. | ||
10 | /// </summary> | ||
11 | public class InstallProgressCounter | ||
12 | { | ||
13 | private int total; | ||
14 | private int completed; | ||
15 | private int step; | ||
16 | private bool moveForward; | ||
17 | private bool enableActionData; | ||
18 | private int progressPhase; | ||
19 | private double scriptPhaseWeight; | ||
20 | |||
21 | public InstallProgressCounter() : this(0.3) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | public InstallProgressCounter(double scriptPhaseWeight) | ||
26 | { | ||
27 | if (!(0 <= scriptPhaseWeight && scriptPhaseWeight <= 1)) | ||
28 | { | ||
29 | throw new ArgumentOutOfRangeException("scriptPhaseWeight"); | ||
30 | } | ||
31 | |||
32 | this.scriptPhaseWeight = scriptPhaseWeight; | ||
33 | } | ||
34 | |||
35 | /// <summary> | ||
36 | /// Gets a number between 0 and 1 that indicates the overall installation progress. | ||
37 | /// </summary> | ||
38 | public double Progress { get; private set; } | ||
39 | |||
40 | public void ProcessMessage(InstallMessage messageType, Record messageRecord) | ||
41 | { | ||
42 | // This MSI progress-handling code was mostly borrowed from burn and translated from C++ to C#. | ||
43 | |||
44 | switch (messageType) | ||
45 | { | ||
46 | case InstallMessage.ActionStart: | ||
47 | if (this.enableActionData) | ||
48 | { | ||
49 | this.enableActionData = false; | ||
50 | } | ||
51 | break; | ||
52 | |||
53 | case InstallMessage.ActionData: | ||
54 | if (this.enableActionData) | ||
55 | { | ||
56 | if (this.moveForward) | ||
57 | { | ||
58 | this.completed += this.step; | ||
59 | } | ||
60 | else | ||
61 | { | ||
62 | this.completed -= this.step; | ||
63 | } | ||
64 | |||
65 | this.UpdateProgress(); | ||
66 | } | ||
67 | break; | ||
68 | |||
69 | case InstallMessage.Progress: | ||
70 | this.ProcessProgressMessage(messageRecord); | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | private void ProcessProgressMessage(Record progressRecord) | ||
76 | { | ||
77 | // This MSI progress-handling code was mostly borrowed from burn and translated from C++ to C#. | ||
78 | |||
79 | if (progressRecord == null || progressRecord.FieldCount == 0) | ||
80 | { | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | int fieldCount = progressRecord.FieldCount; | ||
85 | int progressType = progressRecord.GetInteger(1); | ||
86 | string progressTypeString = String.Empty; | ||
87 | switch (progressType) | ||
88 | { | ||
89 | case 0: // Master progress reset | ||
90 | if (fieldCount < 4) | ||
91 | { | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | this.progressPhase++; | ||
96 | |||
97 | this.total = progressRecord.GetInteger(2); | ||
98 | if (this.progressPhase == 1) | ||
99 | { | ||
100 | // HACK!!! this is a hack courtesy of the Windows Installer team. It seems the script planning phase | ||
101 | // is always off by "about 50". So we'll toss an extra 50 ticks on so that the standard progress | ||
102 | // doesn't go over 100%. If there are any custom actions, they may blow the total so we'll call this | ||
103 | // "close" and deal with the rest. | ||
104 | this.total += 50; | ||
105 | } | ||
106 | |||
107 | this.moveForward = (progressRecord.GetInteger(3) == 0); | ||
108 | this.completed = (this.moveForward ? 0 : this.total); // if forward start at 0, if backwards start at max | ||
109 | this.enableActionData = false; | ||
110 | |||
111 | this.UpdateProgress(); | ||
112 | break; | ||
113 | |||
114 | case 1: // Action info | ||
115 | if (fieldCount < 3) | ||
116 | { | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | if (progressRecord.GetInteger(3) == 0) | ||
121 | { | ||
122 | this.enableActionData = false; | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | this.enableActionData = true; | ||
127 | this.step = progressRecord.GetInteger(2); | ||
128 | } | ||
129 | break; | ||
130 | |||
131 | case 2: // Progress report | ||
132 | if (fieldCount < 2 || this.total == 0 || this.progressPhase == 0) | ||
133 | { | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | if (this.moveForward) | ||
138 | { | ||
139 | this.completed += progressRecord.GetInteger(2); | ||
140 | } | ||
141 | else | ||
142 | { | ||
143 | this.completed -= progressRecord.GetInteger(2); | ||
144 | } | ||
145 | |||
146 | this.UpdateProgress(); | ||
147 | break; | ||
148 | |||
149 | case 3: // Progress total addition | ||
150 | this.total += progressRecord.GetInteger(2); | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | private void UpdateProgress() | ||
156 | { | ||
157 | if (this.progressPhase < 1 || this.total == 0) | ||
158 | { | ||
159 | this.Progress = 0; | ||
160 | } | ||
161 | else if (this.progressPhase == 1) | ||
162 | { | ||
163 | this.Progress = this.scriptPhaseWeight * Math.Min(this.completed, this.total) / this.total; | ||
164 | } | ||
165 | else if (this.progressPhase == 2) | ||
166 | { | ||
167 | this.Progress = this.scriptPhaseWeight + | ||
168 | (1 - this.scriptPhaseWeight) * Math.Min(this.completed, this.total) / this.total; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | this.Progress = 1; | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | } | ||