Skip to content

Commit

Permalink
First Commit
Browse files Browse the repository at this point in the history
First Commit
  • Loading branch information
ryanries committed Jun 8, 2015
1 parent c36df38 commit 99c0d4e
Show file tree
Hide file tree
Showing 7 changed files with 431 additions and 0 deletions.
217 changes: 217 additions & 0 deletions Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// Main.cpp
// UniversalPauseButton
// Ryan Ries, 2015
// ryan@myotherpcisacloud.com
//
// Must compile in Unicode.

#include <Windows.h>
#include <Psapi.h>
#include <stdio.h>
#include "resource.h"

#define WM_TRAYICON (WM_USER + 1)

typedef LONG(NTAPI* _NtSuspendProcess) (IN HANDLE ProcessHandle);
typedef LONG(NTAPI* _NtResumeProcess) (IN HANDLE ProcessHandle);

_NtSuspendProcess NtSuspendProcess = (_NtSuspendProcess)GetProcAddress(GetModuleHandle(L"ntdll"), "NtSuspendProcess");
_NtResumeProcess NtResumeProcess = (_NtResumeProcess)GetProcAddress(GetModuleHandle(L"ntdll"), "NtResumeProcess");

NOTIFYICONDATA G_TrayNotifyIconData;
HANDLE G_Mutex;


// The WindowProc (callback) for WinMain's WindowClass.
// Basically the system tray does nothing except lets the user know that it's running.
// If the user clicks the tray icon it will ask if they want to exit the app.
LRESULT CALLBACK WindowClassCallback(_In_ HWND Window, _In_ UINT Message, _In_ WPARAM WParam, _In_ LPARAM LParam)
{
LRESULT Result = 0;

switch (Message)
{
case WM_TRAYICON:
{
if (LParam == WM_LBUTTONDOWN || LParam == WM_RBUTTONDOWN)
{
if (MessageBox(Window, L"Quit UniversalPauseButton?", L"Are you sure?", MB_YESNO | MB_ICONQUESTION) == IDYES)
{
Shell_NotifyIcon(NIM_DELETE, &G_TrayNotifyIconData);
PostQuitMessage(0);
}
}
}
default:
{
Result = DefWindowProc(Window, Message, WParam, LParam);
break;
}
}
return(Result);
}

// Entry point.
int CALLBACK WinMain(_In_ HINSTANCE Instance, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ int)
{
G_Mutex = CreateMutex(NULL, FALSE, L"UniversalPauseButton");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, L"An instance of the program is already running.", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
return(ERROR_ALREADY_EXISTS);
}

WNDCLASS SysTrayWindowClass = { 0 };

SysTrayWindowClass.style = CS_HREDRAW | CS_VREDRAW;
SysTrayWindowClass.hInstance = Instance;
SysTrayWindowClass.lpszClassName = L"UniversalPauseButton_Systray_WindowClass";
SysTrayWindowClass.hbrBackground = CreateSolidBrush(RGB(255, 0, 255));
SysTrayWindowClass.lpfnWndProc = WindowClassCallback;

if (RegisterClass(&SysTrayWindowClass) == 0)
{
MessageBox(NULL, L"Failed to register WindowClass!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
return(E_FAIL);
}

HWND SystrayWindow = CreateWindowEx(
WS_EX_TOOLWINDOW,
SysTrayWindowClass.lpszClassName,
L"UniversalPauseButton_Systray_Window",
WS_ICONIC,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
Instance,
0);

if (SystrayWindow == 0)
{
MessageBox(NULL, L"Failed to create SystrayWindow!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
return(E_FAIL);
}

G_TrayNotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
G_TrayNotifyIconData.hWnd = SystrayWindow;
G_TrayNotifyIconData.uID = 1982;
G_TrayNotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
G_TrayNotifyIconData.uCallbackMessage = WM_TRAYICON;

wcscpy_s(G_TrayNotifyIconData.szTip, L"Universal Pause Button v1.0");

G_TrayNotifyIconData.hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 0, 0, NULL);

if (G_TrayNotifyIconData.hIcon == NULL)
{
MessageBox(NULL, L"Failed to load systray icon resource!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
return(E_FAIL);
}

if (Shell_NotifyIcon(NIM_ADD, &G_TrayNotifyIconData) == FALSE)
{
MessageBox(NULL, L"Failed to register systray icon!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
return(E_FAIL);
}

MSG SysTrayWindowMessage = { 0 };
static int PauseKeyWasDown = 0;
DWORD PreviouslySuspendedProcessID = 0;
wchar_t PreviouslySuspendedProcessText[256] = { 0 };

while (SysTrayWindowMessage.message != WM_QUIT)
{
while (PeekMessage(&SysTrayWindowMessage, SystrayWindow, 0, 0, PM_REMOVE))
{
DispatchMessage(&SysTrayWindowMessage);
}

int PauseKeyIsDown = GetAsyncKeyState(VK_PAUSE);

if (PauseKeyIsDown && !PauseKeyWasDown)
{
HWND ForegroundWindow = GetForegroundWindow();
if (ForegroundWindow)
{
DWORD ProcessID = 0;
GetWindowThreadProcessId(ForegroundWindow, &ProcessID);
if (ProcessID != 0)
{
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
if (ProcessHandle != 0)
{
if (PreviouslySuspendedProcessID == 0)
{
NtSuspendProcess(ProcessHandle);
PreviouslySuspendedProcessID = ProcessID;
GetWindowText(ForegroundWindow, PreviouslySuspendedProcessText, sizeof(PreviouslySuspendedProcessText) / sizeof(wchar_t));
}
else if (PreviouslySuspendedProcessID == ProcessID)
{
NtResumeProcess(ProcessHandle);
PreviouslySuspendedProcessID = 0;
memset(PreviouslySuspendedProcessText, 0, sizeof(PreviouslySuspendedProcessText));
}
else
{
// The user pressed the pause button while focused on another process than what was
// originally paused and the first process is still paused.
DWORD AllProcesses[2048] = { 0 };
DWORD BytesReturned = 0;
BOOL PreviouslySuspendedProcessIsStillRunning = FALSE;

if (EnumProcesses(AllProcesses, sizeof(AllProcesses), &BytesReturned) != 0)
{
for (DWORD Counter = 0; Counter < (BytesReturned / sizeof(DWORD)); Counter++)
{
if ((AllProcesses[Counter] != 0) && AllProcesses[Counter] == PreviouslySuspendedProcessID)
{
PreviouslySuspendedProcessIsStillRunning = TRUE;
}
}
if (PreviouslySuspendedProcessIsStillRunning)
{
wchar_t MessageBoxBuffer[1024] = { 0 };
_snwprintf_s(MessageBoxBuffer, sizeof(MessageBoxBuffer), L"You must first unpause %s (PID %d) before pausing another program.", PreviouslySuspendedProcessText, PreviouslySuspendedProcessID);
MessageBox(ForegroundWindow, MessageBoxBuffer, L"Universal Pause Button", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL);
}
else
{
// The paused process is no more, so reset.
PreviouslySuspendedProcessID = 0;
memset(PreviouslySuspendedProcessText, 0, sizeof(PreviouslySuspendedProcessText));
}
}
else
{
MessageBox(NULL, L"EnumProcesses failed!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
}
}
CloseHandle(ProcessHandle);
}
else
{
MessageBox(NULL, L"OpenProcess failed!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
}
}
else
{
MessageBox(NULL, L"Unable to get process ID of foreground window!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
}
}
else
{
MessageBox(NULL, L"Unable to detect foreground window!", L"UniversalPauseButton Error", MB_OK | MB_ICONERROR);
}
}

PauseKeyWasDown = PauseKeyIsDown;

Sleep(10);
}

return(S_OK);
}
Binary file added UniversalPauseButton.rc
Binary file not shown.
28 changes: 28 additions & 0 deletions UniversalPauseButton.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UniversalPauseButton", "UniversalPauseButton.vcxproj", "{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|Win32.ActiveCfg = Debug|Win32
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|Win32.Build.0 = Debug|Win32
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|x64.ActiveCfg = Debug|x64
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Debug|x64.Build.0 = Debug|x64
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|Win32.ActiveCfg = Release|Win32
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|Win32.Build.0 = Release|Win32
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|x64.ActiveCfg = Release|x64
{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
149 changes: 149 additions & 0 deletions UniversalPauseButton.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{229438CB-2B5E-4C34-B1CE-F9AC14B0C47C}</ProjectGuid>
<RootNamespace>UniversalPauseButton</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\Temp\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="UniversalPauseButton.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="pause.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Loading

0 comments on commit 99c0d4e

Please sign in to comment.