-
Notifications
You must be signed in to change notification settings - Fork 0
/
SingleInstanceCmd.cpp
140 lines (105 loc) · 3.18 KB
/
SingleInstanceCmd.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
//
// Copyright (c) Roland Pihlakas 2017 - 2020
// roland@simplify.ee
//
// Roland Pihlakas licenses this file to you under the Mozilla Public License, ver 2.0.
// See the LICENSE file for more information.
//
#include "stdafx.h"
const TCHAR *SkipArg(const TCHAR *p)
{
if (*p == '"' && *(++p))
{
while (*p && *p != '"')
++p;
if (*p)
++p;
}
else
{
while (*p && *p != ' ')
++p;
}
while (*p == ' ') ++p;
return p;
} //TCHAR *SkipArg(TCHAR *p)
int _tmain(int argc, const _TCHAR* argv[])
{
if (argc < 3)
{
wprintf(L"Copyright (c) Roland Pihlakas 2017-2020, roland@simplify.ee");
wprintf(L"");
wprintf(L"\nUsage:\n");
wprintf(L"SingleInstanceCmd.exe mutexname [-] cmd [args]\n");
wprintf(L"- indicates that no job object must be created");
return 1;
}
const _TCHAR* mutexName = argv[1];
PROCESS_INFORMATION processInformation;
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
HANDLE mutex = CreateMutex(NULL, true, mutexName);
DWORD lastError = GetLastError();
if (!mutex || lastError == ERROR_ALREADY_EXISTS)
{
wprintf(L"\nMutex exist:\n");
CloseHandle(mutex);
return lastError;
}
const TCHAR *p = GetCommandLine();
p = SkipArg(p); //SingleInstanceCmd.exe
p = SkipArg(p); //mutexname
if (p[0] == '-' && (p[1] == ' ' || p[1] == '\t')) //do not create job
{
p = SkipArg(p);
}
else
{
//assign a job object so that child processes will be killed when parent (SingleInstanceCmd.exe) is killed
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;
DWORD outSize;
BOOL success;
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682409(v=vs.85).aspx
// If the object existed before the function call, the function returns a handle to the existing job object and GetLastError returns ERROR_ALREADY_EXISTS.
HANDLE job = CreateJobObject(NULL, NULL);
success = QueryInformationJobObject(
job,
JobObjectExtendedLimitInformation,
&jobInfo,
sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
&outSize
);
jobInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
// jobInfo.MaximumWorkingSetSize = size
success = SetInformationJobObject(
job,
JobObjectExtendedLimitInformation,
&jobInfo,
sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)
);
//A handle to the process to associate with the job object. The handle must have the PROCESS_SET_QUOTA and PROCESS_TERMINATE access rights.
HANDLE process = OpenProcess
(
/*dwDesiredAccess = */PROCESS_SET_QUOTA | PROCESS_TERMINATE,
/*bInheritHandle = */FALSE,
GetCurrentProcessId()
);
BOOL success_assign = AssignProcessToJobObject(job, process);
success = CloseHandle(process);
} // if (p[0] == '-' && (p[1] == ' ' || p[1] == '\t')) //do not create job
if (CreateProcess(0, (TCHAR *)p, 0, 0, false, 0, 0, 0, &startupInfo, &processInformation))
{
DWORD exitCode;
WaitForSingleObject(processInformation.hProcess, INFINITE);
GetExitCodeProcess(processInformation.hProcess, &exitCode);
CloseHandle(processInformation.hThread);
CloseHandle(processInformation.hProcess);
return exitCode;
}
else
{
lastError = GetLastError();
wprintf(L"\nCreateProcess failed: error %d\n", lastError);
CloseHandle(mutex);
return lastError;
}
}