-
Notifications
You must be signed in to change notification settings - Fork 1
/
Suite.cpp
304 lines (286 loc) · 11.5 KB
/
Suite.cpp
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#include "SuiteMain.h"
#include "SuiteExterns.h"
#include "SuiteCommon.h"
#include "SuiteSettings.h"
#include "SuiteExternalRelations.h"
#include <memory>
#include <cstdlib>
#include <windows.h>
#ifdef DEBUG
#include <iostream>
#endif
enum class CmdRes:char {DEFAULT, SETTINGS_SET, EXTERNAL_CALLED, ERR_MANY_ARGS, ERR_FEW_ARGS, ERR_UNKNOWN, ERR_NOT_IMPLEMENTED};
enum class FstCmd:char {DEFAULT, LONG_PRESS, SHORT_PRESS, SHELL};
CmdRes ProcessSettingsOptions(std::unique_ptr<SuiteSettings> &Settings, int cmd_argc, wchar_t** cmd_argv, int cmd_shift);
#define ARG_ALL L"machine"
#define ARG_CUR L"user"
#ifdef OBSOLETE_WWINMAIN
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nCmdShow)
{
LPWSTR lpCmdLine=GetCommandLineW();
//We should drop first argument which is executable path
//And it's more of a convention that most programmers adhere to than strict requirement
//Because actually you can call CreateProcess explicitly passing application name and omitting it from command line, which is a separate argument (not the case with ShellExecuteEx)
bool inside_quotes=false;
while (*lpCmdLine>L' '||(*lpCmdLine&&inside_quotes)) {
if (*lpCmdLine==L'\"')
inside_quotes=!inside_quotes;
lpCmdLine++;
}
while (*lpCmdLine&&(*lpCmdLine<=L' '))
lpCmdLine++;
#else
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
#endif
SuiteExterns::MakeInstance();
std::unique_ptr<SuiteSettings> Settings;
//Even though SuiteSettings supports storing configs in registry and in INI files on per-section basis - we doesn't support it for now
//Storing setting in INI on per-section basis is not so useful feature
//While storing settings in the registry seems to be useful, it's also controversial: SnK scripts can't be stored in the registry and should be stored elsewhere
//Currently SnK scripts are stored with binary for registry settings, so they can't be used out of the box for per-user (in contrast with per-machine) use
//Command line options:
// /S machine|user [ARG1] [ARG2] - schedule application with Task Scheduler (run w/ highest privileges), arguments will be passed as command line options
// /A machine|user [ARG1] [ARG2] - add application to Autorun, arguments will be passed as command line options
// /U machine|user - delete scheduled application from Task Scheduler
// /R machine|user - remove application from Autorun
// /P machine|user - add application directory to Path environment variable
// /C machine|user - remove application directory to Path environment variable
// /i [INI_PATH] - launch application and store settings in ini file pointed by INI_PATH argument or, if absent, in HotkeySuite.ini located in application directory
// /a [machine|user] - launch application and store settings in ini file located in per-user (user) or all-user (machine) AppData directory (automatically selected if argument is absent)
// NO ARGUMENTS GIVEN - launch application and automatically select ini file location
// /s ... - immidiately run single press event and exit (used with /i and /a options or w/o arguments)
// /l ... - immidiately run long press event and exit (used with /i and /a options or w/o arguments)
// /p ... - launch SnK shell and exit (used with /i and /a options or w/o arguments)
CmdRes cmd_res=CmdRes::DEFAULT;
FstCmd fst_cmd=FstCmd::DEFAULT;
int ext_res;
if (wcslen(lpCmdLine)) {
wchar_t** cmd_argv;
int cmd_argc;
#ifdef DEBUG
std::wcerr<<L"CMDLINE = \""<<lpCmdLine<<L"\""<<std::endl;
#endif
if ((cmd_argv=CommandLineToArgvW(lpCmdLine, &cmd_argc))) {
#ifdef DEBUG
int tst_argc=cmd_argc;
while (tst_argc--)
std::wcerr<<L"ARG["<<tst_argc<<L"] = \""<<cmd_argv[tst_argc]<<L"\""<<std::endl;
#endif
if (cmd_argc) {
if (!wcscmp(cmd_argv[0], L"/s"))
fst_cmd=FstCmd::SHORT_PRESS;
else if (!wcscmp(cmd_argv[0], L"/l"))
fst_cmd=FstCmd::LONG_PRESS;
else if (!wcscmp(cmd_argv[0], L"/p"))
fst_cmd=FstCmd::SHELL;
if (fst_cmd!=FstCmd::DEFAULT) {
if (cmd_argc>1) cmd_res=ProcessSettingsOptions(Settings, cmd_argc, cmd_argv, 1);
} else {
if (!wcscmp(cmd_argv[0], L"/S")) {
if (cmd_argc>4) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>1) {
if (!wcsncmp(cmd_argv[1], ARG_CUR, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::Schedule(true, cmd_argv+2, cmd_argc-2);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else if (!wcsncmp(cmd_argv[1], ARG_ALL, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::Schedule(false, cmd_argv+2, cmd_argc-2);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
cmd_res=CmdRes::ERR_FEW_ARGS;
}
} else if (!wcscmp(cmd_argv[0], L"/A")) {
if (cmd_argc>4) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>1) {
if (!wcsncmp(cmd_argv[1], ARG_CUR, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::AddToAutorun(true, cmd_argv+2, cmd_argc-2);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else if (!wcsncmp(cmd_argv[1], ARG_ALL, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::AddToAutorun(false, cmd_argv+2, cmd_argc-2);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
cmd_res=CmdRes::ERR_FEW_ARGS;
}
} else if (!wcscmp(cmd_argv[0], L"/U")) {
if (cmd_argc>2) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>1) {
if (!wcsncmp(cmd_argv[1], ARG_CUR, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::Unschedule(true);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else if (!wcsncmp(cmd_argv[1], ARG_ALL, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::Unschedule(false);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
cmd_res=CmdRes::ERR_FEW_ARGS;
}
} else if (!wcscmp(cmd_argv[0], L"/R")) {
if (cmd_argc>2) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>1) {
if (!wcsncmp(cmd_argv[1], ARG_CUR, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::RemoveFromAutorun(true);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else if (!wcsncmp(cmd_argv[1], ARG_ALL, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::RemoveFromAutorun(false);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
cmd_res=CmdRes::ERR_FEW_ARGS;
}
} else if (!wcscmp(cmd_argv[0], L"/P")) {
if (cmd_argc>2) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>1) {
if (!wcsncmp(cmd_argv[1], ARG_CUR, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::AddToPath(true);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else if (!wcsncmp(cmd_argv[1], ARG_ALL, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::AddToPath(false);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
cmd_res=CmdRes::ERR_FEW_ARGS;
}
} else if (!wcscmp(cmd_argv[0], L"/C")) {
if (cmd_argc>2) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>1) {
if (!wcsncmp(cmd_argv[1], ARG_CUR, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::RemoveFromPath(true);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else if (!wcsncmp(cmd_argv[1], ARG_ALL, wcslen(cmd_argv[1]))) {
ext_res=SuiteExtRel::RemoveFromPath(false);
cmd_res=CmdRes::EXTERNAL_CALLED;
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
cmd_res=CmdRes::ERR_FEW_ARGS;
}
} else {
cmd_res=ProcessSettingsOptions(Settings, cmd_argc, cmd_argv, 0);
}
}
}
LocalFree(cmd_argv);
} else {
ErrorMessage(L"Failed to parse command line!");
return ERR_SUITE+2;
}
}
if (cmd_res==CmdRes::EXTERNAL_CALLED)
return ext_res;
if (cmd_res!=CmdRes::DEFAULT&&cmd_res!=CmdRes::SETTINGS_SET) {
if (cmd_res==CmdRes::ERR_UNKNOWN) ErrorMessage(L"Unknown command line argument!");
if (cmd_res==CmdRes::ERR_MANY_ARGS) ErrorMessage(L"Too many command line arguments!");
if (cmd_res==CmdRes::ERR_FEW_ARGS) ErrorMessage(L"Not enough command line arguments!");
if (cmd_res==CmdRes::ERR_NOT_IMPLEMENTED) ErrorMessage(L"Function not implemented!");
return ERR_SUITE+2;
}
if (cmd_res==CmdRes::DEFAULT) {
Settings.reset(new SuiteSettingsIni());
if (!Settings->IsStored()) {
Settings.reset(new SuiteSettingsAppData());
if (!Settings->IsStored()) {
Settings.reset(new SuiteSettingsIni());
#ifdef DEBUG
std::wcerr<<L"DEFAULT SETTINGS_INI: INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
} else {
#ifdef DEBUG
std::wcerr<<L"STORED SETTINGS_APPDATA: INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
}
} else {
#ifdef DEBUG
std::wcerr<<L"STORED SETTINGS_INI: INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
}
}
if (!Settings->SaveSettings()) {
ErrorMessage(L"Failed to load settings!");
return ERR_SUITE+1;
}
switch (fst_cmd) {
case FstCmd::SHELL:
return SuiteExtRel::LaunchCommandPrompt(Settings.get(), true);
case FstCmd::LONG_PRESS:
case FstCmd::SHORT_PRESS:
return SuiteExtRel::FireEvent(fst_cmd==FstCmd::LONG_PRESS, Settings.get());
default:
{
int suite_main_err=SuiteMain(Settings.get()); //Generates it's own error messages and sets (returns) exit code accordingly
if (suite_main_err==ERR_ELEVATE)
SuiteExtRel::RestartApplication(lpCmdLine, true);
else if (suite_main_err==ERR_RESTART)
SuiteExtRel::RestartApplication(lpCmdLine, false);
return suite_main_err;
}
}
}
CmdRes ProcessSettingsOptions(std::unique_ptr<SuiteSettings> &Settings, int cmd_argc, wchar_t** cmd_argv, int cmd_shift)
{
CmdRes cmd_res=CmdRes::DEFAULT;
if (!wcscmp(cmd_argv[cmd_shift], L"/i")) {
if (cmd_argc>cmd_shift+2) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>cmd_shift+1) {
Settings.reset(new SuiteSettingsIni(cmd_argv[cmd_shift+1]));
cmd_res=CmdRes::SETTINGS_SET;
#ifdef DEBUG
std::wcerr<<L"SET SETTINGS_INI (PATH): INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
} else {
Settings.reset(new SuiteSettingsIni());
cmd_res=CmdRes::SETTINGS_SET;
#ifdef DEBUG
std::wcerr<<L"SET SETTINGS_INI (AUTO): INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
}
} else if (!wcscmp(cmd_argv[cmd_shift], L"/a")) {
if (cmd_argc>cmd_shift+2) {
cmd_res=CmdRes::ERR_MANY_ARGS;
} else if (cmd_argc>cmd_shift+1) {
if (!wcsncmp(cmd_argv[cmd_shift+1], ARG_CUR, wcslen(cmd_argv[cmd_shift+1]))) {
Settings.reset(new SuiteSettingsAppData(true));
cmd_res=CmdRes::SETTINGS_SET;
#ifdef DEBUG
std::wcerr<<L"SET SETTINGS_APPDATA (CURRENT): INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
} else if (!wcsncmp(cmd_argv[cmd_shift+1], ARG_ALL, wcslen(cmd_argv[cmd_shift+1]))) {
Settings.reset(new SuiteSettingsAppData(false));
cmd_res=CmdRes::SETTINGS_SET;
#ifdef DEBUG
std::wcerr<<L"SET SETTINGS_APPDATA (ALL): INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
} else {
Settings.reset(new SuiteSettingsAppData());
cmd_res=CmdRes::SETTINGS_SET;
#ifdef DEBUG
std::wcerr<<L"SET SETTINGS_APPDATA (AUTO): INI_PATH="<<Settings->GetStoredLocation()<<std::endl;
#endif
}
} else {
cmd_res=CmdRes::ERR_UNKNOWN;
}
return cmd_res;
}