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
|
// Copyright 2015-2022 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include <windows.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "../overlay.h"
#include "overlay_exe.h"
#define UNUSED(x) ((void) x)
typedef int (*OverlayHelperProcessMain)(unsigned int magic, HANDLE parent);
// Signal to the overlay DLL that it should not inject
// into this process.
extern "C" __declspec(dllexport) void mumbleSelfDetection(){};
// Alert shows a fatal error dialog and waits for the user to click OK.
static void Alert(LPCWSTR title, LPCWSTR msg) {
MessageBox(nullptr, msg, title, MB_OK | MB_ICONERROR);
}
// GetExecutableDirPath returns the directory that
// mumble_ol_helper.exe resides in.
static std::wstring GetExecutableDirPath() {
wchar_t path[MAX_PATH];
if (GetModuleFileNameW(nullptr, path, MAX_PATH) == 0)
return std::wstring();
if (!PathRemoveFileSpecW(path))
return std::wstring();
std::wstring exePath(path);
return exePath.append(L"\\");
}
// ConfigureEnvironment prepares mumble_ol_helper.exe's environment to
// run mumble_ol.dll's OverlayHelperProcessMain() function.
static bool ConfigureEnvironment() {
std::wstring exePath = GetExecutableDirPath();
// Remove the current directory from the DLL search path.
if (!SetDllDirectoryW(L""))
return false;
// Set mumble_ol_helper.exe's directory as the current working directory.
if (!SetCurrentDirectoryW(exePath.c_str()))
return false;
return true;
}
// GetAbsoluteMumbleOverlayDllPath returns the absolute path to
// mumble_ol.dll - the DLL containing the Mumble overlay code.
static std::wstring GetAbsoluteMumbleOverlayDllPath() {
std::wstring exePath = GetExecutableDirPath();
if (exePath.empty())
return std::wstring();
std::wstring absDLLPath(exePath);
absDLLPath.append(L"\\");
absDLLPath.append(MUMBLE_OVERLAY_DLL_NAME);
return absDLLPath;
}
// GetCommandLineArgs returns the command line arguments
// passed to the process.
// If the returned vector has a length of 0, an unknown
// error occurred.
static std::vector< std::wstring > GetCommandLineArgs() {
std::vector< std::wstring > args;
LPWSTR cmdLine = GetCommandLine();
if (!cmdLine) {
return args;
}
int argc = 0;
LPWSTR *argv = CommandLineToArgvW(cmdLine, &argc);
if (!argv) {
return args;
}
for (int i = 0; i < argc; i++) {
args.push_back(std::wstring(argv[i]));
}
return args;
}
int main(int argc, char **argv) {
UNUSED(argc);
UNUSED(argv);
// Mumble passes the OVERLAY_MAGIC_NUMBER it was built
// with the first argument to this helper process.
//
// This is done for two reasons.
//
// The first reason is that we need to ensure
// compatibility between Mumble, the overlay helper,
// and the overlay itself.
//
// The second reason is that it is an easy way to catch
// users accidentally double-clicking on the overlay
// helper's EXE file. We can detect these non-Mumble
// initiated launches by checking if we were passed any
// arguments at all. If no parameters are passed, we
// display a nice alert dialog directing users to
// 'mumble.exe' instead.
unsigned int magic = 0;
HANDLE parent = 0;
{
std::vector< std::wstring > args = GetCommandLineArgs();
// If there is only a single argument, it's the program name.
// That probably means that a user has double-clicked
// the executable. Tell them to run 'mumble.exe' instead.
//
// This also handles the case where GetCommandLineArgs returns
// an empty vector (the error case).
if (args.size() <= 1) {
Alert(L"Mumble Overlay", L"This program is not meant to be run by itself. Run 'mumble.exe' instead.");
return OVERLAY_HELPER_ERROR_EXE_NO_ARGUMENTS;
}
// The Mumble process passes the overlay magic number,
// and a HANDLE in numeric form as its only two arguments.
// We must have both of them to continue.
if (args.size() < 3) {
return OVERLAY_HELPER_ERROR_TOO_FEW_ARGUMENTS;
}
std::wstring magicNumberStr = args[1];
std::wstring handleStr = args[2];
try {
unsigned long passedInMagic = std::stoul(magicNumberStr);
magic = static_cast< unsigned int >(passedInMagic);
} catch (std::exception &) {
return OVERLAY_HELPER_ERROR_EXE_INVALID_MAGIC_ARGUMENT;
}
try {
unsigned long long passedInHandle = std::stoull(handleStr);
parent = reinterpret_cast< HANDLE >(passedInHandle & 0xFFFFFFFFULL);
} catch (std::exception &) {
return OVERLAY_HELPER_ERROR_EXE_INVALID_HANDLE_ARGUMENT;
}
}
if (magic != OVERLAY_MAGIC_NUMBER) {
return OVERLAY_HELPER_ERROR_EXE_MAGIC_MISMATCH;
}
if (!ConfigureEnvironment()) {
return OVERLAY_HELPER_ERROR_EXE_CONFIGURE_ENVIRONMENT;
}
std::wstring absDLLPath = GetAbsoluteMumbleOverlayDllPath();
if (absDLLPath.empty()) {
return OVERLAY_HELPER_ERROR_EXE_GET_DLL_PATH;
}
HMODULE dll = LoadLibraryExW(absDLLPath.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!dll) {
return OVERLAY_HELPER_ERROR_EXE_LOAD_DLL;
}
OverlayHelperProcessMain entryPoint =
reinterpret_cast< OverlayHelperProcessMain >(GetProcAddress(dll, "OverlayHelperProcessMain"));
if (!entryPoint) {
return OVERLAY_HELPER_ERROR_EXE_LOOKUP_ENTRY_POINT;
}
return entryPoint(magic, parent);
}
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, wchar_t *cmdArg, int cmdShow) {
UNUSED(instance);
UNUSED(prevInstance);
UNUSED(cmdArg);
UNUSED(cmdShow);
return main(0, nullptr);
}
|