Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 17)
project(close_window LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(close_window main.cpp)
target_compile_definitions(close_window PRIVATE UNICODE _UNICODE)
@@ -0,0 +1,11 @@
# Simple application to simulate application termination by MSI
This is a simple application that sends the Window messages `WM_QUERYENDSESSION` and `WM_ENDSESSION` to all windows of an application.
Those messages are sent by MSI when a current running application should quit.
Qt 5 handles those window messages incorrect causing our client to close, with this application the behaviour can be validated.
## Use
```
close_window.exe qsfera.exe
```
If invoked without an argument it will try to close qsfera.exe
@@ -0,0 +1,92 @@
#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
#include <memory>
#include <vector>
PROCESSENTRY32W getProcess(std::wstring_view name) {
std::unique_ptr<HANDLE,decltype(&CloseHandle)> snapShot(new HANDLE, &CloseHandle);
*snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
PROCESSENTRY32W pEntry = {};
pEntry.dwSize = sizeof( pEntry );
BOOL ok = Process32FirstW(*snapShot, &pEntry);
while (ok)
{
if (name == pEntry.szExeFile)
{
std::wcout << pEntry.szExeFile << " " << pEntry.th32ProcessID << std::endl;
return pEntry;
}
ok = Process32NextW(*snapShot, &pEntry);
}
return {};
}
std::wstring getWindowTitle(HWND hwnd) {
std::wstring buf(1024, '\0');
const auto size = GetWindowTextW(hwnd, buf.data(), buf.size());
if (!size) {
return {};
}
buf.resize(size);
return buf;
}
struct WindowData {
WindowData(DWORD pid)
: pid(pid)
{}
DWORD pid;
std::vector<HWND> windows;
};
WindowData getHWND(DWORD pid) {
WindowData data(pid);
EnumWindows([](HWND hwnd,LPARAM lParam) -> BOOL{
WindowData* data = reinterpret_cast<WindowData*>(lParam);
DWORD lpdwProcessId;
GetWindowThreadProcessId(hwnd,&lpdwProcessId);
if(lpdwProcessId==data->pid)
{
data->windows.push_back(hwnd);
std::wcout << data->pid << " " << hwnd << std::endl;
}
return true;
}, reinterpret_cast<LPARAM>(&data));
return data;
}
WindowData getHWND(std::wstring_view name) {
std::wcout << name << std::endl;
auto process = getProcess(name);
return getHWND(process.th32ProcessID);
}
template <class T>
void broadcast(const WindowData &dest, UINT msg, WPARAM wParam,T lParam) {
for (const auto w : dest.windows) {
auto result = SendMessageW(w, msg, wParam, reinterpret_cast<LPARAM>(&lParam));
std::wcout << "Window: " << getWindowTitle(w) << " HWND: " << w << " Result: " << result << std::endl;
}
}
int main()
{
const auto commandLine = GetCommandLineW();
int argc;
wchar_t **argv = CommandLineToArgvW(commandLine, &argc);
const auto process = getHWND(argc == 2 ? argv[1] : L"qsfera.exe");
// const auto process = getHWND(L"WINDOW_TEST.exe");
std::wcout << "Query: WM_QUERYENDSESSION" << std::endl;
broadcast(process, WM_QUERYENDSESSION, 0, ENDSESSION_CLOSEAPP);
std::wcout << "Kill: WM_ENDSESSION" << std::endl;
broadcast(process, WM_ENDSESSION, 1, ENDSESSION_CLOSEAPP);
return 0;
}