Skip to content

Commit ab93ca0

Browse files
committed
single instance: move task into delegate
1 parent f9da6bc commit ab93ca0

6 files changed

Lines changed: 122 additions & 85 deletions

File tree

FlashpointSecurePlayer/DownloadsBefore.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public async Task ActivateAsync(string templateName, List<string> downloadsBefor
2929
// we know the file downloaded all the way before the
3030
// server/software starts
3131
//DownloadBeforeElement downloadBeforeElement = null;
32+
33+
if (downloadsBeforeNames == null) {
34+
return;
35+
}
36+
3237
ProgressManager.CurrentGoal.Start(downloadsBeforeNames.Count);
3338

3439
try {

FlashpointSecurePlayer/FlashpointSecurePlayerGUI.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ private async Task ActivateModificationsAsync(TemplateElement templateElement, E
10171017
if (modificationsElement.ElementInformation.IsPresent) {
10181018
if (modificationsElement.SingleInstance.ElementInformation.IsPresent) {
10191019
try {
1020-
singleInstance.Activate(TemplateName);
1020+
singleInstance.Activate(TemplateName, this);
10211021
} catch (InvalidModificationException) {
10221022
//LogExceptionToLauncher(ex);
10231023
throw;

FlashpointSecurePlayer/ProgressManager.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -393,14 +393,10 @@ private static ProgressBarStyle ProgressBarStyle {
393393
if (ProgressBar == null) {
394394
return;
395395
}
396-
397-
if (ProgressBar.InvokeRequired) {
398-
ProgressBar.Invoke(new MethodInvoker(delegate () {
399-
ProgressBar.Style = value;
400-
}));
401-
} else {
396+
397+
ProgressBar.InvokeIfRequired(new MethodInvoker(delegate () {
402398
ProgressBar.Style = value;
403-
}
399+
}));
404400
}
405401
}
406402

@@ -418,14 +414,10 @@ private static int ProgressBarValue {
418414
if (ProgressBar == null) {
419415
return;
420416
}
421-
422-
if (ProgressBar.InvokeRequired) {
423-
ProgressBar.Invoke(new MethodInvoker(delegate () {
424-
ProgressBar.Value = value;
425-
}));
426-
} else {
417+
418+
ProgressBar.InvokeIfRequired(new MethodInvoker(delegate () {
427419
ProgressBar.Value = value;
428-
}
420+
}));
429421
}
430422
}
431423

FlashpointSecurePlayer/RegistryStates.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public enum TYPE {
3535

3636
//private const int IMPORT_TIMEOUT = 5;
3737
private const int IMPORT_TIMEOUT = 60;
38+
private const int IMPORT_MILLISECONDS = 1000;
3839
private const string IMPORT_RESUME = "FLASHPOINTSECUREPLAYERREGISTRYSTATEIMPORTRESUME";
3940
private const string IMPORT_PAUSE = "FLASHPOINTSECUREPLAYERREGISTRYSTATEIMPORTPAUSE";
4041

@@ -753,9 +754,9 @@ public async Task StartImportAsync(string templateName, BINARY_TYPE binaryType)
753754
}
754755

755756
//if (sync) {
756-
//Thread.Sleep(1000);
757+
//Thread.Sleep(IMPORT_MILLISECONDS);
757758
//} else {
758-
await Task.Delay(1000).ConfigureAwait(true);
759+
await Task.Delay(IMPORT_MILLISECONDS).ConfigureAwait(true);
759760
//}
760761
}
761762

@@ -795,9 +796,9 @@ private async Task StopImportAsync(bool sync) {
795796
}
796797

797798
if (sync) {
798-
Thread.Sleep(1000);
799+
Thread.Sleep(IMPORT_MILLISECONDS);
799800
} else {
800-
await Task.Delay(1000).ConfigureAwait(true);
801+
await Task.Delay(IMPORT_MILLISECONDS).ConfigureAwait(true);
801802
}
802803
}
803804

FlashpointSecurePlayer/Shared.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,14 @@ public static void HandleAntecedentTask(Task antecedentTask) {
22112211
throw ex;
22122212
}
22132213

2214+
public static void InvokeIfRequired(this Control control, MethodInvoker method) {
2215+
if (control.InvokeRequired) {
2216+
control.Invoke(method);
2217+
} else {
2218+
method();
2219+
}
2220+
}
2221+
22142222
public static async Task<Uri> DownloadAsync(string name) {
22152223
await downloadSemaphoreSlim.WaitAsync().ConfigureAwait(true);
22162224

@@ -2577,7 +2585,7 @@ public static void HideWindow(ref ProcessStartInfo processStartInfo) {
25772585

25782586
public static StringBuilder GetCreateProcessCommandLine(ProcessStartInfo processStartInfo) {
25792587
if (processStartInfo == null) {
2580-
throw new ArgumentNullException("processStartInfo must not be null.");
2588+
throw new ArgumentNullException("The processStartInfo is null.");
25812589
}
25822590

25832591
string fileName = processStartInfo.FileName.Trim();
@@ -2606,7 +2614,7 @@ public static void StartProcessCreateBreakawayFromJob(ProcessStartInfo processSt
26062614
process = null;
26072615

26082616
if (processStartInfo == null) {
2609-
throw new ArgumentNullException("processStartInfo must not be null.");
2617+
throw new ArgumentNullException("The processStartInfo is null.");
26102618
}
26112619

26122620
if (processStartInfo.UseShellExecute) {

FlashpointSecurePlayer/SingleInstance.cs

Lines changed: 95 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,79 @@ namespace FlashpointSecurePlayer {
2020
public class SingleInstance : Modifications {
2121
public SingleInstance(EventHandler importStart, EventHandler importStop) : base(importStart, importStop) { }
2222

23-
// function to create a real MessageBox which
24-
// automatically closes upon completion of tasks
25-
private DialogResult? ShowClosableMessageBox(Task[] tasks, string text, string caption, MessageBoxButtons messageBoxButtons, MessageBoxIcon messageBoxIcon) {
26-
Form closableForm = new Form() {
27-
Size = new Size(0, 0)
28-
};
29-
30-
closableForm.BringToFront();
31-
32-
// need this because dialogResult defaults to Cancel when
33-
// we want it to default to null
34-
bool dialogResultSet = true;
35-
36-
Task.WhenAll(tasks).ContinueWith(delegate (Task antecedentTask) {
37-
HandleAntecedentTask(antecedentTask);
38-
39-
// this closes the form hosting the Message Box and
40-
// causes it to stop blocking
41-
closableForm.Close();
42-
dialogResultSet = false;
43-
}, TaskScheduler.FromCurrentSynchronizationContext());
44-
45-
// this line blocks execution, but the task above causes it to stop blocking
46-
DialogResult dialogResult = MessageBox.Show(closableForm, text, caption, messageBoxButtons, messageBoxIcon);
23+
private delegate Task[] ClosableMessageBoxTasksDelegate(CancellationToken token);
24+
private delegate Task ClosableMessageBoxTaskDelegate(CancellationToken token);
25+
26+
// function to create a MessageBox which
27+
// automatically closes upon completion of multiple tasks
28+
private DialogResult? MessageBoxShowClosable(Form owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, ClosableMessageBoxTasksDelegate tasksDelegate) {
29+
if (owner == null) {
30+
throw new ArgumentNullException("The owner is null.");
31+
}
4732

48-
if (!dialogResultSet) {
49-
return null;
33+
Form closable = null;
34+
35+
// owner is required for this invoke
36+
owner.InvokeIfRequired(new MethodInvoker(delegate () {
37+
// the form is created, but not shown
38+
// its owner is set so the Message Box will act as an owned window
39+
closable = new Form {
40+
Owner = owner
41+
};
42+
}));
43+
44+
using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource()) {
45+
try {
46+
Task task = Task.WhenAll(
47+
tasksDelegate(
48+
cancellationTokenSource.Token
49+
)
50+
).ContinueWith(
51+
delegate (Task antecedentTask) {
52+
HandleAntecedentTask(antecedentTask);
53+
54+
// this closes the form hosting the Message Box and
55+
// causes it to stop blocking
56+
closable.InvokeIfRequired(new MethodInvoker(delegate () {
57+
closable.Close();
58+
}));
59+
},
60+
61+
TaskScheduler.FromCurrentSynchronizationContext()
62+
);
63+
64+
DialogResult? dialogResult = null;
65+
66+
// this blocks execution, but the task above causes it to stop blocking
67+
// if the dialog was closed upon completion of the tasks, we return null
68+
// faulted/cancelled task status doesn't count
69+
// (because it happens last, the task must run to completion to close the dialog)
70+
closable.InvokeIfRequired(new MethodInvoker(delegate () {
71+
dialogResult = MessageBox.Show(closable, text, caption, buttons, icon);
72+
}));
73+
return task.Status == TaskStatus.RanToCompletion ? null : dialogResult;
74+
} finally {
75+
cancellationTokenSource.Cancel();
76+
}
5077
}
51-
return dialogResult;
5278
}
5379

54-
// single task version
55-
private DialogResult? ShowClosableMessageBox(Task task, string text, string caption, MessageBoxButtons messageBoxButtons, MessageBoxIcon messageBoxIcon) {
56-
return ShowClosableMessageBox(new Task[] { task }, text, caption, messageBoxButtons, messageBoxIcon);
80+
// overload for a single task
81+
private DialogResult? MessageBoxShowClosable(Form owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, ClosableMessageBoxTaskDelegate taskDelegate) {
82+
return MessageBoxShowClosable(
83+
owner,
84+
text,
85+
caption,
86+
buttons,
87+
icon,
88+
89+
delegate (CancellationToken token) {
90+
return new Task[] { taskDelegate(token) };
91+
}
92+
);
5793
}
5894

59-
public override void Activate(string templateName) {
95+
public void Activate(string templateName, Form owner) {
6096
base.Activate(templateName);
6197

6298
if (String.IsNullOrEmpty(TemplateName)) {
@@ -97,6 +133,10 @@ public override void Activate(string templateName) {
97133
return;
98134
}
99135

136+
if (owner == null) {
137+
throw new ArgumentNullException("The owner is null.");
138+
}
139+
100140
const int PROCESS_BY_NAME_STRICT_WAIT_FOR_EXIT_MILLISECONDS = 1000;
101141

102142
Process[] processesByName = null;
@@ -108,19 +148,22 @@ public override void Activate(string templateName) {
108148

109149
do {
110150
if (processesByNameStrict != null) {
111-
// for future versions: would be nice if ShowClosableMessageBox created this token source
112-
// and passed it as an argument to the tasks that we give to it
113-
// (since you'll probably always want it)
114-
// but unsure how to make the WhenAll in ShowClosableMessageBox pass the arguments
115-
// to the task, or how to make the task itself recieve them
116-
// maybe ThreadPool.QueueUserWorkItem does this?
117-
using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource()) {
118-
CancellationToken token = cancellationTokenSource.Token;
119-
120-
// don't allow preceding further until
121-
// all processes with the same name have been killed
122-
DialogResult? dialogResult = ShowClosableMessageBox(
123-
Task.Run(delegate () {
151+
// don't allow preceding further until
152+
// all processes with the same name have been killed
153+
DialogResult? dialogResult = MessageBoxShowClosable(
154+
owner,
155+
156+
String.Format(
157+
Properties.Resources.ProcessCompatibilityConflict,
158+
activeProcessName
159+
),
160+
161+
Properties.Resources.FlashpointSecurePlayer,
162+
MessageBoxButtons.OKCancel,
163+
MessageBoxIcon.Warning,
164+
165+
delegate (CancellationToken token) {
166+
return Task.Run(delegate () {
124167
// copy this, so it doesn't get set to null upon hitting OK
125168
Stack<Process> _processesByNameStrict = new Stack<Process>(processesByNameStrict);
126169

@@ -130,7 +173,8 @@ public override void Activate(string templateName) {
130173
if (processByNameStrict != null) {
131174
// test for cancellation before waiting
132175
// (so we don't wait unnecessarily for the next processes after this one)
133-
while (!token.IsCancellationRequested) {
176+
while (token == null
177+
|| !token.IsCancellationRequested) {
134178
if (processByNameStrict.WaitForExit(PROCESS_BY_NAME_STRICT_WAIT_FOR_EXIT_MILLISECONDS)) {
135179
break;
136180
}
@@ -144,26 +188,13 @@ public override void Activate(string templateName) {
144188
}
145189

146190
_processesByNameStrict = null;
147-
}),
148-
149-
String.Format(
150-
Properties.Resources.ProcessCompatibilityConflict,
151-
activeProcessName
152-
),
153-
154-
Properties.Resources.FlashpointSecurePlayer,
155-
MessageBoxButtons.OKCancel,
156-
MessageBoxIcon.Warning
157-
);
158-
159-
// end the task passed to the Closable Message Box
160-
// we'll be creating a new one on the next loop as necessary
161-
cancellationTokenSource.Cancel();
162-
163-
if (dialogResult == DialogResult.Cancel) {
164-
Application.Exit();
165-
throw new InvalidModificationException("The operation was aborted by the user.");
191+
});
166192
}
193+
);
194+
195+
if (dialogResult == DialogResult.Cancel) {
196+
Application.Exit();
197+
throw new InvalidModificationException("The operation was aborted by the user.");
167198
}
168199

169200
processesByNameStrict = null;

0 commit comments

Comments
 (0)