Privacy Shield A Clean, C++ Win32 Tool for Temporarily Masking Windows

Joined
Jun 12, 2020
Messages
73
Reaction score
3
I've been working on a Windows privacy utility in C++ and wanted to share a cleaned-up release I just finished. It's called "Privacy Shield" and temporarily obscures any visible window with a topmost overlay to protect your screen from prying eyes in shared environments. The interface shows open windows by title, size, and handle; select one and click Protect (or press Enter) to place a full black overlay that follows resizes and moves using a safe 250 ms timer, and it will prompt you to confirm if you want to keep it protected. It supports a tray icon (double-click restores the main window), a global Ctrl+Shift+Q hotkey to quit cleanly, F5 to refresh, Unprotect All, and Esc to minimize to the tray. I fixed memory leaks, ensured timer safety using HWND as a unique identifier, corrected DWM frame bounds for accurate rectangles, implemented proper cleanup on exit, and optimized the window enumeration to eliminate crashes and ghost overlays. It compiles cleanly with standard Win32 libraries—I'd appreciate any feedback or suggestions for improving performance on multi-monitor setups.

C++:
/*


MIT License


Copyright (c) 2025 CoTon_TiGe_MoUaRf



Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:



The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.



This project is divided into two parts for sharing purposes due to its length. Each part can be used independently while maintaining the same terms outlined in this license.



THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


*/
#include <windows.h>

#include <commctrl.h>

#include <dwmapi.h>

#include <shellapi.h>

#include <unordered_map>

#include <vector>

#include <string>

#include <algorithm>

#include <iostream>


#pragma comment(lib, "comctl32.lib")

#pragma comment(lib, "dwmapi.lib")

#pragma comment(lib, "shell32.lib")


#define WM_TRAY_MSG (WM_USER + 1)

#define HOTKEY_QUIT_ID 1


#define ID_LIST 100

#define ID_PROTECT 101

#define ID_UNPROTECT 102

#define ID_REFRESH 103

#define ID_TRAY 104

#define ID_EXIT 105


struct WindowInfo {

    HWND hwnd;

    std::string title;

    RECT rect;

};


struct ProtectedWindow {

    HWND original;

    HWND overlay;

    UINT_PTR timerId;

    RECT lastRect;

    bool valid;

};


std::unordered_map<HWND, ProtectedWindow> protectedWindows;

std::vector<WindowInfo> windowList;


HWND hMainWnd = NULL;

HWND hTrayWnd = NULL;

NOTIFYICONDATAA nid = {0};

bool isTrayOnly = false;


// Forward declarations

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);


// Utility: get visual bounds (DWM extended frame) with fallback

bool GetVisualWindowRect(HWND hwnd, RECT& outRect) {

    RECT r = {0};

    HRESULT hr = DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(r));

    if (SUCCEEDED(hr)) {

        outRect = r;

        return true;

    }

    return GetWindowRect(hwnd, &outRect) != 0;

}


// Overlay window proc

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_NCHITTEST:

            return HTTRANSPARENT; // let clicks fall through

        case WM_DESTROY:

            return 0;

        default:

            return DefWindowProcA(hwnd, msg, wParam, lParam);

    }

}


// Create overlay covering rect (in screen coords)

HWND CreateMaskOverlay(const RECT& rect) {

    HINSTANCE hInst = GetModuleHandle(NULL);

   

    static bool registered = false;

    if (!registered) {

        WNDCLASSEXA wc = {0};

        wc.cbSize = sizeof(wc);

        wc.lpfnWndProc = OverlayWndProc;

        wc.hInstance = hInst;

        wc.lpszClassName = "PrivacyMaskFixedOverlay_v2";

        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        RegisterClassExA(&wc);

        registered = true;

    }


    int w = rect.right - rect.left;

    int h = rect.bottom - rect.top;

    HWND overlay = CreateWindowExA(

        WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT,

        "PrivacyMaskFixedOverlay_v2", "Protected", WS_POPUP,

        rect.left, rect.top, w, h,

        NULL, NULL, hInst, NULL

    );


    if (!overlay) return NULL;


    // Opaque black

    SetLayeredWindowAttributes(overlay, RGB(0,0,0), 255, LWA_ALPHA);

    SetWindowPos(overlay, HWND_TOPMOST, rect.left, rect.top, w, h, SWP_NOACTIVATE | SWP_SHOWWINDOW);

    return overlay;

}

// ✅ UNPROTECT SÉCURISÉ

void UnprotectWindow(HWND originalHwnd) {

    auto it = protectedWindows.find(originalHwnd);

    if (it == protectedWindows.end()) return;

   

    ProtectedWindow& pw = it->second;

   

    // Kill timer

    if (pw.timerId) {

        KillTimer(NULL, pw.timerId);

        pw.timerId = 0;

    }

   

    // Destroy overlay

    if (IsWindow(pw.overlay)) {

        DestroyWindow(pw.overlay);

    }

   

    // Restore original window

    if (IsWindow(pw.original)) {

        ShowWindow(pw.original, SW_RESTORE);

    }

   

    // Remove from map

    protectedWindows.erase(it);

}

// ✅ TIMER SÉCURISÉ : utilise HWND comme clé unique

void CALLBACK SafeOverlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {

    HWND originalHwnd = (HWND)idEvent;

   

    auto it = protectedWindows.find(originalHwnd);

    if (it == protectedWindows.end()) return;

   

    ProtectedWindow& pw = it->second;

   

    // Vérification de validité

    if (!pw.valid || !IsWindow(pw.original) || !IsWindow(pw.overlay)) {

        UnprotectWindow(originalHwnd);

        return;

    }

   

    RECT rect;

    if (!GetVisualWindowRect(pw.original, rect)) {

        return;

    }

   

    // Si rect changé, update overlay

    if (memcmp(&rect, &pw.lastRect, sizeof(RECT)) != 0) {

        pw.lastRect = rect;

        int w = rect.right - rect.left;

        int h = rect.bottom - rect.top;

        SetWindowPos(pw.overlay, HWND_TOPMOST, rect.left, rect.top, w, h,

                    SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOZORDER);

    }

}





// ✅ PROTECT SÉCURISÉ

void ProtectWindow(HWND hwnd) {

    RECT rect;

    if (!GetVisualWindowRect(hwnd, rect)) return;

   

    if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0) return;

   

    // Déjà protégé ?

    if (protectedWindows.count(hwnd)) return;

   

    HWND overlay = CreateMaskOverlay(rect);

    if (!overlay) return;

   

    ProtectedWindow pw;

    pw.original = hwnd;

    pw.overlay = overlay;

    pw.timerId = SetTimer(NULL, (UINT_PTR)hwnd, 250, SafeOverlayTimerProc);

    pw.lastRect = rect;

    pw.valid = true;

   

    protectedWindows[hwnd] = pw;

   

    if (MessageBoxA(hMainWnd, "Window protected. Unprotect now?", "Privacy Shield",

                   MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL) {

        UnprotectWindow(hwnd);

    }

}


// ✅ ENUMWINDOWS EFFICACE

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {

    HWND hList = (HWND)lParam;

   

    if (IsWindowVisible(hwnd) && !IsIconic(hwnd)) {

        char title[512] = {0};

        GetWindowTextA(hwnd, title, sizeof(title));

        if (strlen(title) > 0) {

            RECT rect;

            if (!GetVisualWindowRect(hwnd, rect)) return TRUE;

           

            bool isProtected = protectedWindows.count(hwnd) > 0;

            std::string prefix = isProtected ? "Protected: " : "Window: ";

           

            WindowInfo info = {hwnd, std::string(title), rect};

            windowList.push_back(info);

           

            int w = rect.right - rect.left;

            int h = rect.bottom - rect.top;

            char buf[1024];

            sprintf_s(buf, sizeof(buf), "%s%s (%dx%d) [0x%p]",

                     prefix.c_str(), title, w, h, (void*)hwnd);

            SendMessageA(hList, LB_ADDSTRING, 0, (LPARAM)buf);

        }

    }

    return TRUE;

}


// Refresh the listbox content

void RefreshWindowList(HWND hList) {

    SendMessageA(hList, LB_RESETCONTENT, 0, 0);

    windowList.clear();

   

    // ✅ Utilise EnumWindows (plus efficace)

    EnumWindows(EnumWindowsProc, (LPARAM)hList);

}


// Unprotect all

void UnprotectAll() {

    std::vector<HWND> toUnprotect;

    for (const auto& pair : protectedWindows) {

        toUnprotect.push_back(pair.first);

    }

    for (HWND hwnd : toUnprotect) {

        UnprotectWindow(hwnd);

    }

}


// Main window procedure

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_CREATE: {

            CreateWindowA("STATIC", "Available Windows:", WS_VISIBLE | WS_CHILD | SS_LEFT,

                         10, 10, 460, 20, hwnd, NULL, NULL, NULL);


            HWND hList = CreateWindowA("LISTBOX", NULL,

                WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_NOTIFY,

                10, 35, 460, 220, hwnd, (HMENU)ID_LIST, NULL, NULL);


            CreateWindowA("BUTTON", "Protect (Enter)", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                10, 265, 120, 30, hwnd, (HMENU)ID_PROTECT, NULL, NULL);

            CreateWindowA("BUTTON", "Unprotect All", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                140, 265, 120, 30, hwnd, (HMENU)ID_UNPROTECT, NULL, NULL);

            CreateWindowA("BUTTON", "Refresh (F5)", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                270, 265, 100, 30, hwnd, (HMENU)ID_REFRESH, NULL, NULL);

            CreateWindowA("BUTTON", "Show in Tray (Esc)", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                380, 265, 120, 30, hwnd, (HMENU)ID_TRAY, NULL, NULL);

            CreateWindowA("BUTTON", "Quitter", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                10, 305, 120, 30, hwnd, (HMENU)ID_EXIT, NULL, NULL);


            RefreshWindowList(hList);

            break;

        }


        case WM_COMMAND: {

            HWND hList = GetDlgItem(hwnd, ID_LIST);

            int index = (int)SendMessageA(hList, LB_GETCURSEL, 0, 0);


            switch (LOWORD(wParam)) {

                case ID_PROTECT:

                    if (index >= 0 && index < (int)windowList.size()) {

                        ProtectWindow(windowList[index].hwnd);

                        RefreshWindowList(hList);

                    }

                    break;

                case ID_UNPROTECT:

                    UnprotectAll();

                    RefreshWindowList(hList);

                    MessageBoxA(hwnd, "All windows unprotected!", "Privacy Shield", MB_OK | MB_ICONINFORMATION);

                    break;

                case ID_REFRESH:

                    RefreshWindowList(hList);

                    break;

                case ID_TRAY:

                    ShowWindow(hwnd, SW_HIDE);

                    isTrayOnly = true;

                    break;

                case ID_EXIT: {

                    UnprotectAll();

                    Shell_NotifyIconA(NIM_DELETE, &nid);

                    UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

                    PostQuitMessage(0);

                    break;

                }

            }

            break;

        }


        case WM_KEYDOWN: {

            switch (wParam) {

                case VK_RETURN:

                    SendMessage(hwnd, WM_COMMAND, ID_PROTECT, 0);

                    break;

                case VK_F5:

                    SendMessage(hwnd, WM_COMMAND, ID_REFRESH, 0);

                    break;

                case VK_ESCAPE:

                    SendMessage(hwnd, WM_COMMAND, ID_TRAY, 0);

                    break;

            }

            return 0;

        }


        case WM_SYSCOMMAND:

            if (wParam == SC_CLOSE) {

                ShowWindow(hwnd, SW_HIDE);

                return 0;

            }

            break;


        case WM_DESTROY:

            UnprotectAll();

            Shell_NotifyIconA(NIM_DELETE, &nid);

            UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

            PostQuitMessage(0);

            return 0;

       

        case WM_HOTKEY:

            if (wParam == HOTKEY_QUIT_ID) {

                UnprotectAll();

                Shell_NotifyIconA(NIM_DELETE, &nid);

                UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

                PostQuitMessage(0);

            }

            break;

    }

    return DefWindowProcA(hwnd, msg, wParam, lParam);

}


LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    if (msg == WM_TRAY_MSG) {

        if (lParam == WM_LBUTTONDBLCLK) {

            ShowWindow(hMainWnd, SW_RESTORE);

            isTrayOnly = false;

            SetForegroundWindow(hMainWnd);

        }

    }

    return DefWindowProcA(hwnd, msg, wParam, lParam);

}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {

    INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_STANDARD_CLASSES };

    InitCommonControlsEx(&icex);


    // Main window

    WNDCLASSEXA wcMain = {0};

    wcMain.cbSize = sizeof(wcMain);

    wcMain.lpfnWndProc = MainWndProc;

    wcMain.hInstance = hInstance;

    wcMain.lpszClassName = "PrivacyShieldFixedMain_v2";

    wcMain.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    RegisterClassExA(&wcMain);


    hMainWnd = CreateWindowExA(0, wcMain.lpszClassName, "Privacy Shield v2 - Fixed",

        WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,

        500, 350, NULL, NULL, hInstance, NULL);


    // ✅ TRAY WINDOW CORRIGÉ

    WNDCLASSEXA wcTray = {0};

    wcTray.cbSize = sizeof(wcTray);

    wcTray.lpfnWndProc = TrayWndProc;

    wcTray.hInstance = hInstance;

    wcTray.lpszClassName = "PrivacyShieldTray_v2";

    RegisterClassExA(&wcTray);


    hTrayWnd = CreateWindowExA(0, wcTray.lpszClassName, NULL, WS_OVERLAPPED,

                              0,0,0,0, NULL, NULL, hInstance, NULL);

    ShowWindow(hTrayWnd, SW_HIDE); // ✅ CORRIGÉ : montrer le tray window


    ShowWindow(hMainWnd, nCmdShow);

    UpdateWindow(hMainWnd);


    // Tray icon

    nid.cbSize = sizeof(nid);

    nid.hWnd = hTrayWnd;

    nid.uID = 1;

    nid.uFlags = NIF_MESSAGE | NIF_TIP;

    nid.uCallbackMessage = WM_TRAY_MSG;

    strcpy_s(nid.szTip, "Privacy Shield v2 - Double-click");

    Shell_NotifyIconA(NIM_ADD, &nid);


    // Register global hotkey

    if (!RegisterHotKey(NULL, HOTKEY_QUIT_ID, MOD_CONTROL | MOD_SHIFT, 'Q')) {

        MessageBoxA(NULL, "Failed to register hotkey!", "Error", MB_OK | MB_ICONERROR);

    }


    // Message loop

    MSG msg;

    while (GetMessageA(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessageA(&msg);

    }


    // ✅ CLEANUP FINAL COMPLÈT

    UnprotectAll();

    Shell_NotifyIconA(NIM_DELETE, &nid);

    UnregisterHotKey(NULL, HOTKEY_QUIT_ID);


    return 0;

}

I'm not sure about the shortcuts and the double-click, but everything else is there.
 
Joined
Jun 12, 2020
Messages
73
Reaction score
3
Here's the version with shortcuts and working double-click — there's also an interface with a more modern design.

C++:
/*


MIT License


Copyright (c) 2025 CoTon_TiGe_MoUaRf



Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:



The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.



THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


*/
#include <windows.h>

#include <commctrl.h>

#include <dwmapi.h>

#include <shellapi.h>

#include <unordered_map>

#include <vector>

#include <string>

#include <algorithm>

#include <iostream>


#pragma comment(lib, "comctl32.lib")

#pragma comment(lib, "dwmapi.lib")

#pragma comment(lib, "shell32.lib")

#pragma comment(lib, "user32.lib")


#define WM_TRAY_MSG (WM_USER + 1)

#define HOTKEY_QUIT_ID 1

#define TIMER_HIDE_TRAY 2001

#define TIMER_CLEANUP 2002


#define ID_LIST 100

#define ID_PROTECT 101

#define ID_UNPROTECT 102

#define ID_REFRESH 103

#define ID_TRAY 104

#define ID_EXIT 105


struct WindowInfo {

    HWND hwnd;

    std::string title;

    RECT rect;

};


struct ProtectedWindow {

    HWND original;

    HWND overlay;

    UINT_PTR timerId;

    RECT lastRect;

    bool valid;

};


std::unordered_map<HWND, ProtectedWindow> protectedWindows;

std::vector<WindowInfo> windowList;


HWND hMainWnd = NULL;

HWND hTrayWnd = NULL;

NOTIFYICONDATAA nid = {0};

bool isTrayOnly = false;

HACCEL hAccelerator = NULL;

HFONT hFont = NULL;

HWND hListCtrl = NULL;

HWND hStaticLabel = NULL;

HWND hProtectBtn = NULL, hUnprotectBtn = NULL, hRefreshBtn = NULL, hTrayBtn = NULL, hExitBtn = NULL;


// DPI scaling

int GetDpiForWindowOrSystem(HWND hwnd) {

    HDC hdc = GetDC(NULL);

    int dpi = GetDeviceCaps(hdc, LOGPIXELSX);

    ReleaseDC(NULL, hdc);

    return dpi;

}


int ScaleDpi(int value, int dpi) {

    return MulDiv(value, dpi, 96);

}


// Forward declarations

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);

void CALLBACK HideTrayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);

void CALLBACK SafeOverlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);

void ResizeControls(HWND hwnd);


// Utility: get visual bounds (DWM extended frame) with fallback

bool GetVisualWindowRect(HWND hwnd, RECT& outRect) {

    RECT r = {0};

    HRESULT hr = DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(r));

    if (SUCCEEDED(hr)) {

        outRect = r;

        return true;

    }

    return GetWindowRect(hwnd, &outRect) != 0;

}


// Overlay window proc

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_NCHITTEST:

            return HTTRANSPARENT; // let clicks fall through

        case WM_DESTROY:

            return 0;

        default:

            return DefWindowProcA(hwnd, msg, wParam, lParam);

    }

}


// Create overlay covering rect (in screen coords)

HWND CreateMaskOverlay(const RECT& rect) {

    HINSTANCE hInst = GetModuleHandle(NULL);

 

    static bool registered = false;

    if (!registered) {

        WNDCLASSEXA wc = {0};

        wc.cbSize = sizeof(wc);

        wc.lpfnWndProc = OverlayWndProc;

        wc.hInstance = hInst;

        wc.lpszClassName = "PrivacyMaskFixedOverlay_v2";

        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        RegisterClassExA(&wc);

        registered = true;

    }


    int w = rect.right - rect.left;

    int h = rect.bottom - rect.top;

    HWND overlay = CreateWindowExA(

        WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT,

        "PrivacyMaskFixedOverlay_v2", "Protected", WS_POPUP,

        rect.left, rect.top, w, h,

        NULL, NULL, hInst, NULL

    );


    if (!overlay) return NULL;


    // Opaque black

    SetLayeredWindowAttributes(overlay, RGB(0,0,0), 255, LWA_ALPHA);

    SetWindowPos(overlay, HWND_TOPMOST, rect.left, rect.top, w, h, SWP_NOACTIVATE | SWP_SHOWWINDOW);

    return overlay;

}


// UNPROTECT SÉCURISÉ

void UnprotectWindow(HWND originalHwnd) {

    auto it = protectedWindows.find(originalHwnd);

    if (it == protectedWindows.end()) return;

 

    ProtectedWindow& pw = it->second;

 

    // Kill timer

    if (pw.timerId) {

        KillTimer(NULL, pw.timerId);

        pw.timerId = 0;

    }

 

    // Destroy overlay

    if (IsWindow(pw.overlay)) {

        DestroyWindow(pw.overlay);

    }

 

    // Restore original window

    if (IsWindow(pw.original)) {

        ShowWindow(pw.original, SW_RESTORE);

    }

 

    // Remove from map

    protectedWindows.erase(it);

}


// TIMER SÉCURISÉ : utilise HWND comme clé unique

void CALLBACK SafeOverlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {

    HWND originalHwnd = (HWND)idEvent;

 

    auto it = protectedWindows.find(originalHwnd);

    if (it == protectedWindows.end()) return;

 

    ProtectedWindow& pw = it->second;

 

    // Vérification de validité

    if (!pw.valid || !IsWindow(pw.original) || !IsWindow(pw.overlay)) {

        UnprotectWindow(originalHwnd);

        return;

    }

 

    RECT rect;

    if (!GetVisualWindowRect(pw.original, rect)) {

        return;

    }

 

    // Si rect changé, update overlay

    if (memcmp(&rect, &pw.lastRect, sizeof(RECT)) != 0) {

        pw.lastRect = rect;

        int w = rect.right - rect.left;

        int h = rect.bottom - rect.top;

        SetWindowPos(pw.overlay, HWND_TOPMOST, rect.left, rect.top, w, h,

                    SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOZORDER);

    }

}


// PROTECT SÉCURISÉ

void ProtectWindow(HWND hwnd) {

    RECT rect;

    if (!GetVisualWindowRect(hwnd, rect)) return;

 

    if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0) return;

 

    // Déjà protégé ?

    if (protectedWindows.count(hwnd)) return;

 

    HWND overlay = CreateMaskOverlay(rect);

    if (!overlay) return;

 

    ProtectedWindow pw;

    pw.original = hwnd;

    pw.overlay = overlay;

    pw.timerId = SetTimer(NULL, (UINT_PTR)hwnd, 250, SafeOverlayTimerProc);

    pw.lastRect = rect;

    pw.valid = true;

 

    protectedWindows[hwnd] = pw;

}


// ✅ ENUMWINDOWS CORRIGÉ - SUPPRESSION LBS_OWNERDRAWFIXED

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {

    HWND hList = (HWND)lParam;

 

    // ✅ PLUS DE FILTRE TROP STRICT - inclut plus de fenêtres

    if (IsWindowVisible(hwnd) && !IsIconic(hwnd)) {

        char title[512] = {0};

        GetWindowTextA(hwnd, title, sizeof(title));

       

        // ✅ Accepte les titres courts aussi

        if (strlen(title) > 0 && strlen(title) < 256) {

            RECT rect;

            if (!GetVisualWindowRect(hwnd, rect)) return TRUE;

         

            bool isProtected = protectedWindows.count(hwnd) > 0;

            std::string prefix = isProtected ? "[PROTECTED] " : "[AVAILABLE] ";

         

            WindowInfo info = {hwnd, std::string(title), rect};

            windowList.push_back(info);

         

            int w = rect.right - rect.left;

            int h = rect.bottom - rect.top;

            char buf[1024];

            sprintf_s(buf, sizeof(buf), "%s%s (%dx%d) [0x%p]",

                     prefix.c_str(), title, w, h, (void*)hwnd);

            SendMessageA(hList, LB_ADDSTRING, 0, (LPARAM)buf);

        }

    }

    return TRUE;

}


// Refresh the listbox content

void RefreshWindowList(HWND hList) {

    SendMessageA(hList, LB_RESETCONTENT, 0, 0);

    windowList.clear();

    EnumWindows(EnumWindowsProc, (LPARAM)hList);

   

    // ✅ Debug : affiche le nombre de fenêtres trouvées

    char debugMsg[256];

    sprintf_s(debugMsg, sizeof(debugMsg), "Found %zu windows", windowList.size());

    OutputDebugStringA(debugMsg);

}


// Unprotect all

void UnprotectAll() {

    std::vector<HWND> toUnprotect;

    for (const auto& pair : protectedWindows) {

        toUnprotect.push_back(pair.first);

    }

    for (HWND hwnd : toUnprotect) {

        UnprotectWindow(hwnd);

    }

}


// TIMER pour cacher l'icône tray après restauration

void CALLBACK HideTrayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {

    if (idEvent == TIMER_HIDE_TRAY) {

        KillTimer(hwnd, TIMER_HIDE_TRAY);

        Shell_NotifyIconA(NIM_DELETE, &nid);

    }

}


// Resize controls responsively

void ResizeControls(HWND hwnd) {

    RECT rcClient;

    GetClientRect(hwnd, &rcClient);

    int clientW = rcClient.right - rcClient.left;

    int clientH = rcClient.bottom - rcClient.top;

   

    int dpi = GetDpiForWindowOrSystem(hwnd);

    int padding = ScaleDpi(12, dpi);

    int labelH = ScaleDpi(24, dpi);

    int listTop = ScaleDpi(35, dpi);

    int btnH = ScaleDpi(36, dpi);

    int btnAreaH = ScaleDpi(80, dpi);

   

    if (hStaticLabel) {

        SetWindowPos(hStaticLabel, NULL, padding, padding, clientW - 2*padding, labelH,

                    SWP_NOZORDER | SWP_NOACTIVATE);

    }

   

    if (hListCtrl) {

        SetWindowPos(hListCtrl, NULL, padding, listTop,

                    clientW - 2*padding, clientH - listTop - btnAreaH - padding,

                    SWP_NOZORDER | SWP_NOACTIVATE);

    }

   

    if (hProtectBtn && hUnprotectBtn && hRefreshBtn && hTrayBtn && hExitBtn) {

        int btnW = (clientW - 6*padding) / 5;

        int btnTop = clientH - btnAreaH + ScaleDpi(10, dpi);

       

        SetWindowPos(hProtectBtn, NULL, padding, btnTop, btnW, btnH,

                    SWP_NOZORDER | SWP_NOACTIVATE);

        SetWindowPos(hUnprotectBtn, NULL, 2*padding + btnW, btnTop, btnW, btnH,

                    SWP_NOZORDER | SWP_NOACTIVATE);

        SetWindowPos(hRefreshBtn, NULL, 3*padding + 2*btnW, btnTop, btnW, btnH,

                    SWP_NOZORDER | SWP_NOACTIVATE);

        SetWindowPos(hTrayBtn, NULL, 4*padding + 3*btnW, btnTop, btnW, btnH,

                    SWP_NOZORDER | SWP_NOACTIVATE);

        SetWindowPos(hExitBtn, NULL, 5*padding + 4*btnW, btnTop, btnW, btnH,

                    SWP_NOZORDER | SWP_NOACTIVATE);

    }

}


// Main window procedure

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_CREATE: {

            int dpi = GetDpiForWindowOrSystem(NULL);

           

            // Create modern font

            int fontSize = ScaleDpi(10, dpi);

            hFont = CreateFontA(-fontSize, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,

                               ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                               DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI");

           

            // Labels

            hStaticLabel = CreateWindowA("STATIC", "Available Windows:",

                WS_VISIBLE | WS_CHILD | SS_LEFT,

                0, 0, 0, 0, hwnd, NULL, NULL, NULL);

           

            // ✅ LISTBOX CORRIGÉE - SUPPRESSION LBS_OWNERDRAWFIXED

            hListCtrl = CreateWindowA("LISTBOX", NULL,

                WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_NOTIFY | LBS_HASSTRINGS,

                0, 0, 0, 0, hwnd, (HMENU)ID_LIST, NULL, NULL);


            // Buttons with modern spacing

            hProtectBtn = CreateWindowA("BUTTON", "Protect (Enter)",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_PROTECT, NULL, NULL);

           

            hUnprotectBtn = CreateWindowA("BUTTON", "Unprotect All",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_UNPROTECT, NULL, NULL);

           

            hRefreshBtn = CreateWindowA("BUTTON", "Refresh (F5)",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_REFRESH, NULL, NULL);

           

            hTrayBtn = CreateWindowA("BUTTON", "Show in Tray (Esc)",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_TRAY, NULL, NULL);

           

            hExitBtn = CreateWindowA("BUTTON", "Quitter",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_EXIT, NULL, NULL);


            // Apply font to all controls

            HWND controls[] = {hStaticLabel, hListCtrl, hProtectBtn, hUnprotectBtn,

                             hRefreshBtn, hTrayBtn, hExitBtn};

            for (int i = 0; i < 7; i++) {

                if (controls[i]) {

                    SendMessageA(controls[i], WM_SETFONT, (WPARAM)hFont, TRUE);

                }

            }

           

            // ✅ RAFRAÎCHISSEMENT APRÈS CRÉATION DES CONTRÔLES

            ResizeControls(hwnd);

            RefreshWindowList(hListCtrl);

            break;

        }


        case WM_SIZE: {

            ResizeControls(hwnd);

            break;

        }


        case WM_GETMINMAXINFO: {

            LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam;

            int dpi = GetDpiForWindowOrSystem(hwnd);

            pMMI->ptMinTrackSize.x = ScaleDpi(480, dpi);

            pMMI->ptMinTrackSize.y = ScaleDpi(320, dpi);

            return 0;

        }


        case WM_COMMAND: {

            int index = (int)SendMessageA(hListCtrl, LB_GETCURSEL, 0, 0);


            WORD wNotifyCode = HIWORD(wParam);

            WORD wID = LOWORD(wParam);


            // ✅ DOUBLE-CLIC SUR LISTBOX

            if (wID == ID_LIST && wNotifyCode == LBN_DBLCLK) {

                if (index >= 0 && index < (int)windowList.size()) {

                    ProtectWindow(windowList[index].hwnd);

                    RefreshWindowList(hListCtrl);

                }

                break;

            }


            switch (wID) {

                case ID_PROTECT:

                    if (index >= 0 && index < (int)windowList.size()) {

                        ProtectWindow(windowList[index].hwnd);

                        RefreshWindowList(hListCtrl);

                    }

                    break;


                case ID_UNPROTECT:

                    UnprotectAll();

                    RefreshWindowList(hListCtrl);

                    MessageBoxA(hwnd, "All windows unprotected!", "Privacy Shield", MB_OK | MB_ICONINFORMATION);

                    break;


                case ID_REFRESH:

                    RefreshWindowList(hListCtrl);

                    break;


                case ID_TRAY:

                    ShowWindow(hwnd, SW_HIDE);

                    isTrayOnly = true;

                    break;


                case ID_EXIT: {

                    UnprotectAll();

                    Shell_NotifyIconA(NIM_DELETE, &nid);

                    UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

                    PostQuitMessage(0);

                    break;

                }

            }

            break;

        }


        case WM_SYSCOMMAND:

            if (wParam == SC_CLOSE) {

                ShowWindow(hwnd, SW_HIDE);

                return 0;

            }

            break;


        case WM_DESTROY:

            UnprotectAll();

            Shell_NotifyIconA(NIM_DELETE, &nid);

            UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

            if (hAccelerator) DestroyAcceleratorTable(hAccelerator);

            if (hFont) DeleteObject(hFont);

            PostQuitMessage(0);

            return 0;

     

        case WM_HOTKEY:

            if (wParam == HOTKEY_QUIT_ID) {

                UnprotectAll();

                Shell_NotifyIconA(NIM_DELETE, &nid);

                UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

                PostQuitMessage(0);

            }

            break;

    }

    return DefWindowProcA(hwnd, msg, wParam, lParam);

}


// ✅ TRAY WINDOW CORRIGÉE

LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_TRAY_MSG: {
            // ✅ CORRECTION : test correct de lParam

            if ((UINT)lParam == WM_LBUTTONDBLCLK) {

                // ✅ ACTIVATION COMPLÈTE DE LA FENÊTRE

                ShowWindow(hMainWnd, SW_RESTORE);

                SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);

                SetWindowPos(hMainWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

                SetForegroundWindow(hMainWnd);

                BringWindowToTop(hMainWnd);

                isTrayOnly = false;

               

                // ✅ SUPPRESSION DIFFÉRÉE de l'icône tray

                SetTimer(hwnd, TIMER_HIDE_TRAY, 500, HideTrayTimerProc);

            }

            break;

        }

       

        case WM_TIMER:

            if (wParam == TIMER_HIDE_TRAY) {

                KillTimer(hwnd, TIMER_HIDE_TRAY);

                Shell_NotifyIconA(NIM_DELETE, &nid);

            }

            break;

    }

    return DefWindowProcA(hwnd, msg, wParam, lParam);

}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {

    // ✅ DPI AWARENESS - 100% Compatible Win7/8/10/11 (Runtime resolution)

    HMODULE hUser32 = GetModuleHandleA("user32.dll");

    if (hUser32) {

        // Windows 10+ : Per-Monitor DPI V2 (valeur = -4)

        typedef BOOL(WINAPI* SetProcessDpiAwarenessContext_t)(HANDLE);

        SetProcessDpiAwarenessContext_t pSetDpiCtx =

            (SetProcessDpiAwarenessContext_t)GetProcAddress(hUser32, "SetProcessDpiAwarenessContext");

        if (pSetDpiCtx) {

            pSetDpiCtx((HANDLE)(intptr_t)-4);  // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2

        } else {

            // Fallback WinVista+ : System DPI Aware

            typedef BOOL(WINAPI* SetProcessDPIAware_t)(void);

            SetProcessDPIAware_t pSetProcessDPIAware =

                (SetProcessDPIAware_t)GetProcAddress(hUser32, "SetProcessDPIAware");

            if (pSetProcessDPIAware) {

                pSetProcessDPIAware();

            }

        }

    }


    INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES };

    InitCommonControlsEx(&icex);


    // ✅ ACCÉLÉRATEURS (Enter, F5, Escape)

    ACCEL accels[3] = {

        {0, VK_RETURN, ID_PROTECT},

        {FVIRTKEY, VK_F5, ID_REFRESH},

        {0, VK_ESCAPE, ID_TRAY}

    };

    hAccelerator = CreateAcceleratorTableA(accels, 3);


    // Main window class

    WNDCLASSEXA wcMain = {0};

    wcMain.cbSize = sizeof(wcMain);

    wcMain.lpfnWndProc = MainWndProc;

    wcMain.hInstance = hInstance;

    wcMain.lpszClassName = "PrivacyShieldFixedMain_v2";

    wcMain.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    wcMain.hCursor = LoadCursor(NULL, IDC_ARROW);

    wcMain.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wcMain.hIconSm = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 16, 16, 0);

    RegisterClassExA(&wcMain);


    // ✅ CALCUL TAILLE FENÊTRE DPI-AWARE + AdjustWindowRectEx

    int dpi = GetDpiForWindowOrSystem(NULL);

    int clientWidth = ScaleDpi(500, dpi);

    int clientHeight = ScaleDpi(380, dpi);

   

    RECT rcClient = {0, 0, clientWidth, clientHeight};

    DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;

    AdjustWindowRectEx(&rcClient, dwStyle, FALSE, 0);

   

    int windowWidth = rcClient.right - rcClient.left;

    int windowHeight = rcClient.bottom - rcClient.top;


    hMainWnd = CreateWindowExA(

        WS_EX_CONTROLPARENT | WS_EX_APPWINDOW,

        wcMain.lpszClassName,

        "Privacy Shield v2 - Modern UI",

        dwStyle,

        CW_USEDEFAULT, CW_USEDEFAULT,

        windowWidth, windowHeight,

        NULL, NULL, hInstance, NULL

    );


    // ✅ TRAY WINDOW COMPLÈTEMENT CORRIGÉE

    WNDCLASSEXA wcTray = {0};

    wcTray.cbSize = sizeof(wcTray);

    wcTray.lpfnWndProc = TrayWndProc;

    wcTray.hInstance = hInstance;

    wcTray.lpszClassName = "PrivacyShieldTray_v2";

    wcTray.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    wcTray.hCursor = LoadCursor(NULL, IDC_ARROW);

    wcTray.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassExA(&wcTray);


    hTrayWnd = CreateWindowExA(0, wcTray.lpszClassName, NULL, WS_OVERLAPPED,

                              -2000, -2000, 1, 1, NULL, NULL, hInstance, NULL);

   

    // ✅ CRUCIAL : Montrer la fenêtre tray (mais hors écran)

    ShowWindow(hTrayWnd, SW_SHOW);

    UpdateWindow(hTrayWnd);


    ShowWindow(hMainWnd, nCmdShow);

    UpdateWindow(hMainWnd);


    // Tray icon avec moderne tooltip

    nid.cbSize = sizeof(nid);

    nid.hWnd = hTrayWnd;

    nid.uID = 1;

    nid.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON;

    nid.uCallbackMessage = WM_TRAY_MSG;

    nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    strcpy_s(nid.szTip, sizeof(nid.szTip), "Privacy Shield v2 - Double-click to protect windows");

    Shell_NotifyIconA(NIM_ADD, &nid);


    // ✅ HOTKEY APRÈS CRÉATION DES FENÊTRES

    if (!RegisterHotKey(NULL, HOTKEY_QUIT_ID, MOD_CONTROL | MOD_SHIFT, 'Q')) {

        MessageBoxA(NULL, "Failed to register hotkey Ctrl+Shift+Q!", "Privacy Shield", MB_OK | MB_ICONWARNING);

    }


    // Message loop avec accélérateurs

    MSG msg;

    while (GetMessageA(&msg, NULL, 0, 0)) {

        // ✅ ACCÉLÉRATEURS FONCTIONNENT MÊME SUR LISTBOX

        if (!TranslateAcceleratorA(hMainWnd, hAccelerator, &msg)) {

            TranslateMessage(&msg);

            DispatchMessageA(&msg);

        }

    }


    // CLEANUP FINAL COMPLÈT

    UnprotectAll();

    Shell_NotifyIconA(NIM_DELETE, &nid);

    UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

    if (hAccelerator) DestroyAcceleratorTable(hAccelerator);

    if (hFont) DeleteObject(hFont);


    return 0;

}
 
Last edited:
Joined
Jun 12, 2020
Messages
73
Reaction score
3
Here’s the finished version, in my view: pressing the Escape key minimizes the window and you can easily restore it by clicking it; active window names are listed alphabetically; the main window’s size is manually adjustable; the console no longer appears, and the second window is hidden as well.

C++:
/*


MIT License


Copyright (c) 2025 CoTon_TiGe_MoUaRf



Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:



The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.



THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


*/
#include <windows.h>

#include <commctrl.h>

#include <dwmapi.h>

#include <shellapi.h>

#include <unordered_map>

#include <vector>

#include <string>

#include <algorithm>

#include <iostream>


#pragma comment(lib, "comctl32.lib")

#pragma comment(lib, "dwmapi.lib")

#pragma comment(lib, "shell32.lib")

#pragma comment(lib, "user32.lib")


#define WM_TRAY_MSG (WM_USER + 1)

#define HOTKEY_QUIT_ID 1

#define TIMER_HIDE_TRAY 2001

#define TIMER_CLEANUP 2002


#define ID_LIST 100

#define ID_PROTECT 101

#define ID_UNPROTECT 102

#define ID_REFRESH 103

#define ID_TRAY 104

#define ID_EXIT 105

bool windowVisible = true;

struct WindowInfo {

    HWND hwnd;

    std::string title;

    RECT rect;

};


struct ProtectedWindow {

    HWND original;

    HWND overlay;

    UINT_PTR timerId;

    RECT lastRect;

    bool valid;

};


std::unordered_map<HWND, ProtectedWindow> protectedWindows;

std::vector<WindowInfo> windowList;


HWND hMainWnd = NULL;

HWND hTrayWnd = NULL;

NOTIFYICONDATAA nid = {0};

bool isTrayOnly = false;

HACCEL hAccelerator = NULL;

HFONT hFont = NULL;

HWND hListCtrl = NULL;

HWND hStaticLabel = NULL;

HWND hProtectBtn = NULL, hUnprotectBtn = NULL, hRefreshBtn = NULL, hTrayBtn = NULL, hExitBtn = NULL;


// DPI scaling

int GetDpiForWindowOrSystem(HWND hwnd) {

    // Win10+ : GetDpiForWindow (per-window DPI) - PRIORITÉ #1

    HMODULE hUser32 = GetModuleHandleA("user32.dll");

    if (hUser32) {

        typedef UINT(WINAPI* GetDpiForWindow_t)(HWND);

        GetDpiForWindow_t pGetDpiForWindow =

            (GetDpiForWindow_t)GetProcAddress(hUser32, "GetDpiForWindow");

        if (pGetDpiForWindow && IsWindow(hwnd)) {

            UINT dpi = pGetDpiForWindow(hwnd);

            if (dpi > 0) return (int)dpi;

        }

    }

    

    // Fallback : écran primaire (code existant)

    HDC hdc = GetDC(NULL);

    int dpi = GetDeviceCaps(hdc, LOGPIXELSX);

    ReleaseDC(NULL, hdc);

    return dpi;

}


int ScaleDpi(int value, int dpi) {

    return MulDiv(value, dpi, 96);

}


// Forward declarations

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);

void CALLBACK HideTrayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);

void CALLBACK SafeOverlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);

void ResizeControls(HWND hwnd);


// Utility: get visual bounds (DWM extended frame) with fallback

bool GetVisualWindowRect(HWND hwnd, RECT& outRect) {

    RECT r = {0};

    HRESULT hr = DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(r));

    if (SUCCEEDED(hr)) {

        outRect = r;

        return true;

    }

    return GetWindowRect(hwnd, &outRect) != 0;

}


// Overlay window proc

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_NCHITTEST:

            return HTTRANSPARENT; // let clicks fall through

        case WM_DESTROY:

            return 0;

        default:

            return DefWindowProcA(hwnd, msg, wParam, lParam);

    }

}


// Create overlay covering rect (in screen coords)

HWND CreateMaskOverlay(const RECT& rect) {

    HINSTANCE hInst = GetModuleHandle(NULL);

 

    static bool registered = false;

    if (!registered) {

        WNDCLASSEXA wc = {0};

        wc.cbSize = sizeof(wc);

        wc.lpfnWndProc = OverlayWndProc;

        wc.hInstance = hInst;

        wc.lpszClassName = "PrivacyMaskFixedOverlay_v2";

        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        RegisterClassExA(&wc);

        registered = true;

    }


    int w = rect.right - rect.left;

    int h = rect.bottom - rect.top;

    HWND overlay = CreateWindowExA(

        WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT,

        "PrivacyMaskFixedOverlay_v2", "Protected", WS_POPUP,

        rect.left, rect.top, w, h,

        NULL, NULL, hInst, NULL

    );


    if (!overlay) return NULL;


    // Opaque black

    SetLayeredWindowAttributes(overlay, RGB(0,0,0), 255, LWA_ALPHA);

    SetWindowPos(overlay, HWND_TOPMOST, rect.left, rect.top, w, h, SWP_NOACTIVATE | SWP_SHOWWINDOW);

    return overlay;

}


// UNPROTECT SÉCURISÉ

void UnprotectWindow(HWND originalHwnd) {

    auto it = protectedWindows.find(originalHwnd);

    if (it == protectedWindows.end()) return;

 

    ProtectedWindow& pw = it->second;

 

    // Kill timer

    if (pw.timerId) {

        KillTimer(NULL, pw.timerId);

        pw.timerId = 0;

    }

 

    // Destroy overlay

    if (IsWindow(pw.overlay)) {

        DestroyWindow(pw.overlay);

    }

 

    // Restore original window

    if (IsWindow(pw.original)) {

        ShowWindow(pw.original, SW_RESTORE);

    }

 

    // Remove from map

    protectedWindows.erase(it);

}


// TIMER SÉCURISÉ : utilise HWND comme clé unique

void CALLBACK SafeOverlayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {

    HWND originalHwnd = (HWND)idEvent;

 

    auto it = protectedWindows.find(originalHwnd);

    if (it == protectedWindows.end()) return;

 

    ProtectedWindow& pw = it->second;

 

    // Vérification de validité

    if (!pw.valid || !IsWindow(pw.original) || !IsWindow(pw.overlay)) {

        UnprotectWindow(originalHwnd);

        return;

    }

 

    RECT rect;

    if (!GetVisualWindowRect(pw.original, rect)) {

        return;

    }

 

    // Si rect changé, update overlay

    if (memcmp(&rect, &pw.lastRect, sizeof(RECT)) != 0) {

        pw.lastRect = rect;

        int w = rect.right - rect.left;

        int h = rect.bottom - rect.top;

        SetWindowPos(pw.overlay, HWND_TOPMOST, rect.left, rect.top, w, h,

                    SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOZORDER);

    }

}


// PROTECT SÉCURISÉ

void ProtectWindow(HWND hwnd) {

    RECT rect;

    if (!GetVisualWindowRect(hwnd, rect)) return;

 

    if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0) return;

 

    // Déjà protégé ?

    if (protectedWindows.count(hwnd)) return;

 

    HWND overlay = CreateMaskOverlay(rect);

    if (!overlay) return;

 

    ProtectedWindow pw;

    pw.original = hwnd;

    pw.overlay = overlay;

    pw.timerId = SetTimer(NULL, (UINT_PTR)hwnd, 250, SafeOverlayTimerProc);

    pw.lastRect = rect;

    pw.valid = true;

 

    protectedWindows[hwnd] = pw;

}


// ✅ ENUMWINDOWS CORRIGÉ - SUPPRESSION LBS_OWNERDRAWFIXED

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {

    HWND hList = (HWND)lParam;

 

    // ✅ PLUS DE FILTRE TROP STRICT - inclut plus de fenêtres

    if (IsWindowVisible(hwnd) && !IsIconic(hwnd)) {

        char title[512] = {0};

        GetWindowTextA(hwnd, title, sizeof(title));

      

        // ✅ Accepte les titres courts aussi

        if (strlen(title) > 0 && strlen(title) < 256) {

            RECT rect;

            if (!GetVisualWindowRect(hwnd, rect)) return TRUE;

        

            bool isProtected = protectedWindows.count(hwnd) > 0;

            std::string prefix = isProtected ? "[PROTECTED] " : "[AVAILABLE] ";

        

            WindowInfo info = {hwnd, std::string(title), rect};

            windowList.push_back(info);

        

            int w = rect.right - rect.left;

            int h = rect.bottom - rect.top;

            char buf[1024];

            sprintf_s(buf, sizeof(buf), "%s%s (%dx%d) [0x%p]",

                     prefix.c_str(), title, w, h, (void*)hwnd);

            SendMessageA(hList, LB_ADDSTRING, 0, (LPARAM)buf);

        }

    }

    return TRUE;

}


// Refresh the listbox content

void RefreshWindowList(HWND hList) {

    // ✅ VÉRIFICATION CRITIQUE

    if (!IsWindow(hList)) return;

    

    // 1. Reset propre

    SendMessageA(hList, LB_RESETCONTENT, 0, 0);

    windowList.clear();

    

    // 2. Enum + collecte

    EnumWindows(EnumWindowsProc, (LPARAM)hList);

    

    // ✅ SYNCHRONISATION : même taille listbox ↔ windowList

    int listCount = (int)SendMessageA(hList, LB_GETCOUNT, 0, 0);

    if (listCount != (int)windowList.size()) {

        // Debug UNE SEULE FOIS si désync

        char debugMsg[256];

        sprintf_s(debugMsg, sizeof(debugMsg),

                 "SYNC FIXED: list=%d, vector=%zu", listCount, windowList.size());

        OutputDebugStringA(debugMsg);

        

        // Force resync si nécessaire

        windowList.clear();

        SendMessageA(hList, LB_RESETCONTENT, 0, 0);

        EnumWindows(EnumWindowsProc, (LPARAM)hList);

    }

    

    // 3. ✅ TRI ALPHABÉTIQUE (UX améliorée)

    std::sort(windowList.begin(), windowList.end(),

             [](const WindowInfo& a, const WindowInfo& b) {

        return _stricmp(a.title.c_str(), b.title.c_str()) < 0;

    });

    

    // 4. Re-remplissage TRIÉ

    SendMessageA(hList, LB_RESETCONTENT, 0, 0);

    for (const auto& info : windowList) {

        RECT rect = info.rect;

        bool isProtected = protectedWindows.count(info.hwnd) > 0;

        std::string prefix = isProtected ? "[PROTECTED] " : "[AVAILABLE] ";

        

        int w = rect.right - rect.left;

        int h = rect.bottom - rect.top;

        char buf[1024];

        sprintf_s(buf, sizeof(buf), "%s%s (%dx%d) [0x%p]",

                 prefix.c_str(), info.title.c_str(), w, h, (void*)info.hwnd);

        SendMessageA(hList, LB_ADDSTRING, 0, (LPARAM)buf);

    }

    

    // ✅ Sélectionne première fenêtre (UX)

    if (SendMessageA(hList, LB_GETCOUNT, 0, 0) > 0) {

        SendMessageA(hList, LB_SETCURSEL, 0, 0);

    }

    

    // Debug UNIQUEMENT si 0 fenêtre (problème)

    static bool debugShown = false;

    if (windowList.empty() && !debugShown) {

        OutputDebugStringA("WARNING: No windows found - normal if no apps open\r\n");

        debugShown = true;

    }

}


// Unprotect all

void UnprotectAll() {

    std::vector<HWND> toUnprotect;

    // 1. Collecte SÉCURISÉE (map intacte)

    for (const auto& pair : protectedWindows) {

        toUnprotect.push_back(pair.first);

    }

    // 2. Désactivation

    for (HWND hwnd : toUnprotect) {

        UnprotectWindow(hwnd);

    }

    // 3. Nettoyage FINAL

    protectedWindows.clear();

}


// TIMER pour cacher l'icône tray après restauration

void CALLBACK HideTrayTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {

    if (idEvent == TIMER_HIDE_TRAY) {

        KillTimer(hwnd, TIMER_HIDE_TRAY);

        Shell_NotifyIconA(NIM_DELETE, &nid);

    }

}


// Resize controls responsively

void ResizeControls(HWND hwnd) {

    RECT rcClient;

    if (!GetClientRect(hwnd, &rcClient)) return;

    

    int clientW = rcClient.right - rcClient.left;

    int clientH = rcClient.bottom - rcClient.top;

    

    int dpi = GetDpiForWindowOrSystem(hwnd);

    int padding = ScaleDpi(12, dpi);

    int buttonHeight = ScaleDpi(36, dpi);

    int buttonAreaHeight = ScaleDpi(80, dpi);

    int listTop = ScaleDpi(35, dpi);

    

    // ✅ DYNAMIQUE : compte les contrôles existants

    HWND buttons[] = {hProtectBtn, hUnprotectBtn, hRefreshBtn, hTrayBtn, hExitBtn};

    int btnCount = 0;

    for (int i = 0; i < 5; i++) {

        if (IsWindow(buttons[i])) btnCount++;

    }

    

    if (btnCount == 0) return; // Sécurité

    

    int btnWidth = (clientW - (padding * (btnCount + 1))) / btnCount;

    if (btnWidth < ScaleDpi(80, dpi)) btnWidth = ScaleDpi(80, dpi); // Minimum

    

    // ✅ LABEL - responsive + centré verticalement

    if (IsWindow(hStaticLabel)) {

        int labelHeight = ScaleDpi(24, dpi);

        SetWindowPos(hStaticLabel, NULL,

                    padding, padding,

                    clientW - 2 * padding, labelHeight,

                    SWP_NOZORDER | SWP_NOACTIVATE);

    }

    

    // ✅ LISTBOX - maximise l'espace disponible

    if (IsWindow(hListCtrl)) {

        int listHeight = clientH - listTop - buttonAreaHeight - padding;

        if (listHeight > ScaleDpi(100, dpi)) { // Hauteur minimum

            SetWindowPos(hListCtrl, NULL,

                        padding, listTop,

                        clientW - 2 * padding, listHeight,

                        SWP_NOZORDER | SWP_NOACTIVATE);

        }

    }

    

    // ✅ BOUTONS - alignement parfait + dynamique

    if (btnCount > 0) {

        int btnTop = clientH - buttonAreaHeight + ScaleDpi(10, dpi);

        

        int currentX = padding;

        for (int i = 0; i < 5; i++) {

            if (IsWindow(buttons[i])) {

                SetWindowPos(buttons[i], NULL,

                           currentX, btnTop,

                           btnWidth, buttonHeight,

                           SWP_NOZORDER | SWP_NOACTIVATE);

                currentX += btnWidth + padding;

            }

        }

    }

    

    // ✅ Force refresh visuel

    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);

}


// Main window procedure

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    switch (msg) {

        case WM_CREATE: {

            int dpi = GetDpiForWindowOrSystem(NULL);

          

            // Create modern font

            int fontSize = ScaleDpi(10, dpi);

            hFont = CreateFontA(-fontSize, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,

                               ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                               DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI");

          

            // Labels

            hStaticLabel = CreateWindowA("STATIC", "Available Windows:",

                WS_VISIBLE | WS_CHILD | SS_LEFT,

                0, 0, 0, 0, hwnd, NULL, NULL, NULL);

          

            // ✅ LISTBOX CORRIGÉE - SUPPRESSION LBS_OWNERDRAWFIXED

            hListCtrl = CreateWindowA("LISTBOX", NULL,

                WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_NOTIFY | LBS_HASSTRINGS,

                0, 0, 0, 0, hwnd, (HMENU)ID_LIST, NULL, NULL);


            // Buttons with modern spacing

            hProtectBtn = CreateWindowA("BUTTON", "Protect (Enter)",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_PROTECT, NULL, NULL);

          

            hUnprotectBtn = CreateWindowA("BUTTON", "Unprotect All",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_UNPROTECT, NULL, NULL);

          

            hRefreshBtn = CreateWindowA("BUTTON", "Refresh (F5)",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_REFRESH, NULL, NULL);

          

            hTrayBtn = CreateWindowA("BUTTON", "Hide/Show (Esc)",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_TRAY, NULL, NULL);

          

            hExitBtn = CreateWindowA("BUTTON", "Quitter",

                WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,

                0, 0, 0, 0, hwnd, (HMENU)ID_EXIT, NULL, NULL);


            // Apply font to all controls

            HWND controls[] = {hStaticLabel, hListCtrl, hProtectBtn, hUnprotectBtn,

                             hRefreshBtn, hTrayBtn, hExitBtn};

            for (int i = 0; i < 7; i++) {

                if (controls[i]) {

                    SendMessageA(controls[i], WM_SETFONT, (WPARAM)hFont, TRUE);

                }

            }

          

            // ✅ RAFRAÎCHISSEMENT APRÈS CRÉATION DES CONTRÔLES

            ResizeControls(hwnd);

            RefreshWindowList(hListCtrl);

            break;

        }


        case WM_SIZE: {

            ResizeControls(hwnd);

            break;

        }


        case WM_GETMINMAXINFO: {

            LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam;

            int dpi = GetDpiForWindowOrSystem(hwnd);

            pMMI->ptMinTrackSize.x = ScaleDpi(480, dpi);

            pMMI->ptMinTrackSize.y = ScaleDpi(320, dpi);

            return 0;

        }


        case WM_COMMAND: {

            int index = (int)SendMessageA(hListCtrl, LB_GETCURSEL, 0, 0);


            WORD wNotifyCode = HIWORD(wParam);

            WORD wID = LOWORD(wParam);


            // ✅ DOUBLE-CLIC SUR LISTBOX

            if (wID == ID_LIST && wNotifyCode == LBN_DBLCLK) {

                if (index >= 0 && index < (int)windowList.size()) {

                    ProtectWindow(windowList[index].hwnd);

                    RefreshWindowList(hListCtrl);

                }

                break;

            }


            switch (wID) {

                case ID_PROTECT:

                    if (index >= 0 && index < (int)windowList.size()) {

                        ProtectWindow(windowList[index].hwnd);

                        RefreshWindowList(hListCtrl);

                    }

                    break;


                case ID_UNPROTECT:

                    UnprotectAll();

                    RefreshWindowList(hListCtrl);

                    MessageBoxA(hwnd, "All windows unprotected!", "Privacy Shield", MB_OK | MB_ICONINFORMATION);

                    break;


                case ID_REFRESH:

                    RefreshWindowList(hListCtrl);

                    break;


                case ID_TRAY:

    if (windowVisible) {

        // ✅ MINIMISER au lieu de cacher (garde taskbar)

        ShowWindow(hwnd, SW_MINIMIZE);

        isTrayOnly = true;

        windowVisible = false;

    } else {

        // Restaurer depuis minimisé

        ShowWindow(hwnd, SW_RESTORE);

        SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);

        SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

        SetForegroundWindow(hwnd);

        BringWindowToTop(hwnd);

        isTrayOnly = false;

        windowVisible = true;

        SetTimer(hwnd, TIMER_HIDE_TRAY, 500, HideTrayTimerProc);

    }

    break;


                case ID_EXIT: {

                    UnprotectAll();

                    Shell_NotifyIconA(NIM_DELETE, &nid);

                    UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

                    PostQuitMessage(0);

                    break;

                }

            }

            break;

        }


        case WM_SYSCOMMAND:

            if (wParam == SC_CLOSE) {

        ShowWindow(hwnd, SW_MINIMIZE);  // ✅ MINIMISER au lieu de SW_HIDE

        return 0;

    }

            break;


        case WM_DESTROY:

            UnprotectAll();

            Shell_NotifyIconA(NIM_DELETE, &nid);

            UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

            if (hAccelerator) DestroyAcceleratorTable(hAccelerator);

            if (hFont) DeleteObject(hFont);

            PostQuitMessage(0);

            return 0;

    

        case WM_HOTKEY:

            if (wParam == HOTKEY_QUIT_ID) {

                UnprotectAll();

                Shell_NotifyIconA(NIM_DELETE, &nid);

                UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

                PostQuitMessage(0);

            }

            break;

    } // fin de switch (msg)

    return DefWindowProcA(hwnd, msg, wParam, lParam);

}


// ✅ TRAY WINDOW CORRIGÉE

LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_TRAY_MSG: {
            // Vérifier que lParam contient l'événement souris et que hMainWnd est valide
            UINT trayEvent = (UINT)lParam;
            if (trayEvent == WM_LBUTTONDBLCLK && IsWindow(hMainWnd)) {
                // Restaurer et activer la fenêtre principale
                ShowWindow(hMainWnd, SW_RESTORE);
                SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0,
                             SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
                SetWindowPos(hMainWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
                             SWP_NOMOVE | SWP_NOSIZE);
                SetForegroundWindow(hMainWnd);
                BringWindowToTop(hMainWnd);
                isTrayOnly = false;

                // Timer différé pour supprimer l'icône tray (sécurisé)
                if (IsWindow(hMainWnd)) {
                    // Utiliser le timer sur la fenêtre principale pour éviter double exécution
                    SetTimer(hMainWnd, TIMER_HIDE_TRAY, 500, HideTrayTimerProc);
                }
            }
            break;
        }

        case WM_TIMER: {
            if (wParam == TIMER_HIDE_TRAY) {
                // Le timer peut provenir de hMainWnd ou de hwnd : tenter d'arrêter proprement
                KillTimer(hwnd, TIMER_HIDE_TRAY);
                KillTimer(hMainWnd, TIMER_HIDE_TRAY);
                // Supprimer l'icône si nid est valide et la fenêtre tray existe
                if (nid.cbSize && IsWindow(hwnd)) {
                    Shell_NotifyIconA(NIM_DELETE, &nid);
                } else if (nid.cbSize && IsWindow(hMainWnd)) {
                    // cas où le timer était sur hMainWnd
                    Shell_NotifyIconA(NIM_DELETE, &nid);
                }
            }
            break;
        }

        case WM_DESTROY: {
            // Nettoyage : tuer timers et supprimer l'icône si présente
            KillTimer(hwnd, TIMER_HIDE_TRAY);
            KillTimer(hMainWnd, TIMER_HIDE_TRAY);
            if (nid.cbSize) {
                Shell_NotifyIconA(NIM_DELETE, &nid);
            }
            PostQuitMessage(0);
            return 0;
        }

        default:
            break;
    }

    return DefWindowProcA(hwnd, msg, wParam, lParam);
}



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {

    // CACHER CONSOLE INSTANTANÉMENT

    HWND hConsole = GetConsoleWindow();

    if (hConsole != NULL) {

        ShowWindow(hConsole, SW_HIDE);

    }


    // DPI AWARENESS - runtime compatible Win7/8/10/11

    HMODULE hUser32 = GetModuleHandleA("user32.dll");

    if (hUser32) {

        typedef BOOL(WINAPI* SetProcessDpiAwarenessContext_t)(HANDLE);

        SetProcessDpiAwarenessContext_t pSetDpiCtx =

            (SetProcessDpiAwarenessContext_t)GetProcAddress(hUser32, "SetProcessDpiAwarenessContext");

        if (pSetDpiCtx) {

            pSetDpiCtx((HANDLE)(intptr_t)-4); // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2

        } else {

            typedef BOOL(WINAPI* SetProcessDPIAware_t)(void);

            SetProcessDPIAware_t pSetProcessDPIAware =

                (SetProcessDPIAware_t)GetProcAddress(hUser32, "SetProcessDPIAware");

            if (pSetProcessDPIAware) {

                pSetProcessDPIAware();

            }

        }

    }


    INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES };

    InitCommonControlsEx(&icex);


    // ACCELERATORS (Enter, F5, Escape)

    ACCEL accels[3] = {

        {0, VK_RETURN, ID_PROTECT},

        {FVIRTKEY, VK_F5, ID_REFRESH},

        {0, VK_ESCAPE, ID_TRAY}

    };

    hAccelerator = CreateAcceleratorTableA(accels, 3);


    // Main window class

    WNDCLASSEXA wcMain = { 0 };

    wcMain.cbSize = sizeof(wcMain);

    wcMain.lpfnWndProc = MainWndProc;

    wcMain.hInstance = hInstance;

    wcMain.lpszClassName = "PrivacyShieldFixedMain_v2";

    wcMain.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    wcMain.hCursor = LoadCursor(NULL, IDC_ARROW);

    wcMain.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wcMain.hIconSm = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 16, 16, 0);

    RegisterClassExA(&wcMain);


    // CALCUL TAILLE FENÊTRE DPI-AWARE + AdjustWindowRectEx

    int dpi = GetDpiForWindowOrSystem(NULL);

    int clientWidth = ScaleDpi(500, dpi);

    int clientHeight = ScaleDpi(380, dpi);

    RECT rcClient = { 0, 0, clientWidth, clientHeight };

    DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;

    AdjustWindowRectEx(&rcClient, dwStyle, FALSE, 0);

    int windowWidth = rcClient.right - rcClient.left;

    int windowHeight = rcClient.bottom - rcClient.top;


    hMainWnd = CreateWindowExA(

        WS_EX_CONTROLPARENT | WS_EX_APPWINDOW,

        wcMain.lpszClassName,

        "Privacy Shield v2 - Modern UI",

        dwStyle,

        CW_USEDEFAULT, CW_USEDEFAULT,

        windowWidth, windowHeight,

        NULL, NULL, hInstance, NULL);

    windowVisible = true;


    // TRAY WINDOW - VERSION ULTRA-SÉCURISÉE

    WNDCLASSEXA wcTray = { 0 };

    wcTray.cbSize = sizeof(wcTray);

    wcTray.lpfnWndProc = TrayWndProc;

    wcTray.hInstance = hInstance;

    wcTray.lpszClassName = "PrivacyShieldTray_v2";

    wcTray.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    wcTray.hCursor = LoadCursor(NULL, IDC_ARROW);

    wcTray.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassExA(&wcTray); // ENREGISTREMENT AVANT CreateWindowExA


    hTrayWnd = CreateWindowExA(

        WS_EX_TOOLWINDOW,    // TOOLWINDOW (pas dans taskbar)

        wcTray.lpszClassName,

        NULL,

        WS_OVERLAPPED,       // WS_OVERLAPPED obligatoire

        -2000, -2000,        // position hors écran sûre

        1, 1,                // 1x1 (pas 0x0)

        NULL, NULL, hInstance, NULL);


    // VÉRIFICATION CRITIQUE + LOG

    if (!hTrayWnd) {

        DWORD error = GetLastError();

        char buf[256];

        sprintf_s(buf, sizeof(buf), "CRITICAL: CreateWindowExA(hTrayWnd) FAILED! Error: %lu\r\n", error);

        OutputDebugStringA(buf);

        MessageBoxA(NULL, buf, "Privacy Shield - FATAL ERROR", MB_OK | MB_ICONERROR);

        return -1;

    }


    // AFFICHAGE SANS FOCUS (requis pour Shell_NotifyIcon)

    ShowWindow(hTrayWnd, SW_SHOWNA); // SW_SHOWNA = show without activation

    UpdateWindow(hTrayWnd);


    // Montrer la fenêtre principale

    ShowWindow(hMainWnd, nCmdShow);

    UpdateWindow(hMainWnd);


    // Tray icon avec tooltip moderne

    nid.cbSize = sizeof(nid);

    nid.hWnd = hTrayWnd;

    nid.uID = 1;

    nid.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON;

    nid.uCallbackMessage = WM_TRAY_MSG;

    nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    strcpy_s(nid.szTip, sizeof(nid.szTip), "Privacy Shield v2 - Double-click to protect windows");

    Shell_NotifyIconA(NIM_ADD, &nid);


    // HOTKEY APRÈS CRÉATION DES FENÊTRES

    if (!RegisterHotKey(NULL, HOTKEY_QUIT_ID, MOD_CONTROL | MOD_SHIFT, 'Q')) {

        MessageBoxA(NULL, "Failed to register hotkey Ctrl+Shift+Q!", "Privacy Shield", MB_OK | MB_ICONWARNING);

    }
    

    // Message loop avec accélérateurs

    MSG msg;

    while (GetMessageA(&msg, NULL, 0, 0)) {

        if (IsWindow(hMainWnd) && !TranslateAcceleratorA(hMainWnd, hAccelerator, &msg)) {

            TranslateMessage(&msg);

            DispatchMessageA(&msg);

        }

    }


    // CLEANUP FINAL

    UnprotectAll();

    if (nid.cbSize) {

        Shell_NotifyIconA(NIM_DELETE, &nid);

    }

    UnregisterHotKey(NULL, HOTKEY_QUIT_ID);

    if (hAccelerator) DestroyAcceleratorTable(hAccelerator);

    if (hFont) DeleteObject(hFont);


    return 0;

}

Feel free to suggest improvements or new features—it's open source for that exact reason.
 
Joined
Jun 12, 2020
Messages
73
Reaction score
3
The new version of Privacy Shield represents a complete overhaul into an advanced task manager, transitioning from a basic ListBox to a sophisticated multi-column ListView that displays the status, title, dimensions of windows, and detailed process stats (name, RAM in MB, CPU percentage, threads). It implements a thread-safe caching system with mutexes for process information, a real-time search bar to filter by title/process, an icon-based toolbar, dynamic global statistics (top RAM/CPU) through timers, automatic protection for the five largest windows, detection of Windows dark mode, saving and restoring window position/size, an expanded DPI-aware UI, ScopedHandle for memory management, enhanced visual feedback, and optimal compatibility with Windows 7 to 11.

Update link
 
Last edited:
Joined
Jun 12, 2020
Messages
73
Reaction score
3
The new version of Privacy Shield introduces a comprehensive system of customizable themes with three modes (light, dark, and custom) that dynamically apply colors to backgrounds, text, and buttons using custom brushes and dedicated WM_CTLCOLOR message handlers, with automatic detection of Windows' dark mode. It also includes low-level system hooks for enhanced protection, blocking PrintScreen keys, Alt+Tab and Alt+Escape combinations, disabling mouse clicks on hidden areas, and preventing screenshot attempts via WM_PRINT/WM_PRINTCLIENT on protected windows. Performance optimization is evident through a static cache for GetProcessMemoryInfo, avoiding repeated calls to GetProcAddress. The interface features an extended toolbar with buttons dedicated to themes and hooks, a statistics bar that updates in real-time displaying protection status, and increased robustness through thorough checks on control creation and fonts with secure fallbacks during the main window initialization.

New update link
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,470
Messages
2,571,807
Members
48,797
Latest member
PeterSimpson
Top