How to solve this redundant drawing issue for window splitter?

Luigi Tofano 20 Reputation points
2025-05-09T23:20:43.27+00:00
    // Win32-Desktop-Tab-Overlay-Splitter-RichEdit.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include <commctrl.h>
#include <iostream>
#include "resource.h"
#pragma comment(lib, "comctl32.lib")
#define ID_TABCTRL 100
#define ID_SPLITTER 101
#define MAX_LOADSTRING 100
HINSTANCE hInst;
HWND hWnd;
RECT hWnd_Rect;
HWND hwndTabMain;
HWND hwndDrawArea;
HWND hwndOverlay;
HWND hSplitter;
HWND hRichEdit;
int splitterPos = 200; // Initial splitter position
static WNDPROC OldSplitterProc;
static bool isDragging = false;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
ATOM                RegisterWindowClasses(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK    SplitterProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
void AllocateConsole();
void UpdateOverlayPosition(HWND hWnd, HWND hwndTabMain, HWND hwndOverlay);
void AllocateConsole() {
    AllocConsole();
    FILE* fpOut;
    freopen_s(&fpOut, "CONOUT$", "w", stdout);
    FILE* fpIn;
    freopen_s(&fpIn, "CONIN$", "r", stdin);
    FILE* fpErr;
    freopen_s(&fpErr, "CONOUT$", "w", stderr);
    std::cout << "Console window initialized successfully!" << std::endl;
}
LRESULT CALLBACK DrawAreaProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rect;
        GetClientRect(hwnd, &rect);
        HBRUSH whiteBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
        FillRect(hdc, &rect, whiteBrush);
        HPEN blackPen = (HPEN)GetStockObject(BLACK_PEN);
        HPEN oldPen = (HPEN)SelectObject(hdc, blackPen);
        MoveToEx(hdc, 0, 0, NULL);
        LineTo(hdc, rect.right, rect.bottom);
        SelectObject(hdc, oldPen);
        EndPaint(hwnd, &ps);
        return 0;
    }
    case WM_LBUTTONDOWN: {
        int x = LOWORD(lParam);
        int y = HIWORD(lParam);
        std::cout << "DrawArea Left Click at: (" << x << ", " << y << ")" << std::endl;
        return 0;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK OverlayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rect;
        GetClientRect(hwnd, &rect);
        HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
        HPEN oldPen = (HPEN)SelectObject(hdc, redPen);
        MoveToEx(hdc, rect.left, rect.top, NULL);
        LineTo(hdc, rect.right, rect.bottom);
        MoveToEx(hdc, rect.right, rect.top, NULL);
        LineTo(hdc, rect.left, rect.bottom);
        MoveToEx(hdc, rect.left, rect.top, NULL);
        LineTo(hdc, rect.right, rect.top);
        MoveToEx(hdc, rect.right, rect.top, NULL);
        LineTo(hdc, rect.right, rect.bottom);
        MoveToEx(hdc, rect.right, rect.bottom, NULL);
        LineTo(hdc, rect.left, rect.bottom);
        MoveToEx(hdc, rect.left, rect.bottom, NULL);
        LineTo(hdc, rect.left, rect.top);
        SelectObject(hdc, oldPen);
        DeleteObject(redPen);
        EndPaint(hwnd, &ps);
        std::cout << "OverlayProc: WM_PAINT completed" << std::endl;
        return 0;
    }
    case WM_LBUTTONDOWN: {
        int x = LOWORD(lParam);
        int y = HIWORD(lParam);
        std::cout << "Overlay Left Click at: (" << x << ", " << y << ")" << std::endl;
        POINT pt = { x, y };
        ClientToScreen(hwnd, &pt);
        ScreenToClient(hwndDrawArea, &pt);
        pt.x -= 4;
        pt.y -= 4;
        if (pt.x < 0) pt.x = 0;
        if (pt.y < 0) pt.y = 0;
        std::cout << "Forwarding click to DrawArea at: (" << pt.x << ", " << pt.y << ")" << std::endl;
        SendMessage(hwndDrawArea, WM_LBUTTONDOWN, wParam, MAKELPARAM(pt.x, pt.y));
        return 0;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK SplitterProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_LBUTTONDOWN:
        SetCapture(hWnd);
        isDragging = true;
        return 0;
    case WM_MOUSEMOVE:
        if (isDragging) {
            POINT pt;
            GetCursorPos(&pt);
            ScreenToClient(GetParent(hWnd), &pt);
            int newSplitterPos = pt.y;
            RECT rect;
            GetClientRect(GetParent(hWnd), &rect);
            if (newSplitterPos < 100) newSplitterPos = 100;
            if (newSplitterPos > rect.bottom - 100) newSplitterPos = rect.bottom - 100;
            MoveWindow(hwndTabMain, 0, 0, rect.right, newSplitterPos, TRUE);
            MoveWindow(hSplitter, 0, newSplitterPos, rect.right, 5, TRUE);
            MoveWindow(hRichEdit, 0, newSplitterPos + 5, rect.right, rect.bottom - newSplitterPos - 5, TRUE);
            RECT displayRect1 = { 0, 0, rect.right, newSplitterPos };
            TabCtrl_AdjustRect(hwndTabMain, FALSE, &displayRect1);
            MoveWindow(hwndDrawArea, displayRect1.left, displayRect1.top,
                displayRect1.right - displayRect1.left, displayRect1.bottom - displayRect1.top, TRUE);
            UpdateOverlayPosition(GetParent(hWnd), hwndTabMain, hwndOverlay);
            splitterPos = newSplitterPos;
            // Invalidate draw area and overlay to force repaint
            InvalidateRect(hwndDrawArea, NULL, TRUE);
            InvalidateRect(hwndOverlay, NULL, TRUE);
        }
        return 0;
    case WM_LBUTTONUP:
        ReleaseCapture();
        isDragging = false;
        return 0;
    case WM_SETCURSOR:
        SetCursor(LoadCursor(NULL, IDC_SIZENS));
        return TRUE;
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        RECT rc;
        GetClientRect(hWnd, &rc);
        FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
        EndPaint(hWnd, &ps);
        return 0;
    }
    }
    return CallWindowProc(OldSplitterProc, hWnd, msg, wParam, lParam);
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WIN32DESKTOPSPLITTERTABRICHEDITOVERLAYMOUSECLICKS, szWindowClass, MAX_LOADSTRING);
    RegisterWindowClasses(hInstance);
    AllocateConsole();
    if (!InitInstance(hInstance, nCmdShow))
    {
        return FALSE;
    }
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32DESKTOPSPLITTERTABRICHEDITOVERLAYMOUSECLICKS));
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}
ATOM RegisterWindowClasses(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDC_WIN32DESKTOPSPLITTERTABRICHEDITOVERLAYMOUSECLICKS));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32DESKTOPSPLITTERTABRICHEDITOVERLAYMOUSECLICKS);
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    RegisterClassExW(&wcex);
    WNDCLASS wcDrawingArea = { 0 };
    wcDrawingArea.lpfnWndProc = DrawAreaProc;
    wcDrawingArea.hInstance = hInstance;
    wcDrawingArea.lpszClassName = L"DrawArea";
    RegisterClass(&wcDrawingArea);
    WNDCLASSEX wcOverlay = { 0 };
    wcOverlay.cbSize = sizeof(WNDCLASSEX);
    wcOverlay.lpfnWndProc = OverlayProc;
    wcOverlay.hInstance = hInstance;
    wcOverlay.lpszClassName = L"OverlayWindow";
    wcOverlay.hbrBackground = NULL;
    wcOverlay.style = CS_HREDRAW | CS_VREDRAW;
    wcOverlay.hCursor = LoadCursor(nullptr, IDC_ARROW);
    return RegisterClassEx(&wcOverlay);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance;
    hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    if (!hWnd)
    {
        return FALSE;
    }
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    GetWindowRect(hWnd, &hWnd_Rect);
    std::cout << "Main Window Initial Position and Size:" << std::endl;
    std::cout << "Left: " << hWnd_Rect.left << ", Top: " << hWnd_Rect.top << std::endl;
    std::cout << "Right: " << hWnd_Rect.right << ", Bottom: " << hWnd_Rect.bottom << std::endl;
    std::cout << "Width: " << (hWnd_Rect.right - hWnd_Rect.left) << ", Height: " << (hWnd_Rect.bottom - hWnd_Rect.top) << std::endl;
    return TRUE;
}
void UpdateOverlayPosition(HWND hWnd, HWND hwndTabMain, HWND hwndOverlay) {
    // Get tab control dimensions
    RECT tabWindowRect;
    GetWindowRect(hwndTabMain, &tabWindowRect);
    RECT tabItemRect;
    SendMessage(hwndTabMain, TCM_GETITEMRECT, 0, (LPARAM)&tabItemRect);
    int tabHeight = tabItemRect.bottom - tabItemRect.top;
    RECT tabClientRect;
    GetClientRect(hwndTabMain, &tabClientRect);
    POINT clientTL = { tabClientRect.left, tabClientRect.top };
    ClientToScreen(hwndTabMain, &clientTL);
    int borderTop = clientTL.y - tabWindowRect.top;
    RECT tabRectSC = tabWindowRect;
    tabRectSC.top += tabHeight + borderTop;
    int overlayWidth = tabRectSC.right - tabRectSC.left;
    int overlayHeight = tabRectSC.bottom - tabRectSC.top;
    // Reposition the overlay window
    SetWindowPos(hwndOverlay, HWND_TOP, tabRectSC.left, tabRectSC.top, overlayWidth, overlayHeight, SWP_NOACTIVATE | SWP_SHOWWINDOW);
    // Prepare device contexts
    HDC hdcScreen = GetDC(NULL);
    HDC hdcMem = CreateCompatibleDC(hdcScreen);
    // Create a 32-bit bitmap with alpha channel
    BITMAPINFO bmi = { 0 };
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = overlayWidth;
    bmi.bmiHeader.biHeight = -overlayHeight; // Top-down bitmap
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32; // 32-bit for ARGB
    bmi.bmiHeader.biCompression = BI_RGB;
    void* pBits;
    HBITMAP hbmMem = CreateDIBSection(hdcScreen, &bmi, DIB_RGB_COLORS, &pBits, NULL, 0);
    if (!hbmMem) {
        ReleaseDC(NULL, hdcScreen);
        DeleteDC(hdcMem);
        return;
    }
    SelectObject(hdcMem, hbmMem);
    // Cast pBits to access pixel data (ARGB format: AABBGGRR)
    DWORD* pixels = (DWORD*)pBits;
    for (int y = 0; y < overlayHeight; y++) {
        for (int x = 0; x < overlayWidth; x++) {
            pixels[y * overlayWidth + x] = 0x00000000; // Fully transparent (A=0, RGB=0)
        }
    }
    // Draw the red 'X' with alpha = 255
    HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
    HPEN oldPen = (HPEN)SelectObject(hdcMem, redPen);
    MoveToEx(hdcMem, 0, 0, NULL);
    LineTo(hdcMem, overlayWidth - 1, overlayHeight - 1);
    MoveToEx(hdcMem, overlayWidth - 1, 0, NULL);
    LineTo(hdcMem, 0, overlayHeight - 1);
    SelectObject(hdcMem, oldPen);
    DeleteObject(redPen);
    // Ensure drawn pixels have alpha = 255 (optional, GDI might handle this)
    // This step can be skipped if GDI sets alpha correctly for drawn lines
    // For precision, you could use GetPixel/SetPixel or a scanline approach, but it's overkill here
    // Update the layered window
    BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; // Use per-pixel alpha
    POINT ptDst = { tabRectSC.left, tabRectSC.top };
    SIZE size = { overlayWidth, overlayHeight };
    POINT ptSrc = { 0, 0 };
    UpdateLayeredWindow(hwndOverlay, hdcScreen, &ptDst, &size, hdcMem, &ptSrc, 0, &bf, ULW_ALPHA);
    // Clean up
    DeleteObject(hbmMem);
    DeleteDC(hdcMem);
    ReleaseDC(NULL, hdcScreen);
    std::cout << "UpdateOverlayPosition: Left=" << tabRectSC.left << ", Top=" << tabRectSC.top
        << ", Width=" << overlayWidth << ", Height=" << overlayHeight << std::endl;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE: {
        INITCOMMONCONTROLSEX icex = { sizeof(INITCOMMONCONTROLSEX), ICC_TAB_CLASSES };
        InitCommonControlsEx(&icex);
        LoadLibrary(L"Msftedit.dll");
        RECT rect;
        GetClientRect(hWnd, &rect);
        int clientWidth = rect.right;
        int clientHeight = rect.bottom;
        if (clientHeight == 0) clientHeight = 1;
        splitterPos = clientHeight / 2;
        hwndTabMain = CreateWindowEx(0, WC_TABCONTROL, L"",
            WS_CHILD | WS_VISIBLE,
            0, 0, clientWidth, splitterPos, hWnd, (HMENU)ID_TABCTRL, hInst, NULL);
        TCITEM tcItem1 = { TCIF_TEXT, 0, 0, (LPWSTR)L"Tab 1" };
        TabCtrl_InsertItem(hwndTabMain, 0, &tcItem1);
        hSplitter = CreateWindowEx(0, L"STATIC", L"",
            WS_CHILD | WS_VISIBLE | SS_NOTIFY,
            0, splitterPos, clientWidth, 5, hWnd, (HMENU)ID_SPLITTER, hInst, NULL);
        hRichEdit = CreateWindowEx(0, L"RICHEDIT50W", L"",
            WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE,
            0, splitterPos + 5, clientWidth, clientHeight - splitterPos - 5, hWnd, NULL, hInst, NULL);
        hwndDrawArea = CreateWindowEx(0, L"DrawArea", L"",
            WS_CHILD | WS_VISIBLE,
            0, 0, 0, 0, hWnd, NULL, hInst, NULL);
        hwndOverlay = CreateWindowEx(
            WS_EX_LAYERED,
            L"OverlayWindow", L"",
            WS_POPUP | WS_VISIBLE,
            0, 0, 0, 0,
            hWnd,
            NULL,
            hInst,
            NULL
        );
        SetLayeredWindowAttributes(hwndOverlay, 0, 128, LWA_ALPHA);
        OldSplitterProc = (WNDPROC)SetWindowLongPtr(hSplitter, GWLP_WNDPROC, (LONG_PTR)SplitterProc);
        SendMessage(hWnd, WM_SIZE, 0, 0);
        return 0;
    }
    case WM_MOVE: {
        std::cout << "WndProc:WM_MOVE: Main window moved to (" << LOWORD(lParam) << ", " << HIWORD(lParam) << ")" << std::endl;
        UpdateOverlayPosition(hWnd, hwndTabMain, hwndOverlay);
        return 0;
    }
    case WM_SIZE: {
        std::cout << "WndProc:WM_SIZE:" << std::endl;
        RECT rect;
        GetClientRect(hWnd, &rect);
        int clientWidth = rect.right;
        int clientHeight = rect.bottom;
        if (splitterPos < 100) splitterPos = 100;
        if (splitterPos > clientHeight - 100) splitterPos = clientHeight - 100;
        MoveWindow(hwndTabMain, 0, 0, clientWidth, splitterPos, TRUE);
        MoveWindow(hSplitter, 0, splitterPos, clientWidth, 5, TRUE);
        MoveWindow(hRichEdit, 0, splitterPos + 5, clientWidth, clientHeight - splitterPos - 5, TRUE);
        RECT displayRect1 = { 0, 0, clientWidth, splitterPos };
        TabCtrl_AdjustRect(hwndTabMain, FALSE, &displayRect1);
        MoveWindow(hwndDrawArea, displayRect1.left, displayRect1.top,
            displayRect1.right - displayRect1.left, displayRect1.bottom - displayRect1.top, TRUE);
        UpdateOverlayPosition(hWnd, hwndTabMain, hwndOverlay);
        return 0;
    }
    case WM_COMMAND: {
        int wmId = LOWORD(wParam);
        switch (wmId) {
        case IDM_ABOUT:
            SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            SetWindowPos(hwndOverlay, hwndTabMain, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
            std::cout << "IDM_ABOUT: hwndOverlay restored above hwndTabMain" << std::endl;
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
                   break;
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
    }
                 break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

Screenshot 2025-05-09 160636

As the splitter is dragged downwards the 'X' in the upper window pane redraws however the it appears so far the old 'X' isn't cleared. I tried a few attempts at clearing it however I didn't find the correct way of doing so yet.

How can this redundant drawing issue be solved for such a window splitter?

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,932 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 89,221 Reputation points
    2025-05-10T08:40:20.1033333+00:00

    You don't clear the background

    You can add FillRect, like :

    LRESULT CALLBACK OverlayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
        switch (msg) {
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            RECT rect;
            GetClientRect(hwnd, &rect);
    
            HBRUSH hBrush = CreateSolidBrush(RGB(55, 55, 55));
            FillRect(hdc, &rect, hBrush);
            DeleteObject(hBrush);
    
            HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
            HPEN oldPen = (HPEN)SelectObject(hdc, redPen);
            MoveToEx(hdc, rect.left, rect.top, NULL);
            LineTo(hdc, rect.right, rect.bottom);
            MoveToEx(hdc, rect.right, rect.top, NULL);
            LineTo(hdc, rect.left, rect.bottom);
            MoveToEx(hdc, rect.left, rect.top, NULL);
            LineTo(hdc, rect.right, rect.top);
            MoveToEx(hdc, rect.right, rect.top, NULL);
            LineTo(hdc, rect.right, rect.bottom);
            MoveToEx(hdc, rect.right, rect.bottom, NULL);
            LineTo(hdc, rect.left, rect.bottom);
            MoveToEx(hdc, rect.left, rect.bottom, NULL);
            LineTo(hdc, rect.left, rect.top);
            SelectObject(hdc, oldPen);
            DeleteObject(redPen);
            EndPaint(hwnd, &ps);
            std::cout << "OverlayProc: WM_PAINT completed" << std::endl;
            return 0;
        }
        case WM_LBUTTONDOWN: {
            int x = LOWORD(lParam);
            int y = HIWORD(lParam);
            std::cout << "Overlay Left Click at: (" << x << ", " << y << ")" << std::endl;
            POINT pt = { x, y };
            ClientToScreen(hwnd, &pt);
            ScreenToClient(hwndDrawArea, &pt);
            pt.x -= 4;
            pt.y -= 4;
            if (pt.x < 0) pt.x = 0;
            if (pt.y < 0) pt.y = 0;
            std::cout << "Forwarding click to DrawArea at: (" << pt.x << ", " << pt.y << ")" << std::endl;
            SendMessage(hwndDrawArea, WM_LBUTTONDOWN, wParam, MAKELPARAM(pt.x, pt.y));
            return 0;
        }
    
        }
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    
    
    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.