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