diff options
-rw-r--r-- | overlay/lib.cpp | 18 | ||||
-rw-r--r-- | overlay/overlay_exe/overlay_exe.cpp | 32 | ||||
-rw-r--r-- | overlay/overlay_exe/overlay_exe.h | 19 | ||||
-rw-r--r-- | src/mumble/Overlay_win.cpp | 32 | ||||
-rw-r--r-- | src/mumble/Overlay_win.h | 1 |
5 files changed, 93 insertions, 9 deletions
diff --git a/overlay/lib.cpp b/overlay/lib.cpp index e9eeb4370..9358212c0 100644 --- a/overlay/lib.cpp +++ b/overlay/lib.cpp @@ -448,13 +448,29 @@ extern "C" __declspec(dllexport) void __cdecl PrepareD3D9(); // Via dxgi.cpp extern "C" __declspec(dllexport) void __cdecl PrepareDXGI(); -extern "C" __declspec(dllexport) int __cdecl OverlayHelperProcessMain(unsigned int magic) { +void __stdcall OverlayHelperProcessParentDeathThread(void *udata) { + HANDLE parent = reinterpret_cast<HANDLE>(udata); + DWORD status = WaitForSingleObject(parent, INFINITE); + if (status != WAIT_OBJECT_0) { + ExitProcess(OVERLAY_HELPER_ERROR_DLL_PDEATH_WAIT_FAIL); + } + + ExitProcess(0); +} + +extern "C" __declspec(dllexport) int __cdecl OverlayHelperProcessMain(unsigned int magic, HANDLE parent) { int retval = 0; if (GetOverlayMagicVersion() != magic) { return OVERLAY_HELPER_ERROR_DLL_MAGIC_MISMATCH; } + HANDLE pcheckHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) OverlayHelperProcessParentDeathThread, + reinterpret_cast<void *>(parent), 0, NULL); + if (pcheckHandle == 0) { + return OVERLAY_HELPER_ERROR_DLL_PDEATH_THREAD_ERROR; + } + PrepareD3D9(); PrepareDXGI(); diff --git a/overlay/overlay_exe/overlay_exe.cpp b/overlay/overlay_exe/overlay_exe.cpp index be9dbc653..bee53bdf7 100644 --- a/overlay/overlay_exe/overlay_exe.cpp +++ b/overlay/overlay_exe/overlay_exe.cpp @@ -40,7 +40,7 @@ #define UNUSED(x) ((void)x) -typedef int (*OverlayHelperProcessMain)(unsigned int magic); +typedef int (*OverlayHelperProcessMain)(unsigned int magic, HANDLE parent); // Signal to the overlay DLL that it should not inject // into this process. @@ -116,6 +116,7 @@ int main(int argc, char **argv) { // display a nice alert dialog directing users to // 'mumble.exe' instead. unsigned int magic = 0; + HANDLE parent = 0; { std::wstring commandLine(GetCommandLine()); @@ -123,21 +124,40 @@ int main(int argc, char **argv) { // if the program was passed any arguments. If we don't // find them, it probably means that a user has double-clicked // the executable. Tell them to run 'mumble.exe' instead. - size_t sep = commandLine.find(std::wstring(L" ")); + std::wstring doubleSpace = std::wstring(L" "); + size_t sep = commandLine.find(doubleSpace); if (sep == std::string::npos) { Alert(L"Mumble Overlay", L"This program is not meant to be run by itself. Run 'mumble.exe' instead."); return OVERLAY_HELPER_ERROR_EXE_MISSING_MAGIC_ARGUMENT; } - // We expect that the Mumble process passes the overlay - // magic number that it is built with to us. - std::wstring magicNumberStr = commandLine.substr(sep); + // The Mumble process passes the overlay magic number, + // and a HANDLE in numeric form as its only two arguments. + // Let's try to parse the command line to extract them... + std::wstring args = commandLine.substr(sep + doubleSpace.length()); + sep = args.find(std::wstring(L" ")); + if (sep == std::string::npos) { + return OVERLAY_HELPER_ERROR_TOO_FEW_ARGUMENTS; + } + if (args.length() <= sep + 1) { + return OVERLAY_HELPER_ERROR_TOO_FEW_ARGUMENTS; + } + std::wstring magicNumberStr = args.substr(0, sep); + std::wstring handleStr = args.substr(sep+1); + 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) { @@ -163,7 +183,7 @@ int main(int argc, char **argv) { return OVERLAY_HELPER_ERROR_EXE_LOOKUP_ENTRY_POINT; } - return entryPoint(magic); + return entryPoint(magic, parent); } int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, wchar_t *cmdArg, int cmdShow) { diff --git a/overlay/overlay_exe/overlay_exe.h b/overlay/overlay_exe/overlay_exe.h index bbd9d2e20..e950aeed9 100644 --- a/overlay/overlay_exe/overlay_exe.h +++ b/overlay/overlay_exe/overlay_exe.h @@ -64,14 +64,27 @@ enum OverlayHelperError { /// the 'OverlayHelperProcessMain' entry point in the
/// overlay DLL.
OVERLAY_HELPER_ERROR_EXE_LOOKUP_ENTRY_POINT = -7,
+ /// The overlay helper process was uanble to parse
+ /// the commandline arguments it was passed.
+ /// The helper process exepcts two arguments, and this
+ /// error occurs if it only finds one.
+ OVERLAY_HELPER_ERROR_TOO_FEW_ARGUMENTS = -8,
+ /// The magic number on the command line of the overlay
+ /// helper process could not be converted to a HANDLE.
+ OVERLAY_HELPER_ERROR_EXE_INVALID_HANDLE_ARGUMENT = -9,
- /// The magic number passed to the overlay DLL's
+ /// The magic number passed to the overlay DLL's
/// OverlayHelperProcessMain function did not match
/// the overlay DLL's built-in magic number.
OVERLAY_HELPER_ERROR_DLL_MAGIC_MISMATCH = -1000,
/// The overlay helper process exited due to an error
/// in the Windows message loop.
OVERLAY_HELPER_ERROR_DLL_MESSAGE_LOOP = -1001,
+ /// The parent death thread could not be created.
+ OVERLAY_HELPER_ERROR_DLL_PDEATH_THREAD_ERROR = -1002,
+ /// The helper's WaitForSingleObject call on its parent
+ /// process failed unexpectedly.
+ OVERLAY_HELPER_ERROR_DLL_PDEATH_WAIT_FAIL = -1003,
};
/// OverlayHelperErrorToString converts an OverlayHelperError value
@@ -86,8 +99,12 @@ static inline const char *OverlayHelperErrorToString(OverlayHelperError err) { OHE(OVERLAY_HELPER_ERROR_EXE_GET_DLL_PATH);
OHE(OVERLAY_HELPER_ERROR_EXE_LOAD_DLL);
OHE(OVERLAY_HELPER_ERROR_EXE_LOOKUP_ENTRY_POINT);
+ OHE(OVERLAY_HELPER_ERROR_TOO_FEW_ARGUMENTS);
+ OHE(OVERLAY_HELPER_ERROR_EXE_INVALID_HANDLE_ARGUMENT);
OHE(OVERLAY_HELPER_ERROR_DLL_MAGIC_MISMATCH);
OHE(OVERLAY_HELPER_ERROR_DLL_MESSAGE_LOOP);
+ OHE(OVERLAY_HELPER_ERROR_DLL_PDEATH_THREAD_ERROR);
+ OHE(OVERLAY_HELPER_ERROR_DLL_PDEATH_WAIT_FAIL);
}
return NULL;
}
diff --git a/src/mumble/Overlay_win.cpp b/src/mumble/Overlay_win.cpp index 4b5dda0bd..e401743ae 100644 --- a/src/mumble/Overlay_win.cpp +++ b/src/mumble/Overlay_win.cpp @@ -74,8 +74,33 @@ static bool canRun64BitPrograms() { OverlayPrivateWin::OverlayPrivateWin(QObject *p) : OverlayPrivate(p) { m_active = false; + // Acquire a handle to ourselves and duplicate it. We duplicate it because + // want it to be inheritable by our helper processes, and the handle returned + // by GetCurrentProcess is not inheritable. Duplicating it makes it inheritable. + // This allows our helper processes to access the handle. + // + // The helper processes need a handle to us, their parent, to be able to listen + // detect when our process dies. + // + // The value of the handle is passed as an argument to the helper processes via + // the command line as a number. The HANDLE type in Windows is typedef'd to LPVOID, + // but for handles that are supposed to be shared between processes (like a process + // handle that we are using), only the lower 32-bits of the HANDLE are considered: + // + // "When sharing a handle between 32-bit and 64-bit applications, only the lower + // 32 bits are significant [...]" + // + // from https://msdn.microsoft.com/en-us/library/aa384203.aspx + HANDLE curproc = GetCurrentProcess(); + if (!DuplicateHandle(curproc, curproc, curproc, &m_mumble_handle, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + qFatal("OverlayPrivateWin: unable to duplicate handle to the Mumble process."); + return; + } + m_helper_exe_path = QString::fromLatin1("%1/mumble_ol.exe").arg(qApp->applicationDirPath()); - m_helper_exe_args = QStringList(QString::number(OVERLAY_MAGIC_NUMBER)); + m_helper_exe_args << QString::number(OVERLAY_MAGIC_NUMBER) + << QString::number(reinterpret_cast<quintptr>(m_mumble_handle)); m_helper_process = new QProcess(this); connect(m_helper_process, SIGNAL(started()), @@ -124,6 +149,11 @@ OverlayPrivateWin::OverlayPrivateWin(QObject *p) : OverlayPrivate(p) { OverlayPrivateWin::~OverlayPrivateWin() { m_active = false; + + if (!CloseHandle(m_mumble_handle)) { + qFatal("OverlayPrivateWin: unable to close Mumble process handle."); + return; + } } void OverlayPrivateWin::startHelper(QProcess *helper) { diff --git a/src/mumble/Overlay_win.h b/src/mumble/Overlay_win.h index 4fb6bd7c0..171fc32a9 100644 --- a/src/mumble/Overlay_win.h +++ b/src/mumble/Overlay_win.h @@ -71,6 +71,7 @@ class OverlayPrivateWin : public OverlayPrivate { QTimer *m_helper64_restart_timer;
bool m_helper64_enabled;
+ HANDLE m_mumble_handle;
bool m_active;
void startHelper(QProcess *helper);
|