Skip to content

Commit

Permalink
Use mutex to force single instance.
Browse files Browse the repository at this point in the history
  • Loading branch information
KnockKnockP committed Jun 27, 2024
1 parent 0465176 commit 989583f
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 46 deletions.
32 changes: 32 additions & 0 deletions src/windows/InstanceMutex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "InstanceMutex.hpp"

void InstanceMutex::Close()
{
if (m_handle)
{
CloseHandle(m_handle);
m_handle = NULL;
}
}

HRESULT InstanceMutex::Init()
{
#ifdef DISABLE_SINGLE_INSTANCE
return 0;
#else

SetLastError(NO_ERROR);
m_handle = CreateMutex(NULL, TRUE, L"DiscordMessenger");

const DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
Close();

return error;
#endif
}

InstanceMutex::~InstanceMutex()
{
Close();
}
15 changes: 15 additions & 0 deletions src/windows/InstanceMutex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <windows.h>

class InstanceMutex
{
private:
HANDLE m_handle = NULL;

void Close();

public:
HRESULT Init();
~InstanceMutex();
};
61 changes: 15 additions & 46 deletions src/windows/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
#include "ProgressDialog.hpp"
#include "AutoComplete.hpp"
#include "ShellNotification.hpp"
#include "InstanceMutex.hpp"
#include "../discord/LocalSettings.hpp"
#include "../discord/WebsocketClient.hpp"
#include "../discord/UpdateChecker.hpp"

#include <tlhelp32.h>
#include <system_error>

// proportions:
Expand Down Expand Up @@ -1437,7 +1437,7 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
GetShellNotification()->Callback(wParam, lParam);
break;
}
case SW_RESTORE:
case WM_RESTORE:
GetFrontend()->RestoreWindow();
break;
}
Expand Down Expand Up @@ -1573,59 +1573,28 @@ HTTPClient* GetHTTPClient()
return g_pHTTPClient;
}

//https://stackoverflow.com/a/48207646
static void GetAllWindowsFromProcessID(const DWORD dwProcessID, std::vector <HWND>& vhWnds)
{
HWND hCurWnd = NULL;
do
{
hCurWnd = FindWindowEx(NULL, hCurWnd, NULL, NULL);
DWORD dwProcID = 0;
GetWindowThreadProcessId(hCurWnd, &dwProcID);
if (dwProcID == dwProcessID)
{
vhWnds.push_back(hCurWnd);
}
} while (hCurWnd != NULL);
}
InstanceMutex g_instanceMutex;

static bool CheckExistingProcesses()
static bool ForceSingleInstance(LPCWSTR pClassName)
{
TCHAR fileNameRaw[MAX_PATH];
GetModuleFileName(NULL, fileNameRaw, MAX_PATH);
TCHAR* fileName = PathFindFileName(fileNameRaw);

PROCESSENTRY32 processEntry32;
processEntry32.dwSize = sizeof(PROCESSENTRY32);
HRESULT hResult = g_instanceMutex.Init();

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
const DWORD selfPid = GetCurrentProcessId();
if (hResult != ERROR_ALREADY_EXISTS)
return false;

if (Process32First(snapshot, &processEntry32))
HWND hWnd = FindWindow(pClassName, NULL);
if (hWnd)
{
while (Process32Next(snapshot, &processEntry32))
{
if (!_tcscmp(processEntry32.szExeFile, fileName) && processEntry32.th32ProcessID != selfPid)
{
std::vector<HWND> windows;
GetAllWindowsFromProcessID(processEntry32.th32ProcessID, windows);

for (HWND window : windows) {
SendMessage(window, SW_RESTORE, 0, 0);
}

return true;
}
}
SendMessage(hWnd, WM_RESTORE, 0, 0);
}

CloseHandle(snapshot);
return false;
return true;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nShowCmd)
{
if (CheckExistingProcesses())
LPCWSTR pClassName = TEXT("DiscordMessengerClass");

if (ForceSingleInstance(pClassName))
return 0;

g_hInstance = hInstance;
Expand Down Expand Up @@ -1657,7 +1626,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin

wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = TEXT("DiscordMessengerClass");
wc.lpszClassName = pClassName;
wc.hbrBackground = g_backgroundBrush;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = g_Icon = LoadIcon(hInstance, MAKEINTRESOURCE(DMIC(IDI_ICON)));
Expand Down
1 change: 1 addition & 0 deletions src/windows/WindowMessages.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ enum eWmUserMsgs
WM_RECREATEMEMBERLIST,

WM_UPDATETEXTSIZE = WM_APP, // used by the MessageEditor
WM_RESTORE,
};
2 changes: 2 additions & 0 deletions vs/DiscordMessenger.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@
<ClInclude Include="..\src\windows\GuildLister.hpp" />
<ClInclude Include="..\src\windows\ImageLoader.hpp" />
<ClInclude Include="..\src\windows\ImageViewer.hpp" />
<ClInclude Include="..\src\windows\InstanceMutex.hpp" />
<ClInclude Include="..\src\windows\LoadingMessage.hpp" />
<ClInclude Include="..\src\windows\LogonDialog.hpp" />
<ClInclude Include="..\src\windows\Main.hpp" />
Expand Down Expand Up @@ -568,6 +569,7 @@
<ClCompile Include="..\src\windows\GuildLister.cpp" />
<ClCompile Include="..\src\windows\ImageLoader.cpp" />
<ClCompile Include="..\src\windows\ImageViewer.cpp" />
<ClCompile Include="..\src\windows\InstanceMutex.cpp" />
<ClCompile Include="..\src\windows\LoadingMessage.cpp" />
<ClCompile Include="..\src\windows\LogonDialog.cpp" />
<ClCompile Include="..\src\windows\Main.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions vs/DiscordMessenger.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,9 @@
<ClInclude Include="..\src\discord\DiscordClientConfig.hpp">
<Filter>Header Files\Discord</Filter>
</ClInclude>
<ClInclude Include="..\src\windows\InstanceMutex.hpp">
<Filter>Header Files\Windows</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\windows\ProfileView.cpp">
Expand Down Expand Up @@ -799,5 +802,8 @@
<ClCompile Include="..\src\discord\DiscordClientConfig.cpp">
<Filter>Source Files\Discord</Filter>
</ClCompile>
<ClCompile Include="..\src\windows\InstanceMutex.cpp">
<Filter>Source Files\Windows</Filter>
</ClCompile>
</ItemGroup>
</Project>

0 comments on commit 989583f

Please sign in to comment.