Skip to content

Commit 99c0d4e

Browse files
committed
First Commit
First Commit
1 parent c36df38 commit 99c0d4e

File tree

7 files changed

+431
-0
lines changed

7 files changed

+431
-0
lines changed

Main.cpp

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
// Main.cpp
2+
// UniversalPauseButton
3+
// Ryan Ries, 2015
4+
// ryan@myotherpcisacloud.com
5+
//
6+
// Must compile in Unicode.
7+
8+
#include <Windows.h>
9+
#include <Psapi.h>
10+
#include <stdio.h>
11+
#include "resource.h"
12+
13+
#define WM_TRAYICON (WM_USER + 1)
14+
15+
typedef LONG(NTAPI* _NtSuspendProcess) (IN HANDLE ProcessHandle);
16+
typedef LONG(NTAPI* _NtResumeProcess) (IN HANDLE ProcessHandle);
17+
18+
_NtSuspendProcess NtSuspendProcess = (_NtSuspendProcess)GetProcAddress(GetModuleHandle(L"ntdll"), "NtSuspendProcess");
19+
_NtResumeProcess NtResumeProcess = (_NtResumeProcess)GetProcAddress(GetModuleHandle(L"ntdll"), "NtResumeProcess");
20+
21+
NOTIFYICONDATA G_TrayNotifyIconData;
22+
HANDLE G_Mutex;
23+
24+
25+
// The WindowProc (callback) for WinMain's WindowClass.
26+
// Basically the system tray does nothing except lets the user know that it's running.
27+
// If the user clicks the tray icon it will ask if they want to exit the app.
28+
LRESULT CALLBACK WindowClassCallback(_In_ HWND Window, _In_ UINT Message, _In_ WPARAM WParam, _In_ LPARAM LParam)
29+
{
30+
LRESULT Result = 0;
31+
32+
switch (Message)
33+
{
34+
case WM_TRAYICON:
35+
{
36+
if (LParam == WM_LBUTTONDOWN || LParam == WM_RBUTTONDOWN)
37+
{
38+
if (MessageBox(Window, L"Quit UniversalPauseButton?", L"Are you sure?", MB_YESNO | MB_ICONQUESTION) == IDYES)
39+
{
40+
Shell_NotifyIcon(NIM_DELETE, &G_TrayNotifyIconData);
41+
PostQuitMessage(0);
42+
}
43+
}
44+
}
45+
default:
46+
{
47+
Result = DefWindowProc(Window, Message, WParam, LParam);
48+
break;
49+
}
50+
}
51+
return(Result);
52+
}
53+
54+
// Entry point.
55+
int CALLBACK WinMain(_In_ HINSTANCE Instance, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ int)
56+
{
57+
G_Mutex = CreateMutex(NULL, FALSE, L"UniversalPauseButton");
58+
if (GetLastError() == ERROR_ALREADY_EXISTS)
59+
{
60+
MessageBox(NULL, L"An instance of the program is already running.", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
61+
return(ERROR_ALREADY_EXISTS);
62+
}
63+
64+
WNDCLASS SysTrayWindowClass = { 0 };
65+
66+
SysTrayWindowClass.style = CS_HREDRAW | CS_VREDRAW;
67+
SysTrayWindowClass.hInstance = Instance;
68+
SysTrayWindowClass.lpszClassName = L"UniversalPauseButton_Systray_WindowClass";
69+
SysTrayWindowClass.hbrBackground = CreateSolidBrush(RGB(255, 0, 255));
70+
SysTrayWindowClass.lpfnWndProc = WindowClassCallback;
71+
72+
if (RegisterClass(&SysTrayWindowClass) == 0)
73+
{
74+
MessageBox(NULL, L"Failed to register WindowClass!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
75+
return(E_FAIL);
76+
}
77+
78+
HWND SystrayWindow = CreateWindowEx(
79+
WS_EX_TOOLWINDOW,
80+
SysTrayWindowClass.lpszClassName,
81+
L"UniversalPauseButton_Systray_Window",
82+
WS_ICONIC,
83+
CW_USEDEFAULT,
84+
CW_USEDEFAULT,
85+
CW_USEDEFAULT,
86+
CW_USEDEFAULT,
87+
0,
88+
0,
89+
Instance,
90+
0);
91+
92+
if (SystrayWindow == 0)
93+
{
94+
MessageBox(NULL, L"Failed to create SystrayWindow!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
95+
return(E_FAIL);
96+
}
97+
98+
G_TrayNotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
99+
G_TrayNotifyIconData.hWnd = SystrayWindow;
100+
G_TrayNotifyIconData.uID = 1982;
101+
G_TrayNotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
102+
G_TrayNotifyIconData.uCallbackMessage = WM_TRAYICON;
103+
104+
wcscpy_s(G_TrayNotifyIconData.szTip, L"Universal Pause Button v1.0");
105+
106+
G_TrayNotifyIconData.hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 0, 0, NULL);
107+
108+
if (G_TrayNotifyIconData.hIcon == NULL)
109+
{
110+
MessageBox(NULL, L"Failed to load systray icon resource!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
111+
return(E_FAIL);
112+
}
113+
114+
if (Shell_NotifyIcon(NIM_ADD, &G_TrayNotifyIconData) == FALSE)
115+
{
116+
MessageBox(NULL, L"Failed to register systray icon!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
117+
return(E_FAIL);
118+
}
119+
120+
MSG SysTrayWindowMessage = { 0 };
121+
static int PauseKeyWasDown = 0;
122+
DWORD PreviouslySuspendedProcessID = 0;
123+
wchar_t PreviouslySuspendedProcessText[256] = { 0 };
124+
125+
while (SysTrayWindowMessage.message != WM_QUIT)
126+
{
127+
while (PeekMessage(&SysTrayWindowMessage, SystrayWindow, 0, 0, PM_REMOVE))
128+
{
129+
DispatchMessage(&SysTrayWindowMessage);
130+
}
131+
132+
int PauseKeyIsDown = GetAsyncKeyState(VK_PAUSE);
133+
134+
if (PauseKeyIsDown && !PauseKeyWasDown)
135+
{
136+
HWND ForegroundWindow = GetForegroundWindow();
137+
if (ForegroundWindow)
138+
{
139+
DWORD ProcessID = 0;
140+
GetWindowThreadProcessId(ForegroundWindow, &ProcessID);
141+
if (ProcessID != 0)
142+
{
143+
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
144+
if (ProcessHandle != 0)
145+
{
146+
if (PreviouslySuspendedProcessID == 0)
147+
{
148+
NtSuspendProcess(ProcessHandle);
149+
PreviouslySuspendedProcessID = ProcessID;
150+
GetWindowText(ForegroundWindow, PreviouslySuspendedProcessText, sizeof(PreviouslySuspendedProcessText) / sizeof(wchar_t));
151+
}
152+
else if (PreviouslySuspendedProcessID == ProcessID)
153+
{
154+
NtResumeProcess(ProcessHandle);
155+
PreviouslySuspendedProcessID = 0;
156+
memset(PreviouslySuspendedProcessText, 0, sizeof(PreviouslySuspendedProcessText));
157+
}
158+
else
159+
{
160+
// The user pressed the pause button while focused on another process than what was
161+
// originally paused and the first process is still paused.
162+
DWORD AllProcesses[2048] = { 0 };
163+
DWORD BytesReturned = 0;
164+
BOOL PreviouslySuspendedProcessIsStillRunning = FALSE;
165+
166+
if (EnumProcesses(AllProcesses, sizeof(AllProcesses), &BytesReturned) != 0)
167+
{
168+
for (DWORD Counter = 0; Counter < (BytesReturned / sizeof(DWORD)); Counter++)
169+
{
170+
if ((AllProcesses[Counter] != 0) && AllProcesses[Counter] == PreviouslySuspendedProcessID)
171+
{
172+
PreviouslySuspendedProcessIsStillRunning = TRUE;
173+
}
174+
}
175+
if (PreviouslySuspendedProcessIsStillRunning)
176+
{
177+
wchar_t MessageBoxBuffer[1024] = { 0 };
178+
_snwprintf_s(MessageBoxBuffer, sizeof(MessageBoxBuffer), L"You must first unpause %s (PID %d) before pausing another program.", PreviouslySuspendedProcessText, PreviouslySuspendedProcessID);
179+
MessageBox(ForegroundWindow, MessageBoxBuffer, L"Universal Pause Button", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL);
180+
}
181+
else
182+
{
183+
// The paused process is no more, so reset.
184+
PreviouslySuspendedProcessID = 0;
185+
memset(PreviouslySuspendedProcessText, 0, sizeof(PreviouslySuspendedProcessText));
186+
}
187+
}
188+
else
189+
{
190+
MessageBox(NULL, L"EnumProcesses failed!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
191+
}
192+
}
193+
CloseHandle(ProcessHandle);
194+
}
195+
else
196+
{
197+
MessageBox(NULL, L"OpenProcess failed!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
198+
}
199+
}
200+
else
201+
{
202+
MessageBox(NULL, L"Unable to get process ID of foreground window!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
203+
}
204+
}
205+
else
206+
{
207+
MessageBox(NULL, L"Unable to detect foreground window!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
208+
}
209+
}
210+
211+
PauseKeyWasDown = PauseKeyIsDown;
212+
213+
Sleep(10);
214+
}
215+
216+
return(S_OK);
217+
}

UniversalPauseButton.rc

5.19 KB
Binary file not shown.

UniversalPauseButton.sln

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 2013
4+
VisualStudioVersion = 12.0.31101.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UniversalPauseButton", "UniversalPauseButton.vcxproj", "{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Win32 = Debug|Win32
11+
Debug|x64 = Debug|x64
12+
Release|Win32 = Release|Win32
13+
Release|x64 = Release|x64
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|Win32.ActiveCfg = Debug|Win32
17+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|Win32.Build.0 = Debug|Win32
18+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|x64.ActiveCfg = Debug|x64
19+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|x64.Build.0 = Debug|x64
20+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|Win32.ActiveCfg = Release|Win32
21+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|Win32.Build.0 = Release|Win32
22+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|x64.ActiveCfg = Release|x64
23+
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|x64.Build.0 = Release|x64
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
EndGlobal

UniversalPauseButton.vcxproj

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Debug|Win32">
5+
<Configuration>Debug</Configuration>
6+
<Platform>Win32</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Debug|x64">
9+
<Configuration>Debug</Configuration>
10+
<Platform>x64</Platform>
11+
</ProjectConfiguration>
12+
<ProjectConfiguration Include="Release|Win32">
13+
<Configuration>Release</Configuration>
14+
<Platform>Win32</Platform>
15+
</ProjectConfiguration>
16+
<ProjectConfiguration Include="Release|x64">
17+
<Configuration>Release</Configuration>
18+
<Platform>x64</Platform>
19+
</ProjectConfiguration>
20+
</ItemGroup>
21+
<PropertyGroup Label="Globals">
22+
<ProjectGuid>{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}</ProjectGuid>
23+
<RootNamespace>UniversalPauseButton</RootNamespace>
24+
</PropertyGroup>
25+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
26+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
27+
<ConfigurationType>Application</ConfigurationType>
28+
<UseDebugLibraries>true</UseDebugLibraries>
29+
<PlatformToolset>v120</PlatformToolset>
30+
<CharacterSet>Unicode</CharacterSet>
31+
</PropertyGroup>
32+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
33+
<ConfigurationType>Application</ConfigurationType>
34+
<UseDebugLibraries>true</UseDebugLibraries>
35+
<PlatformToolset>v120</PlatformToolset>
36+
<CharacterSet>Unicode</CharacterSet>
37+
</PropertyGroup>
38+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
39+
<ConfigurationType>Application</ConfigurationType>
40+
<UseDebugLibraries>false</UseDebugLibraries>
41+
<PlatformToolset>v120</PlatformToolset>
42+
<WholeProgramOptimization>true</WholeProgramOptimization>
43+
<CharacterSet>Unicode</CharacterSet>
44+
</PropertyGroup>
45+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
46+
<ConfigurationType>Application</ConfigurationType>
47+
<UseDebugLibraries>false</UseDebugLibraries>
48+
<PlatformToolset>v120</PlatformToolset>
49+
<WholeProgramOptimization>true</WholeProgramOptimization>
50+
<CharacterSet>Unicode</CharacterSet>
51+
</PropertyGroup>
52+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
53+
<ImportGroup Label="ExtensionSettings">
54+
</ImportGroup>
55+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
56+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
57+
</ImportGroup>
58+
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
59+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
60+
</ImportGroup>
61+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
62+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
63+
</ImportGroup>
64+
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
65+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
66+
</ImportGroup>
67+
<PropertyGroup Label="UserMacros" />
68+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
69+
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
70+
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
71+
</PropertyGroup>
72+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
73+
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
74+
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
75+
</PropertyGroup>
76+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
77+
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
78+
</PropertyGroup>
79+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
80+
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
81+
</PropertyGroup>
82+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
83+
<ClCompile>
84+
<WarningLevel>Level4</WarningLevel>
85+
<Optimization>Disabled</Optimization>
86+
<SDLCheck>true</SDLCheck>
87+
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
88+
</ClCompile>
89+
<Link>
90+
<GenerateDebugInformation>true</GenerateDebugInformation>
91+
</Link>
92+
</ItemDefinitionGroup>
93+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
94+
<ClCompile>
95+
<WarningLevel>Level4</WarningLevel>
96+
<Optimization>Disabled</Optimization>
97+
<SDLCheck>true</SDLCheck>
98+
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
99+
</ClCompile>
100+
<Link>
101+
<GenerateDebugInformation>true</GenerateDebugInformation>
102+
</Link>
103+
</ItemDefinitionGroup>
104+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
105+
<ClCompile>
106+
<WarningLevel>Level4</WarningLevel>
107+
<Optimization>MaxSpeed</Optimization>
108+
<FunctionLevelLinking>true</FunctionLevelLinking>
109+
<IntrinsicFunctions>true</IntrinsicFunctions>
110+
<SDLCheck>true</SDLCheck>
111+
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
112+
</ClCompile>
113+
<Link>
114+
<GenerateDebugInformation>true</GenerateDebugInformation>
115+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
116+
<OptimizeReferences>true</OptimizeReferences>
117+
</Link>
118+
</ItemDefinitionGroup>
119+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
120+
<ClCompile>
121+
<WarningLevel>Level4</WarningLevel>
122+
<Optimization>MaxSpeed</Optimization>
123+
<FunctionLevelLinking>true</FunctionLevelLinking>
124+
<IntrinsicFunctions>true</IntrinsicFunctions>
125+
<SDLCheck>true</SDLCheck>
126+
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
127+
</ClCompile>
128+
<Link>
129+
<GenerateDebugInformation>true</GenerateDebugInformation>
130+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
131+
<OptimizeReferences>true</OptimizeReferences>
132+
</Link>
133+
</ItemDefinitionGroup>
134+
<ItemGroup>
135+
<ClCompile Include="Main.cpp" />
136+
</ItemGroup>
137+
<ItemGroup>
138+
<ClInclude Include="resource.h" />
139+
</ItemGroup>
140+
<ItemGroup>
141+
<ResourceCompile Include="UniversalPauseButton.rc" />
142+
</ItemGroup>
143+
<ItemGroup>
144+
<Image Include="pause.ico" />
145+
</ItemGroup>
146+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
147+
<ImportGroup Label="ExtensionTargets">
148+
</ImportGroup>
149+
</Project>

0 commit comments

Comments
 (0)