-
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathProgram.cs
More file actions
174 lines (156 loc) · 6.23 KB
/
Program.cs
File metadata and controls
174 lines (156 loc) · 6.23 KB
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
using CommandLine;
using System;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Threading;
using System.Windows.Forms;
namespace GeoTagNinja;
internal static class Program
{
private const string PipeErrorAbandonedMutexException = "AbandonedMutexException";
private const string PipeErrorConnectionTimeout = "Connection timed out: ";
private const string PipeErrorIoError = "IO Error: ";
private const string PipeErrorAccessDenied = "Access Denied: ";
private const string PipeErrorCouldNotConnect = "Could not connect to other GTN instance";
private const string PipeErrorUnexpectedError = "Unexpected Error: ";
public static string CollectionFileLocation;
public static string FolderToLaunchIn;
public static bool CollectionModeEnabled;
public const string SingleInstancePipeName = "GeoTagNinjaSingleInstance";
/// <summary>
/// If true, this is the "first" instance of the program
/// </summary>
public static bool SingleInstanceHighlander;
/// <summary>
/// A Mutex that is held by the first instance of the application
/// </summary>
private static Mutex _singleInstanceMutex = new(initiallyOwned: false, name: "GeoTagNinja.SingleInstance");
/// <summary>
/// The main entry point for the application.
/// Usage: either leave the args blank or do: geotagninja.exe --collection="c:\temp\collection.txt" or some such.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(defaultValue: false);
_ = Parser.Default.ParseArguments<OptionsMutuallyExclusive>(args: args)
.WithParsed(action: o =>
{
if (File.Exists(path: o.Collection))
{
CollectionFileLocation = o.Collection;
CollectionModeEnabled = true;
}
if (!string.IsNullOrWhiteSpace(value: o.Folder))
{
// o.Folder can be a number of things depending on how the user executes, ie could be -f C:\temp or -f=C:\temp or "" enclosed etc
// yes i know this can be doen in one step but it's easier to debug/follow like thi
// 1. remove any ""s
string trimmedPath = o.Folder.Replace(oldValue: "\"", newValue: "");
// 2. remove "=" if any
trimmedPath = trimmedPath.TrimStart('=');
// 3. remove "\" from the end.
trimmedPath = trimmedPath.TrimEnd(Convert.ToChar(value: "\\"));
if (Directory.Exists(path: trimmedPath))
{
FolderToLaunchIn = trimmedPath;
}
}
});
// Brief wait in case current instance is exiting
try
{
SingleInstanceHighlander = _singleInstanceMutex.WaitOne(millisecondsTimeout: 1000);
}
catch (AbandonedMutexException)
{
// Other application did not release Mutex properly
_ = MessageBox.Show(text: PipeErrorAbandonedMutexException);
}
if (!SingleInstanceHighlander)
{
PassInfoToRunningInstance();
}
else
{
Application.Run(mainForm: new FrmMainApp());
_singleInstanceMutex.ReleaseMutex();
}
}
/// <summary>
/// Passes information to the already running first instance of
/// GTN using a named pipe.
/// </summary>
private static void PassInfoToRunningInstance()
{
NamedPipeClientStream pipeClient = new(
serverName: ".", pipeName: SingleInstancePipeName, direction: PipeDirection.Out, options: PipeOptions.None,
impersonationLevel: TokenImpersonationLevel.Identification);
try
{
pipeClient.Connect(timeout: 3000);
}
catch (TimeoutException ex)
{
_ = MessageBox.Show(text: PipeErrorConnectionTimeout + ex.Message);
return;
}
catch (IOException ex)
{
_ = MessageBox.Show(text: PipeErrorIoError + ex.Message);
return;
}
catch (UnauthorizedAccessException ex)
{
_ = MessageBox.Show(text: PipeErrorAccessDenied + ex.Message);
return;
}
catch (Exception ex)
{
_ = MessageBox.Show(text: PipeErrorUnexpectedError + ex.Message);
return;
}
// Could not get hold of server - abort
if (!pipeClient.IsConnected)
{
_ = MessageBox.Show(text: PipeErrorCouldNotConnect);
return;
}
try
{
using StreamWriter streamer = new(stream: pipeClient);
streamer.WriteLine(value: "Could not connect to other GTN instance");
streamer.Flush();
streamer.Close();
}
catch (IOException ex)
{
_ = MessageBox.Show(text: PipeErrorIoError + ex.Message);
}
catch (Exception ex)
{
_ = MessageBox.Show(text: PipeErrorUnexpectedError + ex.Message);
}
finally
{
pipeClient.Close();
}
}
/// <summary>
/// Note to self / from https://github.com/commandlineparser/commandline/wiki/Mutually-Exclusive-Options
/// "If you combine a SetName1 option with a SetName2 one, parsing will fail. Options in the SAME set can be combined
/// together,
/// but options cannot be combined across sets"
/// </summary>
private class OptionsMutuallyExclusive
{
[Option(shortName: 'c', longName: "collection", Required = false, SetName = "collection",
HelpText = "Location (full path) of a text file that has the list of files to process, one per line.")]
public string Collection { get; set; }
[Option(shortName: 'f', longName: "folder", Required = false, SetName = "folder",
HelpText = "Folder to open GTN with (likely use with a SendTo command)")]
public string Folder { get; set; }
}
}