Last active
November 25, 2018 23:58
-
-
Save meitinger/fe45ff4618dca607a545525a8edad021 to your computer and use it in GitHub Desktop.
Utility that adds an always-on-top entry in the system menu.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (C) 2008-2018, Manuel Meitinger | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
#include <Windows.h> | |
#pragma comment(linker, "/SUBSYSTEM:WINDOWS") | |
#pragma comment(lib, "Kernel32.lib") | |
#pragma comment(lib, "User32.lib") | |
#ifdef DLL | |
#pragma comment(linker, "/ENTRY:DllMain") | |
#ifdef _WIN64 | |
#pragma comment(linker, "/EXPORT:CallWndProc") | |
#pragma comment(linker, "/EXPORT:GetMsgProc") | |
#else | |
#pragma comment(linker, "/EXPORT:CallWndProc=_CallWndProc@12") | |
#pragma comment(linker, "/EXPORT:GetMsgProc=_GetMsgProc@12") | |
#endif | |
#define COMMAND 0xEFF0 | |
#define MAXLEN 100 | |
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) | |
{ | |
// reduce the working set by disabling thread calls | |
if (fdwReason == DLL_PROCESS_ATTACH) | |
{ | |
DisableThreadLibraryCalls(hinstDLL); | |
} | |
return TRUE; | |
} | |
static LPTSTR GetMenuItemString() | |
{ | |
static LONG initialized = 0; | |
static TCHAR caption[MAXLEN] = TEXT("Always On &Top"); | |
HMODULE taskmgr; | |
HMENU menu; | |
// only try to load the localized string once (thread safe) | |
if (!InterlockedBitTestAndSet(&initialized, 0)) | |
{ | |
// load the task manager as a resource (don't do this at home kids, erm I mean in a business app) | |
if ((taskmgr = LoadLibraryEx(TEXT("taskmgr.exe"), NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE)) != NULL) | |
{ | |
// find the proper menu and get the "always on top" string | |
if ((menu = LoadMenu(taskmgr, MAKEINTRESOURCE(106))) != NULL) | |
{ | |
GetMenuString(menu, 40006, caption, MAXLEN, MF_BYCOMMAND); | |
DestroyMenu(menu); | |
} | |
FreeLibrary(taskmgr); | |
} | |
} | |
// return the localized string | |
return caption; | |
} | |
static VOID InsertOrUpdateMenuItem(HWND window) | |
{ | |
HMENU menu; | |
BOOL isNormal; | |
UINT state; | |
MENUITEMINFO item; | |
// get the system menu handle and the current topmost style | |
if ((menu = GetSystemMenu(window, FALSE)) == NULL) | |
{ | |
return; | |
} | |
isNormal = (GetWindowLongPtr(window, GWL_EXSTYLE) & WS_EX_TOPMOST) == 0; | |
// get the state of the "always on top" entry and... | |
if ((state = GetMenuState(menu, COMMAND, MF_BYCOMMAND)) == -1) | |
{ | |
// ...create it if it doesn't exist or... | |
item.cbSize = sizeof(item); | |
item.fMask = MIIM_CHECKMARKS | MIIM_STATE | MIIM_ID | MIIM_STRING; | |
item.hbmpChecked = NULL; | |
item.hbmpUnchecked = NULL; | |
item.fState = isNormal ? MFS_UNCHECKED : MFS_CHECKED; | |
item.wID = COMMAND; | |
item.dwTypeData = GetMenuItemString(); | |
InsertMenuItem(menu, SC_CLOSE, FALSE, &item); | |
} | |
else | |
{ | |
// ...update the check mark if necessary | |
if (((state & MF_CHECKED) == 0) != isNormal) | |
{ | |
CheckMenuItem(menu, COMMAND, MF_BYCOMMAND | (isNormal ? MFS_UNCHECKED : MFS_CHECKED)); | |
} | |
} | |
} | |
LRESULT CALLBACK CallWndProc(INT code, WPARAM wParam, LPARAM lParam) | |
{ | |
#define msg ((PCWPSTRUCT)lParam) | |
if (code == HC_ACTION) | |
{ | |
switch (msg->message) | |
{ | |
case WM_ACTIVATE: | |
{ | |
// create the custom system menu before WM_INITMENUPOPUP | |
GetSystemMenu(msg->hwnd, FALSE); | |
break; | |
} | |
case WM_INITMENUPOPUP: | |
{ | |
// add or update the "always on top" entry | |
if ((BOOL)HIWORD(msg->lParam) == TRUE) | |
{ | |
InsertOrUpdateMenuItem(msg->hwnd); | |
} | |
break; | |
} | |
case WM_UNINITMENUPOPUP: | |
{ | |
// remove the "always on top" entry | |
if ((HIWORD(msg->lParam) & MF_SYSMENU) != 0) | |
{ | |
DeleteMenu((HMENU)msg->wParam, COMMAND, MF_BYCOMMAND); | |
} | |
break; | |
} | |
} | |
} | |
return CallNextHookEx(NULL, code, wParam, lParam); | |
#undef msg | |
} | |
LRESULT CALLBACK GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) | |
{ | |
#define msg ((PMSG)lParam) | |
if (code == HC_ACTION) | |
{ | |
// update the window's topmost style if the "always on top" entry was clicked | |
if (msg->message == WM_SYSCOMMAND && msg->wParam == COMMAND) | |
{ | |
SetWindowPos(msg->hwnd, (GetWindowLongPtr(msg->hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) == 0 ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); | |
} | |
} | |
return CallNextHookEx(NULL, code, wParam, lParam); | |
#undef msg | |
} | |
#else | |
#include <Psapi.h> | |
#pragma comment(linker, "/ENTRY:Run") | |
#pragma comment(lib, "Psapi.lib") | |
#ifdef _WIN64 | |
#define MUTEX_NAME TEXT("{E88E4EFC-BEDA-463C-AC93-65154B1817FC}") | |
#else | |
#define MUTEX_NAME TEXT("{91383FDC-AF5D-4C17-9347-C3186177EAF6}") | |
#endif | |
void Run(void) | |
{ | |
#define ApiCall(ret) \ | |
{ \ | |
if (!(ret)) \ | |
{ \ | |
exitCode = GetLastError(); \ | |
goto CleanUp; \ | |
} \ | |
} | |
DWORD exitCode = ERROR_SUCCESS; | |
TCHAR baseName[MAX_PATH]; | |
DWORD baseNameLen; | |
HANDLE mutex = NULL; | |
HMODULE library = NULL; | |
HOOKPROC callWndProc; | |
HHOOK callWndHook = NULL; | |
HOOKPROC getMsgProc; | |
HHOOK getMsgHook = NULL; | |
MSG msg; | |
BOOL ret; | |
// get the name of the DLL | |
ApiCall(baseNameLen = GetModuleBaseName(GetCurrentProcess(), NULL, baseName, MAX_PATH)); | |
if (baseName[baseNameLen - 4] != TEXT('.')) | |
{ | |
exitCode = ERROR_BAD_PATHNAME; | |
goto CleanUp; | |
} | |
baseName[baseNameLen - 3] = TEXT('d'); | |
baseName[baseNameLen - 2] = TEXT('l'); | |
baseName[baseNameLen - 1] = TEXT('l'); | |
// ensure that only one instance is running (but don't fail if the test fails) | |
ApiCall(mutex = CreateMutex(NULL, FALSE, MUTEX_NAME)); | |
if (GetLastError() == ERROR_ALREADY_EXISTS) | |
{ | |
exitCode = ERROR_ALREADY_EXISTS; | |
goto CleanUp; | |
} | |
// load the hook library | |
ApiCall(library = LoadLibrary(baseName)); | |
// for injecting the "always on top" entry into the system menu | |
ApiCall(callWndProc = (HOOKPROC)GetProcAddress(library, "CallWndProc")); | |
ApiCall(callWndHook = SetWindowsHookEx(WH_CALLWNDPROC, callWndProc, library, 0)); | |
// initialize the hook for intercepting the entry's command messages | |
ApiCall(getMsgProc = (HOOKPROC)GetProcAddress(library, "GetMsgProc")); | |
ApiCall(getMsgHook = SetWindowsHookEx(WH_GETMESSAGE, getMsgProc, library, 0)); | |
// pump the messages until the end of the session | |
while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) | |
{ | |
if (ret == -1) | |
{ | |
exitCode = GetLastError(); | |
break; | |
} | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
CleanUp: | |
if (mutex != NULL) | |
{ | |
CloseHandle(mutex); | |
} | |
if (getMsgHook != NULL) | |
{ | |
UnhookWindowsHookEx(getMsgHook); | |
} | |
if (callWndHook != NULL) | |
{ | |
UnhookWindowsHookEx(callWndHook); | |
} | |
if (library != NULL) | |
{ | |
FreeLibrary(library); | |
} | |
ExitProcess(exitCode); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment