正确枚举 Winlogon 桌面窗口层次

目录

前言

原理解释

原理实现

 Winlogon 桌面窗口层次


本文出处链接:https://blog.csdn.net/qq_59075481/article/details/141608316

前言

众所周知,从 Windows 7 开始,Winlogon 桌面不再使用 SASWindow 作为背景窗口,而是采用了一套新的安全桌面模式。我发现 CSDN 上在这方面的研究很少。

在我前面的几篇文章里面已经详细分析并实现了,编程化拦截与 Winlogon 有关的登陆事件(如 Ctrl + Alt + Delete 快捷键)。在之前,我浅谈过一些有关 LogonUI Interface 登陆 UI 界面的内容,但并未做详细的解释。这篇文章将就如何动态枚举 Winlogon 桌面的窗口层次并进行记录进行详细的讲解。如有错误,敬请点拨。

专栏文章:

快捷键机制系列文章 | 涟幽 516icon-default.png?t=O83Ahttps://blog.csdn.net/qq_59075481/category_12568641.html

原理解释

首先,我们需要知道 Winlogon 桌面(登陆桌面,运行在控制台会话)和 Default 桌面(用户默认桌面,运行在 UI 会话)均是由 Winlogon.exe 所创建的。

Winlogon.exe 是 Windows 操作系统中负责处理用户登录和注销等会话管理功能的进程。通常情况下,每个控制台会话(即本地会话)会有一个对应的 Winlogon.exe 实例,用于处理用户认证等任务。

UI 会话 是指用户交互的会话,通常指的是图形用户界面(GUI)环境下的桌面会话。每个用户登录到系统时,Windows 会为该用户分配一个会话 ID,并启动一个桌面环境来处理用户的输入和输出。

在多用户环境中,每个用户的 UI 会话可以与一个特定的控制台会话关联。控制台会话是指直接连接到物理屏幕、键盘和鼠标的会话(如通过直接本地登录),而其他 UI 会话则可能是通过远程桌面或其他方式登录的。

所以,用户一般接触最多的就是交互式用户会话和桌面,对于 Winlogon 桌面可能知之甚少。其实用户所熟知的 UAC 对话框,就是运行在 Winlogon 桌面下的系统程序所创建的窗口。

UAC 对话框界面

LogonUI.exe 进程:这是登陆用户交互式界面进程,Winlogon.exe 进程会在需要在登陆桌面下显示交互式界面时,启动该进程。并通过进程间通信(IPC)技术,如管道、RPC 等完成多进程同步事务。用户看到的登陆界面、CAD 界面、UAC 界面均最终由它启动。

LogonUI 运行时模块:LogonUI.exe 实质上是一个加载容器,用于装载运行时需要的接口模块。第一个加载的模块为:LogonUIController.dll。其他运行时模块通过延迟加载技术完成加载。

窗口工作站:窗口工作站是与进程关联的安全对象,包含一个或多个绑定的桌面对象、剪贴板等等。Winlogon 桌面和 Default 桌面默认运行在 Winsta0 窗口工作站下。进程必须以合适的访问权限打开窗口工作站,才能够打开指定的桌面访问句柄。进程每次获取的窗口工作站的访问句柄不同,桌面的访问句柄就不同。如果需要获知对象句柄的名称,则需要通过 WINAPI GetUserObjectInformation。

工作线程:进程连接到窗口工作站后,系统会将桌面分配给建立连接的线程。 

为了在运行时研究清楚 Winlogon 桌面有哪些窗口,就必须切换程序的工作线程然后枚举活动桌面的窗口。

登陆界面示例

频繁切换工作线程绑定的桌面是不被允许的,因为 SetThreadDesktop 之前不能有任何桌面窗口服务正在运作(微软说会造成安全问题)。在实际测试过程当中,我们发现连续第二次切换时就会引起失败。但是我们又需要进行动态监测,所以必须要每次都能够及时切换工作线程的桌面。解决方案很简单,就是每次切换时创建一个新的线程作为工作线程,然后在新的线程里面切换桌面。

然后,打开窗口工作站和桌面需要 SYSTEM 令牌的 Local System 权限,所以必须首先以管理员身份运行,然后再从 SYSTEM 进程复制模拟令牌来重新启动高权限进程。

然后,枚举窗口这边也很简单,通过 EnumWindows 和 EnumChildWindows 枚举并保存窗口层次。

至于桌面的切换检测,最简单的就是通过一个循环不断去获取当前活动桌面(ActiveDesktop),主要通过 OpenInputDesktop 来获取,然后分析桌面名称,当桌面切换到 Winlogon 桌面时切换线程并遍历桌面窗口,当桌面切换到 Default 桌面时,停止记录并保存日志;

原理实现

下面代码在主要登录用户的管理员账户下运行一切正常:

#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>
#include <sstream>
#include <codecvt>
#include <functional>
#include <tlhelp32.h>
#include <userenv.h>
#include <sddl.h>

// 记录窗口信息的结构体,使用宽字符
struct WindowInfo {
    std::wstring className;
    std::wstring windowTitle;
    HWND hwnd;
    std::vector<WindowInfo> children;
};

// 工作线程传递信息的结构体
struct MYTHREADINFO {
    HDESK hDesktop;
    std::vector<WindowInfo> wndInfo;
};

// 启用特定的权限(例如 SeDebugPrivilege)
bool EnablePrivilege(LPCWSTR privilege) {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token." << std::endl;
        return false;
    }

    if (!LookupPrivilegeValueW(NULL, privilege, &luid)) {
        std::wcerr << L"Failed to lookup privilege." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
        std::wcerr << L"Failed to adjust token privileges." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
        std::wcerr << L"The privilege was not assigned." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(hToken);
    return true;
}

// 检查是否以管理员权限运行
bool IsRunAsAdmin() {
    BOOL isAdmin = FALSE;
    PSID administratorsGroup = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) {
        CheckTokenMembership(NULL, administratorsGroup, &isAdmin);
        FreeSid(administratorsGroup);
    }
    return isAdmin == TRUE;
}

// 重新启动并请求管理员权限
bool RelaunchAsAdmin() {
    wchar_t szPath[MAX_PATH];
    if (!GetModuleFileNameW(NULL, szPath, MAX_PATH)) {
        std::wcerr << L"Failed to get module file name." << std::endl;
        return false;
    }

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpVerb = L"runas";  // 请求管理员权限
    sei.lpFile = szPath;
    sei.hwnd = NULL;
    sei.nShow = SW_NORMAL;

    if (!ShellExecuteExW(&sei)) {
        std::wcerr << L"Failed to relaunch as administrator." << std::endl;
        return false;
    }
    return true;
}

// 获取 winlogon 进程的 SYSTEM 令牌
HANDLE GetSystemTokenFromWinlogon() {
    HANDLE hToken = NULL;
    HANDLE hProcess = NULL;

    // 获取 Winlogon 进程的进程ID
    DWORD winlogonPid = 0;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnapshot == INVALID_HANDLE_VALUE) {
        std::wcerr << L"Failed to create process snapshot!" << std::endl;
        return NULL;
    }

    if (Process32First(hProcessSnapshot, &pe32)) {
        do {
            if (_wcsicmp(pe32.szExeFile, L"winlogon.exe") == 0) {
                winlogonPid = pe32.th32ProcessID;
                break;
            }
        } while (Process32Next(hProcessSnapshot, &pe32));
    }
    CloseHandle(hProcessSnapshot);

    if (winlogonPid == 0) {
        std::wcerr << L"Failed to find winlogon.exe process!" << std::endl;
        return NULL;
    }

    // 打开 Winlogon 进程
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, winlogonPid);
    if (!hProcess) {
        std::wcerr << L"Failed to open winlogon process!" << std::endl;
        return NULL;
    }

    // 打开该进程的令牌
    if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token!" << std::endl;
        CloseHandle(hProcess);
        return NULL;
    }

    CloseHandle(hProcess);
    return hToken;
}

// 创建具有 SYSTEM 权限的进程
bool CreateSystemProcess(LPCWSTR applicationName, LPCWSTR commandLine) {
    HANDLE hToken = GetSystemTokenFromWinlogon();
    if (!hToken) {
        std::wcerr << L"Failed to get SYSTEM token!" << std::endl;
        return false;
    }

    // 使用 SYSTEM 权限创建进程
    STARTUPINFOW si = { sizeof(STARTUPINFOW) };
    PROCESS_INFORMATION pi = { 0 };

    if (!CreateProcessAsUserW(hToken, applicationName, const_cast<LPWSTR>(commandLine), NULL,
        NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to create process as SYSTEM!" << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hToken);
    return true;
}

// 检查当前进程是否具有 SYSTEM 权限
bool IsSystem() {
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
        return false;
    }

    DWORD tokenInfoLength = 0;
    GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenInfoLength);

    PTOKEN_USER tokenUser = (PTOKEN_USER)malloc(tokenInfoLength);
    if (!GetTokenInformation(hToken, TokenUser, tokenUser, tokenInfoLength, &tokenInfoLength)) {
        CloseHandle(hToken);
        free(tokenUser);
        return false;
    }

    LPWSTR sidString = NULL;
    ConvertSidToStringSidW(tokenUser->User.Sid, &sidString);
    bool isSystem = (_wcsicmp(sidString, L"S-1-5-18") == 0);

    LocalFree(sidString);
    CloseHandle(hToken);
    free(tokenUser);

    return isSystem;
}

// 递归获取窗口层次,使用宽字符 API
void EnumChildWindowsRecursive(HWND hwndParent, std::vector<WindowInfo>& windowList) {
    wchar_t className[256];
    wchar_t windowTitle[256];

    ZeroMemory(className, sizeof(className));
    ZeroMemory(windowTitle, sizeof(windowTitle));

    // 获取窗口类名和标题
    GetClassNameW(hwndParent, className, sizeof(className) / sizeof(wchar_t));
    GetWindowTextW(hwndParent, windowTitle, sizeof(windowTitle) / sizeof(wchar_t));

    if (className[0] == L'\0') {
        wcscpy_s(className, L"(None)");
    }

    if (windowTitle[0] == L'\0') {
        wcscpy_s(windowTitle, L"(None)");
    }

    WindowInfo windowInfo = { className, windowTitle, hwndParent };

    // 枚举子窗口
    EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* children = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *children);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windowInfo.children));

    windowList.push_back(windowInfo);
}

// 获取当前桌面窗口层次,使用宽字符 API
std::vector<WindowInfo> GetWindowHierarchy() {
    std::vector<WindowInfo> windows;
    EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* windows = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *windows);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windows));
    return windows;
}

// 格式化时间为宽字符格式
std::wstring FormatTime(const std::time_t& time) {
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &time);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);
    return std::wstring(timeBuffer);
}

// 转换宽字符到 UTF-8
std::string WideToUTF8(const std::wstring& wideStr) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    return conv.to_bytes(wideStr);
}

// 保存窗口层次信息到文件,使用 UTF-8 编码
void SaveWindowHierarchy(const std::vector<WindowInfo>& windows, const std::time_t& changeTime, const std::wstring& filename) {
    std::ofstream file(WideToUTF8(filename), std::ios::app | std::ios::binary);  // 使用 binary 防止换行符的意外转换
    if (!file.is_open()) {
        std::wcerr << L"Unable to open file for writing!" << std::endl;
        return;
    }

    // 在文件开头写入 BOM,标识为 UTF-8 编码
    static bool bomWritten = false;
    if (!bomWritten) {
        const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };  // UTF-8 BOM
        file.write(reinterpret_cast<const char*>(bom), sizeof(bom));
        bomWritten = true;
    }

    // 格式化时间为字符串
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &changeTime);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);

    // 写入时间戳
    file << WideToUTF8(std::wstring(timeBuffer)) << "\n";

    // 递归写入窗口信息
    std::function<void(const std::vector<WindowInfo>&, int)> WriteHierarchy;
    WriteHierarchy = [&file, &WriteHierarchy](const std::vector<WindowInfo>& windows, int indent) {
        for (const auto& window : windows) {
            file << std::string(indent, ' ')  // 使用空格进行缩进
                << "Class Name: " << WideToUTF8(window.className)
                << ", Title: " << WideToUTF8(window.windowTitle)
                << ", HWND: " << std::hex << window.hwnd << "\n";
            if (!window.children.empty()) {
                WriteHierarchy(window.children, indent + 4);  // 递归写入子窗口信息
            }
        }
    };

    WriteHierarchy(windows, 0);
    file << "\n";
    file.close();
}

// 获取当前桌面的名称
std::wstring GetDesktopName(HDESK hDesktop) {
    wchar_t desktopName[256];
    DWORD neededLength = 0;

    if (!GetUserObjectInformationW(hDesktop, UOI_NAME, desktopName, sizeof(desktopName), &neededLength)) {
        std::wcerr << L"Failed to get desktop name." << std::endl;
        return L"";
    }

    return std::wstring(desktopName);
}


// 切换到指定桌面并枚举窗口,任务结束后恢复到原始桌面
std::vector<WindowInfo> GetWindowsFromDesktop(HDESK hDesktop) {
    // 获取原始桌面句柄
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到目标桌面
    if (!SetThreadDesktop(hDesktop)) {
        std::wcerr << L"Failed to set thread desktop!" << std::endl;
        return {};
    }

    // 切换后获取窗口层次
    std::vector<WindowInfo> windows = GetWindowHierarchy();

     恢复到原始桌面
    //if (!SetThreadDesktop(hOriginalDesktop)) {
    //    std::wcerr << L"Failed to restore original desktop!" << std::endl;
    //}

    return windows;
}

// 使用辅助线程进行桌面切换和窗口枚举
DWORD WINAPI MonitorDesktopThread(LPVOID param) {
    _wsetlocale(LC_ALL, L"zh-CN");
    MYTHREADINFO* threadInfo = static_cast<MYTHREADINFO*>(param);

    threadInfo->wndInfo = GetWindowsFromDesktop(threadInfo->hDesktop);

    return 0;
}

// 打开窗口工作站并切换到桌面
HDESK OpenDesktopWithWindowStation(LPCWSTR desktopName, HWINSTA hWinsta) {
    // 打开桌面
    HDESK hDesktop = OpenDesktopW(desktopName, 0, FALSE, GENERIC_ALL);
    if (!hDesktop) {
        std::wcerr << L"Failed to open desktop! name = " << desktopName << std::endl;
        CloseWindowStation(hWinsta);
    }

    return hDesktop;
}

// 获取当前活动桌面
HDESK GetActiveDesktop() {
    return OpenInputDesktop(0, FALSE, GENERIC_ALL);
}

// 监控桌面切换
void MonitorDesktop() {

    // 打开窗口工作站
    HWINSTA hWinsta = OpenWindowStationW(L"WinSta0", FALSE, GENERIC_READ | GENERIC_WRITE);
    if (!hWinsta) {
        std::wcerr << L"Failed to open window station!" << std::endl;
        return;
    }

    // 将当前线程关联到工作站
    if (!SetProcessWindowStation(hWinsta)) {
        std::wcerr << L"Failed to set process window station!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    HDESK hDefaultDesk = OpenDesktopWithWindowStation(L"Default", hWinsta);
    HDESK hWinlogonDesk = OpenDesktopWithWindowStation(L"Winlogon", hWinsta);

    if (!hDefaultDesk || !hWinlogonDesk) {
        std::wcerr << L"Failed to open desktops!" << std::endl;
        return;
    }

    std::wcout << L"Monitoring desktop changes (SYSTEM privileges detected)..." << std::endl;
    std::wcout << L"Desktops: Winlogon(" << std::hex << (UINT64)hWinlogonDesk << L"), Default("
        << std::hex << (UINT64)hDefaultDesk << L")." << std::endl;
    
    // 桌面监控代码

    std::vector<WindowInfo> windowHistory;
    bool monitoring = false;

    while (true) {
        // 检查指定按键是否被按下(比如 ESC 键,键码 0x1B)
        if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
            std::wcout << L"Escape key pressed. Exiting monitoring..." << std::endl;
            break;  // 退出循环,结束监控
        }

        HDESK hCurrentDesk = GetActiveDesktop();   // 获取活动桌面句柄

        std::wstring desktopName = GetDesktopName(hCurrentDesk);   // 获取桌面名称

        //std::wcout << L"Current Desktop: " << desktopName << std::endl;

        if (desktopName == L"Winlogon" && !monitoring) {
            std::wcout << L"Switched to Winlogon desktop. Start monitoring window hierarchy..." << std::endl;
            monitoring = true;
            windowHistory.clear();  // 清空之前的记录

            // 切换到 winlogon 桌面并枚举窗口
            MYTHREADINFO info = { hWinlogonDesk };
            HANDLE hThread = CreateThread(NULL, 0, MonitorDesktopThread, &info, 0, NULL);
            if (hThread) {
                WaitForSingleObject(hThread, INFINITE);
                CloseHandle(hThread);
            }
            windowHistory = info.wndInfo;
        }
        else if (desktopName == L"Default" && monitoring) {
            std::wcout << L"Switched back to Default desktop. Stopping monitoring..." << std::endl;
            std::time_t currentTime = std::time(nullptr);
            SaveWindowHierarchy(windowHistory, currentTime, L"D:\\window_hierarchy.log");
            monitoring = false;

            // 显示历史记录
            MessageBoxW(NULL, L"The window hierarchy log has been saved. Check window_hierarchy.log for details.",
                L"History Saved", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL);
        }

        if (monitoring) {
            // 切换到 winlogon 桌面枚举窗口
            MYTHREADINFO info = { hWinlogonDesk };
            HANDLE hThread = CreateThread(NULL, 0, MonitorDesktopThread, &info, 0, NULL);
            if (hThread) {
                WaitForSingleObject(hThread, INFINITE);
                CloseHandle(hThread);
            }

            if (!info.wndInfo.empty()) {
                windowHistory = info.wndInfo;
            }
        }

        Sleep(1000);  // 每秒检查一次
    }

    CloseDesktop(hDefaultDesk);
    CloseDesktop(hWinlogonDesk);
}

int wmain(int argc, wchar_t* argv[]) {
    _wsetlocale(LC_ALL, L"zh-CN");
    // 检查是否为管理员权限运行
    if (!IsRunAsAdmin()) {
        std::wcout << L"Attempting to restart with administrator privileges..." << std::endl;
        if (RelaunchAsAdmin()) {
            return 0;  // 提升后进程将重新启动,当前进程结束
        }
        else {
            std::wcerr << L"Failed to relaunch as administrator." << std::endl;
            return 1;
        }
    }

    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_DEBUG_NAME)) {
        std::wcerr << L"Failed to enable SeDebugPrivilege." << std::endl;
        return 1;
    }

    // 检查 SYSTEM 权限
    if (!IsSystem()) {
        std::wcout << L"Attempting to restart with SYSTEM privileges..." << std::endl;

        // 检查命令行参数,避免无限递归
        if (argc < 2 || _wcsicmp(argv[1], L"system") != 0) {
            // 重新启动自身并传递 "system" 参数
            wchar_t commandLine[MAX_PATH];
            swprintf(commandLine, MAX_PATH, L"%s system", argv[0]);
            if (CreateSystemProcess(argv[0], commandLine)) {
                std::wcout << L"Restarted with SYSTEM privileges." << std::endl;
            }
            else {
                std::wcerr << L"Failed to restart with SYSTEM privileges." << std::endl;
            }
            return 0;
        }
        else {
            std::wcerr << L"Already tried to elevate privileges but failed." << std::endl;
            return 1;
        }
    }

    // 如果当前进程已经是 SYSTEM 权限,则继续执行桌面监控
    MonitorDesktop();
    return 0;
}

版本 Beta 2 修复内容:

  1. 非主用户账户缺少 SE_ASSIGNPRIMARYTOKEN_NAME 特权导致无法创建 SYSTEM 权限的进程(强制修改安全配置并在重启时生效);
  2. 多用户账户登陆下获取到错误的 Winlogon 进程句柄;
  3. 窗口关闭快捷键异常,现在改用注册热键 Ctrl + Shitf + F1 完成;
  4. 在监视窗口时,新增高亮边框效果;
  5. 日志记录完成时,显示当前日志记录的内容;
  6. 使用特权账户启动失败时,给出更多信息;

Beta 2 代码:

#include <windows.h>
#include <iostream>
#include <lmcons.h>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>
#include <sstream>
#include <codecvt>
#include <functional>
#include <tlhelp32.h>
#include <userenv.h>
#include <sddl.h>
#include "resource.h"

#pragma comment(linker,"\"/manifestdependency:type='win32' "\
						"name='Microsoft.Windows.Common-Controls' "\
						"version='6.0.0.0' processorArchitecture='*' "\
						"publicKeyToken='6595b64144ccf1df' language='*'\"")

// 记录窗口信息的结构体,使用宽字符
struct WindowInfo {
    std::wstring className;
    std::wstring windowTitle;
    HWND hwnd;
    std::vector<WindowInfo> children;
};

struct MYTHREADINFO {
    HDESK hDesktop;
    std::vector<WindowInfo> wndInfo;
};

// 文件编码格式
enum class FileEncoding {
    ANSI,
    UTF8,
    UTF16LE,
    UTF16BE,
    UNKNOWN
};

// 用于边框绘制的全局变量
HWND hBorderWnd = NULL;  // 边框窗口句柄
bool borderRunning = false;  // 边框是否正在显示
// 全局变量保存主窗口句柄
HWND hMainWindow = NULL;

HWND GetConsoleHwnd(void)
{
    // https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/obtain-console-window-handle

#define MY_BUFSIZE 1024 // Buffer size for console window titles.
    HWND hwndFound;         // This is what is returned to the caller.
    wchar_t pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated
    // WindowTitle.

    // Format a "unique" NewWindowTitle.

    wsprintfW(pszNewWindowTitle, L"WinlogonWindowsMonitor - %d/%d",
        GetTickCount(),
        GetCurrentProcessId());

    // Change current window title.

    SetConsoleTitleW(pszNewWindowTitle);

    // Ensure window title has been updated.

    Sleep(40);

    // Look for NewWindowTitle.

    hwndFound = FindWindowW(L"ConsoleWindowClass", pszNewWindowTitle);

    if(!hwndFound)
        hwndFound = FindWindowW(L"CASCADIA_HOSTING_WINDOW_CLASS", pszNewWindowTitle);

#undef MY_BUFSIZE
    return(hwndFound);
}

// 获取当前进程的主窗口
HWND GetMainWindowHandle() {
    return GetConsoleHwnd();
}

// 检查当前活动窗口是否是主窗口
bool IsMainWindowActive() {
    HWND hForeground = GetForegroundWindow();  // 获取当前活动窗口
    return hForeground == hMainWindow;         // 比较是否是主窗口
}

// 边框窗口过程
LRESULT CALLBACK BorderWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static int borderWidth = 10;  // 默认边框宽度

    switch (message) {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        RECT rect;
        GetClientRect(hWnd, &rect);

        // 设置边框颜色为蓝色
        HBRUSH brush = CreateSolidBrush(RGB(119, 228, 155));

        // 填充外边框到内边框之间的区域
        RECT outerRect = rect;
        RECT innerRect = rect;

        // 根据边框宽度调整内边框位置
        InflateRect(&innerRect, -borderWidth, -borderWidth);

        // 填充外边框和内边框之间的区域
        if (borderWidth > 0) {
            // 填充四个部分:上边、下边、左边、右边
            RECT topRect = { outerRect.left, outerRect.top, outerRect.right, innerRect.top };
            RECT bottomRect = { outerRect.left, innerRect.bottom, outerRect.right, outerRect.bottom };
            RECT leftRect = { outerRect.left, innerRect.top, innerRect.left, innerRect.bottom };
            RECT rightRect = { innerRect.right, innerRect.top, outerRect.right, innerRect.bottom };

            FillRect(hdc, &topRect, brush);
            FillRect(hdc, &bottomRect, brush);
            FillRect(hdc, &leftRect, brush);
            FillRect(hdc, &rightRect, brush);
        }

        DeleteObject(brush);
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProcW(hWnd, message, wParam, lParam);
    }
    return 0;
}

DWORD WINAPI CloseBorderThread(LPVOID lpParam) {
    HDESK hWinlogonDesk = static_cast<HDESK>(lpParam);  // 传递的桌面句柄

    // 获取当前线程的桌面句柄,后面恢复用
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到 Winlogon 桌面
    if (!SetThreadDesktop(hWinlogonDesk)) {
        std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
        return 1;
    }

    // 发送关闭消息
    if (hBorderWnd) {
        PostMessageW(hBorderWnd, WM_DESTROY, 0, 0);
    }

    std::wcout << L"An exit monitoring message has been sent." << std::endl;

    // 恢复到原始桌面
    SetThreadDesktop(hOriginalDesktop);

    return 0;
}


// 边框绘制线程
DWORD WINAPI BorderThread(LPVOID lpParam) {
    std::wcout << L"Monitoring the target desktop..." << std::endl;
    HDESK hWinlogonDesk = static_cast<HDESK>(lpParam);  // 传递的桌面句柄

    // 切换到 Winlogon 桌面
    if (!SetThreadDesktop(hWinlogonDesk)) {
        std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
        return 1;
    }
#define MY_BUFSIZE 1024 // Buffer size for console window titles.
    wchar_t pszWindowClass[MY_BUFSIZE]; // Contains fabricated
    // WindowClass.

    // Format a "unique" WindowClass.
    wsprintfW(pszWindowClass, L"WinlogonMonitorBorderWindowClass[%d::%d]",
        GetTickCount(),
        GetCurrentProcessId());

    HINSTANCE hInstance = GetModuleHandleW(NULL);
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = BorderWndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = pszWindowClass;
    wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));

    if (!RegisterClassW(&wc)) {
        std::wcerr << L"Failed to RegisterClass." << std::endl;
        return 1;
    }

    // 获取屏幕大小并创建无边框窗口
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);

    hBorderWnd = CreateWindowExW(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT,
        wc.lpszClassName, L"WinlogonMonitorBorderWindow", WS_POPUP,
        0, 0, screenWidth, screenHeight, NULL, NULL, hInstance, NULL);

    if (!hBorderWnd) {
        std::wcerr << L"Failed to CreateWindow." << std::endl;
        return 1;
    }

    // 设置窗口透明度
    SetLayeredWindowAttributes(hBorderWnd, RGB(255, 255, 255), 0, LWA_COLORKEY);

    ShowWindow(hBorderWnd, SW_SHOW);
    UpdateWindow(hBorderWnd);

    // 消息循环,等待关闭事件
    MSG msg;
    while (true) {
        // 检查并处理窗口消息
        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    // 销毁窗口
    DestroyWindow(hBorderWnd);

#undef MY_BUFSIZE
    return 0;
}


// 启用特定的权限(例如 SeDebugPrivilege)
bool EnablePrivilege(LPCWSTR privilege) {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token." << std::endl;
        return false;
    }

    if (!LookupPrivilegeValueW(NULL, privilege, &luid)) {
        std::wcerr << L"Failed to lookup privilege." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
        std::wcerr << L"Failed to adjust token privileges." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
        std::wcerr << L"The privilege was not assigned." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(hToken);
    return true;
}

// 检查是否以管理员权限运行
bool IsRunAsAdmin() {
    BOOL isAdmin = FALSE;
    PSID administratorsGroup = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) {
        CheckTokenMembership(NULL, administratorsGroup, &isAdmin);
        FreeSid(administratorsGroup);
    }
    return isAdmin == TRUE;
}

// 重新启动并请求管理员权限
bool RelaunchAsAdmin() {
    wchar_t szPath[MAX_PATH];
    if (!GetModuleFileNameW(NULL, szPath, MAX_PATH)) {
        std::wcerr << L"Failed to get module file name." << std::endl;
        return false;
    }

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpVerb = L"runas";  // 请求管理员权限
    sei.lpFile = szPath;
    sei.hwnd = NULL;
    sei.nShow = SW_NORMAL;

    if (!ShellExecuteExW(&sei)) {
        std::wcerr << L"Failed to relaunch as administrator." << std::endl;
        return false;
    }
    return true;
}

DWORD WINAPI GetActiveConsoleSessionId() {
    return WTSGetActiveConsoleSessionId();
}


BOOL WINAPI IsProcessInSession(DWORD processId, DWORD sessionId) {
    DWORD session;
    if (!ProcessIdToSessionId(processId, &session)) {
        printf("Error: ProcessIdToSessionId failed.\n");
        return FALSE;
    }
    return session == sessionId;
}


DWORD WINAPI FindWinlogonProcessId() {
    DWORD dwProcessId = 0;
    DWORD activeSessionId = GetActiveConsoleSessionId();
    if (activeSessionId == 0xFFFFFFFF) {
        printf("Error: Unable to retrieve active console session ID.\n");
        return 0;
    }

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        printf("Error: CreateToolhelp32Snapshot failed.\n");
        return 0;
    }

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(snapshot, &entry)) {
        printf("Error: Process32First failed.\n");
        CloseHandle(snapshot);
        return 0;
    }

    do {

        if (entry.cntThreads <= 1u) continue; // 跳过僵尸进程

        if (_wcsicmp(entry.szExeFile, L"winlogon.exe") == 0) {
            if (IsProcessInSession(entry.th32ProcessID, activeSessionId)) {
                dwProcessId = entry.th32ProcessID;
                break;
            }
        }
    } while (Process32Next(snapshot, &entry));

    CloseHandle(snapshot);
    return dwProcessId;
}

// 获取 winlogon 进程的 SYSTEM 令牌
HANDLE GetSystemTokenFromWinlogon() {
    HANDLE hToken = NULL;
    HANDLE hProcess = NULL;
    HANDLE hSystemToken = NULL;  // 存储复制后的 SYSTEM 令牌

    // 获取 Winlogon 进程的进程ID
    DWORD winlogonPid = FindWinlogonProcessId();

    if (winlogonPid == 0) {
        std::wcerr << L"Failed to find winlogon.exe process!" << std::endl;
        return NULL;
    }

    std::wcout << L"winlogon.exe PID: "  << winlogonPid << std::endl;

    // 打开 Winlogon 进程
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, winlogonPid);
    if (!hProcess) {
        std::wcerr << L"Failed to open winlogon process!" << std::endl;
        return NULL;
    }

    // 打开该进程的令牌
    if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token!" << std::endl;
        CloseHandle(hProcess);
        return NULL;
    }

    // 复制令牌以使其可用于新进程
    if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hSystemToken)) {
        std::wcerr << L"Failed to duplicate SYSTEM token!" << std::endl;
        CloseHandle(hToken);
        CloseHandle(hProcess);
        return NULL;
    }

    // 关闭原始的令牌和进程句柄
    CloseHandle(hToken);
    CloseHandle(hProcess);
    return hSystemToken;
}

// 创建具有 SYSTEM 权限的进程
bool CreateSystemProcess(LPCWSTR applicationName, LPCWSTR commandLine) {
    HANDLE hToken = GetSystemTokenFromWinlogon();
    if (!hToken) {
        std::wcerr << L"Failed to get SYSTEM token!" << std::endl;
        return false;
    }

    // 使用 SYSTEM 权限创建进程
    STARTUPINFOW si = { sizeof(STARTUPINFOW) };
    PROCESS_INFORMATION pi = { 0 };

    if (!CreateProcessAsUserW(hToken, applicationName, const_cast<LPWSTR>(commandLine), NULL,
        NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to create process as SYSTEM! err = " << GetLastError() << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hToken);
    return true;
}

// 检查当前进程是否具有 SYSTEM 权限
bool IsSystem() {
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
        return false;
    }

    DWORD tokenInfoLength = 0;
    GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenInfoLength);

    PTOKEN_USER tokenUser = (PTOKEN_USER)malloc(tokenInfoLength);
    if (!GetTokenInformation(hToken, TokenUser, tokenUser, tokenInfoLength, &tokenInfoLength)) {
        CloseHandle(hToken);
        free(tokenUser);
        return false;
    }

    LPWSTR sidString = NULL;
    ConvertSidToStringSidW(tokenUser->User.Sid, &sidString);
    bool isSystem = (_wcsicmp(sidString, L"S-1-5-18") == 0);

    LocalFree(sidString);
    CloseHandle(hToken);
    free(tokenUser);

    return isSystem;
}

// 递归获取窗口层次,使用宽字符 API
void EnumChildWindowsRecursive(HWND hwndParent, std::vector<WindowInfo>& windowList) {
    wchar_t className[256];
    wchar_t windowTitle[256];

    ZeroMemory(className, sizeof(className));
    ZeroMemory(windowTitle, sizeof(windowTitle));

    // 获取窗口类名和标题
    GetClassNameW(hwndParent, className, sizeof(className) / sizeof(wchar_t));
    GetWindowTextW(hwndParent, windowTitle, sizeof(windowTitle) / sizeof(wchar_t));

    if (className[0] == L'\0') {
        wcscpy_s(className, L"(None)");
    }

    if (windowTitle[0] == L'\0') {
        wcscpy_s(windowTitle, L"(None)");
    }

    WindowInfo windowInfo = { className, windowTitle, hwndParent };

    // 枚举子窗口
    EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* children = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *children);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windowInfo.children));

    windowList.push_back(windowInfo);
}

// 获取当前桌面窗口层次,使用宽字符 API
std::vector<WindowInfo> GetWindowHierarchy() {
    std::vector<WindowInfo> windows;
    EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* windows = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *windows);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windows));
    return windows;
}

// 格式化时间为宽字符格式
std::wstring FormatTime(const std::time_t& time) {
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &time);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);
    return std::wstring(timeBuffer);
}

// 转换宽字符到 UTF-8
std::string WideToUTF8(const std::wstring& wideStr) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    return conv.to_bytes(wideStr);
}

// 保存窗口层次信息到文件,使用 UTF-8 编码
void SaveWindowHierarchy(const std::vector<WindowInfo>& windows, const std::time_t& changeTime, const std::wstring& filename) {
    std::ofstream file(WideToUTF8(filename), std::ios::app | std::ios::binary);  // 使用 binary 防止换行符的意外转换
    if (!file.is_open()) {
        std::wcerr << L"Unable to open file for writing!" << std::endl;
        return;
    }

    // 在文件开头写入 BOM,标识为 UTF-8 编码
    static bool bomWritten = false;
    if (!bomWritten) {
        const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };  // UTF-8 BOM
        file.write(reinterpret_cast<const char*>(bom), sizeof(bom));
        bomWritten = true;
    }

    // 格式化时间为字符串
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &changeTime);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);

    // 写入时间戳
    file << WideToUTF8(std::wstring(timeBuffer)) << "\n";

    // 递归写入窗口信息
    std::function<void(const std::vector<WindowInfo>&, int)> WriteHierarchy;
    WriteHierarchy = [&file, &WriteHierarchy](const std::vector<WindowInfo>& windows, int indent) {
        for (const auto& window : windows) {
            file << std::string(indent, ' ')  // 使用空格进行缩进
                << "Class Name: " << WideToUTF8(window.className)
                << ", Title: " << WideToUTF8(window.windowTitle)
                << ", HWND: " << std::hex << window.hwnd << "\n";
            if (!window.children.empty()) {
                WriteHierarchy(window.children, indent + 4);  // 递归写入子窗口信息
            }
        }
    };

    WriteHierarchy(windows, 0);
    file << "\n";
    file.close();
}

// 获取当前桌面的名称
std::wstring GetDesktopName(HDESK hDesktop) {
    wchar_t desktopName[256];
    DWORD neededLength = 0;

    if (!GetUserObjectInformationW(hDesktop, UOI_NAME, desktopName, sizeof(desktopName), &neededLength)) {
        std::wcerr << L"Failed to get desktop name." << std::endl;
        return L"";
    }

    return std::wstring(desktopName);
}


// 切换到指定桌面并枚举窗口,任务结束后恢复到原始桌面
std::vector<WindowInfo> GetWindowsFromDesktop(HDESK hDesktop) {
    // 获取原始桌面句柄
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到目标桌面
    if (!SetThreadDesktop(hDesktop)) {
        std::wcerr << L"Failed to set thread desktop!" << std::endl;
        return {};
    }

    // 切换后获取窗口层次
    std::vector<WindowInfo> windows = GetWindowHierarchy();

     恢复到原始桌面
    //if (!SetThreadDesktop(hOriginalDesktop)) {
    //    std::wcerr << L"Failed to restore original desktop!" << std::endl;
    //}

    return windows;
}

// 使用辅助线程进行桌面切换和窗口枚举
DWORD WINAPI MonitorDesktopThread(LPVOID param) {
    _wsetlocale(LC_ALL, L"zh-CN");
    MYTHREADINFO* threadInfo = static_cast<MYTHREADINFO*>(param);

    threadInfo->wndInfo = GetWindowsFromDesktop(threadInfo->hDesktop);

    return 0;
}

// 打开窗口工作站并切换到桌面
HDESK OpenDesktopWithWindowStation(LPCWSTR desktopName, HWINSTA hWinsta) {
    // 打开桌面
    HDESK hDesktop = OpenDesktopW(desktopName, 0, FALSE, GENERIC_ALL);
    if (!hDesktop) {
        std::wcerr << L"Failed to open desktop! name = " << desktopName << std::endl;
        CloseWindowStation(hWinsta);
    }

    return hDesktop;
}

// 获取当前活动桌面
HDESK GetActiveDesktop() {
    return OpenInputDesktop(0, FALSE, GENERIC_ALL);
}

// 对话框过程函数
INT_PTR CALLBACK HistoryDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
    static std::wstring* historyText = nullptr;

    switch (message) {
    case WM_INITDIALOG:
    {
        historyText = reinterpret_cast<std::wstring*>(lParam);

        // 获取编辑控件句柄
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
        if (hEdit) {
            // 设置文本
            SetWindowTextW(hEdit, historyText->c_str());
        }
    }
    return (INT_PTR)TRUE;

    case WM_SIZE:
    {
        // 获取对话框的新尺寸
        int width = LOWORD(lParam);   // 新的宽度
        int height = HIWORD(lParam);  // 新的高度
        

        // 调整编辑控件大小
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
        if (hEdit) {
            int margin = 25;
            MoveWindow(hEdit, margin, margin, width - 2 * margin, height - 80, TRUE);
        }

        // 调整OK按钮的位置
        HWND hButtonOK = GetDlgItem(hDlg, IDOK);
        if (hButtonOK) {
            int buttonWidth = 120;
            int buttonHeight = 35;
            int margin = 15;
            // 按钮位于对话框底部,右边留一定的边距
            MoveWindow(hButtonOK, width - buttonWidth - margin, height - buttonHeight - margin, buttonWidth, buttonHeight, TRUE);
        }
    }
    break;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;

    default:
        return FALSE;
    }
    return FALSE;
}

// 监控桌面切换
void MonitorDesktop() {

    // 注册 Ctrl + Shift + F1 组合键为全局热键 (ID = 1)
    if (!RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_SHIFT, VK_F1)) {
        std::wcerr << L"Failed to register hotkey for Ctrl + Shift + F1." << std::endl;
        return;
    }

    // 打开窗口工作站
    HWINSTA hWinsta = OpenWindowStationW(L"WinSta0", FALSE, GENERIC_READ | GENERIC_WRITE);
    if (!hWinsta) {
        std::wcerr << L"Failed to open window station!" << std::endl;
        return;
    }

    // 将当前线程关联到工作站
    if (!SetProcessWindowStation(hWinsta)) {
        std::wcerr << L"Failed to set process window station!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    HDESK hDefaultDesk = OpenDesktopWithWindowStation(L"Default", hWinsta);
    HDESK hWinlogonDesk = OpenDesktopWithWindowStation(L"Winlogon", hWinsta);

    if (!hDefaultDesk || !hWinlogonDesk) {
        std::wcerr << L"Failed to open desktops!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    std::wcout << L"Monitoring desktop changes (SYSTEM privileges detected)..." << std::endl;
    std::wcout << L"Desktops: Winlogon(" << std::hex << (UINT64)hWinlogonDesk << L"), Default("
        << std::hex << (UINT64)hDefaultDesk << L")." << std::endl;
    
    // 桌面监控代码

    std::vector<WindowInfo> windowHistory;
    bool monitoring = false;

    HANDLE hBorderThread = NULL;  // 边框线程句柄

    while (true) {
        MSG msg;
        // 非阻塞的消息检查
        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (IsMainWindowActive() && msg.message == WM_HOTKEY && msg.wParam == 1) {
                // Ctrl + Shift + F1 热键触发,退出循环
                std::wcout << L"Ctrl + Shift + F1 pressed. Exiting monitoring..." << std::endl;
                Sleep(1000);
                goto exit_monitoring;
            }
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }

        HDESK hCurrentDesk = GetActiveDesktop();   // 获取活动桌面句柄

        std::wstring desktopName = GetDesktopName(hCurrentDesk);   // 获取桌面名称

        //std::wcout << L"Current Desktop: " << desktopName << std::endl;

        if (desktopName == L"Winlogon" && !monitoring) {
            std::wcout << L"Switched to Winlogon desktop. Start monitoring window hierarchy..." << std::endl;
            monitoring = true;
            windowHistory.clear();  // 清空之前的记录

            // 启动边框绘制线程,并传递 Winlogon 桌面句柄
            if (!borderRunning) {
                hBorderThread = CreateThread(NULL, 0, BorderThread, (LPVOID)hWinlogonDesk, 0, NULL);
                borderRunning = true;
            }

            // 切换到 winlogon 桌面并枚举窗口
            MYTHREADINFO info = { hWinlogonDesk };
            HANDLE hThread = CreateThread(NULL, 0, MonitorDesktopThread, &info, 0, NULL);
            if (hThread) {
                WaitForSingleObject(hThread, INFINITE);
                CloseHandle(hThread);
            }
            windowHistory = info.wndInfo;
        }
        else if (desktopName == L"Default" && monitoring) {
            std::wcout << L"Switched back to Default desktop. Stopping monitoring..." << std::endl;
            std::time_t currentTime = std::time(nullptr);
            SaveWindowHierarchy(windowHistory, currentTime, L"D:\\window_hierarchy.log");
            monitoring = false;

            // 启动关闭边框的线程
            if (borderRunning) {
                HANDLE hCloseThread = CreateThread(NULL, 0, CloseBorderThread, (LPVOID)hWinlogonDesk, 0, NULL);
                WaitForSingleObject(hCloseThread, INFINITE);  // 等待线程完成
                CloseHandle(hCloseThread);
                borderRunning = false;
            }

            // 构建窗口层次信息文本
            std::wstringstream ss;
            for (const auto& win : windowHistory) {
                ss << L"Class Name: " << win.className << L", Title: " << win.windowTitle
                    << L", HWND: " << std::hex << win.hwnd << L"\r\n";
            }
            std::wstring historyText = ss.str();

            // 显示历史记录对话框
            DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), NULL, HistoryDialogProc, (LPARAM)&historyText);
        }

        //if (monitoring) {
        //    // 切换到 winlogon 桌面枚举窗口
        //    MYTHREADINFO info = { hWinlogonDesk };
        //    HANDLE hThread = CreateThread(NULL, 0, MonitorDesktopThread, &info, 0, NULL);
        //    if (hThread) {
        //        WaitForSingleObject(hThread, INFINITE);
        //        CloseHandle(hThread);
        //    }

        //    if (!info.wndInfo.empty()) {
        //        windowHistory = info.wndInfo;
        //    }
        //}

        Sleep(1000);  // 每秒检查一次
    }

exit_monitoring:
    // 注销热键
    UnregisterHotKey(NULL, 1);

    // 清理
    CloseDesktop(hDefaultDesk);
    CloseDesktop(hWinlogonDesk);
    CloseWindowStation(hWinsta);
}


// 检测文件编码
FileEncoding DetectFileEncoding(const std::wstring& filePath) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open file for encoding detection: " << filePath << std::endl;
        return FileEncoding::UNKNOWN;
    }

    unsigned char bom[3] = { 0 };
    file.read(reinterpret_cast<char*>(bom), 3);
    file.close();

    // Check BOM (Byte Order Mark)
    if (bom[0] == 0xFF && bom[1] == 0xFE) {
        return FileEncoding::UTF16LE;  // UTF-16 Little Endian
    }
    else if (bom[0] == 0xFE && bom[1] == 0xFF) {
        return FileEncoding::UTF16BE;  // UTF-16 Big Endian
    }
    else if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) {
        return FileEncoding::UTF8;     // UTF-8 with BOM
    }
    else {
        return FileEncoding::ANSI;     // Default to ANSI
    }
}

// 读取文件内容,处理不同编码格式
bool ReadFileWithEncoding(const std::wstring& filePath, std::wstring& content) {
    FileEncoding encoding = DetectFileEncoding(filePath);

    if (encoding == FileEncoding::UTF16LE || encoding == FileEncoding::UTF16BE) {
        // Use wide string stream to read UTF-16 encoded file
        std::wifstream wfile(filePath, std::ios::binary);
        if (!wfile.is_open()) {
            std::wcerr << L"Failed to open UTF-16 file: " << filePath << std::endl;
            return false;
        }
        wfile.imbue(std::locale(wfile.getloc(), new std::codecvt_utf16<wchar_t, 0x10FFFF, std::little_endian>));
        std::wstringstream wss;
        wss << wfile.rdbuf();
        content = wss.str();
        wfile.close();
    }
    else if (encoding == FileEncoding::UTF8) {
        // Use standard string stream to read UTF-8 encoded file
        std::ifstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open UTF-8 file: " << filePath << std::endl;
            return false;
        }
        std::stringstream ss;
        ss << file.rdbuf();
        std::string utf8Content = ss.str();

        // Convert UTF-8 string to wide string
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        content = converter.from_bytes(utf8Content);
        file.close();
    }
    else if (encoding == FileEncoding::ANSI) {
        // Use standard string stream to read ANSI encoded file
        std::ifstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open ANSI file: " << filePath << std::endl;
            return false;
        }
        std::stringstream ss;
        ss << file.rdbuf();
        std::string ansiContent = ss.str();

        // Convert ANSI string to wide string (using current locale)
        content = std::wstring(ansiContent.begin(), ansiContent.end());
        file.close();
    }
    else {
        std::wcerr << L"Unknown file encoding." << std::endl;
        return false;
    }
    return true;
}


// 宽字符到多字节字符的转换 (ANSI)
std::string WideStringToString(const std::wstring& wstr) {
    if (wstr.empty()) return std::string();

    // 使用系统默认代码页 (CP_ACP) 将宽字符转换为多字节字符
    int size_needed = WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string str(size_needed, 0);
    WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), &str[0], size_needed, NULL, NULL);
    return str;
}

// 根据编码保存修改后的文件内容
bool ModifyAndSaveFileWithEncoding(const std::wstring& filePath, const std::wstring& content) {
    FileEncoding encoding = DetectFileEncoding(filePath);

    if (encoding == FileEncoding::UTF16LE) {
        // Save as UTF-16 Little Endian
        std::wofstream wfile(filePath, std::ios::binary);
        if (!wfile.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        wfile.imbue(std::locale(wfile.getloc(), new std::codecvt_utf16<wchar_t, 0x10FFFF, std::little_endian>));
        wfile << content;
        wfile.close();
    }
    else if (encoding == FileEncoding::UTF8) {
        // Save as UTF-8
        std::ofstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::string utf8Content = converter.to_bytes(content);
        file << utf8Content;
        file.close();
    }
    else if (encoding == FileEncoding::ANSI) {
        // Save as ANSI
        std::ofstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        std::string ansiContent = WideStringToString(content);
        file << ansiContent;
        file.close();
    }
    else {
        std::wcerr << L"Unknown file encoding, cannot save file." << std::endl;
        return false;
    }
    return true;
}

// 修改 SeAssignPrimaryTokenPrivilege 权限
bool ModifySeAssignPrimaryTokenPrivilege(const std::wstring& configFilePath, const std::wstring& userName) {
    std::wstring content;

    // 读取文件内容
    if (!ReadFileWithEncoding(configFilePath, content)) {
        std::wcerr << L"Failed to read configuration file with correct encoding." << std::endl;
        return false;
    }

    // 查找并修改 SeAssignPrimaryTokenPrivilege
    size_t pos = content.find(L"SeAssignPrimaryTokenPrivilege");
    if (pos != std::wstring::npos) {
        size_t endPos = content.find(L"\n", pos) - 1;
        std::wstring line = content.substr(pos, endPos - pos);

        // 检查是否包含当前用户
        if (line.find(userName) == std::wstring::npos) {
            line += L"," + userName;
            content.replace(pos, endPos - pos, line);
        }
    }

    // 保存修改后的文件
    if (!ModifyAndSaveFileWithEncoding(configFilePath, content)) {
        std::wcerr << L"Failed to save modified configuration file." << std::endl;
        return false;
    }

    return true;
}

// 执行命令
bool ExecuteCommandWithOutput(const std::wstring& command, std::wstring& output) {
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hRead, hWrite;

    // Initialize security attributes for pipe handles
    ZeroMemory(&sa, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;

    // Create a pipe for the child process's STDOUT and STDERR
    if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
        std::wcerr << L"Failed to create pipe." << std::endl;
        return false;
    }

    // Ensure the read handle to the pipe is not inherited
    if (!SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0)) {
        std::wcerr << L"Failed to set handle information." << std::endl;
        return false;
    }

    // Set up the STARTUPINFO structure for the child process
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;
    si.dwFlags |= STARTF_USESTDHANDLES;  // Redirect STDOUT and STDERR to the pipe

    // Set up the PROCESS_INFORMATION structure
    ZeroMemory(&pi, sizeof(pi));

    // Create the child process with CREATE_NO_WINDOW to avoid showing a new console window
    if (!CreateProcessW(NULL, const_cast<LPWSTR>(command.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to execute command: " << command << std::endl;
        CloseHandle(hRead);
        CloseHandle(hWrite);
        return false;
    }

    // Close the write end of the pipe in the parent process
    CloseHandle(hWrite);

    // Read the output from the child process
    DWORD bytesRead;
    CHAR buffer[4096];
    std::string ansiResult;
    BOOL success = FALSE;

    ZeroMemory(buffer, sizeof(buffer) * sizeof(CHAR));

    // Continuously read from the pipe until there's no more data
    while (true) {
        success = ReadFile(hRead, buffer, sizeof(buffer) - 1, &bytesRead, NULL);
        if (!success || bytesRead == 0) {
            break;  // No more data to read
        }
        buffer[bytesRead] = '\0';  // Null-terminate the buffer
        ansiResult += buffer;      // Collect the ANSI result
    }

    // Close handles
    CloseHandle(hRead);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    // If the result is empty, return "Output is empty"
    if (ansiResult[0] == '\0') {
        output = L"\n(no message)\n";
        return true;
    }

    // Convert the ANSI result to wide string (UTF-16) for proper Unicode handling
    int wideSize = MultiByteToWideChar(CP_ACP, 0, ansiResult.c_str(), -1, NULL, 0);
    if (wideSize == 0) {
        std::wcerr << L"Failed to convert output to wide string." << std::endl;
        return false;
    }

    std::wstring wideResult(wideSize, 0);
    MultiByteToWideChar(CP_ACP, 0, ansiResult.c_str(), -1, &wideResult[0], wideSize);

    output = wideResult;
    return true;
}

// 判断文件是否存在
BOOL IsFileExist(const std::wstring& wsFile)
{
    DWORD dwAttrib = GetFileAttributesW(wsFile.c_str());
    return INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

// 导出安全策略
bool ExportSecurityPolicy(const std::wstring& outputFile, std::wstring& output) {
    // https://blog.csdn.net/u012494876/article/details/51204615
    if (IsFileExist(outputFile)) {  // 判断配置文件是否已经存在
        std::wcout << L"The configuration file already exists. Attempting to delete it." << std::endl;
        if (!DeleteFileW(outputFile.c_str())) {
            std::wcerr << L"Failed to delete the configuration file." << std::endl;
            return false;
        }
    }

    std::wstring command = L"secedit /export /cfg " + outputFile;
    return ExecuteCommandWithOutput(command, output);
}

// 应用修改后的安全策略
bool ApplySecurityPolicy(const std::wstring& configFilePath, const std::wstring& dbFilePath, std::wstring& output) {
    std::wstring command = L"secedit /configure /db " + dbFilePath + L" /cfg " + configFilePath + L" /overwrite /quiet";
    return ExecuteCommandWithOutput(command, output);
}

// 获取系统盘符
std::wstring GetSystemDrive() {
    wchar_t systemPath[MAX_PATH];
    if (GetSystemDirectoryW(systemPath, MAX_PATH)) {
        return std::wstring(systemPath).substr(0, 3);  // 返回盘符部分,例如 C:
    }
    return L"C:\\";  // 如果获取失败,返回默认 C 盘符
}

// 获取当前用户账户名称
std::wstring GetCurrentUserName() {
    wchar_t userName[UNLEN + 1];
    DWORD size = UNLEN + 1;
    if (GetUserNameW(userName, &size)) {
        return std::wstring(userName);
    }
    return L"";  // 返回空字符串表示获取失败
}

// 提示用户注销
void PromptUserToLogout() {
    // Ask the user if they want to log off and re-log in
    int result = MessageBoxW(NULL,
        L"The security settings have been updated. Would you like to log off now and apply the changes?",
        L"Log Off Confirmation",
        MB_YESNO | MB_ICONQUESTION | MB_SYSTEMMODAL);

    if (result == IDYES) {
        // Log off the user
        if (!ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, SHTDN_REASON_MAJOR_OTHER)) {
            std::wcerr << L"Failed to log off the user." << std::endl;
        }
    }
    else {
        std::wcout << L"User chose not to log off." << std::endl;
    }
}

bool ChangeAssignPrimaryTokenPrivilege() {
    std::wstring systemDrive = GetSystemDrive();
    std::wstring configFilePath = systemDrive + L"gp.inf";
    std::wstring dbFilePath = systemDrive + L"test.sdb";
    std::wstring userName = GetCurrentUserName();
    std::wstring output;

    if (userName.empty()) {
        std::wcerr << L"Failed to retrieve the current user name." << std::endl;
        return false;
    }

    if (!ExportSecurityPolicy(configFilePath, output)) {
        std::wcerr << L"Failed to export security policy." << std::endl;
        return false;
    }

    std::wcout << L"\nExportSecurityPolicy message: \n" << output << std::endl;

    if (!ModifySeAssignPrimaryTokenPrivilege(configFilePath, userName)) {
        std::wcerr << L"Failed to modify SeAssignPrimaryTokenPrivilege." << std::endl;
        return false;
    }

    if (!ApplySecurityPolicy(configFilePath, dbFilePath, output)) {
        std::wcerr << L"Failed to apply security policy." << std::endl;
        return false;
    }

    std::wcout << L"\nApplySecurityPolicy message: \n" << output << std::endl;

    PromptUserToLogout();

    return true;
}

int wmain(int argc, wchar_t* argv[]) {
    // 宽字符中文支持
    _wsetlocale(LC_ALL, L"zh-CN");

    // 获取当前进程的主窗口
    hMainWindow = GetMainWindowHandle();
    if (!hMainWindow) {
        std::cerr << "Failed to find main window." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }
    std::cout << "Main window handle: " << std::hex << hMainWindow << std::endl;

    // 检查是否为管理员权限运行
    if (!IsRunAsAdmin()) {
        std::wcout << L"Attempting to restart with administrator privileges..." << std::endl;
        if (RelaunchAsAdmin()) {
            return 0;  // 提升后进程将重新启动,当前进程结束
        }
        else {
            std::wcerr << L"Failed to relaunch as administrator." << std::endl;
            system("pause > nul 2 > nul");
            return 1;
        }
    }

    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_DEBUG_NAME)) {
        std::wcerr << L"Failed to enable SeDebugPrivilege." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }

    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_INCREASE_QUOTA_NAME)) {
        std::wcerr << L"Failed to enable SeIncreaseQuotaPrivilege." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }
    
    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME)) {
        std::wcerr << L"Failed to enable SeAssignPrimaryTokenPrivilege." << std::endl;
        if (!ChangeAssignPrimaryTokenPrivilege()) {
            std::wcerr << L"Failed to enable primary token assignment privilege"
                << L" by modifying security configuration." << std::endl;
        }
        std::wcout << L"Press any key to close app.";
        system("pause > nul 2 > nul");
        return 1;
    }

    // 检查 SYSTEM 权限
    if (!IsSystem()) {
        std::wcout << L"Attempting to restart with SYSTEM privileges..." << std::endl;

        // 检查命令行参数,避免无限递归
        if (argc < 2 || _wcsicmp(argv[1], L"system") != 0) {
            // 重新启动自身并传递 "system" 参数
            wchar_t commandLine[MAX_PATH];
            swprintf(commandLine, MAX_PATH, L"%s system", argv[0]);
            if (CreateSystemProcess(argv[0], commandLine)) {
                std::wcout << L"Restarted with SYSTEM privileges." << std::endl;
            }
            else {
                std::wcerr << L"Failed to restart with SYSTEM privileges." << std::endl;
                system("pause > nul 2 > nul");
            }
            return 0;
        }
        else {
            std::wcerr << L"Already tried to elevate privileges but failed." << std::endl;
            system("pause > nul 2 > nul");
            return 1;
        }
    }
    // 如果当前进程已经是 SYSTEM 权限,则继续执行桌面监控
    MonitorDesktop();
    std::wcout << L"Press any key to close app.";
    system("pause > nul 2 > nul");
    return 0;
}

版本 Beta 3 修复内容: 

  1. 修复了进程退出时不检查主窗口是否关闭的问题(但异步对话框的关闭未完成,将在后续更新中修复);
  2. 修复了不能连续监视的问题,现在在监视 Winlogon 桌面时,每隔 1 秒扫描一次窗口层次并产生日志哈希。当窗口层次发生变化时,记录新的窗口层次信息到日志文件;
  3. 只在返回 Default 桌面时弹窗显示最近一次记录的窗口层次,其他由日志记录保存;
  4. 新增在监视窗口时显示状态信息,状态信息默认对齐在屏幕左下角;

已知未修复问题:

  1.  DialogBox 的文本框中文本过长或者行数过多时不支持滚动条滑动翻页;
  2. 部分资源释放和指针的检查代码不够健硕;

Beta 3 代码:

#include <windows.h>
#include <iostream>
#include <lmcons.h>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>
#include <sstream>
#include <codecvt>
#include <functional>
#include <tlhelp32.h>
#include <userenv.h>
#include <sddl.h>
#include "resource.h"

#pragma comment(linker,"\"/manifestdependency:type='win32' "\
						"name='Microsoft.Windows.Common-Controls' "\
						"version='6.0.0.0' processorArchitecture='*' "\
						"publicKeyToken='6595b64144ccf1df' language='*'\"")

constexpr auto WM_UPDATE_STATUS = WM_APP + 10;                            // 传递新的状态信息的用户自定义消息
constexpr auto STATUS_MSG_HASH = 0x3456789;                               // 内部校验码(防止外部程序模拟消息)
constexpr auto LOGING_STATUS_INFO = L"Now Monitoring...";                 // 显示提示:正在扫描窗口
constexpr auto COMPLETE_STATUS_INFO = L"Monitoring completed!";           // 显示提示:窗口扫描已完成
constexpr auto LogDir = L"D:\\window_hierarchy.log";                      // 默认日志记录保存位置
constexpr auto MAX_STSTUS_BUFFER = 350;                                   // 状态信息的最大缓冲区大小

// 记录窗口信息的结构体,使用宽字符
struct WindowInfo {
    std::wstring className;
    std::wstring windowTitle;
    HWND hwnd;
    std::vector<WindowInfo> children;
};

// 监视器线程存储
struct MYMONITOR_THREAD_INFO {
    HDESK hDesktop;
    std::vector<WindowInfo> wndInfo;
};

// 状态信息参数传递结构
struct MYSTATUS_UPDATE_THREAD_INFO {
    HDESK hChangeToDesktop;
    WCHAR wcsBuffer[MAX_STSTUS_BUFFER];
};

// 对话框(异步)参数结构(在线程堆栈上传递)
struct DIALOGBOX_PARAM_LIST {
    _In_opt_ HINSTANCE hInstance;
    _In_     LPCWSTR lpTemplateName;
    _In_opt_ HWND hWndParent;
    _In_opt_ DLGPROC lpDialogFunc;
    _In_     LPARAM dwInitParam;
    _In_     size_t cbSize;
    _Out_    INT_PTR   intResponse;
};

// 文件编码格式
enum class FileEncoding {
    ANSI,
    UTF8,
    UTF16LE,
    UTF16BE,
    UNKNOWN
};

// 用于边框绘制的全局变量
HWND hBorderWnd = NULL;  // 边框窗口句柄
bool borderRunning = false;  // 边框是否正在显示
// 全局变量保存主窗口句柄
HWND hMainWindow = NULL;
HANDLE hBroderWndCreateEvent;

// 启用特定的权限(例如 SeDebugPrivilege)
bool EnablePrivilege(LPCWSTR privilege) {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp{};
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token." << std::endl;
        return false;
    }

    if (!LookupPrivilegeValueW(NULL, privilege, &luid)) {
        std::wcerr << L"Failed to lookup privilege." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
        std::wcerr << L"Failed to adjust token privileges." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
        std::wcerr << L"The privilege was not assigned." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(hToken);
    return true;
}

// 检查是否以管理员权限运行
bool IsRunAsAdmin() {
    BOOL isAdmin = FALSE;
    PSID administratorsGroup = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) {
        CheckTokenMembership(NULL, administratorsGroup, &isAdmin);
        FreeSid(administratorsGroup);
    }
    return isAdmin == TRUE;
}

// 重新启动并请求管理员权限
bool RelaunchAsAdmin() {
    wchar_t szPath[MAX_PATH];
    if (!GetModuleFileNameW(NULL, szPath, MAX_PATH)) {
        std::wcerr << L"Failed to get module file name." << std::endl;
        return false;
    }

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpVerb = L"runas";  // 请求管理员权限
    sei.lpFile = szPath;
    sei.hwnd = NULL;
    sei.nShow = SW_NORMAL;

    if (!ShellExecuteExW(&sei)) {
        std::wcerr << L"Failed to relaunch as administrator." << std::endl;
        return false;
    }
    return true;
}

DWORD WINAPI GetActiveConsoleSessionId() {
    return WTSGetActiveConsoleSessionId();
}


BOOL WINAPI IsProcessInSession(DWORD processId, DWORD sessionId) {
    DWORD session;
    if (!ProcessIdToSessionId(processId, &session)) {
        printf("Error: ProcessIdToSessionId failed.\n");
        return FALSE;
    }
    return session == sessionId;
}


DWORD WINAPI FindWinlogonProcessId() {
    DWORD dwProcessId = 0;
    DWORD activeSessionId = GetActiveConsoleSessionId();
    if (activeSessionId == 0xFFFFFFFF) {
        printf("Error: Unable to retrieve active console session ID.\n");
        return 0;
    }

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        printf("Error: CreateToolhelp32Snapshot failed.\n");
        return 0;
    }

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(snapshot, &entry)) {
        printf("Error: Process32First failed.\n");
        CloseHandle(snapshot);
        return 0;
    }

    do {

        if (entry.cntThreads <= 1u) continue; // 跳过僵尸进程

        if (_wcsicmp(entry.szExeFile, L"winlogon.exe") == 0) {
            if (IsProcessInSession(entry.th32ProcessID, activeSessionId)) {
                dwProcessId = entry.th32ProcessID;
                break;
            }
        }
    } while (Process32Next(snapshot, &entry));

    CloseHandle(snapshot);
    return dwProcessId;
}

// 获取 winlogon 进程的 SYSTEM 令牌
HANDLE GetSystemTokenFromWinlogon() {
    HANDLE hToken = NULL;
    HANDLE hProcess = NULL;
    HANDLE hSystemToken = NULL;  // 存储复制后的 SYSTEM 令牌

    // 获取 Winlogon 进程的进程ID
    DWORD winlogonPid = FindWinlogonProcessId();

    if (winlogonPid == 0) {
        std::wcerr << L"Failed to find winlogon.exe process!" << std::endl;
        return NULL;
    }

    std::wcout << L"winlogon.exe PID: " << winlogonPid << std::endl;

    // 打开 Winlogon 进程
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, winlogonPid);
    if (!hProcess) {
        std::wcerr << L"Failed to open winlogon process!" << std::endl;
        return NULL;
    }

    // 打开该进程的令牌
    if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token!" << std::endl;
        CloseHandle(hProcess);
        return NULL;
    }

    // 复制令牌以使其可用于新进程
    if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hSystemToken)) {
        std::wcerr << L"Failed to duplicate SYSTEM token!" << std::endl;
        CloseHandle(hToken);
        CloseHandle(hProcess);
        return NULL;
    }

    // 关闭原始的令牌和进程句柄
    CloseHandle(hToken);
    CloseHandle(hProcess);
    return hSystemToken;
}

// 创建具有 SYSTEM 权限的进程
bool CreateSystemProcess(LPCWSTR applicationName, LPCWSTR commandLine) {
    HANDLE hToken = GetSystemTokenFromWinlogon();
    if (!hToken) {
        std::wcerr << L"Failed to get SYSTEM token!" << std::endl;
        return false;
    }

    // 使用 SYSTEM 权限创建进程
    STARTUPINFOW si = { sizeof(STARTUPINFOW) };
    PROCESS_INFORMATION pi = { 0 };

    if (!CreateProcessAsUserW(hToken, applicationName, const_cast<LPWSTR>(commandLine), NULL,
        NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to create process as SYSTEM! err = " << GetLastError() << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hToken);
    return true;
}

// 检查当前进程是否具有 SYSTEM 权限
bool IsSystem() {
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
        return false;
    }

    DWORD tokenInfoLength = 0;
    GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenInfoLength);

    PTOKEN_USER tokenUser = (PTOKEN_USER)malloc(tokenInfoLength);
    if (!GetTokenInformation(hToken, TokenUser, tokenUser, tokenInfoLength, &tokenInfoLength)) {
        CloseHandle(hToken);
        free(tokenUser);
        return false;
    }

    LPWSTR sidString = NULL;
    ConvertSidToStringSidW(tokenUser->User.Sid, &sidString);
    bool isSystem = (_wcsicmp(sidString, L"S-1-5-18") == 0);

    LocalFree(sidString);
    CloseHandle(hToken);
    free(tokenUser);

    return isSystem;
}


HWND GetConsoleHwnd(void)
{
    // https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/obtain-console-window-handle

#define MY_BUFSIZE 1024 // Buffer size for console window titles.
    HWND hwndFound;         // This is what is returned to the caller.
    wchar_t pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated
    // WindowTitle.

    // Format a "unique" NewWindowTitle.

    wsprintfW(pszNewWindowTitle, L"WinlogonWindowsMonitor - %d/%d",
        GetTickCount(),
        GetCurrentProcessId());

    // Change current window title.

    SetConsoleTitleW(pszNewWindowTitle);

    // Ensure window title has been updated.

    Sleep(40);

    // Look for NewWindowTitle.

    hwndFound = FindWindowW(L"ConsoleWindowClass", pszNewWindowTitle);

    if(!hwndFound)
        hwndFound = FindWindowW(L"CASCADIA_HOSTING_WINDOW_CLASS", pszNewWindowTitle);

#undef MY_BUFSIZE
    return(hwndFound);
}

// 获取当前进程的主窗口
HWND GetMainWindowHandle() {
    return GetConsoleHwnd();
}

// 检查当前活动窗口是否是主窗口
bool IsMainWindowActive() {
    HWND hForeground = GetForegroundWindow();  // 获取当前活动窗口
    return hForeground == hMainWindow;         // 比较是否是主窗口
}

// 边框窗口过程
LRESULT CALLBACK BorderWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static int borderWidth = 10;  // 默认边框宽度
    static wchar_t statusText[MAX_STSTUS_BUFFER];

    switch (message) {
    case WM_CREATE:
    {
        memset(statusText, 0, sizeof(statusText));
        //memcpy(statusText, LOGING_STATUS_INFO, sizeof(statusText) - 5);
        // 窗口创建成功后,发出信号
        SetEvent(hBroderWndCreateEvent);
        break;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        RECT rect;
        GetClientRect(hWnd, &rect);

        // 设置边框颜色为蓝色
        HBRUSH brush = CreateSolidBrush(RGB(119, 228, 155));

        // 填充外边框到内边框之间的区域
        RECT outerRect = rect;
        RECT innerRect = rect;

        // 根据边框宽度调整内边框位置
        InflateRect(&innerRect, -borderWidth, -borderWidth);

        // 填充外边框和内边框之间的区域
        if (borderWidth > 0) {
            // 填充四个部分:上边、下边、左边、右边
            RECT topRect = { outerRect.left, outerRect.top, outerRect.right, innerRect.top };
            RECT bottomRect = { outerRect.left, innerRect.bottom, outerRect.right, outerRect.bottom };
            RECT leftRect = { outerRect.left, innerRect.top, innerRect.left, innerRect.bottom };
            RECT rightRect = { innerRect.right, innerRect.top, outerRect.right, innerRect.bottom };

            FillRect(hdc, &topRect, brush);
            FillRect(hdc, &bottomRect, brush);
            FillRect(hdc, &leftRect, brush);
            FillRect(hdc, &rightRect, brush);
        }

        DeleteObject(brush);

        // 设置字体
        HFONT hFont = CreateFontW(36, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
            DEFAULT_PITCH | FF_SWISS, L"Arial");
        SelectObject(hdc, hFont);

        // 设置文本颜色为高亮(例如绿色)
        SetTextColor(hdc, RGB(0, 255, 0));
        SetBkMode(hdc, TRANSPARENT); // 透明背景

        // 获取窗口文本并绘制在左下方,间隔 50 像素
        rect.left += 50;   // 左侧间隔 50 像素
        rect.bottom -= 50; // 底部间隔 50 像素

        DrawTextW(hdc, statusText, -1, &rect, DT_LEFT | DT_BOTTOM | DT_SINGLELINE);

        DeleteObject(hFont);


        EndPaint(hWnd, &ps);
        break;
    }
    case WM_UPDATE_STATUS:
    {
        if (wParam == STATUS_MSG_HASH) {
            // 获取窗口文本并绘制
            memset(statusText, 0, sizeof(statusText));
            memcpy(statusText, (LPVOID)lParam, sizeof(statusText) - 5);
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);
        }
        return 0;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        break;
        //return DefWindowProcW(hWnd, message, wParam, lParam);
    }
    return DefWindowProcW(hWnd, message, wParam, lParam);
}

DWORD WINAPI CloseBorderThread(LPVOID lpParam) {
    HDESK hWinlogonDesk = static_cast<HDESK>(lpParam);  // 传递的桌面句柄

    // 获取当前线程的桌面句柄,后面恢复用
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到 Winlogon 桌面
    if (!SetThreadDesktop(hWinlogonDesk)) {
        std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
        return 1;
    }

    // 发送关闭消息
    if (hBorderWnd) {
        PostMessageW(hBorderWnd, WM_DESTROY, 0, 0);
    }

    std::wcout << L"An exit monitoring message has been sent." << std::endl;

    // 恢复到原始桌面
    SetThreadDesktop(hOriginalDesktop);

    return 0;
}


// 更新状态窗口显示的文本信息
DWORD WINAPI UpdateStatusWindowTextThread(LPVOID lpParam) {
    if (lpParam == nullptr) {
        std::wcerr << L"Invalid thread parameters." << std::endl;
        return ERROR_INVALID_PARAMETER;
    }

    __try {
        MYSTATUS_UPDATE_THREAD_INFO* info =
            static_cast<MYSTATUS_UPDATE_THREAD_INFO*>(lpParam);

        if (info->hChangeToDesktop == nullptr || info->wcsBuffer == nullptr) {
            std::wcerr << L"Invalid thread parameters." << std::endl;
            return ERROR_INVALID_PARAMETER;
        }

        // 获取当前线程的桌面句柄,后面恢复用
        HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

        // 切换到 Winlogon 桌面
        if (!SetThreadDesktop(info->hChangeToDesktop)) {
            std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
            return 1;
        }

        // 设置新的信息
        if (hBorderWnd) {
            //InvalidateRect(hBorderWnd, NULL, TRUE);
            SendMessageW(hBorderWnd, WM_UPDATE_STATUS, STATUS_MSG_HASH, (LPARAM)info->wcsBuffer);
            //UpdateWindow(hBorderWnd);
        }

        std::wcout << L"UpdateStatusWindowText successfully." << std::endl;

        // 恢复到原始桌面
        SetThreadDesktop(hOriginalDesktop);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        std::wcerr << L"Memory access violation." << std::endl;
        return ERROR_INVALID_ACCESS;
    }

    return 0;
}


// 在监视过程开始时显示提示信息
BOOL StartMonitoringUI(HDESK hWinlogonDesk) {

    // 切换到 winlogon 桌面并发送状态更新消息
    MYSTATUS_UPDATE_THREAD_INFO info = { hWinlogonDesk };
    wcscpy_s(info.wcsBuffer, LOGING_STATUS_INFO);

    HANDLE hThread = CreateThread(NULL, 0, UpdateStatusWindowTextThread, &info, 0, NULL);
    if (hThread) {
        WaitForSingleObject(hThread, 7000);
        CloseHandle(hThread);
        Sleep(1000);   // 刻意的延时
        return TRUE;
    }

    return FALSE;
}


// 在监视过程完成时更新提示信息
BOOL CompleteMonitoringUI(HDESK hWinlogonDesk) {

    // 切换到 winlogon 桌面并发送状态更新消息
    MYSTATUS_UPDATE_THREAD_INFO info = { hWinlogonDesk };
    wcscpy_s(info.wcsBuffer, COMPLETE_STATUS_INFO);

    HANDLE hThread = CreateThread(NULL, 0, UpdateStatusWindowTextThread, &info, 0, NULL);
    if (hThread) {
        WaitForSingleObject(hThread, 7000);
        CloseHandle(hThread);
        Sleep(1000);   // 刻意的延时
        return TRUE;
    }

    return FALSE;
}


// 检查并关闭监视器
BOOL CloseMonitoringUI(HDESK hWinlogonDesk) {

    // 启动关闭边框的线程
    if (borderRunning) {
        HANDLE hCloseThread = CreateThread(NULL, 0, CloseBorderThread, (LPVOID)hWinlogonDesk, 0, NULL);
        WaitForSingleObject(hCloseThread, INFINITE);  // 等待线程完成
        CloseHandle(hCloseThread);
        borderRunning = false;
    }

    return FALSE;
}

// 边框绘制线程
DWORD WINAPI BorderThread(LPVOID lpParam) {
    std::wcout << L"Monitoring the target desktop..." << std::endl;
    HDESK hWinlogonDesk = static_cast<HDESK>(lpParam);  // 传递的桌面句柄

    // 切换到 Winlogon 桌面
    if (!SetThreadDesktop(hWinlogonDesk)) {
        std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
        return 1;
    }
#define MY_BUFSIZE 1024 // Buffer size for console window titles.
    wchar_t pszWindowClass[MY_BUFSIZE]; // Contains fabricated
    // WindowClass.

    // Format a "unique" WindowClass.
    wsprintfW(pszWindowClass, L"WinlogonMonitorBorderWindowClass[%d::%d]",
        GetTickCount(),
        GetCurrentProcessId());

    HINSTANCE hInstance = GetModuleHandleW(NULL);
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = BorderWndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = pszWindowClass;
    wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));

    if (!RegisterClassW(&wc)) {
        std::wcerr << L"Failed to RegisterClass." << std::endl;
        return 1;
    }

    // 获取屏幕大小并创建无边框窗口
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);

    hBorderWnd = CreateWindowExW(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT,
        wc.lpszClassName, L"WinlogonMonitorBorderWindow", WS_POPUP,
        0, 0, screenWidth, screenHeight, NULL, NULL, hInstance, NULL);

    if (!hBorderWnd) {
        std::wcerr << L"Failed to CreateWindow." << std::endl;
        return 1;
    }

    // 设置窗口透明度
    SetLayeredWindowAttributes(hBorderWnd, RGB(255, 255, 255), 0, LWA_COLORKEY);

    ShowWindow(hBorderWnd, SW_SHOW);
    UpdateWindow(hBorderWnd);

    // 消息循环,等待关闭事件
    MSG msg;
    while (true) {
        // 检查并处理窗口消息
        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    // 销毁窗口
    DestroyWindow(hBorderWnd);

#undef MY_BUFSIZE
    return 0;
}


// 递归获取窗口层次,使用宽字符 API
void EnumChildWindowsRecursive(HWND hwndParent, std::vector<WindowInfo>& windowList) {
    wchar_t className[256];
    wchar_t windowTitle[256];

    ZeroMemory(className, sizeof(className));
    ZeroMemory(windowTitle, sizeof(windowTitle));

    // 获取窗口类名和标题
    GetClassNameW(hwndParent, className, sizeof(className) / sizeof(wchar_t));
    GetWindowTextW(hwndParent, windowTitle, sizeof(windowTitle) / sizeof(wchar_t));

    if (className[0] == L'\0') {
        wcscpy_s(className, L"(None)");
    }

    if (windowTitle[0] == L'\0') {
        wcscpy_s(windowTitle, L"(None)");
    }

    WindowInfo windowInfo = { className, windowTitle, hwndParent };

    // 枚举子窗口
    EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* children = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *children);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windowInfo.children));

    windowList.push_back(windowInfo);
}

// 获取当前桌面窗口层次,使用宽字符 API
std::vector<WindowInfo> GetWindowHierarchy() {
    std::vector<WindowInfo> windows;
    EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* windows = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *windows);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windows));
    return windows;
}

// 获取当前窗口层次的哈希值,用于检测窗口层次是否发生变化
std::size_t GetWindowHierarchyHash(const std::vector<WindowInfo>& windows) {
    std::hash<std::wstring> hash_fn;
    std::size_t hash = 0;

    std::function<void(const std::vector<WindowInfo>&)> computeHash;
    computeHash = [&hash_fn, &hash, &computeHash](const std::vector<WindowInfo>& windows) {
        for (const auto& window : windows) {
            hash ^= hash_fn(window.className);
            hash ^= hash_fn(window.windowTitle);
            computeHash(window.children);  // 递归计算子窗口的哈希值
        }
    };

    computeHash(windows);
    return hash;
}

// 格式化时间为宽字符格式
std::wstring FormatTime(const std::time_t& time) {
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &time);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);
    return std::wstring(timeBuffer);
}

// 转换宽字符到 UTF-8
std::string WideToUTF8(const std::wstring& wideStr) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    return conv.to_bytes(wideStr);
}

// 保存窗口层次信息到文件,使用 UTF-8 编码
void SaveWindowHierarchy(const std::vector<WindowInfo>& windows, const std::time_t& changeTime, const std::wstring& filename) {
    std::ofstream file(WideToUTF8(filename), std::ios::app | std::ios::binary);  // 使用 binary 防止换行符的意外转换
    if (!file.is_open()) {
        std::wcerr << L"Unable to open file for writing!" << std::endl;
        return;
    }

    // 在文件开头写入 BOM,标识为 UTF-8 编码
    static bool bomWritten = false;
    if (!bomWritten) {
        const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };  // UTF-8 BOM
        file.write(reinterpret_cast<const char*>(bom), sizeof(bom));
        bomWritten = true;
    }

    // 格式化时间为字符串
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &changeTime);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);

    // 写入时间戳
    file << WideToUTF8(std::wstring(timeBuffer)) << "\n";

    // 递归写入窗口信息
    std::function<void(const std::vector<WindowInfo>&, int)> WriteHierarchy;
    WriteHierarchy = [&file, &WriteHierarchy](const std::vector<WindowInfo>& windows, int indent) {
        for (const auto& window : windows) {
            file << std::string(indent, ' ')  // 使用空格进行缩进
                << "Class Name: " << WideToUTF8(window.className)
                << ", Title: " << WideToUTF8(window.windowTitle)
                << ", HWND: " << std::hex << window.hwnd << "\n";
            if (!window.children.empty()) {
                WriteHierarchy(window.children, indent + 4);  // 递归写入子窗口信息
            }
        }
    };

    WriteHierarchy(windows, 0);
    file << "\n";
    file.close();
}

// 获取当前桌面的名称
std::wstring GetDesktopName(HDESK hDesktop) {
    wchar_t desktopName[256];
    DWORD neededLength = 0;

    if (!GetUserObjectInformationW(hDesktop, UOI_NAME, desktopName, sizeof(desktopName), &neededLength)) {
        std::wcerr << L"Failed to get desktop name." << std::endl;
        return L"";
    }

    return std::wstring(desktopName);
}


// 切换到指定桌面并枚举窗口,任务结束后恢复到原始桌面
std::vector<WindowInfo> GetWindowsFromDesktop(HDESK hDesktop) {
    // 获取原始桌面句柄
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到目标桌面
    if (!SetThreadDesktop(hDesktop)) {
        std::wcerr << L"Failed to set thread desktop!" << std::endl;
        return {};
    }

    // 切换后获取窗口层次
    std::vector<WindowInfo> windows = GetWindowHierarchy();

    // 恢复到原始桌面
    if (!SetThreadDesktop(hOriginalDesktop)) {
        std::wcerr << L"Failed to restore original desktop!" << std::endl;
    }

    return windows;
}

// 使用辅助线程进行桌面切换和窗口枚举
DWORD WINAPI MonitorDesktopThread(LPVOID param) {
    _wsetlocale(LC_ALL, L"zh-CN");
    MYMONITOR_THREAD_INFO* threadInfo = static_cast<MYMONITOR_THREAD_INFO*>(param);

    threadInfo->wndInfo = GetWindowsFromDesktop(threadInfo->hDesktop);

    return 0;
}

// 打开窗口工作站并切换到桌面
HDESK OpenDesktopWithWindowStation(LPCWSTR desktopName, HWINSTA hWinsta) {
    // 打开桌面
    HDESK hDesktop = OpenDesktopW(desktopName, 0, FALSE, GENERIC_ALL);
    if (!hDesktop) {
        std::wcerr << L"Failed to open desktop! name = " << desktopName << std::endl;
        CloseWindowStation(hWinsta);
    }

    return hDesktop;
}

// 获取当前活动桌面
HDESK GetActiveDesktop() {
    return OpenInputDesktop(0, FALSE, GENERIC_ALL);
}

// 对话框过程函数
INT_PTR CALLBACK HistoryDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
    static std::wstring* historyText = nullptr;

    switch (message) {
    case WM_INITDIALOG:
    {
        historyText = reinterpret_cast<std::wstring*>(lParam);

        // 获取编辑控件句柄
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
        if (hEdit) {
            // 设置文本
            SetWindowTextW(hEdit, historyText->c_str());
        }
    }
    return (INT_PTR)TRUE;

    case WM_SIZE:
    {
        // 获取对话框的新尺寸
        int width = LOWORD(lParam);   // 新的宽度
        int height = HIWORD(lParam);  // 新的高度
        

        // 调整编辑控件大小
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
        if (hEdit) {
            int margin = 25;
            MoveWindow(hEdit, margin, margin, width - 2 * margin, height - 80, TRUE);
        }

        // 调整OK按钮的位置
        HWND hButtonOK = GetDlgItem(hDlg, IDOK);
        if (hButtonOK) {
            int buttonWidth = 120;
            int buttonHeight = 35;
            int margin = 15;
            // 按钮位于对话框底部,右边留一定的边距
            MoveWindow(hButtonOK, width - buttonWidth - margin, height - buttonHeight - margin, buttonWidth, buttonHeight, TRUE);
        }
    }
    break;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;

    default:
        return FALSE;
    }
    return FALSE;
}


// 使用辅助线程进行桌面切换和窗口枚举
DWORD WINAPI DialogBoxParamThread(LPVOID param) {
    _wsetlocale(LC_ALL, L"zh-CN");

    if (param == nullptr) {

        return ERROR_INVALID_PARAMETER;
    }

    DIALOGBOX_PARAM_LIST* dialogParam = static_cast<DIALOGBOX_PARAM_LIST*>(param);

    if (dialogParam->lpDialogFunc == nullptr || dialogParam->dwInitParam == NULL) {

        return ERROR_INVALID_PARAMETER;
    }


    dialogParam->intResponse = DialogBoxParamW(dialogParam->hInstance, 
                                                dialogParam->lpTemplateName, 
                                                dialogParam->hWndParent, 
                                                dialogParam->lpDialogFunc, 
                                                dialogParam->dwInitParam);

    Sleep(1000);

    memset(*(WCHAR**)dialogParam->dwInitParam, 0, dialogParam->cbSize);
    delete[] *(WCHAR**)dialogParam->dwInitParam;

    return 0;
}


// 异步显示历史记录对话框
void CreateDialogBoxAsyncW(std::wstring text) {

    WCHAR* wcsText = new (std::nothrow) WCHAR[text.length() + 1];
    const size_t len = (text.length() + 1) * sizeof(WCHAR);

    memset(wcsText, 0, len);
    memcpy(wcsText, text.c_str(), len);

    // 显示历史记录对话框
    DIALOGBOX_PARAM_LIST dialogParam = { GetModuleHandle(NULL), 
                                MAKEINTRESOURCE(IDD_DIALOG1), NULL, 
                                HistoryDialogProc,(LPARAM)&wcsText, len , 0 };
    
    HANDLE hThread = CreateThread(NULL, 0, DialogBoxParamThread, &dialogParam, 0, NULL);
}


// 监控桌面切换
void MonitorDesktop() {

    // 注册 Ctrl + Shift + F1 组合键为全局热键 (ID = 1)
    if (!RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_SHIFT, VK_F1)) {
        std::wcerr << L"Failed to register hotkey for Ctrl + Shift + F1." << std::endl;
        return;
    }

    // 打开窗口工作站
    HWINSTA hWinsta = OpenWindowStationW(L"WinSta0", FALSE, GENERIC_READ | GENERIC_WRITE);
    if (!hWinsta) {
        std::wcerr << L"Failed to open window station!" << std::endl;
        return;
    }

    // 将当前线程关联到工作站
    if (!SetProcessWindowStation(hWinsta)) {
        std::wcerr << L"Failed to set process window station!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    HDESK hDefaultDesk = OpenDesktopWithWindowStation(L"Default", hWinsta);
    HDESK hWinlogonDesk = OpenDesktopWithWindowStation(L"Winlogon", hWinsta);

    if (!hDefaultDesk || !hWinlogonDesk) {
        std::wcerr << L"Failed to open desktops!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    std::wcout << L"Monitoring desktop changes (SYSTEM privileges detected)..." << std::endl;
    std::wcout << L"Desktops: Winlogon(" << std::hex << (UINT64)hWinlogonDesk << L"), Default("
        << std::hex << (UINT64)hDefaultDesk << L")." << std::endl;
    
    // 桌面监控代码

    std::vector<WindowInfo> windowHistory;
    std::size_t prevHash = 0;  // 保存上一次的哈希值
    bool monitoring = false;
    MYMONITOR_THREAD_INFO monitor_info = { hWinlogonDesk };

    HANDLE hBorderThread = NULL;  // 边框线程句柄

    while (true) {
        MSG msg;
        // 非阻塞的消息检查
        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (IsMainWindowActive() && msg.message == WM_HOTKEY && msg.wParam == 1) {
                // Ctrl + Shift + F1 热键触发,退出循环
                std::wcout << L"Ctrl + Shift + F1 pressed. Exiting monitoring..." << std::endl;
                Sleep(1000);
                // 启动关闭边框的线程
                CloseMonitoringUI(hWinlogonDesk);
                goto exit_monitoring;
            }
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }

        HDESK hCurrentDesk = GetActiveDesktop();   // 获取活动桌面句柄

        std::wstring desktopName = GetDesktopName(hCurrentDesk);   // 获取桌面名称

        //std::wcout << L"Current Desktop: " << desktopName << std::endl;

        if (desktopName == L"Winlogon" && !monitoring) {
            std::wcout << L"Switched to Winlogon desktop. Start monitoring window hierarchy..." << std::endl;
            monitoring = true;
            windowHistory.clear();  // 清空之前的记录

            // 创建事件对象
            hBroderWndCreateEvent = CreateEventW(NULL, TRUE, FALSE, NULL);

            // 启动边框绘制线程,并传递 Winlogon 桌面句柄
            if (!borderRunning) {
                hBorderThread = CreateThread(NULL, 0, BorderThread, (LPVOID)hWinlogonDesk, 0, NULL);
                borderRunning = true;
            }

            // 在主线程等待窗口创建完成
            WaitForSingleObject(hBroderWndCreateEvent, INFINITE);

            // 设置状态为:记录中
            StartMonitoringUI(hWinlogonDesk);

            // 切换到 winlogon 桌面并枚举窗口
            
            HANDLE hThread = CreateThread(NULL, 0, MonitorDesktopThread, &monitor_info, 0, NULL);
            if (hThread) {
                WaitForSingleObject(hThread, INFINITE);
                CloseHandle(hThread);
            }
            windowHistory = monitor_info.wndInfo;

            // 计算当前窗口层次的哈希值
            prevHash = GetWindowHierarchyHash(windowHistory);

            // 设置状态为:已完成
            CompleteMonitoringUI(hWinlogonDesk);
        }
        else if (desktopName == L"Default" && monitoring) {
            std::wcout << L"Switched back to Default desktop. Stopping monitoring..." << std::endl;
            std::time_t currentTime = std::time(nullptr);
            SaveWindowHierarchy(windowHistory, currentTime, LogDir);
            monitoring = false;

            // 启动关闭边框的线程
            CloseMonitoringUI(hWinlogonDesk);

            // 格式化时间为字符串
            wchar_t timeBuffer[100];
            tm ti = {};
            localtime_s(&ti, &currentTime);
            std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);

            // 构建窗口层次信息文本
            std::wstringstream ss;
            ss << L"Most Recent History Call ( " << timeBuffer << L" ): \r\n";
            for (const auto& win : windowHistory) {
                ss << L"Class Name: " << win.className << L", Title: " << win.windowTitle
                    << L", HWND: " << std::hex << win.hwnd << L"\r\n";
            }
            std::wstring historyText = ss.str();

            // 显示历史记录对话框
            //DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), NULL, HistoryDialogProc, (LPARAM)&historyText);
            CreateDialogBoxAsyncW(historyText);
        }

        // 检查窗口层次变化
        if (monitoring) {
            HANDLE hThread = CreateThread(NULL, 0, MonitorDesktopThread, &monitor_info, 0, NULL);
            if (hThread) {
                // 设置状态为:记录中
                StartMonitoringUI(hWinlogonDesk);
                WaitForSingleObject(hThread, INFINITE);   // 等待线程结束
                CloseHandle(hThread);
                // 设置状态为:已完成
                CompleteMonitoringUI(hWinlogonDesk);
            }
            std::size_t currentHash = GetWindowHierarchyHash(monitor_info.wndInfo);
            if (currentHash != prevHash) {
                std::wcout << L"Window hierarchy changed. Updating records..." << std::endl;
                windowHistory = monitor_info.wndInfo;
                std::time_t currentTime = std::time(nullptr);
                SaveWindowHierarchy(windowHistory, currentTime, LogDir);
                prevHash = currentHash;
            }
        }

        Sleep(1000);  // 每秒检查一次
    }

exit_monitoring:
    // 注销热键
    UnregisterHotKey(NULL, 1);

    // 清理
    CloseDesktop(hDefaultDesk);
    CloseDesktop(hWinlogonDesk);
    CloseWindowStation(hWinsta);
}


// 检测文件编码
FileEncoding DetectFileEncoding(const std::wstring& filePath) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open file for encoding detection: " << filePath << std::endl;
        return FileEncoding::UNKNOWN;
    }

    unsigned char bom[3] = { 0 };
    file.read(reinterpret_cast<char*>(bom), 3);
    file.close();

    // Check BOM (Byte Order Mark)
    if (bom[0] == 0xFF && bom[1] == 0xFE) {
        return FileEncoding::UTF16LE;  // UTF-16 Little Endian
    }
    else if (bom[0] == 0xFE && bom[1] == 0xFF) {
        return FileEncoding::UTF16BE;  // UTF-16 Big Endian
    }
    else if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) {
        return FileEncoding::UTF8;     // UTF-8 with BOM
    }
    else {
        return FileEncoding::ANSI;     // Default to ANSI
    }
}

// 读取文件内容,处理不同编码格式
bool ReadFileWithEncoding(const std::wstring& filePath, std::wstring& content) {
    FileEncoding encoding = DetectFileEncoding(filePath);

    if (encoding == FileEncoding::UTF16LE || encoding == FileEncoding::UTF16BE) {
        // Use wide string stream to read UTF-16 encoded file
        std::wifstream wfile(filePath, std::ios::binary);
        if (!wfile.is_open()) {
            std::wcerr << L"Failed to open UTF-16 file: " << filePath << std::endl;
            return false;
        }
        wfile.imbue(std::locale(wfile.getloc(), new std::codecvt_utf16<wchar_t, 0x10FFFF, std::little_endian>));
        std::wstringstream wss;
        wss << wfile.rdbuf();
        content = wss.str();
        wfile.close();
    }
    else if (encoding == FileEncoding::UTF8) {
        // Use standard string stream to read UTF-8 encoded file
        std::ifstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open UTF-8 file: " << filePath << std::endl;
            return false;
        }
        std::stringstream ss;
        ss << file.rdbuf();
        std::string utf8Content = ss.str();

        // Convert UTF-8 string to wide string
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        content = converter.from_bytes(utf8Content);
        file.close();
    }
    else if (encoding == FileEncoding::ANSI) {
        // Use standard string stream to read ANSI encoded file
        std::ifstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open ANSI file: " << filePath << std::endl;
            return false;
        }
        std::stringstream ss;
        ss << file.rdbuf();
        std::string ansiContent = ss.str();

        // Convert ANSI string to wide string (using current locale)
        content = std::wstring(ansiContent.begin(), ansiContent.end());
        file.close();
    }
    else {
        std::wcerr << L"Unknown file encoding." << std::endl;
        return false;
    }
    return true;
}


// 宽字符到多字节字符的转换 (ANSI)
std::string WideStringToString(const std::wstring& wstr) {
    if (wstr.empty()) return std::string();

    // 使用系统默认代码页 (CP_ACP) 将宽字符转换为多字节字符
    int size_needed = WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string str(size_needed, 0);
    WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), &str[0], size_needed, NULL, NULL);
    return str;
}

// 根据编码保存修改后的文件内容
bool ModifyAndSaveFileWithEncoding(const std::wstring& filePath, const std::wstring& content) {
    FileEncoding encoding = DetectFileEncoding(filePath);

    if (encoding == FileEncoding::UTF16LE) {
        // Save as UTF-16 Little Endian
        std::wofstream wfile(filePath, std::ios::binary);
        if (!wfile.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        wfile.imbue(std::locale(wfile.getloc(), new std::codecvt_utf16<wchar_t, 0x10FFFF, std::little_endian>));
        wfile << content;
        wfile.close();
    }
    else if (encoding == FileEncoding::UTF8) {
        // Save as UTF-8
        std::ofstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::string utf8Content = converter.to_bytes(content);
        file << utf8Content;
        file.close();
    }
    else if (encoding == FileEncoding::ANSI) {
        // Save as ANSI
        std::ofstream file(filePath);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        std::string ansiContent = WideStringToString(content);
        file << ansiContent;
        file.close();
    }
    else {
        std::wcerr << L"Unknown file encoding, cannot save file." << std::endl;
        return false;
    }
    return true;
}

// 修改 SeAssignPrimaryTokenPrivilege 权限
bool ModifySeAssignPrimaryTokenPrivilege(const std::wstring& configFilePath, const std::wstring& userName) {
    std::wstring content;

    // 读取文件内容
    if (!ReadFileWithEncoding(configFilePath, content)) {
        std::wcerr << L"Failed to read configuration file with correct encoding." << std::endl;
        return false;
    }

    // 查找并修改 SeAssignPrimaryTokenPrivilege
    size_t pos = content.find(L"SeAssignPrimaryTokenPrivilege");
    if (pos != std::wstring::npos) {
        size_t endPos = content.find(L"\n", pos) - 1;
        std::wstring line = content.substr(pos, endPos - pos);

        // 检查是否包含当前用户
        if (line.find(userName) == std::wstring::npos) {
            line += L"," + userName;
            content.replace(pos, endPos - pos, line);
        }
    }

    // 保存修改后的文件
    if (!ModifyAndSaveFileWithEncoding(configFilePath, content)) {
        std::wcerr << L"Failed to save modified configuration file." << std::endl;
        return false;
    }

    return true;
}

// 执行命令
bool ExecuteCommandWithOutput(const std::wstring& command, std::wstring& output) {
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hRead, hWrite;

    // Initialize security attributes for pipe handles
    ZeroMemory(&sa, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;

    // Create a pipe for the child process's STDOUT and STDERR
    if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
        std::wcerr << L"Failed to create pipe." << std::endl;
        return false;
    }

    // Ensure the read handle to the pipe is not inherited
    if (!SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0)) {
        std::wcerr << L"Failed to set handle information." << std::endl;
        return false;
    }

    // Set up the STARTUPINFO structure for the child process
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;
    si.dwFlags |= STARTF_USESTDHANDLES;  // Redirect STDOUT and STDERR to the pipe

    // Set up the PROCESS_INFORMATION structure
    ZeroMemory(&pi, sizeof(pi));

    // Create the child process with CREATE_NO_WINDOW to avoid showing a new console window
    if (!CreateProcessW(NULL, const_cast<LPWSTR>(command.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to execute command: " << command << std::endl;
        CloseHandle(hRead);
        CloseHandle(hWrite);
        return false;
    }

    // Close the write end of the pipe in the parent process
    CloseHandle(hWrite);

    // Read the output from the child process
    DWORD bytesRead;
    CHAR buffer[4096];
    std::string ansiResult;
    BOOL success = FALSE;

    ZeroMemory(buffer, sizeof(buffer) * sizeof(CHAR));

    // Continuously read from the pipe until there's no more data
    while (true) {
        success = ReadFile(hRead, buffer, sizeof(buffer) - 1, &bytesRead, NULL);
        if (!success || bytesRead == 0) {
            break;  // No more data to read
        }
        buffer[bytesRead] = '\0';  // Null-terminate the buffer
        ansiResult += buffer;      // Collect the ANSI result
    }

    // Close handles
    CloseHandle(hRead);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    // If the result is empty, return "Output is empty"
    if (ansiResult[0] == '\0') {
        output = L"\n(no message)\n";
        return true;
    }

    // Convert the ANSI result to wide string (UTF-16) for proper Unicode handling
    int wideSize = MultiByteToWideChar(CP_ACP, 0, ansiResult.c_str(), -1, NULL, 0);
    if (wideSize == 0) {
        std::wcerr << L"Failed to convert output to wide string." << std::endl;
        return false;
    }

    std::wstring wideResult(wideSize, 0);
    MultiByteToWideChar(CP_ACP, 0, ansiResult.c_str(), -1, &wideResult[0], wideSize);

    output = wideResult;
    return true;
}

// 判断文件是否存在
BOOL IsFileExist(const std::wstring& wsFile)
{
    DWORD dwAttrib = GetFileAttributesW(wsFile.c_str());
    return INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

// 导出安全策略
bool ExportSecurityPolicy(const std::wstring& outputFile, std::wstring& output) {
    // https://blog.csdn.net/u012494876/article/details/51204615
    if (IsFileExist(outputFile)) {  // 判断配置文件是否已经存在
        std::wcout << L"The configuration file already exists. Attempting to delete it." << std::endl;
        if (!DeleteFileW(outputFile.c_str())) {
            std::wcerr << L"Failed to delete the configuration file." << std::endl;
            return false;
        }
    }

    std::wstring command = L"secedit /export /cfg " + outputFile;
    return ExecuteCommandWithOutput(command, output);
}

// 应用修改后的安全策略
bool ApplySecurityPolicy(const std::wstring& configFilePath, const std::wstring& dbFilePath, std::wstring& output) {
    std::wstring command = L"secedit /configure /db " + dbFilePath + L" /cfg " + configFilePath + L" /overwrite /quiet";
    return ExecuteCommandWithOutput(command, output);
}

// 获取系统盘符
std::wstring GetSystemDrive() {
    wchar_t systemPath[MAX_PATH];
    if (GetSystemDirectoryW(systemPath, MAX_PATH)) {
        return std::wstring(systemPath).substr(0, 3);  // 返回盘符部分,例如 C:
    }
    return L"C:\\";  // 如果获取失败,返回默认 C 盘符
}

// 获取当前用户账户名称
std::wstring GetCurrentUserName() {
    wchar_t userName[UNLEN + 1];
    DWORD size = UNLEN + 1;
    if (GetUserNameW(userName, &size)) {
        return std::wstring(userName);
    }
    return L"";  // 返回空字符串表示获取失败
}

// 提示用户注销
void PromptUserToLogout() {
    // Ask the user if they want to log off and re-log in
    int result = MessageBoxW(NULL,
        L"The security settings have been updated. Would you like to log off now and apply the changes?",
        L"Log Off Confirmation",
        MB_YESNO | MB_ICONQUESTION | MB_SYSTEMMODAL);

    if (result == IDYES) {
        // Log off the user
        if (!ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, SHTDN_REASON_MAJOR_OTHER)) {
            std::wcerr << L"Failed to log off the user." << std::endl;
        }
    }
    else {
        std::wcout << L"User chose not to log off." << std::endl;
    }
}

bool ChangeAssignPrimaryTokenPrivilege() {
    std::wstring systemDrive = GetSystemDrive();
    std::wstring configFilePath = systemDrive + L"gp.inf";
    std::wstring dbFilePath = systemDrive + L"test.sdb";
    std::wstring userName = GetCurrentUserName();
    std::wstring output;

    if (userName.empty()) {
        std::wcerr << L"Failed to retrieve the current user name." << std::endl;
        return false;
    }

    if (!ExportSecurityPolicy(configFilePath, output)) {
        std::wcerr << L"Failed to export security policy." << std::endl;
        return false;
    }

    std::wcout << L"\nExportSecurityPolicy message: \n" << output << std::endl;

    if (!ModifySeAssignPrimaryTokenPrivilege(configFilePath, userName)) {
        std::wcerr << L"Failed to modify SeAssignPrimaryTokenPrivilege." << std::endl;
        return false;
    }

    if (!ApplySecurityPolicy(configFilePath, dbFilePath, output)) {
        std::wcerr << L"Failed to apply security policy." << std::endl;
        return false;
    }

    std::wcout << L"\nApplySecurityPolicy message: \n" << output << std::endl;

    PromptUserToLogout();

    return true;
}

int wmain(int argc, wchar_t* argv[]) {
    // 宽字符中文支持
    _wsetlocale(LC_ALL, L"zh-CN");

    // 获取当前进程的主窗口
    hMainWindow = GetMainWindowHandle();
    if (!hMainWindow) {
        std::cerr << "Failed to find main window." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }
    std::cout << "Main window handle: " << std::hex << hMainWindow << std::endl;

    // 检查是否为管理员权限运行
    if (!IsRunAsAdmin()) {
        std::wcout << L"Attempting to restart with administrator privileges..." << std::endl;
        if (RelaunchAsAdmin()) {
            return 0;  // 提升后进程将重新启动,当前进程结束
        }
        else {
            std::wcerr << L"Failed to relaunch as administrator." << std::endl;
            system("pause > nul 2 > nul");
            return 1;
        }
    }

    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_DEBUG_NAME)) {
        std::wcerr << L"Failed to enable SeDebugPrivilege." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }

    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_INCREASE_QUOTA_NAME)) {
        std::wcerr << L"Failed to enable SeIncreaseQuotaPrivilege." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }
    
    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME)) {
        std::wcerr << L"Failed to enable SeAssignPrimaryTokenPrivilege." << std::endl;
        if (!ChangeAssignPrimaryTokenPrivilege()) {
            std::wcerr << L"Failed to enable primary token assignment privilege"
                << L" by modifying security configuration." << std::endl;
        }
        std::wcout << L"Press any key to close app.";
        system("pause > nul 2 > nul");
        return 1;
    }

    // 检查 SYSTEM 权限
    if (!IsSystem()) {
        std::wcout << L"Attempting to restart with SYSTEM privileges..." << std::endl;

        // 检查命令行参数,避免无限递归
        if (argc < 2 || _wcsicmp(argv[1], L"system") != 0) {
            // 重新启动自身并传递 "system" 参数
            wchar_t commandLine[MAX_PATH];
            swprintf(commandLine, MAX_PATH, L"%s system", argv[0]);
            if (CreateSystemProcess(argv[0], commandLine)) {
                std::wcout << L"Restarted with SYSTEM privileges." << std::endl;
            }
            else {
                std::wcerr << L"Failed to restart with SYSTEM privileges." << std::endl;
                system("pause > nul 2 > nul");
            }
            return 0;
        }
        else {
            std::wcerr << L"Already tried to elevate privileges but failed." << std::endl;
            system("pause > nul 2 > nul");
            return 1;
        }
    }
    // 如果当前进程已经是 SYSTEM 权限,则继续执行桌面监控
    MonitorDesktop();
    std::wcout << L"Press any key to close app.";
    system("pause > nul 2 > nul");
    return 0;
}

版本 1.0.0.3 修复内容:

  1. 修复了在创建历史记录对话框时,在堆栈上传递共享地址导致的内存访问问题;
  2. 修复了发送窗口关闭消息但但有时候不能够完成退出的问题;
  3. 修复了多线程的等待和检查机制(部分地方之前采用了无限等待或者不安全的检查);
  4. 根据 C++20 ,取消了对 codecvt 头文件及其 API 的使用;
  5. 使用静态链接和 Win32 的绝对路径缓解使用当前目录的模块劫持漏洞;
  6. 修复在部分系统上,日志文本不正确回车换行的问题;

版本 1.0.0.3 代码:

#include <windows.h>
#include <iostream>
#include <lmcons.h>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>
#include <sstream>
#include <functional>
#include <tlhelp32.h>
#include <userenv.h>
#include <sddl.h>
#include "resource.h"

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "advapi32.lib")

#pragma comment(linker,"\"/manifestdependency:type='win32' "\
						"name='Microsoft.Windows.Common-Controls' "\
						"version='6.0.0.0' processorArchitecture='*' "\
						"publicKeyToken='6595b64144ccf1df' language='*'\"")

constexpr auto WM_UPDATE_STATUS = WM_APP + 10;                            // 传递新的状态信息的用户自定义消息
constexpr auto STATUS_MSG_HASH = 0x3456789;                               // 内部校验码(防止外部程序模拟消息)
constexpr auto LOGING_STATUS_INFO = L"Now Monitoring...";                 // 显示提示:正在扫描窗口
constexpr auto COMPLETE_STATUS_INFO = L"Monitoring completed!";           // 显示提示:窗口扫描已完成
constexpr auto LOG_FILE_NAME = L"window_hierarchy.log";                   // 默认日志记录保存位置
constexpr auto MAX_STSTUS_BUFFER = 350;                                   // 状态信息的最大缓冲区大小
constexpr auto MONITOR_THREAD_TIMEOUT = 25000;                            // 窗口监视器线程超时(默认 25 秒)
constexpr auto CREATE_BORDER_WINDOW_TIMEOUT = 0x493E0;                    // 边框窗口创建超时(默认 5 分钟)

constexpr auto SYSTEM32_NAME = L"System32";


// 记录窗口信息的结构体,使用宽字符
struct WindowInfo {
    std::wstring className;
    std::wstring windowTitle;
    HWND hwnd;
    std::vector<WindowInfo> children;
};

// 监视器线程存储
struct MYMONITOR_THREAD_INFO {
    HDESK hDesktop;
    std::vector<WindowInfo> wndInfo;
};

// 状态信息参数传递结构
struct MYSTATUS_UPDATE_THREAD_INFO {
    HDESK hChangeToDesktop;
    WCHAR wcsBuffer[MAX_STSTUS_BUFFER];
};

// 文件编码格式(处理系统安全配置文件时用到)
enum class FileEncoding {
    ANSI,
    UTF8,
    UTF16LE,
    UTF16BE,
    UNKNOWN
};

// 对话框(异步)参数结构(使用深拷贝)
struct DIALOGBOX_PARAM_LIST {
    HINSTANCE hInstance;       // 使用默认初始化值
    LPCWSTR lpTemplateName;    // 模板名称
    HWND hWndParent;           // 父窗口句柄
    DLGPROC lpDialogFunc;      // 对话框过程
    LPARAM dwInitParam;        // 初始化参数
    size_t cbSize;             // 参数大小
    INT_PTR intResponse;       // 响应值

    DIALOGBOX_PARAM_LIST() : hInstance(nullptr), lpTemplateName(nullptr), hWndParent(nullptr),
        lpDialogFunc(nullptr), dwInitParam(0), cbSize(0), intResponse(0) {}

    // 复制构造函数,用于深拷贝
    DIALOGBOX_PARAM_LIST(const DIALOGBOX_PARAM_LIST& other) {
        hInstance = other.hInstance;
        lpTemplateName = other.lpTemplateName;
        hWndParent = other.hWndParent;
        lpDialogFunc = other.lpDialogFunc;
        cbSize = other.cbSize;
        intResponse = other.intResponse;

        // 深拷贝 dwInitParam
        if (other.dwInitParam != 0 && other.cbSize > 0) {
            dwInitParam = (LPARAM)new BYTE[other.cbSize];
            std::memcpy((void*)dwInitParam, (void*)other.dwInitParam, other.cbSize);
        }
        else {
            dwInitParam = 0;
        }
    }

    // 析构函数,释放深拷贝的内存
    ~DIALOGBOX_PARAM_LIST() {
        if (dwInitParam != 0) {
            delete[](BYTE*)dwInitParam;
            dwInitParam = 0;
        }
    }

    // 赋值运算符重载,确保安全的深拷贝
    DIALOGBOX_PARAM_LIST& operator=(const DIALOGBOX_PARAM_LIST& other) {
        if (this == &other) return *this;

        hInstance = other.hInstance;
        lpTemplateName = other.lpTemplateName;
        hWndParent = other.hWndParent;
        lpDialogFunc = other.lpDialogFunc;
        cbSize = other.cbSize;
        intResponse = other.intResponse;

        if (dwInitParam != 0) {
            delete[](BYTE*)dwInitParam;
        }

        // 深拷贝 dwInitParam
        if (other.dwInitParam != 0 && other.cbSize > 0) {
            dwInitParam = (LPARAM)new BYTE[other.cbSize];
            std::memcpy((void*)dwInitParam, (void*)other.dwInitParam, other.cbSize);
        }
        else {
            dwInitParam = 0;
        }

        return *this;
    }
};

// 用于边框绘制的全局变量
HWND hBorderWnd = NULL;  // 边框窗口句柄
bool borderRunning = false;  // 边框是否正在显示
// 全局变量保存主窗口句柄
HWND hMainWindow = NULL;
HANDLE hBroderWndCreateEvent;

// 获取当前进程完整文件路径的函数
std::wstring GetCurrentProcessFullPath() {
    // 初始缓冲区大小
    DWORD size = MAX_PATH;
    std::vector<wchar_t> buffer(size);

    // 获取当前进程句柄
    HANDLE hProcess = GetCurrentProcess();

    // 查询完整的进程路径,可能需要多次尝试
    while (true) {
        if (QueryFullProcessImageNameW(hProcess, 0, buffer.data(), &size)) {
            return std::wstring(buffer.data(), size);
        }
        else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
            // 缓冲区大小不足,扩大缓冲区
            size += MAX_PATH;
            buffer.resize(size);
        }
        else {
            // 其他错误情况,返回空字符串
            std::wcerr << L"Failed to get full process image name. Error: " << GetLastError() << std::endl;
            return L"";
        }
    }
}

// 获取当前进程所在目录的函数
std::wstring GetCurrentProcessDirectory() {
    std::wstring fullPath = GetCurrentProcessFullPath();
    if (fullPath.empty()) {
        std::wcerr << L"Failed to get process full path." << std::endl;
        return L"";
    }

    size_t lastBackslashPos = fullPath.find_last_of(L"\\/");
    if (lastBackslashPos != std::wstring::npos) {
        return fullPath.substr(0, lastBackslashPos);  // 提取目录部分
    }
    else {
        std::wcerr << L"Failed to find directory in path." << std::endl;
        return L"";
    }
}

// 启用特定的权限(例如 SeDebugPrivilege)
bool EnablePrivilege(LPCWSTR privilege) {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp{};
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token." << std::endl;
        return false;
    }

    if (!LookupPrivilegeValueW(NULL, privilege, &luid)) {
        std::wcerr << L"Failed to lookup privilege." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
        std::wcerr << L"Failed to adjust token privileges." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
        std::wcerr << L"The privilege was not assigned." << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(hToken);
    return true;
}

// 检查是否以管理员权限运行
bool IsRunAsAdmin() {
    BOOL isAdmin = FALSE;
    PSID administratorsGroup = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) {
        CheckTokenMembership(NULL, administratorsGroup, &isAdmin);
        FreeSid(administratorsGroup);
    }
    return isAdmin == TRUE;
}

// 重新启动并请求管理员权限
bool RelaunchAsAdmin() {
    std::wstring szPath = GetCurrentProcessFullPath();
    if (szPath.empty()) {
        std::wcerr << L"Failed to get module file name." << std::endl;
        return false;
    }

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpVerb = L"runas";  // 请求管理员权限
    sei.lpFile = szPath.c_str();
    sei.hwnd = NULL;
    sei.nShow = SW_NORMAL;

    if (!ShellExecuteExW(&sei)) {
        std::wcerr << L"Failed to relaunch as administrator." << std::endl;
        return false;
    }
    return true;
}

// 获取当前控制台的活动会话
DWORD WINAPI GetActiveConsoleSessionId() {
    return WTSGetActiveConsoleSessionId();
}

// 判断进程是否在给定的会话中
BOOL WINAPI IsProcessInSession(DWORD processId, DWORD sessionId) {
    DWORD session;
    if (!ProcessIdToSessionId(processId, &session)) {
        printf("Error: ProcessIdToSessionId failed.\n");
        return FALSE;
    }
    return session == sessionId;
}

// 获取当前会话的 Winlogon 进程的 PID
DWORD WINAPI FindWinlogonProcessId() {
    DWORD dwProcessId = 0;
    DWORD activeSessionId = GetActiveConsoleSessionId();
    if (activeSessionId == 0xFFFFFFFF) {
        printf("Error: Unable to retrieve active console session ID.\n");
        return 0;
    }

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot == INVALID_HANDLE_VALUE) {
        printf("Error: CreateToolhelp32Snapshot failed.\n");
        return 0;
    }

    PROCESSENTRY32W entry{};
    entry.dwSize = sizeof(PROCESSENTRY32W);

    if (!Process32FirstW(snapshot, &entry)) {
        printf("Error: Process32First failed.\n");
        CloseHandle(snapshot);
        return 0;
    }

    do {

        if (entry.cntThreads <= 1u) continue; // 跳过僵尸进程

        if (_wcsicmp(entry.szExeFile, L"winlogon.exe") == 0) {
            if (IsProcessInSession(entry.th32ProcessID, activeSessionId)) {
                dwProcessId = entry.th32ProcessID;
                break;
            }
        }
    } while (Process32NextW(snapshot, &entry));

    CloseHandle(snapshot);
    return dwProcessId;
}

// 获取 winlogon 进程的 SYSTEM 令牌
HANDLE GetSystemTokenFromWinlogon() {
    HANDLE hToken = nullptr;
    HANDLE hProcess = nullptr;
    HANDLE hSystemToken = nullptr;  // 存储复制后的 SYSTEM 令牌

    // 获取 Winlogon 进程的进程ID
    DWORD winlogonPid = FindWinlogonProcessId();

    if (winlogonPid == 0) {
        std::wcerr << L"Failed to find winlogon.exe process!" << std::endl;
        return nullptr;
    }

    std::wcout << L"winlogon.exe PID: " << winlogonPid << std::endl;

    // 打开 Winlogon 进程
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, winlogonPid);
    if (!hProcess) {
        std::wcerr << L"Failed to open winlogon process!" << std::endl;
        return nullptr;
    }

    // 打开该进程的令牌
    if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &hToken)) {
        std::wcerr << L"Failed to open process token!" << std::endl;
        CloseHandle(hProcess);
        return nullptr;
    }

    // 复制令牌以使其可用于新进程
    if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, nullptr, SecurityImpersonation, TokenPrimary, &hSystemToken)) {
        std::wcerr << L"Failed to duplicate SYSTEM token!" << std::endl;
        CloseHandle(hToken);
        CloseHandle(hProcess);
        return nullptr;
    }

    // 关闭原始的令牌和进程句柄
    CloseHandle(hToken);
    CloseHandle(hProcess);
    return hSystemToken;
}

// 创建具有 SYSTEM 权限的进程
bool CreateSystemProcess(LPCWSTR applicationName, LPCWSTR commandLine) {
    HANDLE hToken = GetSystemTokenFromWinlogon();
    if (!hToken) {
        std::wcerr << L"Failed to get SYSTEM token!" << std::endl;
        return false;
    }

    // 使用 SYSTEM 权限创建进程
    STARTUPINFOW si = { sizeof(STARTUPINFOW) };
    PROCESS_INFORMATION pi = { 0 };

    if (!CreateProcessAsUserW(hToken, applicationName, const_cast<LPWSTR>(commandLine), NULL,
        NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to create process as SYSTEM! err = " << GetLastError() << std::endl;
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hToken);
    return true;
}

// 检查当前进程是否至少在 SYSTEM 用户组(Local System)
bool IsSystem() {
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
        return false;
    }

    DWORD tokenInfoLength = 0;
    GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenInfoLength);

    PTOKEN_USER tokenUser = (PTOKEN_USER)malloc(tokenInfoLength);
    if (!GetTokenInformation(hToken, TokenUser, tokenUser, tokenInfoLength, &tokenInfoLength)) {
        CloseHandle(hToken);
        free(tokenUser);
        return false;
    }

    LPWSTR sidString = NULL;
    ConvertSidToStringSidW(tokenUser->User.Sid, &sidString);
    bool isSystem = (_wcsicmp(sidString, L"S-1-5-18") == 0);

    LocalFree(sidString);
    CloseHandle(hToken);
    free(tokenUser);

    return isSystem;
}


// 获取当前控制台窗口句柄
HWND GetConsoleHwnd(void)
{
    // https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/obtain-console-window-handle

#define MY_BUFSIZE 1024 // 控制台窗口标题的缓冲区大小。
    HWND hwndFound;         // 这是返回给调用方的内容。
    wchar_t pszNewWindowTitle[MY_BUFSIZE]; // 包含编造的
                                           // 窗口标题

    // 构造一个“独特的”NewWindowTitle。

    wsprintfW(pszNewWindowTitle, L"WinlogonWindowsMonitor - %d/%d",
        GetTickCount(),
        GetCurrentProcessId());

    // 更改当前窗口标题。

    SetConsoleTitleW(pszNewWindowTitle);

    // 确保窗口标题已更新。

    Sleep(40);

    // 查找 NewWindowTitle。

    hwndFound = FindWindowW(L"ConsoleWindowClass", pszNewWindowTitle);

    if(!hwndFound)
        hwndFound = FindWindowW(L"CASCADIA_HOSTING_WINDOW_CLASS", pszNewWindowTitle);

#undef MY_BUFSIZE
    return(hwndFound);
}

// 获取当前进程的主窗口
HWND GetMainWindowHandle() {
    return GetConsoleHwnd();
}

// 检查当前活动窗口是否是主窗口
bool IsMainWindowActive() {
    HWND hForeground = GetForegroundWindow();  // 获取当前活动窗口
    return hForeground == hMainWindow;         // 比较是否是主窗口
}

// 边框窗口过程
LRESULT CALLBACK BorderWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static int borderWidth = 10;  // 默认边框宽度
    static wchar_t statusText[MAX_STSTUS_BUFFER];

    switch (message) {
    case WM_CREATE:
    {
        // 清空存储状态提示信息的缓冲区
        memset(statusText, 0, sizeof(statusText));
        //memcpy(statusText, LOGING_STATUS_INFO, sizeof(statusText) - 5);
        
        // 窗口创建成功后,发出信号
        SetEvent(hBroderWndCreateEvent);
        break;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        RECT rect;
        GetClientRect(hWnd, &rect);

        // 设置边框颜色为蓝色
        HBRUSH brush = CreateSolidBrush(RGB(119, 228, 155));

        // 填充外边框到内边框之间的区域
        RECT outerRect = rect;
        RECT innerRect = rect;

        // 根据边框宽度调整内边框位置
        InflateRect(&innerRect, -borderWidth, -borderWidth);

        // 填充外边框和内边框之间的区域
        if (borderWidth > 0) {
            // 填充四个部分:上边、下边、左边、右边
            RECT topRect = { outerRect.left, outerRect.top, outerRect.right, innerRect.top };
            RECT bottomRect = { outerRect.left, innerRect.bottom, outerRect.right, outerRect.bottom };
            RECT leftRect = { outerRect.left, innerRect.top, innerRect.left, innerRect.bottom };
            RECT rightRect = { innerRect.right, innerRect.top, outerRect.right, innerRect.bottom };

            FillRect(hdc, &topRect, brush);
            FillRect(hdc, &bottomRect, brush);
            FillRect(hdc, &leftRect, brush);
            FillRect(hdc, &rightRect, brush);
        }

        DeleteObject(brush);

        // 设置字体
        HFONT hFont = CreateFontW(36, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
            DEFAULT_PITCH | FF_SWISS, L"Arial");
        SelectObject(hdc, hFont);

        // 设置文本颜色为高亮(例如绿色)
        SetTextColor(hdc, RGB(0, 255, 0));
        SetBkMode(hdc, TRANSPARENT); // 透明背景

        // 获取窗口文本并绘制在左下方,间隔 50 像素
        rect.left += 50;   // 左侧间隔 50 像素
        rect.bottom -= 50; // 底部间隔 50 像素

        DrawTextW(hdc, statusText, -1, &rect, DT_LEFT | DT_BOTTOM | DT_SINGLELINE);

        DeleteObject(hFont);


        EndPaint(hWnd, &ps);
        break;
    }
    case WM_UPDATE_STATUS:
    {
        if (wParam == STATUS_MSG_HASH) {
            // 获取窗口文本并绘制
            memset(statusText, 0, sizeof(statusText));
            memcpy(statusText, (LPVOID)lParam, sizeof(statusText) - 5);
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);
        }
        return 0;
    }
    case WM_CLOSE:
        DestroyWindow(hWnd);
        // 其他:用户已取消。什么都不做。
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProcW(hWnd, message, wParam, lParam);
}

DWORD WINAPI CloseBorderThread(LPVOID lpParam) {
    HDESK hWinlogonDesk = static_cast<HDESK>(lpParam);  // 传递的桌面句柄
    HWND hBorderWndBack = hBorderWnd;
    //std::wcout << L"hWinlogonDesk in thread: " << hWinlogonDesk << std::endl;

    // 获取当前线程的桌面句柄,后面恢复用
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到 Winlogon 桌面
    if (!SetThreadDesktop(hWinlogonDesk)) {
        std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
        return 1;
    }

    // 发送关闭消息
    if (hBorderWndBack != nullptr && IsWindow(hBorderWndBack)) {
        // 最小化窗口
        CloseWindow(hBorderWndBack);

        // 关闭窗口
        SendMessageW(hBorderWndBack, WM_CLOSE, 0, 0);
        
        // 销毁窗口(发送 WM_DESTROY 和 WM_NCDESTROY 消息)
        DestroyWindow(hBorderWndBack);
    }

    std::wcout << L"An exit monitoring message has been sent." << std::endl;

    // 恢复到原始桌面
    SetThreadDesktop(hOriginalDesktop);

    return 0;
}


// 更新状态窗口显示的文本信息
DWORD WINAPI UpdateStatusWindowTextThread(LPVOID lpParam) {
    if (lpParam == nullptr) {
        std::wcerr << L"Invalid thread parameters." << std::endl;
        return ERROR_INVALID_PARAMETER;
    }

    __try {
        MYSTATUS_UPDATE_THREAD_INFO* info =
            static_cast<MYSTATUS_UPDATE_THREAD_INFO*>(lpParam);

        if (info->hChangeToDesktop == nullptr || info->wcsBuffer == nullptr) {
            std::wcerr << L"Invalid thread parameters." << std::endl;
            return ERROR_INVALID_PARAMETER;
        }

        // 获取当前线程的桌面句柄,后面恢复用
        HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

        // 切换到 Winlogon 桌面
        if (!SetThreadDesktop(info->hChangeToDesktop)) {
            std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
            return 1;
        }

        // 设置新的信息
        if (hBorderWnd) {
            // 发送 WM_APP 类型消息给目标窗口过程
            SendMessageW(hBorderWnd, WM_UPDATE_STATUS, STATUS_MSG_HASH, (LPARAM)info->wcsBuffer);
        }

        std::wcout << L"Update Status Text: " << info->wcsBuffer << std::endl;

        // 恢复到原始桌面
        SetThreadDesktop(hOriginalDesktop);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        std::wcerr << L"Memory access violation." << std::endl;
        return ERROR_INVALID_ACCESS;
    }

    return 0;
}


// 在监视过程开始时显示提示信息
BOOL StartMonitoringUI(HDESK hWinlogonDesk) {

    // 切换到 winlogon 桌面并发送状态更新消息
    MYSTATUS_UPDATE_THREAD_INFO info = { hWinlogonDesk };
    wcscpy_s(info.wcsBuffer, LOGING_STATUS_INFO);

    HANDLE hThread = CreateThread(NULL, 0, UpdateStatusWindowTextThread, &info, 0, NULL);
    if (hThread) {
        WaitForSingleObject(hThread, 7000);
        CloseHandle(hThread);
        Sleep(300);   // 刻意的延时, TODO: 未来仅在绘制部
                       // 分做延时动画而不是对发消息的线程做延时
        return TRUE;
    }

    return FALSE;
}


// 在监视过程完成时更新提示信息
BOOL CompleteMonitoringUI(HDESK hWinlogonDesk) {

    // 切换到 winlogon 桌面并发送状态更新消息
    MYSTATUS_UPDATE_THREAD_INFO info = { hWinlogonDesk };
    wcscpy_s(info.wcsBuffer, COMPLETE_STATUS_INFO);

    HANDLE hThread = CreateThread(NULL, 0, UpdateStatusWindowTextThread, &info, 0, NULL);
    if (hThread) {
        WaitForSingleObject(hThread, 7000);
        CloseHandle(hThread);
        Sleep(300);   // 刻意的延时
        return TRUE;
    }

    return FALSE;
}


// 检查并关闭监视器
BOOL CloseMonitoringUI(HDESK hWinlogonDesk) {

    // 启动关闭边框的线程
    if (borderRunning) {
        //std::wcout << L"hWinlogonDesk call: " << hWinlogonDesk << std::endl;
        HANDLE hCloseThread = CreateThread(NULL, 0, CloseBorderThread, 
            (LPVOID)hWinlogonDesk, 0, NULL);
        WaitForSingleObject(hCloseThread, INFINITE);  // 等待线程完成
        CloseHandle(hCloseThread);
        borderRunning = false;
    }

    return FALSE;
}

// 边框绘制线程
DWORD WINAPI BorderThread(LPVOID lpParam) {
    std::wcout << L"Monitoring the target desktop..." << std::endl;
    HDESK hWinlogonDesk = static_cast<HDESK>(lpParam);  // 传递的桌面句柄

    // 切换到 Winlogon 桌面
    if (!SetThreadDesktop(hWinlogonDesk)) {
        std::wcerr << L"Failed to set thread desktop to Winlogon." << std::endl;
        return 1;
    }
#define MY_BUFSIZE 1024 
    wchar_t pszWindowClass[MY_BUFSIZE]; 

    // 构造一个特殊的窗口类名
    wsprintfW(pszWindowClass, L"WinlogonMonitorBorderWindowClass[%d::%d]",
        GetTickCount(),
        GetCurrentProcessId());

    HINSTANCE hInstance = GetModuleHandleW(NULL);
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = BorderWndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = pszWindowClass;
    wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));

    if (!RegisterClassW(&wc)) {
        std::wcerr << L"Failed to RegisterClass." << std::endl;
        return 1;
    }

    // 获取屏幕大小并创建无边框窗口
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);

    hBorderWnd = CreateWindowExW(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT,
        wc.lpszClassName, L"WinlogonMonitorBorderWindow", WS_POPUP,
        0, 0, screenWidth, screenHeight, NULL, NULL, hInstance, NULL);

    if (!hBorderWnd) {
        std::wcerr << L"Failed to CreateWindow." << std::endl;
        return 1;
    }

    // 设置窗口透明度
    SetLayeredWindowAttributes(hBorderWnd, RGB(255, 255, 255), 0, LWA_COLORKEY);

    ShowWindow(hBorderWnd, SW_SHOW);
    UpdateWindow(hBorderWnd);

    // 消息循环,等待关闭事件
    MSG msg;
    while (true) {
        // 检查并处理窗口消息
        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    // 销毁窗口
    DestroyWindow(hBorderWnd);

#undef MY_BUFSIZE
    return 0;
}


// 递归获取窗口层次,使用宽字符 API
void EnumChildWindowsRecursive(HWND hwndParent, std::vector<WindowInfo>& windowList) {
    wchar_t className[256];
    wchar_t windowTitle[256];

    ZeroMemory(className, sizeof(className));
    ZeroMemory(windowTitle, sizeof(windowTitle));

    // 获取窗口类名和标题
    GetClassNameW(hwndParent, className, sizeof(className) / sizeof(wchar_t));
    GetWindowTextW(hwndParent, windowTitle, sizeof(windowTitle) / sizeof(wchar_t));

    if (className[0] == L'\0') {
        wcscpy_s(className, L"(None)");
    }

    if (windowTitle[0] == L'\0') {
        wcscpy_s(windowTitle, L"(None)");
    }

    WindowInfo windowInfo = { className, windowTitle, hwndParent };

    // 枚举子窗口
    EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* children = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *children);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windowInfo.children));

    windowList.push_back(windowInfo);
}

// 获取当前桌面窗口层次,使用宽字符 API
std::vector<WindowInfo> GetWindowHierarchy() {
    std::vector<WindowInfo> windows;
    EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
        std::vector<WindowInfo>* windows = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
        EnumChildWindowsRecursive(hwnd, *windows);
        return TRUE;
        }, reinterpret_cast<LPARAM>(&windows));
    return windows;
}

// 获取当前窗口层次的哈希值,用于检测窗口层次是否发生变化
std::size_t GetWindowHierarchyHash(const std::vector<WindowInfo>& windows) {
    std::hash<std::wstring> hash_fn;
    std::size_t hash = 0;

    std::function<void(const std::vector<WindowInfo>&)> computeHash;
    computeHash = [&hash_fn, &hash, &computeHash](const std::vector<WindowInfo>& windows) {
        for (const auto& window : windows) {
            hash ^= hash_fn(window.className);
            hash ^= hash_fn(window.windowTitle);
            computeHash(window.children);  // 递归计算子窗口的哈希值
        }
    };

    computeHash(windows);
    return hash;
}

// 格式化时间为宽字符格式
std::wstring FormatTime(const std::time_t& time) {
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &time);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), 
        L"%Y-%m-%d %H:%M:%S", &ti);
    return std::wstring(timeBuffer);
}

// 宽字符到 UTF-8 的转换(使用 UTF-8 目标编码)
std::string WideStringToUTF8(const std::wstring& wideStr) {
    if (wideStr.empty()) return std::string();

    // 计算转换所需的缓冲区大小
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), 
        static_cast<int>(wideStr.size()), NULL, 0, NULL, NULL);
    if (size_needed <= 0) {
        throw std::runtime_error("WideCharToMultiByte failed to calculate buffer size.");
    }

    // 分配缓冲区并进行转换
    std::string str(size_needed, 0);
    int bytes_written = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), 
        static_cast<int>(wideStr.size()), &str[0], size_needed, NULL, NULL);
    if (bytes_written <= 0) {
        throw std::runtime_error("WideCharToMultiByte failed to convert string to UTF-8.");
    }

    return str;
}

// UTF-8 到宽字符的转换
std::wstring UTF8ToWideString(const std::string& utf8Str) {
    if (utf8Str.empty()) return std::wstring();

    // 获取所需的宽字符缓冲区大小(包括空终止符)
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), 
        static_cast<int>(utf8Str.size()), NULL, 0);
    if (size_needed <= 0) {
        throw std::runtime_error("MultiByteToWideChar failed to calculate buffer size.");
    }

    std::wstring wideStr(size_needed, 0);
    int chars_written = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), 
        static_cast<int>(utf8Str.size()), &wideStr[0], size_needed);
    if (chars_written <= 0) {
        throw std::runtime_error("MultiByteToWideChar failed to convert UTF-8 string to wide string.");
    }

    return wideStr;
}


// 将 ANSI 字符串转换为宽字符串(根据当前系统代码页)
std::wstring ANSIToWideString(const std::string& ansiStr, UINT codePage = CP_ACP) {
    if (ansiStr.empty()) return std::wstring();

    int size_needed = MultiByteToWideChar(codePage, 0, ansiStr.c_str(), 
        static_cast<int>(ansiStr.size()), NULL, 0);
    if (size_needed <= 0) {
        throw std::runtime_error("MultiByteToWideChar failed to calculate buffer size.");
    }

    std::wstring wideStr(size_needed, 0);
    MultiByteToWideChar(codePage, 0, ansiStr.c_str(), 
        static_cast<int>(ansiStr.size()), &wideStr[0], size_needed);
    return wideStr;
}

// 将宽字符转换为 ANSI 编码的字符串(基于当前系统的代码页)
std::string WideStringToANSI(const std::wstring& wideStr, UINT codePage = CP_ACP) {
    if (wideStr.empty()) return std::string();

    int size_needed = WideCharToMultiByte(codePage, 0, wideStr.c_str(),
        static_cast<int>(wideStr.size()), NULL, 0, NULL, NULL);
    if (size_needed <= 0) {
        throw std::runtime_error("WideCharToMultiByte failed to calculate buffer size.");
    }

    std::string ansiStr(size_needed, 0);
    WideCharToMultiByte(codePage, 0, wideStr.c_str(), 
        static_cast<int>(wideStr.size()),
        &ansiStr[0], size_needed, NULL, NULL);
    return ansiStr;
}

// 读取 UTF-8 文件内容并转换为宽字符串
bool ReadUTF8File(const std::wstring& filePath, std::wstring& content) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open UTF-8 file: " << filePath << std::endl;
        return false;
    }

    std::stringstream ss;
    ss << file.rdbuf();
    std::string utf8Content = ss.str();
    file.close();

    // 将 UTF-8 内容转换为宽字符内容
    content = UTF8ToWideString(utf8Content);
    return true;
}

// 手动读取 UTF-16 LE 编码的文件
bool ReadUTF16LEFile(const std::wstring& filePath, std::wstring& content) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open UTF-16 LE file: " << filePath << std::endl;
        return false;
    }

    // 跳过 BOM (2 bytes)
    file.seekg(2, std::ios::beg);

    std::wstringstream wss;
    char buffer[2];
    while (file.read(buffer, 2)) {
        // Little Endian 解码为 wchar_t
        wchar_t wchar = (static_cast<unsigned char>(buffer[1]) << 8)
            | static_cast<unsigned char>(buffer[0]);
        wss << wchar;
    }

    content = wss.str();
    file.close();
    return true;
}

// 手动转换 UTF-16 BE 到宽字符
std::wstring ConvertUTF16BEToWideString(const std::vector<char>& buffer) {
    if (buffer.size() % 2 != 0) {
        throw std::runtime_error("Invalid UTF-16 BE byte stream length.");
    }

    std::wstring result;
    for (size_t i = 0; i < buffer.size(); i += 2) {
        // 将两个字节转换为 wchar_t,并转换字节序
        wchar_t wchar = (static_cast<unsigned char>(buffer[i]) << 8) |
            static_cast<unsigned char>(buffer[i + 1]);
        result += wchar;
    }
    return result;
}

// 保存窗口层次信息到文件,使用 UTF-8 编码
void SaveWindowHierarchy(
    const std::vector<WindowInfo>& windows,
    const std::time_t& changeTime, 
    const std::wstring& filename
) {
    std::ofstream file(WideStringToUTF8(filename), 
        std::ios::app | std::ios::binary);  // 使用 binary 防止换行符的意外转换
    if (!file.is_open()) {
        std::wcerr << L"Unable to open file for writing!" << std::endl;
        return;
    }

    // 在文件开头写入 BOM,标识为 UTF-8 编码
    static bool bomWritten = false;
    if (!bomWritten) {
        const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };  // UTF-8 BOM
        file.write(reinterpret_cast<const char*>(bom), sizeof(bom));
        bomWritten = true;
    }

    // 格式化时间为字符串
    wchar_t timeBuffer[100];
    tm ti = {};
    localtime_s(&ti, &changeTime);
    std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);

    // 写入时间戳
    file << WideStringToUTF8(std::wstring(timeBuffer)) << "\r\n";

    // 递归写入窗口信息
    std::function<void(const std::vector<WindowInfo>&, int)> WriteHierarchy;
    WriteHierarchy = [&file, &WriteHierarchy](const std::vector<WindowInfo>& windows, int indent) {
        for (const auto& window : windows) {
            file << std::string(indent, ' ')  // 使用空格进行缩进
                << "Class Name: " << WideStringToUTF8(window.className)
                << ", Title: " << WideStringToUTF8(window.windowTitle)
                << ", HWND: " << std::hex << window.hwnd << "\r\n";
            if (!window.children.empty()) {
                WriteHierarchy(window.children, indent + 4);  // 递归写入子窗口信息
            }
        }
    };

    WriteHierarchy(windows, 0);
    file << "\r\n";
    file.close();
}

// 获取当前桌面的名称
std::wstring GetDesktopName(HDESK hDesktop) {
    wchar_t desktopName[256]{};
    DWORD neededLength = 0;

    if (!GetUserObjectInformationW(hDesktop, UOI_NAME, desktopName, 
        sizeof(desktopName), &neededLength)) {
        std::wcerr << L"Failed to get desktop name." << std::endl;
        return L"";
    }

    return std::wstring(desktopName);
}


// 切换到指定桌面并枚举窗口,任务结束后恢复到原始桌面
std::vector<WindowInfo> GetWindowsFromDesktop(HDESK hDesktop) {
    // 获取原始桌面句柄
    HDESK hOriginalDesktop = GetThreadDesktop(GetCurrentThreadId());

    // 切换到目标桌面
    if (!SetThreadDesktop(hDesktop)) {
        std::wcerr << L"Failed to set thread desktop!" << std::endl;
        return {};
    }

    // 切换后获取窗口层次
    std::vector<WindowInfo> windows = GetWindowHierarchy();

    // 恢复到原始桌面
    if (!SetThreadDesktop(hOriginalDesktop)) {
        std::wcerr << L"Failed to restore original desktop!" << std::endl;
    }

    return windows;
}

// 使用辅助线程进行桌面切换和窗口枚举
DWORD WINAPI MonitorDesktopThread(LPVOID param) {
    _wsetlocale(LC_ALL, L"zh-CN");
    MYMONITOR_THREAD_INFO* threadInfo = static_cast<MYMONITOR_THREAD_INFO*>(param);

    threadInfo->wndInfo = GetWindowsFromDesktop(threadInfo->hDesktop);

    return 0;
}

// 打开窗口工作站并切换到桌面
HDESK OpenDesktopWithWindowStation(LPCWSTR desktopName, HWINSTA hWinsta) {
    // 打开桌面
    HDESK hDesktop = OpenDesktopW(desktopName, 0, FALSE, GENERIC_ALL);
    if (!hDesktop) {
        std::wcerr << L"Failed to open desktop! name = " << desktopName << std::endl;
        CloseWindowStation(hWinsta);
    }

    return hDesktop;
}

// 获取当前活动桌面
HDESK GetActiveDesktop() {
    return OpenInputDesktop(0, FALSE, GENERIC_ALL);
}

// 对话框过程函数
INT_PTR CALLBACK HistoryDialogProc(
    HWND hDlg, 
    UINT message, 
    WPARAM wParam, 
    LPARAM lParam
) {
    static std::wstring* historyText = nullptr;

    switch (message) {
    case WM_INITDIALOG:
    {
        historyText = reinterpret_cast<std::wstring*>(lParam);

        // 获取编辑控件句柄
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
        if (hEdit) {
            // 设置文本
            SetWindowTextW(hEdit, historyText->c_str());
        }
    }
    return (INT_PTR)TRUE;

    case WM_SIZE:
    {
        // 获取对话框的新尺寸
        int width = LOWORD(lParam);   // 新的宽度
        int height = HIWORD(lParam);  // 新的高度
        

        // 调整编辑控件大小
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
        if (hEdit) {
            int margin = 25;
            MoveWindow(hEdit, margin, margin, 
                width - 2 * margin,
                height - 80, TRUE);
        }

        // 调整OK按钮的位置
        HWND hButtonOK = GetDlgItem(hDlg, IDOK);
        if (hButtonOK) {
            int buttonWidth = 120;
            int buttonHeight = 35;
            int margin = 15;
            // 按钮位于对话框底部,右边留一定的边距
            MoveWindow(hButtonOK, width - buttonWidth - margin,
                height - buttonHeight - margin,
                buttonWidth, buttonHeight, TRUE);
        }
    }
    break;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;

    default:
        return FALSE;
    }
    return FALSE;
}


// 使用辅助线程进行桌面切换和窗口枚举
DWORD WINAPI DialogBoxParamThread(LPVOID param) {
    _wsetlocale(LC_ALL, L"zh-CN");

    if (param == nullptr) {
        return ERROR_INVALID_PARAMETER;
    }

    DIALOGBOX_PARAM_LIST* dialogParam = static_cast<DIALOGBOX_PARAM_LIST*>(param);

    // 使用副本进行操作
    DIALOGBOX_PARAM_LIST localCopy = *dialogParam;
    delete dialogParam;  // 删除传入的原始参数

    if (localCopy.lpDialogFunc == nullptr || localCopy.dwInitParam == 0) {
        return ERROR_INVALID_PARAMETER;
    }

    //std::wcout << L"localCopy.dwInitParam " << std::hex << localCopy.dwInitParam << std::endl;

    localCopy.intResponse = DialogBoxParamW(localCopy.hInstance,
        localCopy.lpTemplateName,
        localCopy.hWndParent,
        localCopy.lpDialogFunc,
        (LPARAM)&(localCopy.dwInitParam));

    Sleep(1000);

    // 清理 dwInitParam 的内容,不删除外部指针
    memset((void*)localCopy.dwInitParam, 0, localCopy.cbSize);

    return 0;
}


// 异步显示历史记录对话框
void CreateDialogBoxAsyncW(std::wstring text) {
    const size_t cbSize = text.length() + 1;
    WCHAR* wcsText = new (std::nothrow) WCHAR[cbSize];
    wcscpy_s(wcsText, cbSize, text.c_str());

    // 显示历史记录对话框
    DIALOGBOX_PARAM_LIST* param = new DIALOGBOX_PARAM_LIST();  // 动态分配结构体
    param->hInstance = GetModuleHandleW(NULL);
    param->lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG1);
    param->hWndParent = NULL;
    param->lpDialogFunc = HistoryDialogProc;
    param->cbSize = cbSize * sizeof(WCHAR);
    param->dwInitParam = (LPARAM)wcsText;  // 动态分配内存并赋值

    //std::wcout << L"WindowsLog: " << text << std::endl;
    
    HANDLE hThread = CreateThread(NULL, 0, DialogBoxParamThread, param, 0, NULL);
}


// 监控桌面切换
void MonitorDesktop() {

    // 注册 Ctrl + Shift + F1 组合键为全局热键 (ID = 1)
    if (!RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_SHIFT, VK_F1)) {
        std::wcerr << L"Failed to register hotkey for Ctrl + Shift + F1." << std::endl;
        return;
    }

    // 打开窗口工作站
    HWINSTA hWinsta = OpenWindowStationW(L"WinSta0", FALSE, GENERIC_READ | GENERIC_WRITE);
    if (!hWinsta) {
        std::wcerr << L"Failed to open window station!" << std::endl;
        return;
    }

    // 将当前线程关联到工作站
    if (!SetProcessWindowStation(hWinsta)) {
        std::wcerr << L"Failed to set process window station!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    HDESK hDefaultDesk = OpenDesktopWithWindowStation(L"Default", hWinsta);
    HDESK hWinlogonDesk = OpenDesktopWithWindowStation(L"Winlogon", hWinsta);

    if (!hDefaultDesk || !hWinlogonDesk) {
        std::wcerr << L"Failed to open desktops!" << std::endl;
        CloseWindowStation(hWinsta);
        return;
    }

    std::wcout << L"Monitoring desktop changes (SYSTEM privileges detected)..." << std::endl;
    std::wcout << L"Desktops: Winlogon(" << std::hex << (UINT64)hWinlogonDesk << L"), Default("
        << std::hex << (UINT64)hDefaultDesk << L")." << std::endl;
    
    // 桌面监控代码

    // 获取文件所在目录
    std::wstring szLogPath = GetCurrentProcessDirectory();
    if (szLogPath.empty()) {
        std::wcerr << L"Failed to get module file path." << std::endl;
        szLogPath = L".\\";
        szLogPath += LOG_FILE_NAME;
    }
    else {
        // 追加日志文件名,构成完整的日志路径
        szLogPath += L"\\";
        szLogPath += LOG_FILE_NAME;
    }

    std::vector<WindowInfo> windowHistory;
    std::size_t prevHash = 0;  // 保存上一次的哈希值
    bool monitoring = false;
    MYMONITOR_THREAD_INFO monitor_info = { hWinlogonDesk };
    HANDLE hBorderThread = nullptr;  // 边框线程句柄
    DWORD errCnt = 0;         // 循环中发生非致命错误次数

    while (errCnt <= 5u) {
        MSG msg;
        // 非阻塞的消息检查
        while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
            if (IsMainWindowActive() && msg.message == WM_HOTKEY && msg.wParam == 1) {
                // Ctrl + Shift + F1 热键触发,退出循环
                std::wcout << L"Ctrl + Shift + F1 pressed. Exiting monitoring..." << std::endl;
                Sleep(1000);
                // 启动关闭边框的线程
                CloseMonitoringUI(hWinlogonDesk);
                goto exit_monitoring;
            }
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }

        HDESK hCurrentDesk = GetActiveDesktop();   // 获取活动桌面句柄

        std::wstring desktopName = GetDesktopName(hCurrentDesk);   // 获取桌面名称

        //std::wcout << L"Current Desktop: " << desktopName << std::endl;

        if (desktopName == L"Winlogon" && !monitoring) {
            std::wcout << L"Switched to Winlogon desktop. Start monitoring window hierarchy..." << std::endl;
            monitoring = true;
            windowHistory.clear();  // 清空之前的记录

            // 创建事件对象
            hBroderWndCreateEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);

            // 启动边框绘制线程,并传递 Winlogon 桌面句柄
            if (!borderRunning) {
                hBorderThread = CreateThread(nullptr, 0, BorderThread, (LPVOID)hWinlogonDesk, 0, nullptr);
                borderRunning = true;
            }

            // 在主线程等待窗口创建完成
            WaitForSingleObject(hBroderWndCreateEvent, CREATE_BORDER_WINDOW_TIMEOUT);

            DWORD dwCreateBwndRet = 0;
            SetLastError(0);    // 错误代码清零
            dwCreateBwndRet == WaitForSingleObject(hBroderWndCreateEvent,
                CREATE_BORDER_WINDOW_TIMEOUT);
            if (dwCreateBwndRet != WAIT_OBJECT_0) {
                std::wcerr << L"WaitForSingleObject signal a failed: " << dwCreateBwndRet
                    << L", GetLastError() == " << GetLastError() << std::endl;
                CloseHandle(hBroderWndCreateEvent);
                ++errCnt;    // 增加错误计数
                monitoring = false;
                // 启动关闭边框的线程
                CloseMonitoringUI(hWinlogonDesk);
                TerminateThread(hBorderThread, 0);
                continue;
            }

            // 设置状态为:记录中
            StartMonitoringUI(hWinlogonDesk);

            // 切换到 winlogon 桌面并枚举窗口
            HANDLE hThread = CreateThread(nullptr, 0, MonitorDesktopThread, &monitor_info, 0, nullptr);
            if (hThread) {
                DWORD waitRet = 0;
                SetLastError(0);    // 错误代码清零
                waitRet == WaitForSingleObject(hThread, MONITOR_THREAD_TIMEOUT);
                if (waitRet != WAIT_OBJECT_0) {
                    std::wcerr << L"WaitForSingleObject signal a failed: " << waitRet
                        << L", GetLastError() == " << GetLastError() << std::endl;
                    CloseHandle(hThread);
                    ++errCnt;    // 增加错误计数
                    monitoring = false;
                    // 启动关闭边框的线程
                    CloseMonitoringUI(hWinlogonDesk);
                    TerminateThread(hBorderThread, 0);
                    continue;
                }
                CloseHandle(hThread);
                errCnt = 0;   // 错误计数归零
            }

            windowHistory = monitor_info.wndInfo;

            // 计算当前窗口层次的哈希值
            prevHash = GetWindowHierarchyHash(windowHistory);

            // 设置状态为:已完成
            CompleteMonitoringUI(hWinlogonDesk);
        }
        else if (desktopName == L"Default" && monitoring) {
            std::wcout << L"Switched back to Default desktop. Stopping monitoring..." << std::endl;
            std::time_t currentTime = std::time(nullptr);
            SaveWindowHierarchy(windowHistory, currentTime, szLogPath.c_str());
            monitoring = false;

            // 启动关闭边框的线程
            CloseMonitoringUI(hWinlogonDesk);

            // 格式化时间为字符串
            wchar_t timeBuffer[100];
            tm ti = {};
            localtime_s(&ti, &currentTime);
            std::wcsftime(timeBuffer, sizeof(timeBuffer) / sizeof(wchar_t), L"%Y-%m-%d %H:%M:%S", &ti);

            // 构建窗口层次信息文本
            std::wstringstream ss;
            ss << L"Most Recent History Call ( " << timeBuffer << L" ): \r\n";
            for (const auto& win : windowHistory) {
                ss << L"Class Name: " << win.className << L", Title: " << win.windowTitle
                    << L", HWND: " << std::hex << win.hwnd << L"\r\n";
            }
            std::wstring historyText = ss.str();

            // 显示历史记录对话框(使用线程实现非阻滞)
            CreateDialogBoxAsyncW(historyText);
        }

        // 检查窗口层次变化
        if (monitoring) {
            SetLastError(0);
            HANDLE hThread = CreateThread(nullptr, 0, MonitorDesktopThread, &monitor_info, 0, nullptr);
            if (hThread) {
                // 设置状态为:记录中
                StartMonitoringUI(hWinlogonDesk);
                //WaitForSingleObject(hThread, INFINITE);   // 等待线程结束
                //CloseHandle(hThread);
                 设置状态为:已完成
                //CompleteMonitoringUI(hWinlogonDesk);
                DWORD waitRet = 0;
                SetLastError(0);
                waitRet == WaitForSingleObject(hThread, MONITOR_THREAD_TIMEOUT);
                if (waitRet != WAIT_OBJECT_0) {
                    std::wcerr << L"WaitForSingleObject signal a failed: " << waitRet
                        << L", GetLastError() == " << GetLastError() << std::endl;
                    CloseHandle(hThread);
                    ++errCnt;    // 增加错误计数
                    monitoring = false;
                    // 启动关闭边框的线程
                    CloseMonitoringUI(hWinlogonDesk);
                    TerminateThread(hBorderThread, 0);
                    continue;
                }

                errCnt = 0;   // 错误计数归零
                CloseHandle(hThread);
                
                // 设置状态为:已完成
                CompleteMonitoringUI(hWinlogonDesk);

                // 检查并更新窗口层次
                std::size_t currentHash = GetWindowHierarchyHash(monitor_info.wndInfo);
                if (currentHash != prevHash) {
                    std::wcout << L"Window hierarchy changed. Updating records..." << std::endl;
                    windowHistory = monitor_info.wndInfo;
                    std::time_t currentTime = std::time(nullptr);
                    SaveWindowHierarchy(windowHistory, currentTime, szLogPath.c_str());
                    prevHash = currentHash;
                }
            }
            else {  // CreateThread failed 
                std::wcerr << L"Create Monitor-Desktop thread failed, GetLastError() == "
                    << GetLastError() << std::endl;
            }
        }

        Sleep(1000);  // 每秒检查一次
    }

exit_monitoring:
    // 注销热键
    UnregisterHotKey(NULL, 1);

    // 清理
    CloseDesktop(hDefaultDesk);
    CloseDesktop(hWinlogonDesk);
    CloseWindowStation(hWinsta);
}


// 检测文件编码
FileEncoding DetectFileEncoding(const std::wstring& filePath) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open file for encoding detection: " << filePath << std::endl;
        return FileEncoding::UNKNOWN;
    }

    unsigned char bom[3] = { 0 };
    file.read(reinterpret_cast<char*>(bom), 3);
    file.close();

    // 检查 BOM(字节顺序标记, Byte Order Mark)
    if (bom[0] == 0xFF && bom[1] == 0xFE) {
        return FileEncoding::UTF16LE;  // UTF-16 LE
    }
    else if (bom[0] == 0xFE && bom[1] == 0xFF) {
        return FileEncoding::UTF16BE;  // UTF-16 BE
    }
    else if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) {
        return FileEncoding::UTF8;     // UTF-8 (BOM)
    }
    else {
        return FileEncoding::ANSI;     // 默认解析为 ANSI
    }
}

// 读取文件内容,处理不同编码格式
bool ReadFileWithEncoding(const std::wstring& filePath, std::wstring& content) {
    FileEncoding encoding = DetectFileEncoding(filePath);

    if (encoding == FileEncoding::UTF16LE) {
        // 读取 UTF-16 LE 编码的文件
        //std::wcout << L"UTF16-LE" << std::endl;
        return ReadUTF16LEFile(filePath, content);
    }
    else if (encoding == FileEncoding::UTF16BE) {
        // 读取 UTF-16 BE 编码的文件,手动处理字节序
        std::ifstream file(filePath, std::ios::binary);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open UTF-16 file: " << filePath << std::endl;
            return false;
        }

        // 跳过 BOM(2 个字节)
        file.seekg(2, std::ios::beg);

        // 读取文件到缓冲区
        std::vector<char> buffer((std::istreambuf_iterator<char>(file)),
            std::istreambuf_iterator<char>());

        file.close();

        // 转换为宽字符
        content = ConvertUTF16BEToWideString(buffer);
    }
    else if (encoding == FileEncoding::UTF8) {
        return ReadUTF8File(filePath, content);
    }
    else if (encoding == FileEncoding::ANSI) {
        // 读取 ANSI 编码的文件
        std::ifstream file(filePath, std::ios::binary);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open ANSI file: " << filePath << std::endl;
            return false;
        }
        std::stringstream ss;
        ss << file.rdbuf();
        std::string ansiContent = ss.str();
        content = ANSIToWideString(ansiContent);
        file.close();
    }
    else {
        std::wcerr << L"Unknown file encoding." << std::endl;
        return false;
    }
    return true;
}

// 将宽字符内容保存为 UTF-8 文件
bool SaveAsUTF8(const std::wstring& filePath, const std::wstring& content) {
    std::ofstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
        return false;
    }

    // 写入 UTF-8 BOM
    const char bom[] = { '\xEF', '\xBB', '\xBF' };
    file.write(bom, sizeof(bom));

    // 将宽字符转换为 UTF-8 编码
    std::string utf8Content = WideStringToUTF8(content);
    file.write(utf8Content.c_str(), utf8Content.size());
    file.close();
    return true;
}

// 将宽字符内容保存为 UTF-16 LE 文件(不使用 codecvt)
bool SaveAsUTF16LE(const std::wstring& filePath, const std::wstring& content) {
    std::ofstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
        return false;
    }

    // 写入 BOM
    const char bom[] = { '\xFF', '\xFE' };
    file.write(bom, sizeof(bom));

    // 将宽字符转换为 UTF-16 Little Endian 编码字节流
    for (wchar_t wc : content) {
        char16_t utf16LE = static_cast<char16_t>(wc);
        file.write(reinterpret_cast<const char*>(&utf16LE), sizeof(utf16LE));
    }

    file.close();
    return true;
}

// 将宽字符内容保存为 UTF-16 BE 文件
bool SaveAsUTF16BE(const std::wstring& filePath, const std::wstring& content) {
    std::ofstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
        return false;
    }

    // 写入 BOM
    const char bom[] = { '\xFE', '\xFF' };
    file.write(bom, sizeof(bom));

    // 将宽字符转换为 UTF-16 Big Endian 编码字节流
    for (wchar_t wc : content) {
        char16_t utf16BE = (static_cast<unsigned char>(wc >> 8) & 0xFF)
            | (static_cast<unsigned char>(wc & 0xFF) << 8);
        file.write(reinterpret_cast<const char*>(&utf16BE), sizeof(utf16BE));
    }

    file.close();
    return true;
}

// 根据编码保存修改后的文件内容
bool ModifyAndSaveFileWithEncoding(const std::wstring& filePath, const std::wstring& content) {
    FileEncoding encoding = DetectFileEncoding(filePath);

    if (encoding == FileEncoding::UTF16LE) {
        // 保存为 UTF-16 Little Endian 编码
        return SaveAsUTF16LE(filePath, content);
    }
    else if (encoding == FileEncoding::UTF16BE) {
        // 保存为 UTF-16 Big Endian 编码
        return SaveAsUTF16BE(filePath, content);
    }
    else if (encoding == FileEncoding::UTF8) {
        // 保存为 UTF-8 编码
        std::ofstream file(filePath, std::ios::binary);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }

        // 写入 UTF-8 BOM
        const char bom[] = { '\xEF', '\xBB', '\xBF' };
        file.write(bom, sizeof(bom));

        std::string utf8Content = WideStringToUTF8(content);
        file.write(utf8Content.c_str(), utf8Content.size());
        file.close();
    }
    else if (encoding == FileEncoding::ANSI) {
        // 保存为 ANSI 编码
        std::ofstream file(filePath, std::ios::binary);
        if (!file.is_open()) {
            std::wcerr << L"Failed to open file for writing: " << filePath << std::endl;
            return false;
        }
        std::string ansiContent = WideStringToANSI(content);
        file.write(ansiContent.c_str(), ansiContent.size());
        file.close();
    }
    else {
        std::wcerr << L"Unknown file encoding, cannot save file." << std::endl;
        return false;
    }
    return true;
}

// 修改 SeAssignPrimaryTokenPrivilege 权限
bool ModifySeAssignPrimaryTokenPrivilege(const std::wstring& configFilePath, const std::wstring& userName) {
    std::wstring content;

    // 读取文件内容
    if (!ReadFileWithEncoding(configFilePath, content)) {
        std::wcerr << L"Failed to read configuration file with correct encoding." << std::endl;
        return false;
    }

    // 查找并修改 SeAssignPrimaryTokenPrivilege
    size_t pos = content.find(L"SeAssignPrimaryTokenPrivilege");
    if (pos != std::wstring::npos) {
        size_t endPos = content.find(L"\n", pos) - 1;
        std::wstring line = content.substr(pos, endPos - pos);

        // 检查是否包含当前用户
        if (line.find(userName) == std::wstring::npos) {
            line += L"," + userName;
            content.replace(pos, endPos - pos, line);
        }
    }

    // 保存修改后的文件
    if (!ModifyAndSaveFileWithEncoding(configFilePath, content)) {
        std::wcerr << L"Failed to save modified configuration file." << std::endl;
        return false;
    }

    return true;
}

// 执行命令
bool ExecuteCommandWithOutput(const std::wstring& command, std::wstring& output) {
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hRead, hWrite;

    // 初始化管道句柄的安全属性
    ZeroMemory(&sa, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = nullptr;

    // 为子进程的 STDOUT 和 STDERR 创建管道
    if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
        std::wcerr << L"Failed to create pipe." << std::endl;
        return false;
    }

    // 确保管道的读取句柄未被继承
    if (!SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0)) {
        std::wcerr << L"Failed to set handle information." << std::endl;
        return false;
    }

    // 为子进程设置 STARTUPINFO 结构
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;
    si.dwFlags |= STARTF_USESTDHANDLES;  // 将 STDOUT 和 STDERR 重定向到管道

    // 设置 PROCESS_INFORMATION 结构
    ZeroMemory(&pi, sizeof(pi));

    // 使用 Create_NO_WINDOW 创建子进程,以避免显示新的控制台窗口
    if (!CreateProcessW(NULL, const_cast<LPWSTR>(command.c_str()), NULL, NULL, 
        TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
        std::wcerr << L"Failed to execute command: " << command << std::endl;
        CloseHandle(hRead);
        CloseHandle(hWrite);
        return false;
    }

    // 关闭父进程中管道的写入端
    CloseHandle(hWrite);

    // 读取子进程的输出
    DWORD bytesRead;
    CHAR buffer[4096];
    std::string ansiResult;
    BOOL success = FALSE;

    ZeroMemory(buffer, sizeof(buffer) * sizeof(CHAR));

    // 从管道中连续读取,直到没有更多数据
    while (true) {
        success = ReadFile(hRead, buffer, sizeof(buffer) - 1, &bytesRead, NULL);
        if (!success || bytesRead == 0) {
            break;  // 没有更多数据要读取
        }
        buffer[bytesRead] = '\0';  // 缓冲区结束标记
        ansiResult += buffer;      // 收集 ANSI 编码的结果
    }

    // 关闭手柄
    CloseHandle(hRead);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    // 如果结果为空,则返回“no message”
    if (ansiResult[0] == '\0') {
        output = L"\n(no message)\n";
        return true;
    }

    // 将 ANSI 结果转换为宽字符串以进行正确的 Unicode 处理
    int wideSize = MultiByteToWideChar(CP_ACP, 0, ansiResult.c_str(), -1, NULL, 0);
    if (wideSize == 0) {
        std::wcerr << L"Failed to convert output to wide string." << std::endl;
        return false;
    }

    std::wstring wideResult(wideSize, 0);
    MultiByteToWideChar(CP_ACP, 0, ansiResult.c_str(), -1, &wideResult[0], wideSize);

    output = wideResult;
    return true;
}

// 判断文件是否存在
BOOL IsFileExist(const std::wstring& wsFile)
{
    DWORD dwAttrib = GetFileAttributesW(wsFile.c_str());
    return INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

// 导出安全策略
// secedit /export /cfg C:\gp.inf
bool ExportSecurityPolicy(const std::wstring& system32Dir, const std::wstring& outputFile, std::wstring& output) {
    // https://blog.csdn.net/u012494876/article/details/51204615
    if (IsFileExist(outputFile)) {  // 判断配置文件是否已经存在
        std::wcout << L"The configuration file already exists. Attempting to delete it." << std::endl;
        if (!DeleteFileW(outputFile.c_str())) {
            std::wcerr << L"Failed to delete the configuration file." << std::endl;
            return false;
        }
    }

    std::wstring command = system32Dir + L"\\secedit.exe /export /cfg " + outputFile;
    return ExecuteCommandWithOutput(command, output);
}

// 应用修改后的安全策略
// secedit /configure /db test.sdb /cfg C:\gp.inf /overwrite /log hisecws.log /quiet
bool ApplySecurityPolicy(const std::wstring& system32Dir, const std::wstring& configFilePath,
    const std::wstring& dbFilePath, std::wstring& output) {
    std::wstring command = system32Dir + L"\\secedit.exe /configure /db " + dbFilePath + L" /cfg "
        + configFilePath + L" /overwrite /quiet";
    return ExecuteCommandWithOutput(command, output);
}

// 获取系统盘符
std::wstring GetSystemDrive() {
    wchar_t systemPath[MAX_PATH];
    if (GetSystemDirectoryW(systemPath, MAX_PATH)) {
        return std::wstring(systemPath).substr(0, 3);  // 返回盘符部分,例如 C:/
    }
    return L"";  // 如果获取失败,返回默认 C 盘符
}

// 获取当前用户账户名称
std::wstring GetCurrentUserName() {
    wchar_t userName[UNLEN + 1];
    DWORD size = UNLEN + 1;
    if (GetUserNameW(userName, &size)) {
        return std::wstring(userName);
    }
    return L"";  // 返回空字符串表示获取失败
}

// 提示用户注销
void PromptUserToLogout() {
    // 询问用户是否要注销并重新登录
    int result = MessageBoxW(NULL,
        L"The security settings have been updated. Would you like to log off now and apply the changes?",
        L"Log Off Confirmation",
        MB_YESNO | MB_ICONQUESTION | MB_SYSTEMMODAL);

    if (result == IDYES) {
        // 注销用户
        if (!ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, SHTDN_REASON_MAJOR_OTHER)) {
            std::wcerr << L"Failed to log off the user." << std::endl;
        }
    }
    else {
        std::wcout << L"User chose not to log off." << std::endl;
    }
}

// 解除用户获取 AssignPrimaryTokenPrivilege 的限制
//    (修改系统配置文件,需要注销并重新登陆)
bool ChangeAssignPrimaryTokenPrivilege() {
    std::wstring systemDrive = GetSystemDrive();
    std::wstring system32Dir = systemDrive + L"Windows\\" + SYSTEM32_NAME;
    std::wstring configFilePath = systemDrive + L"gpSvcInfo.inf";
    std::wstring dbFilePath = systemDrive + L"gpSvcdata.sdb";
    std::wstring userName = GetCurrentUserName();
    std::wstring output;

    if (systemDrive.empty()) {
        std::wcerr << L"Failed to retrieve the current system root path." << std::endl;
        return false;
    }

    if (userName.empty()) {
        std::wcerr << L"Failed to retrieve the current user name." << std::endl;
        return false;
    }

    if (!ExportSecurityPolicy(system32Dir, configFilePath, output)) {
        std::wcerr << L"Failed to export security policy." << std::endl;
        return false;
    }

    std::wcout << L"\nExportSecurityPolicy message: \n" << output << std::endl;

    if (!ModifySeAssignPrimaryTokenPrivilege(configFilePath, userName)) {
        std::wcerr << L"Failed to modify SeAssignPrimaryTokenPrivilege." << std::endl;
        return false;
    }

    if (!ApplySecurityPolicy(system32Dir, configFilePath, dbFilePath, output)) {
        std::wcerr << L"Failed to apply security policy." << std::endl;
        return false;
    }

    std::wcout << L"\nApplySecurityPolicy message: \n" << output << std::endl;

    PromptUserToLogout();

    return true;
}

int wmain(int argc, wchar_t* argv[]) {
    // 宽字符中文支持
    _wsetlocale(LC_ALL, L"zh-CN");

    // 获取当前进程的主窗口
    hMainWindow = GetMainWindowHandle();
    if (!hMainWindow) {
        std::cerr << "Failed to find main window." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }
    std::cout << "Main window handle: " << std::hex << hMainWindow << std::endl;

    // 检查是否为管理员权限运行
    if (!IsRunAsAdmin()) {
        std::wcout << L"Attempting to restart with administrator privileges..." << std::endl;
        if (RelaunchAsAdmin()) {
            return 0;  // 提升后进程将重新启动,当前进程结束
        }
        else {
            std::wcerr << L"Fatal Error." << std::endl;
            system("pause > nul 2 > nul");
            return 1;
        }
    }

    // 启用 SeDebugPrivilege
    if (!EnablePrivilege(SE_DEBUG_NAME)) {
        std::wcerr << L"Failed to enable SeDebugPrivilege." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }

    // 启用 SeIncreaseQuotaPrivilege
    if (!EnablePrivilege(SE_INCREASE_QUOTA_NAME)) {
        std::wcerr << L"Failed to enable SeIncreaseQuotaPrivilege." << std::endl;
        system("pause > nul 2 > nul");
        return 1;
    }
    
    // 启用 SeAssignPrimaryTokenPrivilege
    if (!EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME)) {
        std::wcerr << L"Failed to enable SeAssignPrimaryTokenPrivilege." << std::endl;
        if (!ChangeAssignPrimaryTokenPrivilege()) {
            std::wcerr << L"Failed to enable primary token assignment privilege"
                << L" by modifying security configuration." << std::endl;
        }
        std::wcout << L"Press any key to close app.";
        system("pause > nul 2 > nul");
        return 1;
    }

    // 检查 SYSTEM 权限
    if (!IsSystem()) {
        std::wcout << L"Attempting to restart with SYSTEM privileges..." << std::endl;

        // 检查命令行参数,避免无限递归
        if (argc < 2 || _wcsicmp(argv[1], L"system") != 0) {
            // 重新启动自身并传递 "system" 参数
            wchar_t commandLine[MAX_PATH];
            swprintf(commandLine, MAX_PATH, L"%s system", argv[0]);
            if (CreateSystemProcess(argv[0], commandLine)) {
                std::wcout << L"Restarted with SYSTEM privileges." << std::endl;
            }
            else {
                std::wcerr << L"Failed to restart with SYSTEM privileges." << std::endl;
                system("pause > nul 2 > nul");
            }
            return 0;
        }
        else {
            std::wcerr << L"Already tried to elevate privileges but failed." << std::endl;
            system("pause > nul 2 > nul");
            return 1;
        }
    }
    // 如果当前进程已经是 SYSTEM 权限,则继续执行桌面监控
    MonitorDesktop();
    std::wcout << L"Press any key to close app.";
    system("pause > nul 2 > nul");
    return 0;
}

编译时设置监视器高 DPI 识别,和以管理员身份启动。

运行效果如下:

测试截图

初次应用修改配置(提示需要注销用户后重启):

系统配置自动化修改

Winlogon 桌面屏幕描边 + 提示信息:

全屏覆盖提示窗口(透明)

监视器窗口最近一次历史记录信息回放:

最近一次历史记录信息

1.0.0.2 版本开始日志记录存在放在当前目录 "window_hierarchy.log" 文件中。

日志记录样例

 Winlogon 桌面窗口层次

Winlogon 桌面默认是没有窗口的,所以是黑色背景。当执行任务时,具有窗口。当在 UAC 界面时,背景窗口是 Credential Dialog Xaml Host 窗口;当在 CAD 或登陆界面时,背景窗口是 LogonUI Logon Window。

备注:由于博主时间有限,更多信息请自行探索。

参考文献:


本文出处链接:https://blog.csdn.net/qq_59075481/article/details/141608316。 

本文发布于:2024.08.27;更新于:2024.08.27 / 29, 2024.09.26。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涟幽516

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值