15 Commits

16 changed files with 836 additions and 1204 deletions

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 W0LF aka 'dreamforce' Copyright (c) 2020-2024 Vladislav Salikov aka W0LF
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,48 +1,34 @@
## wCenterWindow ## wCenterWindow
This program centers the current active window by a `LCTRL + LWIN + C` hotkey, Copyright (c) 2020-2024 Vladislav Salikov aka W0LF.<br>
or pressing `LCTRL + LWIN + MMB` (Middle Mouse Button). Program icon made by Kirill Topov.
---
This program centers the current active window by a `LCTRL + LWIN + C` hotkey, or pressing `LCTRL + LWIN + MMB` (Middle Mouse Button).
`LCTRL + LWIN + V` - manual editing of size and position of the window. `LCTRL + LWIN + V` - manual editing of size and position of the window.
You can use `LCTRL + LWIN + I` hotkey for hide/show trayicon. `LCTRL + LWIN + I` hotkey is used to hide/show trayicon.
You can also use commandline option `/hide` for hide trayicon at startup. You can also use commandline option `/hide` to hide trayicon at startup.
The `/noupdate` option is used to disable check for updates. By default, the program checks for updates upon startup and once a day. The `/noupdate` commandline option is used to disable check for updates. By default, the program checks for updates upon startup and once a day.
The `Use workarea` option means that the window is centered without a taskbar, otherwise, the full resolution of the monitor will be used. The `Use workarea` option (at popup menu) means that the window is centered without a taskbar, otherwise, the full resolution of the monitor will be used.
If some windows does not centers you should run wCenterWindow with administrative rights. If some windows does not centers, you should run wCenterWindow with administrative rights.
## Automatic startup ## Automatic startup
Usually, to start the application when Windows starts, it is enough to put the application's shortcut in the "Startup" folder -\ Usually, to start the application when Windows starts, it is enough to put the application's shortcut in the "Startup" folder -
"C:\Users\\<*Your user name*>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup". (The easiest way to get there - press 'WIN + R' and type 'shell:startup').\ "C:\Users\\<*Your user name*>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup".
(The easiest way to get there - press 'WIN + R' and type `shell:startup`).<br>
However, in this case wCenterWindow will not be able to work with windows that are open with elevated privileges. However, in this case wCenterWindow will not be able to work with windows that are open with elevated privileges.
And if you enable the "Run as administrator" option in the shortcut, then wCenterWindow will not start. This is related to the security of Windows (maybe only in 10/11, I did not check).\ And if you enable the "Run as administrator" option in the shortcut, then wCenterWindow will not start. This is related to the security of Windows (maybe only in 10/11, I did not check).
This behavior can be bypassed by creating a task in the Task Scheduler with the "Run with highest privileges" option.\ This behavior can be bypassed by creating a task in the Task Scheduler with the "Run with highest privileges" option.<br>
**Note:** If you run wCenterWindow via the Task Scheduler, I highly recommend enabling the "Delay task for" option for 15-30 seconds, otherwise you may get an error message "Can't create tray icon". **Note:** If you run wCenterWindow via the Task Scheduler, I highly recommend enabling the "Delay task for" option for 15-30 seconds, otherwise you may get an error message "Can't create tray icon".
## License ## License
MIT License This software is licensed under a [MIT License](https://mit-license.org).<br>
This software uses the [PicoJSON](https://github.com/kazuho/picojson) - a C++ JSON parser / serializer by Kazuho Oku.
Copyright (c) 2023 W0LF aka 'dreamforce'
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,25 +1,3 @@
## MIT License
##
## Copyright (c) 2023 W0LF aka 'dreamforce'
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included in all
## copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
# Update Version v2.1 # Update Version v2.1
# Required module: PSIni # Required module: PSIni
# Installation: Install-Module -Name PsIni # Installation: Install-Module -Name PsIni

Binary file not shown.

View File

@@ -1,25 +1,4 @@
@ECHO OFF @ECHO OFF
:: MIT License
::
:: Copyright (c) 2023 W0LF aka 'dreamforce'
::
:: Permission is hereby granted, free of charge, to any person obtaining a copy
:: of this software and associated documentation files (the "Software"), to deal
:: in the Software without restriction, including without limitation the rights
:: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
:: copies of the Software, and to permit persons to whom the Software is
:: furnished to do so, subject to the following conditions:
::
:: The above copyright notice and this permission notice shall be included in all
:: copies or substantial portions of the Software.
::
:: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
:: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
:: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
:: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
:: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
:: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
:: SOFTWARE.
:: In VisualStudio add to Pre-Build events: :: In VisualStudio add to Pre-Build events:
:: "$(SolutionDir)pre-build.cmd" "$(SolutionDir)" "$(ProjectDir)" :: "$(SolutionDir)pre-build.cmd" "$(SolutionDir)" "$(ProjectDir)"

View File

@@ -1,25 +1,3 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// CLogger.cpp // CLogger.cpp
@@ -28,17 +6,14 @@
#include <filesystem> #include <filesystem>
#include <strsafe.h> #include <strsafe.h>
inline wchar_t* CLogger::GetTimeStamp() inline wchar_t* CLogger::GetTimeStamp() {
{
GetLocalTime(&lt); GetLocalTime(&lt);
StringCchPrintfW(logTimeBuffer, _countof(logTimeBuffer), L"%d-%02d-%02d %02d:%02d:%02d.%03d | ", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); StringCchPrintfW(logTimeBuffer, _countof(logTimeBuffer), L"%d-%02d-%02d %02d:%02d:%02d.%03d | ", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
return logTimeBuffer; return logTimeBuffer;
} }
void CLogger::Out(const wchar_t* fmt, ...) void CLogger::Out(const wchar_t* fmt, ...) {
{ if (fsLogFile.is_open()) {
if (fsLogFile.is_open())
{
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
@@ -49,18 +24,15 @@ void CLogger::Out(const wchar_t* fmt, ...)
} }
} }
void CLogger::Init() void CLogger::Init() {
{
wchar_t szPath[MAX_PATH] = { 0 }; wchar_t szPath[MAX_PATH] = { 0 };
DWORD dwPathLength = GetModuleFileNameW(NULL, szPath, MAX_PATH); DWORD dwPathLength = GetModuleFileNameW(NULL, szPath, MAX_PATH);
DWORD dwError = GetLastError(); DWORD dwError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == dwError) if (ERROR_INSUFFICIENT_BUFFER == dwError) {
{
MessageBoxW(NULL, L"Warning!\nPath to log file is too long! Working without logging.", szAppTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL); MessageBoxW(NULL, L"Warning!\nPath to log file is too long! Working without logging.", szAppTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL);
return; return;
} }
if (NULL == dwPathLength) if (NULL == dwPathLength) {
{
MessageBoxW(NULL, L"Warning!\nCan't get application's filename! Working without logging.", szAppTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL); MessageBoxW(NULL, L"Warning!\nCan't get application's filename! Working without logging.", szAppTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL);
return; return;
} }
@@ -75,31 +47,26 @@ void CLogger::Init()
log_path = L"D:\\test.log"; log_path = L"D:\\test.log";
#endif #endif
fsLogFile.open(log_path, std::ios::trunc); fsLogFile.open(log_path, std::ios::trunc);
if (fsLogFile.is_open()) if (fsLogFile.is_open()) {
{
InitializeCriticalSection(&cs); InitializeCriticalSection(&cs);
fsLogFile << "\xEF\xBB\xBF"; // (0xEF, 0xBB, 0xBF) - UTF-8 BOM fsLogFile << "\xEF\xBB\xBF"; // (0xEF, 0xBB, 0xBF) - UTF-8 BOM
fsLogFile.imbue(std::locale("en-US.utf8")); fsLogFile.imbue(std::locale("en-US.utf8"));
fsLogFile << GetTimeStamp() << "[ " << szAppTitleVer.c_str() << " ] Start log." << std::endl; fsLogFile << GetTimeStamp() << "[ " << szAppTitleVer.c_str() << " ] Start log." << std::endl;
fsLogFile << GetTimeStamp() << "Logfile: \"" << log_path.native() << "\"" << std::endl; fsLogFile << GetTimeStamp() << "Logfile: \"" << log_path.native() << "\"" << std::endl;
} }
else else {
{
MessageBoxW(NULL, L"Warning!\nCan't create log file! Working without logging.", szAppTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL); MessageBoxW(NULL, L"Warning!\nCan't create log file! Working without logging.", szAppTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL);
} }
} }
CLogger::CLogger(const wchar_t* _appTitle) CLogger::CLogger(const wchar_t* _appTitle) {
{
szAppTitle = _appTitle; szAppTitle = _appTitle;
szAppTitleVer = _appTitle; szAppTitleVer = _appTitle;
Init(); Init();
} }
CLogger::~CLogger() CLogger::~CLogger() {
{ if (fsLogFile) {
if (fsLogFile)
{
fsLogFile << GetTimeStamp() << "Stop log." << std::endl; fsLogFile << GetTimeStamp() << "Stop log." << std::endl;
fsLogFile.close(); fsLogFile.close();
DeleteCriticalSection(&cs); DeleteCriticalSection(&cs);

View File

@@ -1,25 +1,3 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// CLogger.h // CLogger.h
@@ -29,8 +7,7 @@
#define MAX_LOGBUFFER_LENGTH 512 #define MAX_LOGBUFFER_LENGTH 512
class CLogger class CLogger {
{
public: public:
void Out(const wchar_t*, ...); void Out(const wchar_t*, ...);
CLogger(const wchar_t*); CLogger(const wchar_t*);

View File

@@ -1,25 +1,3 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// framework.h // framework.h

View File

@@ -2,48 +2,38 @@
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by wCenterWindow.rc // Used by wCenterWindow.rc
// //
#define IDS_CLASSNAME 102 #define IDS_CLASSNAME 100
#define IDS_APP_TITLE 103 #define IDS_APP_TITLE 101
#define IDD_ABOUTBOX 104 #define IDI_TRAYICON 102
#define IDI_TRAYICON 105 #define IDR_MENU 103
#define IDR_MENU 106 #define ID_POPUPMENU_ICON 104
#define ID_POPUPMENU_ICON 107 #define ID_POPUPMENU_AREA 105
#define ID_POPUPMENU_AREA 108 #define ID_POPUPMENU_HELP 106
#define ID_POPUPMENU_HELP 109 #define ID_POPUPMENU_ABOUT 107
#define ID_POPUPMENU_ABOUT 110 #define ID_POPUPMENU_EXIT 108
#define ID_POPUPMENU_EXIT 111 #define IDS_HELP 109
#define IDS_HELP 112 #define IDS_ERR_MAIN 110
#define IDS_ERR_MAIN 113 #define IDS_ERR_CLASS 111
#define IDS_ERR_CLASS 114 #define IDS_ERR_WND 112
#define IDS_ERR_WND 115 #define IDS_ERR_ICON 113
#define IDS_ERR_ICON 116 #define IDS_ERR_MENU 114
#define IDS_ERR_MENU 117 #define IDS_ERR_POPUP 115
#define IDS_ERR_POPUP 118 #define IDS_ERR_HOOK 116
#define IDS_ERR_HOOK 119 #define IDS_ERR_TIMER 117
#define IDS_ERR_TIMER 120 #define IDS_ERR_HEAP 118
#define IDS_ERR_HEAP 121 #define IDS_ERR_MAXMIN 119
#define IDS_ERR_MAXMIN 122 #define IDS_RUNNING 120
#define IDS_RUNNING 123 #define IDT_TIMER 121
#define IDT_TIMER 124 #define IDD_MANUAL_EDITING 1000
#define IDS_LICENSE 125 #define IDC_EDIT_X 1001
#define IDR_MAINFRAME 128 #define IDC_EDIT_Y 1002
#define IDD_MANUAL_EDITING 129 #define IDC_EDIT_WIDTH 1003
#define IDC_EDIT_X 1000 #define IDC_EDIT_HEIGHT 1004
#define IDC_EDIT_Y 1001 #define IDC_EDIT_TITLE 1005
#define IDC_EDIT_WIDTH 1002 #define IDC_EDIT_CLASS 1006
#define IDC_EDIT_HEIGHT 1003 #define IDC_BUTTON_SET 1007
#define IDC_EDIT_TITLE 1004 #define IDC_BUTTON_CENTER 1008
#define IDC_EDIT_CLASS 1005 #define IDC_BUTTON_CLOSE 1009
#define IDC_BUTTON_SET 1006
#define IDC_BUTTON_CENTER 1007
#define IDC_BUTTON_CLOSE 1008
#define IDC_ABOUTHELP 1009
#define IDC_DONATIONLINK 1010
#define IDC_DONATIONTEXT 1011
#define IDC_ABOUT_PROGNAME 1012
#define IDC_ABOUT_COPYRIGHT 1013
#define IDC_ABOUT_BUILDTIME 1014
#define IDC_ABOUTEDIT 1015
#define IDC_STATIC -1 #define IDC_STATIC -1
// Next default values for new objects // Next default values for new objects
@@ -51,9 +41,9 @@
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1 #define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 130 #define _APS_NEXT_RESOURCE_VALUE 200
#define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1016 #define _APS_NEXT_CONTROL_VALUE 1010
#define _APS_NEXT_SYMED_VALUE 126 #define _APS_NEXT_SYMED_VALUE 122
#endif #endif
#endif #endif

View File

@@ -1,25 +1,5 @@
// MIT License // wCenterWindow
// // targetver.h
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once #pragma once
// // Including SDKDDKVer.h defines the highest available Windows platform. // // Including SDKDDKVer.h defines the highest available Windows platform.

View File

@@ -1,25 +1,3 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// updater.h // updater.h
@@ -33,8 +11,7 @@
picojson::value json; picojson::value json;
struct Version struct Version {
{
UINT Major = 0; UINT Major = 0;
UINT Minor = 0; UINT Minor = 0;
UINT Build = 0; UINT Build = 0;
@@ -46,15 +23,13 @@ void FillVersionStructure(Version& ver, const std::wstring& str);
std::vector<std::wstring> Split(const std::wstring& s, wchar_t delim); std::vector<std::wstring> Split(const std::wstring& s, wchar_t delim);
std::wstring ConvertUtf8ToWide(const std::string& str); std::wstring ConvertUtf8ToWide(const std::string& str);
UINT WINAPI Updater(void*) UINT WINAPI Updater(void*) {
{
logger.Out(L"Entering the %s() function", TEXT(__FUNCTION__)); logger.Out(L"Entering the %s() function", TEXT(__FUNCTION__));
logger.Out(L"[UPDT] Sleeping %d seconds", T0); logger.Out(L"[UPDT] Sleeping %d seconds", T0);
Sleep(T0 * 1000); // 10 seconds Sleep(T0 * 1000); // 10 seconds
if (!GetLatestRelease(GITHUB_URI)) if (!GetLatestRelease(GITHUB_URI)) {
{
logger.Out(L"[UPDT] %s(%d): Failed getting releases!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): Failed getting releases!", TEXT(__FUNCTION__), __LINE__);
MessageBoxW(NULL, L"Failed getting releases!", szTitle, MB_OK | MB_ICONERROR); MessageBoxW(NULL, L"Failed getting releases!", szTitle, MB_OK | MB_ICONERROR);
@@ -67,30 +42,25 @@ UINT WINAPI Updater(void*)
picojson::object obj, obj2; picojson::object obj, obj2;
picojson::object::iterator it, it2; picojson::object::iterator it, it2;
if (json.is<picojson::object>()) if (json.is<picojson::object>()) {
{
logger.Out(L"[UPDT] %s(%d): Parsing JSON object", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): Parsing JSON object", TEXT(__FUNCTION__), __LINE__);
obj = json.get<picojson::object>(); obj = json.get<picojson::object>();
it = obj.find("message"), it2; it = obj.find("message"), it2;
if (it != obj.end()) if (it != obj.end()) {
{
std::string u = (*it).second.get<std::string>(); std::string u = (*it).second.get<std::string>();
logger.Out(L"[UPDT] %s(%d): Error! The url is %s", TEXT(__FUNCTION__), __LINE__, u); logger.Out(L"[UPDT] %s(%d): Error! The url is %s", TEXT(__FUNCTION__), __LINE__, u);
return 102; return 102;
_endthreadex(102); _endthreadex(102);
} }
for (it = obj.begin(); it != obj.end(); it++) for (it = obj.begin(); it != obj.end(); it++) {
{
if ((*it).first == "tag_name") j_tag_name = ConvertUtf8ToWide((*it).second.to_str()); if ((*it).first == "tag_name") j_tag_name = ConvertUtf8ToWide((*it).second.to_str());
if ((*it).first == "html_url") j_page_url = ConvertUtf8ToWide((*it).second.to_str()); if ((*it).first == "html_url") j_page_url = ConvertUtf8ToWide((*it).second.to_str());
if ((*it).first == "assets" && (*it).second.is<picojson::array>()) if ((*it).first == "assets" && (*it).second.is<picojson::array>()) {
{
picojson::array a = (*it).second.get<picojson::array>(); picojson::array a = (*it).second.get<picojson::array>();
obj2 = a[0].get<picojson::object>(); obj2 = a[0].get<picojson::object>();
for (it2 = obj2.begin(); it2 != obj2.end(); it2++) for (it2 = obj2.begin(); it2 != obj2.end(); it2++) {
{
if ((*it2).first == "name") j_file_name = ConvertUtf8ToWide((*it2).second.to_str()); if ((*it2).first == "name") j_file_name = ConvertUtf8ToWide((*it2).second.to_str());
if ((*it2).first == "browser_download_url") j_file_url = ConvertUtf8ToWide((*it2).second.to_str()); if ((*it2).first == "browser_download_url") j_file_url = ConvertUtf8ToWide((*it2).second.to_str());
if ((*it2).first == "size") j_file_size = static_cast<int64_t>((*it2).second.get<double>()); if ((*it2).first == "size") j_file_size = static_cast<int64_t>((*it2).second.get<double>());
@@ -98,8 +68,7 @@ UINT WINAPI Updater(void*)
} }
} }
} }
else else {
{
logger.Out(L"[UPDT] %s(%d): Error! Cannot recognize JSON object!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): Error! Cannot recognize JSON object!", TEXT(__FUNCTION__), __LINE__);
return 103; return 103;
_endthreadex(103); _endthreadex(103);
@@ -119,23 +88,19 @@ UINT WINAPI Updater(void*)
FillVersionStructure(verApp, TEXT(VERSION_STR)); FillVersionStructure(verApp, TEXT(VERSION_STR));
FillVersionStructure(verGh, gh_version); FillVersionStructure(verGh, gh_version);
if ((verGh.Major > verApp.Major) || (verGh.Minor > verApp.Minor) || (verGh.Build > verApp.Build) || (verGh.Patch > verApp.Patch)) if ((verGh.Major > verApp.Major) || (verGh.Minor > verApp.Minor) || (verGh.Build > verApp.Build) || (verGh.Patch > verApp.Patch)) {
{
logger.Out(L"[UPDT] %s(%d): An update is available!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): An update is available!", TEXT(__FUNCTION__), __LINE__);
if (IDYES == MessageBoxW(NULL, L"An update is available!\nDo you want to open the download page?", szTitle, MB_YESNO | MB_ICONINFORMATION)) if (IDYES == MessageBoxW(NULL, L"An update is available!\nDo you want to open the download page?", szTitle, MB_YESNO | MB_ICONINFORMATION)) {
{
logger.Out(L"[UPDT] %s(%d): Opening download page by default browser", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): Opening download page by default browser", TEXT(__FUNCTION__), __LINE__);
ShellExecuteW(NULL, L"open", j_page_url.c_str(), NULL, NULL, SW_SHOW); ShellExecuteW(NULL, L"open", j_page_url.c_str(), NULL, NULL, SW_SHOW);
} }
else else {
{
logger.Out(L"[UPDT] %s(%d): The user refused the update", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): The user refused the update", TEXT(__FUNCTION__), __LINE__);
} }
} }
else else {
{
logger.Out(L"[UPDT] %s(%d): No updates is available", TEXT(__FUNCTION__), __LINE__); logger.Out(L"[UPDT] %s(%d): No updates is available", TEXT(__FUNCTION__), __LINE__);
} }
@@ -145,8 +110,7 @@ UINT WINAPI Updater(void*)
_endthreadex(0); _endthreadex(0);
} }
bool GetLatestRelease(const std::wstring& urn) bool GetLatestRelease(const std::wstring& urn) {
{
std::wstring user_agent = L"User-Agent: "; std::wstring user_agent = L"User-Agent: ";
user_agent.append(szTitle); user_agent.append(szTitle);
const std::wstring url = GITHUB_URL; const std::wstring url = GITHUB_URL;
@@ -156,30 +120,25 @@ bool GetLatestRelease(const std::wstring& urn)
logger.Out(L"[UPDT] %s(%d): %s", TEXT(__FUNCTION__), __LINE__, user_agent.c_str()); logger.Out(L"[UPDT] %s(%d): %s", TEXT(__FUNCTION__), __LINE__, user_agent.c_str());
HINTERNET hInternet = InternetOpenW(user_agent.c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); HINTERNET hInternet = InternetOpenW(user_agent.c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet != NULL) if (hInternet != NULL) {
{
HINTERNET hConnect = InternetConnectW(hInternet, url.c_str(), INTERNET_DEFAULT_HTTPS_PORT, L"", L"", INTERNET_SERVICE_HTTP, INTERNET_FLAG_SECURE, 0); HINTERNET hConnect = InternetConnectW(hInternet, url.c_str(), INTERNET_DEFAULT_HTTPS_PORT, L"", L"", INTERNET_SERVICE_HTTP, INTERNET_FLAG_SECURE, 0);
if (hConnect != NULL) if (hConnect != NULL) {
{
HINTERNET hRequest = HttpOpenRequestW(hConnect, L"GET", urn.c_str(), NULL, NULL, NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_UI, 0); HINTERNET hRequest = HttpOpenRequestW(hConnect, L"GET", urn.c_str(), NULL, NULL, NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_UI, 0);
if (hRequest != NULL) if (hRequest != NULL) {
{
BOOL isSend = HttpSendRequestW(hRequest, NULL, 0, 0, 0); BOOL isSend = HttpSendRequestW(hRequest, NULL, 0, 0, 0);
if (isSend) if (isSend) {
{
char szData[1024]{ 0 }; char szData[1024]{ 0 };
DWORD dwBytesRead = 0; DWORD dwBytesRead = 0;
std::string buffer; std::string buffer;
do do {
{
InternetReadFile(hRequest, szData, sizeof(szData), &dwBytesRead); InternetReadFile(hRequest, szData, sizeof(szData), &dwBytesRead);
buffer.append(szData, dwBytesRead); buffer.append(szData, dwBytesRead);
} while (dwBytesRead != 0); }
while (dwBytesRead != 0);
picojson::parse(json, buffer); picojson::parse(json, buffer);
std::string jerr = picojson::get_last_error(); std::string jerr = picojson::get_last_error();
if (!jerr.empty()) if (!jerr.empty()) {
{
logger.Out(L"[UPDT] %s(%d): Error while parsing JSON object: %s", TEXT(__FUNCTION__), __LINE__, ConvertUtf8ToWide(jerr)); logger.Out(L"[UPDT] %s(%d): Error while parsing JSON object: %s", TEXT(__FUNCTION__), __LINE__, ConvertUtf8ToWide(jerr));
MessageBoxW(NULL, L"Error while parsing JSON object!", szTitle, MB_OK | MB_ICONERROR); MessageBoxW(NULL, L"Error while parsing JSON object!", szTitle, MB_OK | MB_ICONERROR);
@@ -187,31 +146,27 @@ bool GetLatestRelease(const std::wstring& urn)
} }
} }
else else {
{
err = GetLastError(); err = GetLastError();
logger.Out(L"[UPDT] %s(%d): HttpSendRequestW() error: %d", TEXT(__FUNCTION__), __LINE__, err); logger.Out(L"[UPDT] %s(%d): HttpSendRequestW() error: %d", TEXT(__FUNCTION__), __LINE__, err);
ret = false; ret = false;
} }
} }
else else {
{
err = GetLastError(); err = GetLastError();
logger.Out(L"[UPDT] %s(%d): HttpOpenRequestW() error: %d", TEXT(__FUNCTION__), __LINE__, err); logger.Out(L"[UPDT] %s(%d): HttpOpenRequestW() error: %d", TEXT(__FUNCTION__), __LINE__, err);
ret = false; ret = false;
} }
InternetCloseHandle(hRequest); InternetCloseHandle(hRequest);
} }
else else {
{
err = GetLastError(); err = GetLastError();
logger.Out(L"[UPDT] %s(%d): InternetConnectW() error: %d", TEXT(__FUNCTION__), __LINE__, err); logger.Out(L"[UPDT] %s(%d): InternetConnectW() error: %d", TEXT(__FUNCTION__), __LINE__, err);
ret = false; ret = false;
} }
InternetCloseHandle(hConnect); InternetCloseHandle(hConnect);
} }
else else {
{
err = GetLastError(); err = GetLastError();
logger.Out(L"[UPDT] %s(%d): InternetOpenW() error: %d", TEXT(__FUNCTION__), __LINE__, err); logger.Out(L"[UPDT] %s(%d): InternetOpenW() error: %d", TEXT(__FUNCTION__), __LINE__, err);
ret = false; ret = false;
@@ -220,8 +175,7 @@ bool GetLatestRelease(const std::wstring& urn)
return ret; return ret;
} }
std::vector<std::wstring> Split(const std::wstring& s, wchar_t delim) std::vector<std::wstring> Split(const std::wstring& s, wchar_t delim) {
{
std::vector<std::wstring> result; std::vector<std::wstring> result;
std::wstringstream ss(s); std::wstringstream ss(s);
std::wstring item; std::wstring item;
@@ -229,8 +183,7 @@ std::vector<std::wstring> Split(const std::wstring& s, wchar_t delim)
return result; return result;
} }
void FillVersionStructure(Version& ver, const std::wstring& str) void FillVersionStructure(Version& ver, const std::wstring& str) {
{
std::vector<std::wstring> v; std::vector<std::wstring> v;
v = Split(str, '.'); v = Split(str, '.');
if (v.size() < 4) v.push_back(L"0"); if (v.size() < 4) v.push_back(L"0");
@@ -240,8 +193,7 @@ void FillVersionStructure(Version& ver, const std::wstring& str)
ver.Patch = std::stoul(v[3]); ver.Patch = std::stoul(v[3]);
} }
std::wstring ConvertUtf8ToWide(const std::string& str) std::wstring ConvertUtf8ToWide(const std::string& str) {
{
int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0); int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
std::wstring wstr(count, 0); std::wstring wstr(count, 0);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], count); MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], count);

View File

@@ -1,25 +1,3 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// updater.h // updater.h

View File

@@ -1,31 +1,6 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// wCenterWindow.cpp // wCenterWindow.cpp
// TODO: Change the formatting of source files.
// TODO: Add the name of app's icon author to the About dialog.
// TODO: Move the InitCommonControlsEx() function to the WinMain().
// TODO: Split main cpp-file to separate files. // TODO: Split main cpp-file to separate files.
// TODO: Make the automatic updater (download, unzip and replace executable). // TODO: Make the automatic updater (download, unzip and replace executable).
// TODO: Change keyboard low-level hook to RegisterHotKey function. (Is it really needed?) // TODO: Change keyboard low-level hook to RegisterHotKey function. (Is it really needed?)
@@ -34,7 +9,7 @@
#include "wCenterWindow.h" #include "wCenterWindow.h"
#include "updater.h" #include "updater.h"
#define NO_DONATION //#define NO_DONATION
#define KEY_I 0x49 #define KEY_I 0x49
#define KEY_C 0x43 #define KEY_C 0x43
#define KEY_V 0x56 #define KEY_V 0x56
@@ -67,10 +42,9 @@ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK KeyboardHookProc(int, WPARAM, LPARAM); LRESULT CALLBACK KeyboardHookProc(int, WPARAM, LPARAM);
LRESULT CALLBACK MouseHookProc(int, WPARAM, LPARAM); LRESULT CALLBACK MouseHookProc(int, WPARAM, LPARAM);
INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); HRESULT CALLBACK AboutCallback(HWND, UINT, WPARAM, LPARAM, LONG_PTR);
static VOID MoveWindowToMonitorCenter(HWND hwnd, BOOL bWorkArea, BOOL bResize) static VOID MoveWindowToMonitorCenter(HWND hwnd, BOOL bWorkArea, BOOL bResize) {
{
logger.Out(L"Entering the %s() function", TEXT(__FUNCTION__)); logger.Out(L"Entering the %s() function", TEXT(__FUNCTION__));
RECT fgwrc = { 0 }; RECT fgwrc = { 0 };
@@ -84,29 +58,33 @@ static VOID MoveWindowToMonitorCenter(HWND hwnd, BOOL bWorkArea, BOOL bResize)
mi.cbSize = sizeof(MONITORINFO); mi.cbSize = sizeof(MONITORINFO);
GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi); GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
RECT area = { 0 }; RECT area = { 0 };
if (bWorkArea) if (bWorkArea) {
{
area.bottom = mi.rcWork.bottom; area.bottom = mi.rcWork.bottom;
area.left = mi.rcWork.left; area.left = mi.rcWork.left;
area.right = mi.rcWork.right; area.right = mi.rcWork.right;
area.top = mi.rcWork.top; area.top = mi.rcWork.top;
} }
else else {
{
area.bottom = mi.rcMonitor.bottom; area.bottom = mi.rcMonitor.bottom;
area.left = mi.rcMonitor.left; area.left = mi.rcMonitor.left;
area.right = mi.rcMonitor.right; area.right = mi.rcMonitor.right;
area.top = mi.rcMonitor.top; area.top = mi.rcMonitor.top;
} }
int aw = area.right - area.left; LONG aw = area.right - area.left;
int ah = area.bottom - area.top; LONG ah = area.bottom - area.top;
if (nWidth > aw && bResize) nWidth = aw; if ((nWidth > aw) && bResize) nWidth = aw;
if (nHeight > ah && bResize) nHeight = ah; if ((nHeight > ah) && bResize) nHeight = ah;
if (area.left < 0) aw = -aw; if (area.left < 0) {
if (area.top < 0) ah = -ah; aw = -aw;
int x = (aw - nWidth) / 2; area.left = 0;
int y = (ah - nHeight) / 2; }
if (area.top < 0) {
ah = -ah;
area.top = 0;
}
int x = area.left + (aw - nWidth) / 2;
int y = area.top + (ah - nHeight) / 2;
logger.Out(L"%s(%d): Moving the window to %d, %d", TEXT(__FUNCTION__), __LINE__, x, y); logger.Out(L"%s(%d): Moving the window to %d, %d", TEXT(__FUNCTION__), __LINE__, x, y);
@@ -117,15 +95,13 @@ static VOID MoveWindowToMonitorCenter(HWND hwnd, BOOL bWorkArea, BOOL bResize)
logger.Out(L"Exit from the %s() function", TEXT(__FUNCTION__)); logger.Out(L"Exit from the %s() function", TEXT(__FUNCTION__));
} }
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
{
WCHAR szClass[MAX_LOADSTRING]{ 0 }; // Window's class WCHAR szClass[MAX_LOADSTRING]{ 0 }; // Window's class
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, _countof(szTitle)); LoadStringW(hInstance, IDS_APP_TITLE, szTitle, _countof(szTitle));
LoadStringW(hInstance, IDS_CLASSNAME, szClass, _countof(szClass)); LoadStringW(hInstance, IDS_CLASSNAME, szClass, _countof(szClass));
if (FindWindowW(szClass, NULL)) if (FindWindowW(szClass, NULL)) {
{
ShowError(IDS_RUNNING, szTitle); ShowError(IDS_RUNNING, szTitle);
return -10; return -10;
} }
@@ -137,10 +113,8 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
logger.Out(L"Arguments count: %d", nArgs - 1); logger.Out(L"Arguments count: %d", nArgs - 1);
if (nArgs > 1) if (nArgs > 1) {
{ for (int i = 1; i < nArgs; i++) {
for (int i = 1; i < nArgs; i++)
{
logger.Out(L"Argument %d: %s", i, szArglist[i]); logger.Out(L"Argument %d: %s", i, szArglist[i]);
if (0 == lstrcmpiW(szArglist[i], L"/hide")) fShowIcon = FALSE; if (0 == lstrcmpiW(szArglist[i], L"/hide")) fShowIcon = FALSE;
if (0 == lstrcmpiW(szArglist[i], L"/noupdate")) fCheckUpdates = FALSE; if (0 == lstrcmpiW(szArglist[i], L"/noupdate")) fCheckUpdates = FALSE;
@@ -160,23 +134,20 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.lpszClassName = szClass; wcex.lpszClassName = szClass;
wcex.hIconSm = hIconSmall; wcex.hIconSm = hIconSmall;
if (!RegisterClassExW(&wcex)) if (!RegisterClassExW(&wcex)) {
{
ShowError(IDS_ERR_CLASS, szTitle); ShowError(IDS_ERR_CLASS, szTitle);
return -9; return -9;
} }
HWND hMainWnd = CreateWindowExW(0, szClass, szTitle, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); HWND hMainWnd = CreateWindowExW(0, szClass, szTitle, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
if (!hMainWnd) if (!hMainWnd) {
{
ShowError(IDS_ERR_WND, szTitle); ShowError(IDS_ERR_WND, szTitle);
return -8; return -8;
} }
#ifndef _DEBUG #ifndef _DEBUG
HHOOK hMouseHook = SetWindowsHookExW(WH_MOUSE_LL, MouseHookProc, GetModuleHandleW(NULL), NULL); HHOOK hMouseHook = SetWindowsHookExW(WH_MOUSE_LL, MouseHookProc, GetModuleHandleW(NULL), NULL);
if (!hMouseHook) if (!hMouseHook) {
{
logger.Out(L"%s(%d): Mouse hook creation failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Mouse hook creation failed!", TEXT(__FUNCTION__), __LINE__);
ShowError(IDS_ERR_HOOK, szTitle); ShowError(IDS_ERR_HOOK, szTitle);
@@ -186,8 +157,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
#endif // !_DEBUG #endif // !_DEBUG
HHOOK hKbdHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleW(NULL), NULL); HHOOK hKbdHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleW(NULL), NULL);
if (!hKbdHook) if (!hKbdHook) {
{
logger.Out(L"%s(%d): Keyboard hook creation failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Keyboard hook creation failed!", TEXT(__FUNCTION__), __LINE__);
ShowError(IDS_ERR_HOOK, szTitle); ShowError(IDS_ERR_HOOK, szTitle);
@@ -196,8 +166,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
logger.Out(L"%s(%d): The keyboard hook was successfully installed", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The keyboard hook was successfully installed", TEXT(__FUNCTION__), __LINE__);
HMENU hMenu = LoadMenuW(hInstance, MAKEINTRESOURCE(IDR_MENU)); HMENU hMenu = LoadMenuW(hInstance, MAKEINTRESOURCE(IDR_MENU));
if (!hMenu) if (!hMenu) {
{
logger.Out(L"%s(%d): Loading context menu failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Loading context menu failed!", TEXT(__FUNCTION__), __LINE__);
ShowError(IDS_ERR_MENU, szTitle); ShowError(IDS_ERR_MENU, szTitle);
return -5; return -5;
@@ -205,8 +174,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
logger.Out(L"%s(%d): Context menu successfully loaded", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Context menu successfully loaded", TEXT(__FUNCTION__), __LINE__);
hPopup = GetSubMenu(hMenu, 0); hPopup = GetSubMenu(hMenu, 0);
if (!hPopup) if (!hPopup) {
{
logger.Out(L"%s(%d): Creating popup menu failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Creating popup menu failed!", TEXT(__FUNCTION__), __LINE__);
ShowError(IDS_ERR_POPUP, szTitle); ShowError(IDS_ERR_POPUP, szTitle);
return -4; return -4;
@@ -223,15 +191,13 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
HANDLE hHeap = GetProcessHeap(); HANDLE hHeap = GetProcessHeap();
szWinTitleBuffer = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, MAX_WINTITLE_BUFFER_LENGTH); szWinTitleBuffer = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, MAX_WINTITLE_BUFFER_LENGTH);
if (nullptr == szWinTitleBuffer) if (nullptr == szWinTitleBuffer) {
{
ShowError(IDS_ERR_HEAP, szTitle); ShowError(IDS_ERR_HEAP, szTitle);
return -3; return -3;
} }
szWinClassBuffer = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, MAX_WINTITLE_BUFFER_LENGTH); szWinClassBuffer = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, MAX_WINTITLE_BUFFER_LENGTH);
if (nullptr == szWinClassBuffer) if (nullptr == szWinClassBuffer) {
{
ShowError(IDS_ERR_HEAP, szTitle); ShowError(IDS_ERR_HEAP, szTitle);
return -2; return -2;
} }
@@ -239,15 +205,12 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
MSG msg; MSG msg;
BOOL bRet; BOOL bRet;
while ((bRet = GetMessageW(&msg, NULL, 0, 0)) != 0) while ((bRet = GetMessageW(&msg, NULL, 0, 0)) != 0) {
{ if (bRet == -1) {
if (bRet == -1)
{
ShowError(IDS_ERR_MAIN, szTitle); ShowError(IDS_ERR_MAIN, szTitle);
return -1; return -1;
} }
else else {
{
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessageW(&msg); DispatchMessageW(&msg);
} }
@@ -265,15 +228,13 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmd
HeapFree(hHeap, NULL, szWinClassBuffer); HeapFree(hHeap, NULL, szWinClassBuffer);
HeapFree(hHeap, NULL, szWinTitleBuffer); HeapFree(hHeap, NULL, szWinTitleBuffer);
logger.Out(L"Exit from the %s() function, msg.wParam = 0x%0*tX", TEXT(__FUNCTION__), (sizeof(int) * 2), static_cast<int>(msg.wParam)); logger.Out(L"Exit from the %s() function, msg.wParam = 0x%0*tX", TEXT(__FUNCTION__), (sizeof(UINT_PTR) * 2), static_cast<UINT_PTR>(msg.wParam));
return static_cast<int>(msg.wParam); return static_cast<UINT_PTR>(msg.wParam);
} }
LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lParam) {
{ switch (message) {
switch (message)
{
case WM_CREATE: case WM_CREATE:
{ {
logger.Out(L"%s(%d): Recived WM_CREATE message", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Recived WM_CREATE message", TEXT(__FUNCTION__), __LINE__);
@@ -288,14 +249,12 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
StringCchCopyW(nid.szTip, _countof(nid.szTip), szTitle); StringCchCopyW(nid.szTip, _countof(nid.szTip), szTitle);
uMsgRestore = RegisterWindowMessageW(L"TaskbarCreated"); uMsgRestore = RegisterWindowMessageW(L"TaskbarCreated");
if (!uMsgRestore) if (!uMsgRestore) {
{
logger.Out(L"%s(%d): Registering 'TaskbarCreated' message failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Registering 'TaskbarCreated' message failed!", TEXT(__FUNCTION__), __LINE__);
} }
logger.Out(L"%s(%d): The 'TaskbarCreated' message successfully registered", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The 'TaskbarCreated' message successfully registered", TEXT(__FUNCTION__), __LINE__);
if (fCheckUpdates) if (fCheckUpdates) {
{
if (!SetTimer(hMainWnd, IDT_TIMER, (T1 * 1000 - T0 * 1000), NULL)) // 50 seconds if (!SetTimer(hMainWnd, IDT_TIMER, (T1 * 1000 - T0 * 1000), NULL)) // 50 seconds
{ {
logger.Out(L"%s(%d): Creating timer failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Creating timer failed!", TEXT(__FUNCTION__), __LINE__);
@@ -309,18 +268,15 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
case WM_TIMER: case WM_TIMER:
{ {
if (fCheckUpdates) if (fCheckUpdates) {
{
logger.Out(L"%s(%d): Checking for updates is enabled", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Checking for updates is enabled", TEXT(__FUNCTION__), __LINE__);
HANDLE hUpdater = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &Updater, NULL, 0, NULL)); HANDLE hUpdater = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &Updater, NULL, 0, NULL));
if (NULL == hUpdater) if (NULL == hUpdater) {
{
DWORD dwLastError = GetLastError(); DWORD dwLastError = GetLastError();
logger.Out(L"%s(%d): Creating Updater thread failed! Error: %d", TEXT(__FUNCTION__), __LINE__, dwLastError); logger.Out(L"%s(%d): Creating Updater thread failed! Error: %d", TEXT(__FUNCTION__), __LINE__, dwLastError);
} }
else else {
{
if (!SetTimer(hMainWnd, IDT_TIMER, (T2 * 1000), NULL)) // 1 day if (!SetTimer(hMainWnd, IDT_TIMER, (T2 * 1000), NULL)) // 1 day
{ {
logger.Out(L"%s(%d): Creating timer failed!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Creating timer failed!", TEXT(__FUNCTION__), __LINE__);
@@ -331,17 +287,16 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
CloseHandle(hUpdater); CloseHandle(hUpdater);
} }
} }
else else {
{
logger.Out(L"%s(%d): Checking for updates is disabled", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Checking for updates is disabled", TEXT(__FUNCTION__), __LINE__);
} }
break; break;
} }
case WM_WCW: // Popup menu handler // Popup menu handler
{ case WM_WCW:
if (WM_CONTEXTMENU == LOWORD(lParam))
{ {
if (WM_CONTEXTMENU == LOWORD(lParam)) {
logger.Out(L"%s(%d): Recived WM_CONTEXTMENU message", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Recived WM_CONTEXTMENU message", TEXT(__FUNCTION__), __LINE__);
POINT pt{ GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam) }; POINT pt{ GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam) };
@@ -353,9 +308,9 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
case WM_COMMAND: case WM_COMMAND:
{ {
int wmId = LOWORD(wParam); int wmId = LOWORD(wParam);
// Parse the menu selections: // Parse the menu selections:
switch (wmId) switch (wmId) {
{
case ID_POPUPMENU_ICON: case ID_POPUPMENU_ICON:
{ {
logger.Out(L"%s(%d): Pressed the 'Hide icon' menuitem", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed the 'Hide icon' menuitem", TEXT(__FUNCTION__), __LINE__);
@@ -376,8 +331,7 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
} }
case ID_POPUPMENU_HELP: case ID_POPUPMENU_HELP:
{ {
if (!bKPressed) if (!bKPressed) {
{
logger.Out(L"%s(%d): Pressed the 'Help' menuitem", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed the 'Help' menuitem", TEXT(__FUNCTION__), __LINE__);
bKPressed = TRUE; bKPressed = TRUE;
@@ -390,12 +344,36 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
} }
case ID_POPUPMENU_ABOUT: case ID_POPUPMENU_ABOUT:
{ {
if (!bKPressed) if (!bKPressed) {
{
logger.Out(L"%s(%d): Pressed the 'About' menuitem", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed the 'About' menuitem", TEXT(__FUNCTION__), __LINE__);
bKPressed = TRUE; bKPressed = TRUE;
DialogBoxParamW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDD_ABOUTBOX), hMainWnd, static_cast<DLGPROC>(About), 0L); WCHAR szContent[MAX_LOADSTRING * 6] = { 0 };
StringCchPrintfW(szContent, ARRAYSIZE(szContent),
L"%s\n%s\n\n%s\n%s\n%s",
TEXT(PRODUCT_COPYRIGHT),
L"Program icon made by Kirill Topov.",
L"This software is licensed under a <A HREF=\"https://mit-license.org\">MIT License</A>.",
L"This software uses the <A HREF=\"https://github.com/kazuho/picojson\">PicoJSON</A> - a C++ JSON parser/serializer by Kazuho Oku.",
#ifndef NO_DONATION
L"\n<A HREF=\"https://www.paypal.com/paypalme/VladislavSalikov\">Donate via PayPal</A>"
#else
L""
#endif // !NO_DONATION
);
TASKDIALOGCONFIG tdc = { 0 };
tdc.cbSize = sizeof(tdc);
tdc.hInstance = GetModuleHandleW(NULL);
tdc.dwFlags = TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_USE_HICON_MAIN | TDF_SIZE_TO_CONTENT;
tdc.dwCommonButtons = TDCBF_OK_BUTTON;
tdc.pszWindowTitle = L"About";
tdc.hMainIcon = hIconLarge;
tdc.pszMainInstruction = TEXT(PRODUCT_NAME_FULL);
tdc.pszContent = szContent;
tdc.pfCallback = AboutCallback;
TaskDialogIndirect(&tdc, NULL, NULL, NULL);
bKPressed = FALSE; bKPressed = FALSE;
} }
break; break;
@@ -430,10 +408,10 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
default: default:
{ {
if (message == uMsgRestore) if (message == uMsgRestore) {
{ logger.Out(L"%s(%d): Recieved the 'TaskbarCreated' message", TEXT(__FUNCTION__), __LINE__);
Shell_NotifyIconW(NIM_DELETE, &nid);
Shell_NotifyIconW(NIM_ADD, &nid); HandlingTrayIcon();
break; break;
} }
return DefWindowProcW(hMainWnd, message, wParam, lParam); return DefWindowProcW(hMainWnd, message, wParam, lParam);
@@ -442,11 +420,9 @@ LRESULT CALLBACK WndProc(HWND hMainWnd, UINT message, WPARAM wParam, LPARAM lPar
return 0; return 0;
} }
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
{
if (WM_MBUTTONUP == wParam) bMPressed = FALSE; if (WM_MBUTTONUP == wParam) bMPressed = FALSE;
if (WM_MBUTTONDOWN == wParam && bLCTRL && bLWIN && !bMPressed) if (WM_MBUTTONDOWN == wParam && bLCTRL && bLWIN && !bMPressed) {
{
logger.Out(L"%s(%d): Pressed LCTRL + LWIN + MMB", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed LCTRL + LWIN + MMB", TEXT(__FUNCTION__), __LINE__);
bMPressed = TRUE; bMPressed = TRUE;
@@ -457,24 +433,21 @@ LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(NULL, nCode, wParam, lParam); return CallNextHookEx(NULL, nCode, wParam, lParam);
} }
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
{
LPKBDLLHOOKSTRUCT pkhs = { 0 }; LPKBDLLHOOKSTRUCT pkhs = { 0 };
pkhs = reinterpret_cast<LPKBDLLHOOKSTRUCT>(lParam); pkhs = reinterpret_cast<LPKBDLLHOOKSTRUCT>(lParam);
if (WM_KEYUP == wParam) if (WM_KEYUP == wParam) {
{
if (VK_LCONTROL == pkhs->vkCode) bLCTRL = FALSE; if (VK_LCONTROL == pkhs->vkCode) bLCTRL = FALSE;
if (VK_LWIN == pkhs->vkCode) bLWIN = FALSE; if (VK_LWIN == pkhs->vkCode) bLWIN = FALSE;
bKPressed = FALSE; bKPressed = FALSE;
} }
if (WM_KEYDOWN == wParam) if (WM_KEYDOWN == wParam) {
{
if (VK_LCONTROL == pkhs->vkCode) bLCTRL = TRUE; if (VK_LCONTROL == pkhs->vkCode) bLCTRL = TRUE;
if (VK_LWIN == pkhs->vkCode) bLWIN = TRUE; if (VK_LWIN == pkhs->vkCode) bLWIN = TRUE;
if (KEY_I == pkhs->vkCode && bLCTRL && bLWIN && !bKPressed) // 'I' key // 'I' key
{ if (KEY_I == pkhs->vkCode && bLCTRL && bLWIN && !bKPressed) {
logger.Out(L"%s(%d): Pressed LCTRL + LWIN + I", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed LCTRL + LWIN + I", TEXT(__FUNCTION__), __LINE__);
bKPressed = TRUE; bKPressed = TRUE;
@@ -483,8 +456,8 @@ LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
return TRUE; return TRUE;
} }
if (KEY_C == pkhs->vkCode && bLCTRL && bLWIN && !bKPressed && !bKEYV) // 'C' key // 'C' key
{ if (KEY_C == pkhs->vkCode && bLCTRL && bLWIN && !bKPressed && !bKEYV) {
logger.Out(L"%s(%d): Pressed LCTRL + LWIN + C", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed LCTRL + LWIN + C", TEXT(__FUNCTION__), __LINE__);
bKPressed = TRUE; bKPressed = TRUE;
@@ -494,14 +467,13 @@ LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
return TRUE; return TRUE;
} }
if (KEY_V == pkhs->vkCode && bLCTRL && bLWIN && !bKPressed && !bKEYV) // 'V' key // 'V' key
{ if (KEY_V == pkhs->vkCode && bLCTRL && bLWIN && !bKPressed && !bKEYV) {
logger.Out(L"%s(%d): Pressed LCTRL + LWIN + V", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed LCTRL + LWIN + V", TEXT(__FUNCTION__), __LINE__);
bKPressed = TRUE; bKEYV = TRUE; bKPressed = TRUE; bKEYV = TRUE;
hFgWnd = GetForegroundWindow(); hFgWnd = GetForegroundWindow();
if (IsWindowApprooved(hFgWnd)) if (IsWindowApprooved(hFgWnd)) {
{
logger.Out(L"%s(%d): Opening the 'Manual editing' dialog", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Opening the 'Manual editing' dialog", TEXT(__FUNCTION__), __LINE__);
DialogBoxParamW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDD_MANUAL_EDITING), hFgWnd, static_cast<DLGPROC>(DlgProc), 0L); DialogBoxParamW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(IDD_MANUAL_EDITING), hFgWnd, static_cast<DLGPROC>(DlgProc), 0L);
@@ -515,12 +487,10 @@ LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(NULL, nCode, wParam, lParam); return CallNextHookEx(NULL, nCode, wParam, lParam);
} }
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT dlgmsg, WPARAM wParam, LPARAM lParam) INT_PTR CALLBACK DlgProc(HWND hDlg, UINT dlgmsg, WPARAM wParam, LPARAM lParam) {
{
RECT rcFW = { 0 }; RECT rcFW = { 0 };
int x, y, w, h; int x, y, w, h;
switch (dlgmsg) switch (dlgmsg) {
{
case WM_INITDIALOG: case WM_INITDIALOG:
{ {
logger.Out(L"%s(%d): Initializing the 'Manual editing' dialog", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Initializing the 'Manual editing' dialog", TEXT(__FUNCTION__), __LINE__);
@@ -544,8 +514,7 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT dlgmsg, WPARAM wParam, LPARAM lParam)
case WM_COMMAND: case WM_COMMAND:
{ {
switch (LOWORD(wParam)) switch (LOWORD(wParam)) {
{
case IDC_BUTTON_SET: case IDC_BUTTON_SET:
{ {
logger.Out(L"%s(%d): Pressed the 'Set' button", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Pressed the 'Set' button", TEXT(__FUNCTION__), __LINE__);
@@ -588,47 +557,38 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT dlgmsg, WPARAM wParam, LPARAM lParam)
return static_cast<INT_PTR>(FALSE); return static_cast<INT_PTR>(FALSE);
} }
BOOL IsWindowApprooved(HWND hFW) BOOL IsWindowApprooved(HWND hFW) {
{
logger.Out(L"Entering the %s() function", TEXT(__FUNCTION__)); logger.Out(L"Entering the %s() function", TEXT(__FUNCTION__));
BOOL bApprooved = FALSE; BOOL bApprooved = FALSE;
if (hFW) if (hFW) {
{ if (GetWindowTextW(hFW, reinterpret_cast<LPWSTR>(szWinTitleBuffer), MAX_WINTITLE_BUFFER_LENGTH)) {
if (GetWindowTextW(hFW, reinterpret_cast<LPWSTR>(szWinTitleBuffer), MAX_WINTITLE_BUFFER_LENGTH))
{
logger.Out(L"%s(%d): Window handle: 0x%p. Title: '%s'", TEXT(__FUNCTION__), __LINE__, hFW, reinterpret_cast<LPWSTR>(szWinTitleBuffer)); logger.Out(L"%s(%d): Window handle: 0x%p. Title: '%s'", TEXT(__FUNCTION__), __LINE__, hFW, reinterpret_cast<LPWSTR>(szWinTitleBuffer));
} }
if (IsIconic(hFW)) if (IsIconic(hFW)) {
{
logger.Out(L"%s(%d): The window is iconified", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The window is iconified", TEXT(__FUNCTION__), __LINE__);
} }
if (IsZoomed(hFW)) if (IsZoomed(hFW)) {
{
logger.Out(L"%s(%d): The window is maximized", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The window is maximized", TEXT(__FUNCTION__), __LINE__);
} }
LONG_PTR wlp = GetWindowLongPtrW(hFW, GWL_STYLE); LONG_PTR wlp = GetWindowLongPtrW(hFW, GWL_STYLE);
if (wlp & WS_CAPTION) if (wlp & WS_CAPTION) {
{ if (!IsIconic(hFW) && !IsZoomed(hFW)) {
if (!IsIconic(hFW) && !IsZoomed(hFW))
{
logger.Out(L"%s(%d): The window is approved!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The window is approved!", TEXT(__FUNCTION__), __LINE__);
bApprooved = TRUE; bApprooved = TRUE;
} }
else ShowError(IDS_ERR_MAXMIN, szTitle); else ShowError(IDS_ERR_MAXMIN, szTitle);
} }
else else {
{
logger.Out(L"%s(%d): The window has no caption!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The window has no caption!", TEXT(__FUNCTION__), __LINE__);
} }
} }
if (!bApprooved) if (!bApprooved) {
{
logger.Out(L"%s(%d): The window is not approved!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): The window is not approved!", TEXT(__FUNCTION__), __LINE__);
} }
@@ -637,20 +597,17 @@ BOOL IsWindowApprooved(HWND hFW)
return bApprooved; return bApprooved;
} }
VOID HandlingTrayIcon() VOID HandlingTrayIcon() {
{
logger.Out(L"Entering the %s() function, fShowIcon = %s", TEXT(__FUNCTION__), fShowIcon ? L"True" : L"False"); logger.Out(L"Entering the %s() function, fShowIcon = %s", TEXT(__FUNCTION__), fShowIcon ? L"True" : L"False");
if (fShowIcon) if (fShowIcon) {
{
BOOL bResult1 = Shell_NotifyIconW(NIM_ADD, &nid); BOOL bResult1 = Shell_NotifyIconW(NIM_ADD, &nid);
logger.Out(L"%s(%d): Shell_NotifyIconW(NIM_ADD) returned %s", TEXT(__FUNCTION__), __LINE__, bResult1 ? L"True" : L"False"); logger.Out(L"%s(%d): Shell_NotifyIconW(NIM_ADD) returned %s", TEXT(__FUNCTION__), __LINE__, bResult1 ? L"True" : L"False");
BOOL bResult2 = Shell_NotifyIconW(NIM_SETVERSION, &nid); BOOL bResult2 = Shell_NotifyIconW(NIM_SETVERSION, &nid);
logger.Out(L"%s(%d): Shell_NotifyIconW(NIM_SETVERSION) returned %s", TEXT(__FUNCTION__), __LINE__, bResult2 ? L"True" : L"False"); logger.Out(L"%s(%d): Shell_NotifyIconW(NIM_SETVERSION) returned %s", TEXT(__FUNCTION__), __LINE__, bResult2 ? L"True" : L"False");
if (!bResult1 || !bResult2) if (!bResult1 || !bResult2) {
{
logger.Out(L"%s(%d): Error creating trayicon!", TEXT(__FUNCTION__), __LINE__); logger.Out(L"%s(%d): Error creating trayicon!", TEXT(__FUNCTION__), __LINE__);
ShowError(IDS_ERR_ICON, szTitle); ShowError(IDS_ERR_ICON, szTitle);
@@ -658,23 +615,20 @@ VOID HandlingTrayIcon()
fShowIcon = FALSE; fShowIcon = FALSE;
} }
} }
else else {
{
Shell_NotifyIconW(NIM_DELETE, &nid); Shell_NotifyIconW(NIM_DELETE, &nid);
} }
logger.Out(L"Exit from the %s() function", TEXT(__FUNCTION__)); logger.Out(L"Exit from the %s() function", TEXT(__FUNCTION__));
} }
VOID ShowError(UINT uID, LPCWSTR szAppTitle) VOID ShowError(UINT uID, LPCWSTR szAppTitle) {
{
WCHAR szErrorText[MAX_LOADSTRING]; // Error's text WCHAR szErrorText[MAX_LOADSTRING]; // Error's text
LoadStringW(GetModuleHandleW(NULL), uID, szErrorText, _countof(szErrorText)); LoadStringW(GetModuleHandleW(NULL), uID, szErrorText, _countof(szErrorText));
MessageBoxW(hFgWnd, szErrorText, szAppTitle, MB_OK | MB_ICONERROR | MB_TOPMOST); MessageBoxW(hFgWnd, szErrorText, szAppTitle, MB_OK | MB_ICONERROR | MB_TOPMOST);
} }
VOID ShowPopupMenu(HWND hMainWnd, POINT pt) VOID ShowPopupMenu(HWND hMainWnd, POINT pt) {
{
SetForegroundWindow(hMainWnd); SetForegroundWindow(hMainWnd);
UINT uFlags = TPM_RIGHTBUTTON; UINT uFlags = TPM_RIGHTBUTTON;
GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0 ? uFlags |= TPM_RIGHTALIGN : uFlags |= TPM_LEFTALIGN; GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0 ? uFlags |= TPM_RIGHTALIGN : uFlags |= TPM_LEFTALIGN;
@@ -682,72 +636,9 @@ VOID ShowPopupMenu(HWND hMainWnd, POINT pt)
PostMessageW(hMainWnd, WM_NULL, 0, 0); PostMessageW(hMainWnd, WM_NULL, 0, 0);
} }
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) HRESULT CALLBACK AboutCallback(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) {
{ if (TDN_HYPERLINK_CLICKED == uMsg) {
INITCOMMONCONTROLSEX icex = { 0 }; ShellExecuteW(hDlg, L"open", reinterpret_cast<LPCWSTR>(lParam), NULL, NULL, SW_SHOW);
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_LINK_CLASS;
InitCommonControlsEx(&icex);
switch (message)
{
case WM_INITDIALOG:
{
logger.Out(L"%s(%d): Initializing the 'About' dialog", TEXT(__FUNCTION__), __LINE__);
WCHAR szAboutProgName[MAX_LOADSTRING];
WCHAR szAboutCopyright[MAX_LOADSTRING];
WCHAR szAboutBuildTime[MAX_LOADSTRING];
WCHAR szAboutLicense[MAX_LOADSTRING * 22];
LoadStringW(GetModuleHandleW(NULL), IDS_LICENSE, szAboutLicense, _countof(szAboutLicense));
MultiByteToWideChar(1251, 0, PRODUCT_NAME_FULL, _countof(PRODUCT_NAME_FULL), szAboutProgName, MAX_LOADSTRING);
MultiByteToWideChar(1251, 0, PRODUCT_COPYRIGHT, _countof(PRODUCT_COPYRIGHT), szAboutCopyright, MAX_LOADSTRING);
MultiByteToWideChar(1251, 0, ABOUT_BUILD, _countof(ABOUT_BUILD), szAboutBuildTime, MAX_LOADSTRING);
SetDlgItemTextW(hDlg, IDC_ABOUT_PROGNAME, szAboutProgName);
SetDlgItemTextW(hDlg, IDC_ABOUT_COPYRIGHT, szAboutCopyright);
SetDlgItemTextW(hDlg, IDC_ABOUT_BUILDTIME, szAboutBuildTime);
SetDlgItemTextW(hDlg, IDC_ABOUTEDIT, szAboutLicense);
#ifdef NO_DONATION
HWND hLink = GetDlgItem(hDlg, IDC_DONATIONLINK);
if (hLink) DestroyWindow(hLink);
HWND hText = GetDlgItem(hDlg, IDC_DONATIONTEXT);
if (hText) DestroyWindow(hText);
#endif // !NO_DONATION
logger.Out(L"%s(%d): End of initializing the 'About' dialog", TEXT(__FUNCTION__), __LINE__);
return static_cast<INT_PTR>(TRUE);
break;
} }
return S_OK;
case WM_NOTIFY:
{
LPNMHDR pNMHdr = (LPNMHDR)lParam;
if ((NM_CLICK == pNMHdr->code || NM_RETURN == pNMHdr->code) && IDC_DONATIONLINK == pNMHdr->idFrom)
{
PNMLINK pNMLink = (PNMLINK)pNMHdr;
LITEM item = pNMLink->item;
ShellExecuteW(NULL, L"open", item.szUrl, NULL, NULL, SW_SHOW);
logger.Out(L"%s(%d): Pressed the donation link! :-)", TEXT(__FUNCTION__), __LINE__);
return static_cast<INT_PTR>(TRUE);
}
break;
}
case WM_COMMAND:
{
if (IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam))
{
EndDialog(hDlg, LOWORD(wParam));
logger.Out(L"%s(%d): Closing the 'About' dialog", TEXT(__FUNCTION__), __LINE__);
return static_cast<INT_PTR>(TRUE);
}
break;
}
}
return static_cast<INT_PTR>(FALSE);
} }

View File

@@ -1,25 +1,3 @@
// MIT License
//
// Copyright (c) 2023 W0LF aka 'dreamforce'
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// wCenterWindow // wCenterWindow
// wCenterWindow.h // wCenterWindow.h
@@ -36,7 +14,7 @@
#define ARCH 86 #define ARCH 86
#endif #endif
#define MAX_LOADSTRING 50 #define MAX_LOADSTRING 64
// Windows Header Files // Windows Header Files
#include <fstream> #include <fstream>

Binary file not shown.

View File

@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments> <LocalDebuggerCommandArguments>/noupdate</LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -11,8 +10,7 @@
</LocalDebuggerCommandArguments> </LocalDebuggerCommandArguments>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments> <LocalDebuggerCommandArguments>/noupdate</LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">