mumble/overlay/overlay_exe/overlay_exe.cpp

220 lines
6.8 KiB
C++

/* Copyright (C) 2011-2013, Benjamin Jemlich <pcgod@users.sourceforge.net>
Copyright (C) 2013-2015, Mikkel Krautz <mikkel@krautz.dk>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the Mumble Developers nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include <shellapi.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(NULL, msg, title, MB_OK|MB_ICONERROR);
}
// GetExecutableDirPath returns the directory that
// mumble_ol.exe resides in.
static std::wstring GetExecutableDirPath() {
wchar_t path[MAX_PATH];
if (GetModuleFileNameW(NULL, 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.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.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 == NULL) {
return args;
}
int argc = 0;
LPWSTR *argv = CommandLineToArgvW(cmdLine, &argc);
if (argv == NULL) {
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 passedInHandle = std::stoul(handleStr);
parent = reinterpret_cast<HANDLE>(passedInHandle & 0xFFFFFFFFUL);
} 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(), NULL, 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, NULL);
}