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