Hello, I have been learning how to use the MS WinAPI, but their documentations is extremely vague in a lot of places, without information on the proper use of functions (PHP.NET manages this just fine!).

But anyhoo. When I handle the WM_DRAWITEM message, it SHOULD display an image on the buttons DC. However, it's just displaying a grey box and nothing else, the image is there. And it should load fine.

Just a note, in the WM_PAINT message, I draw a custom window frame (yet to be changed to allow for resizing, however, that's not the point. The point is that this image loads fine, and is in the same directory. And I use the same method for painting it onto the button as well).

I have checked that it is trying to do it. But creating a MessageBox() mid way through the WM_DRAWITEM (it did show up BTW) however, it is not beign drawn.

I do not want to use MFC or anything else like that.

Also, I have scoured the net, and found nothing decent that actually shows you a full example of how to properly use BS_OWNERDRAW and WM_DRAWITEM, with bitmap images.

Here is the code:

#include <Windows.h>
#include "defs.h"

static HWND X_BUTTON;
BOOL IS_HOVERING_HEADER = FALSE;
WNDPROC X_BUTTON_PROC;
static HWND MAIN_WINDOW;

int xSetButtonState(int state, LPDRAWITEMSTRUCT pdis) {
    HBITMAP xbmpSource;
    HDC hdcSource;
    HDC hdcDest;
    PAINTSTRUCT ps;

    hdcDest = BeginPaint(X_BUTTON, &ps); // Begin paint

    hdcSource = CreateCompatibleDC(GetDC(X_BUTTON));

    switch(state) {
        case ID_BUTTON_STATE_HOVER:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button_hover.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(pdis->hDC, 170, 5, 25, 19, hdcSource, 0, 0, SRCCOPY);
            break;
        case ID_BUTTON_STATE_NORMAL:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(pdis->hDC, 170, 5, 25, 19, hdcSource, 0, 0, SRCCOPY);
            break;
        default:
            return 0;
            break;
    }

    EndPaint(X_BUTTON, &ps);

    DeleteDC(hdcSource);
    DeleteDC(hdcDest);
    DeleteObject(xbmpSource);
}

LRESULT CALLBACK WinProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;
    switch(message) {
        case WM_MOUSEMOVE:
        {
            LPDRAWITEMSTRUCT pdis = (LPDRAWITEMSTRUCT) lParam;
            POINT p;
            GetCursorPos(&p);
            if(p.x > 170 && p.x < 195 && p.y > 5 && p.y < 24) {
                xSetButtonState(ID_BUTTON_STATE_HOVER, pdis);
            }
            break;
        }
        case WM_DRAWITEM:
        {
            LPDRAWITEMSTRUCT pdis = (LPDRAWITEMSTRUCT) lParam;
            if(pdis->hwndItem == X_BUTTON) {
                HDC hdcSource;
                HBITMAP xbmpSource;
                HDC hdcDest;

                hdcDest = BeginPaint(MAIN_WINDOW, &ps); // Begin paint

                hdcSource = CreateCompatibleDC(GetDC(0));

                xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
                SelectObject(hdcSource, xbmpSource);
                BitBlt(hdcDest, 170, 5, 25, 19, hdcSource, 0, 0, SRCERASE);

                EndPaint(MAIN_WINDOW, &ps); // End paint

                DeleteDC(hdcSource);
                DeleteDC(hdcDest);
                DeleteObject(xbmpSource);
            }
            break;
        }
        case WM_PAINT:
        {
            HBITMAP bmpSource;
            HDC hdcSource;
            HDC hdcDest;

            hdcDest = BeginPaint(MAIN_WINDOW, &ps); // Begin paint

            hdcSource = CreateCompatibleDC(GetDC(0));

            bmpSource = (HBITMAP)LoadImage(NULL, L"window.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, bmpSource);
            BitBlt(hdcDest, 0, 0, 200, 200, hdcSource, 0, 0, SRCCOPY);

            EndPaint(MAIN_WINDOW, &ps); // End paint

            DeleteDC(hdcDest);
            DeleteDC(hdcSource);
            DeleteObject(bmpSource);
            break;
        }
        case WM_CREATE:
        {
            X_BUTTON = CreateWindow(
                L"BUTTON",
                L"",
                BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
                170, 5,
                25, 19,
                hWindow,
                (HMENU) ID_X_BUTTON,
                (HINSTANCE) GetWindowLong(hWindow, GWL_HINSTANCE),
                NULL
            );
            break;
        }
        case WM_CLOSE:
            DestroyWindow(hWindow);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWindow, message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) {
    WNDCLASSEX window;
    MSG message;

    window.cbSize = sizeof(WNDCLASSEX);
    window.cbClsExtra = 0;
    window.cbWndExtra = 0;
    window.hInstance = hInstance;
    window.style = 0;
    window.lpszClassName = L"MAIN_CLASS";
    window.lpfnWndProc = WinProc;
    window.lpszMenuName = NULL;
    window.hbrBackground = (HBRUSH) TRANSPARENT;
    window.hCursor = LoadCursor(hInstance, IDC_ARROW);
    window.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    window.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    if(!RegisterClassEx(&window)) {
        MessageBox(NULL, L"Could not register window class!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    MAIN_WINDOW = CreateWindowEx(
        NULL,
        L"MAIN_CLASS",
        L"Styling",
        WS_POPUP | WS_VISIBLE | WS_SYSMENU,
        50, 50,
        200, 200,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if(MAIN_WINDOW == NULL) {
        MessageBox(NULL, L"Could not create window!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    ShowWindow(MAIN_WINDOW, nCmdShow);

    UpdateWindow(MAIN_WINDOW);

    while(GetMessage(&message, MAIN_WINDOW, 0, 0) > 0) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return (int) message.wParam;
}

Thanks!
Caelan.

Edited 3 Years Ago by Echo89

I have updated the code now, can a mod please state this in the first post! Thanks!

#include <Windows.h>
#include "defs.h"

static HWND X_BUTTON;
BOOL IS_HOVERING_HEADER = FALSE;
WNDPROC X_BUTTON_PROC;
static HWND MAIN_WINDOW;
RECT MAIN_WINDOW_CLIENT_RECT;
INT W = 800;
INT H = 400;

int xSetButtonState(int state) {
    HBITMAP xbmpSource;
    HDC hdcSource;
    HDC hdcDest;
    PAINTSTRUCT ps;

    hdcDest = BeginPaint(X_BUTTON, &ps); // Begin paint

    hdcSource = CreateCompatibleDC(NULL);

    switch(state) {
        case ID_BUTTON_STATE_HOVER:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button_hover.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, (W - 30), 5, 25, 19, hdcSource, 0, 0, SRCERASE);
            break;
        case ID_BUTTON_STATE_NORMAL:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, (W - 30), 5, 25, 19, hdcSource, 0, 0, SRCERASE);
            break;
        default:
            return 0;
            break;
    }

    EndPaint(X_BUTTON, &ps);

    DeleteDC(hdcSource);
    DeleteDC(hdcDest);
    DeleteObject(xbmpSource);
}

LRESULT CALLBACK xButtonProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_MOUSEHOVER:
        {
            xSetButtonState(ID_BUTTON_STATE_HOVER);
        }
        case WM_PAINT:
        {
            xSetButtonState(ID_BUTTON_STATE_NORMAL);
        }
        case WM_LBUTTONUP:
        {
            POINT p;
            GetCursorPos(&p);
            ScreenToClient(MAIN_WINDOW, &p);
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                DestroyWindow(MAIN_WINDOW);
            }
        }
        default:
        {
            return CallWindowProc(X_BUTTON_PROC, hWindow, message, wParam, lParam);
        }
    }
    return 0;
}

LRESULT CALLBACK WinProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;
    switch(message) {
        case WM_SIZE:
        {
            GetClientRect(MAIN_WINDOW, &MAIN_WINDOW_CLIENT_RECT);

            W = MAIN_WINDOW_CLIENT_RECT.right - MAIN_WINDOW_CLIENT_RECT.left;
            H = MAIN_WINDOW_CLIENT_RECT.bottom - MAIN_WINDOW_CLIENT_RECT.top;
        }
        case WM_PAINT:
        {
            W = 800;
            H = 400;
            HBITMAP bmpWindowTopLeft = (HBITMAP)LoadImage(NULL, L"window_top_left_129_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTopRight = (HBITMAP)LoadImage(NULL, L"window_top_right_34_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomLeft = (HBITMAP)LoadImage(NULL, L"window_bottom_left_40_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomRight = (HBITMAP)LoadImage(NULL, L"window_bottom_right_40_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowLeftCenter = (HBITMAP)LoadImage(NULL, L"window_left_center_40_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowRightCenter = (HBITMAP)LoadImage(NULL, L"window_right_center_40_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomCenter = (HBITMAP)LoadImage(NULL, L"window_bottom_center_1_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTopCenter = (HBITMAP)LoadImage(NULL, L"window_top_center_1_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowCenter = (HBITMAP)LoadImage(NULL, L"window_center_2_2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTitle = (HBITMAP)LoadImage(NULL, L"window_title.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

            HDC hdcSource;
            HDC hdcDest;

            hdcDest = BeginPaint(MAIN_WINDOW, &ps); // Begin paint

            hdcSource = CreateCompatibleDC(GetDC(0));

            SelectObject(hdcSource, bmpWindowTopLeft);
            BitBlt(hdcDest, 0, 0, 129, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowTopRight);
            BitBlt(hdcDest, (W - 34), 0, 34, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowTopCenter);
            StretchBlt(hdcDest, 129, 0, (W - 34) - 129, 40, hdcSource, 0, 0, 1, 40, SRCCOPY);

            SelectObject(hdcSource, bmpWindowBottomLeft);
            BitBlt(hdcDest, 0, (H - 40), 40, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowBottomRight);
            BitBlt(hdcDest, (W - 40), (H - 40), 40, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowBottomCenter);
            StretchBlt(hdcDest, 40, (H - 40), (W - 40) - 40, 40, hdcSource, 0, 0, 1, 40, SRCCOPY);

            SelectObject(hdcSource, bmpWindowLeftCenter);
            StretchBlt(hdcDest, 0, 40, 40, (H - 40) - 40, hdcSource, 0, 0, 40, 1, SRCCOPY);

            SelectObject(hdcSource, bmpWindowRightCenter);
            StretchBlt(hdcDest, (W - 40), 40, 40, (H - 40) - 40, hdcSource, 0, 0, 40, 1, SRCCOPY);

            SelectObject(hdcSource, bmpWindowCenter);
            StretchBlt(hdcDest, 40, 40, (W - 40) - 40, (H - 40) - 40, hdcSource, 0, 0, 2, 2, SRCCOPY);

            SelectObject(hdcSource, bmpWindowTitle);
            BitBlt(hdcDest, 5, 5, 102, 20, hdcSource, 0, 0, SRCCOPY);

            EndPaint(MAIN_WINDOW, &ps); // End paint

            DeleteDC(hdcDest);
            DeleteDC(hdcSource);
            DeleteObject(bmpWindowTopLeft);
            DeleteObject(bmpWindowTopRight);
            DeleteObject(bmpWindowBottomLeft);
            DeleteObject(bmpWindowBottomRight);
            DeleteObject(bmpWindowLeftCenter);
            DeleteObject(bmpWindowRightCenter);
            DeleteObject(bmpWindowBottomCenter);
            DeleteObject(bmpWindowTopCenter);
            DeleteObject(bmpWindowTopLeft);
            break;
        }
        case WM_CREATE:
        {
            X_BUTTON = CreateWindow(
                L"BUTTON",
                L"",
                WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
                (W - 30), 5,
                25, 19,
                hWindow,
                (HMENU) ID_X_BUTTON,
                NULL,
                NULL
            );

            X_BUTTON_PROC = (WNDPROC) SetWindowLong(X_BUTTON, GWL_WNDPROC, (LONG) xButtonProc);

            break;
        }
        case WM_CLOSE:
            DestroyWindow(hWindow);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWindow, message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) {
    WNDCLASSEX window;
    MSG message;

    window.cbSize = sizeof(WNDCLASSEX);
    window.cbClsExtra = 0;
    window.cbWndExtra = 0;
    window.hInstance = hInstance;
    window.style = 0;
    window.lpszClassName = L"MAIN_CLASS";
    window.lpfnWndProc = WinProc;
    window.lpszMenuName = NULL;
    window.hbrBackground = (HBRUSH) TRANSPARENT;
    window.hCursor = LoadCursor(hInstance, IDC_ARROW);
    window.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    window.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    if(!RegisterClassEx(&window)) {
        MessageBox(NULL, L"Could not register window class!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    MAIN_WINDOW = CreateWindowEx(
        NULL,
        L"MAIN_CLASS",
        L"Styling",
        WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_CLIPCHILDREN,
        50, 50,
        W, H,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if(MAIN_WINDOW == NULL) {
        MessageBox(NULL, L"Could not create window!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    ShowWindow(MAIN_WINDOW, nCmdShow);

    UpdateWindow(MAIN_WINDOW);

    while(GetMessage(&message, MAIN_WINDOW, 0, 0) > 0) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return (int) message.wParam;
}

However, it still does not paint the button with the bitmap image!

Here is a screenshot if it helps!

http://www.imghst.org/uploads/m2oyqxgxvrki.PNG

Notice the X button is just a grey square! It's really annoying!

OK, I have updated the code again, the button now displays, however, it does not change when I hover over it.

Also, the window does not move when I drag the top, even though I have implemented this function.

Any suggestions:

This is currently what it looks like:
http://www.imghst.org/uploads/mbi4q352dlj6.PNG

#include <Windows.h>
#include <windowsx.h>
#include "defs.h"

static HWND X_BUTTON;
INT IS_MOUSE_DOWN_HEADER = FALSE;
WNDPROC X_BUTTON_PROC;
static HWND MAIN_WINDOW;
RECT MAIN_WINDOW_CLIENT_RECT;
INT W = 800;
INT H = 400;
INT IS_HOVERERING_X = FALSE;
PAINTSTRUCT ps;

int xSetButtonState(int state) {
    HBITMAP xbmpSource;
    HDC hdcSource;
    HDC hdcDest;

    hdcDest = BeginPaint(X_BUTTON, &ps); // Begin paint

    hdcSource = CreateCompatibleDC(GetDC(0));

    switch(state) {
        case ID_BUTTON_STATE_HOVER:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button_hover.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, 0, 0, 25, 20, hdcSource, 0, 0, SRCCOPY);
            IS_HOVERERING_X = TRUE;
            break;
        case ID_BUTTON_STATE_NORMAL:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, 0, 0, 25, 20, hdcSource, 0, 0, SRCCOPY);
            IS_HOVERERING_X = FALSE;
            break;
        case ID_BUTTON_STATE_PRESSED:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button_pressed.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, 0, 0, 25, 20, hdcSource, 0, 0, SRCCOPY);
            IS_HOVERERING_X = TRUE;
        default:
            return -1;
            break;
    }

    EndPaint(X_BUTTON, &ps);

    DeleteDC(hdcSource);
    DeleteDC(hdcDest);
    DeleteObject(xbmpSource);
    return 0;
}

LRESULT CALLBACK xButtonProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    POINT p;
    GetCursorPos(&p);
    ScreenToClient(MAIN_WINDOW, &p);
    switch(message) {
        case WM_LBUTTONDOWN:
        {
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                xSetButtonState(ID_BUTTON_STATE_PRESSED);
            }
            break;
        }
        case WM_MOUSEMOVE:
        {
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                xSetButtonState(ID_BUTTON_STATE_HOVER);
            } else {
                IS_HOVERERING_X = FALSE;
            }
            break;
        }
        case WM_PAINT:
        {
            if(IS_HOVERERING_X == FALSE) {
                xSetButtonState(ID_BUTTON_STATE_NORMAL);
            }
            break;
        }
        case WM_LBUTTONUP:
        {
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                DestroyWindow(MAIN_WINDOW);
            }
            break;
        }
        default:
        {
            return CallWindowProc(X_BUTTON_PROC, hWindow, message, wParam, lParam);
        }
    }
    return 0;
}

LRESULT CALLBACK WinProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_MOUSEMOVE:
        {
            int x = GET_X_LPARAM(lParam);
            int y = GET_Y_LPARAM(lParam);

            if(x > 0 && x < (W - 32) && y > 0 && y < 28) {
                SetCursor(LoadCursor(NULL, IDC_SIZEALL));
                switch(wParam) {
                    case MK_LBUTTON:
                    {
                        POINT p_screen;
                        GetCursorPos(&p_screen);
                        MoveWindow(MAIN_WINDOW, p_screen.x - x, p_screen.y - y, W, H, FALSE);
                        break;
                    }
                }
            } else {
                SetCursor(LoadCursor(NULL, IDC_ARROW));
            }

            break;
        }
        case WM_SIZE:
        {
            GetClientRect(MAIN_WINDOW, &MAIN_WINDOW_CLIENT_RECT);

            W = MAIN_WINDOW_CLIENT_RECT.right - MAIN_WINDOW_CLIENT_RECT.left;
            H = MAIN_WINDOW_CLIENT_RECT.bottom - MAIN_WINDOW_CLIENT_RECT.top;
            break;
        }
        case WM_PAINT:
        {
            W = 800;
            H = 400;
            HBITMAP bmpWindowTopLeft = (HBITMAP)LoadImage(NULL, L"window_top_left_129_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTopRight = (HBITMAP)LoadImage(NULL, L"window_top_right_34_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomLeft = (HBITMAP)LoadImage(NULL, L"window_bottom_left_40_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomRight = (HBITMAP)LoadImage(NULL, L"window_bottom_right_40_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowLeftCenter = (HBITMAP)LoadImage(NULL, L"window_left_center_40_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowRightCenter = (HBITMAP)LoadImage(NULL, L"window_right_center_40_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomCenter = (HBITMAP)LoadImage(NULL, L"window_bottom_center_1_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTopCenter = (HBITMAP)LoadImage(NULL, L"window_top_center_1_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowCenter = (HBITMAP)LoadImage(NULL, L"window_center_2_2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTitle = (HBITMAP)LoadImage(NULL, L"window_title.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

            HDC hdcSource;
            HDC hdcDest;

            hdcDest = BeginPaint(MAIN_WINDOW, &ps); // Begin paint

            hdcSource = CreateCompatibleDC(GetDC(0));

            SelectObject(hdcSource, bmpWindowTopLeft);
            BitBlt(hdcDest, 0, 0, 129, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowTopRight);
            BitBlt(hdcDest, (W - 34), 0, 34, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowTopCenter);
            StretchBlt(hdcDest, 129, 0, (W - 34) - 129, 40, hdcSource, 0, 0, 1, 40, SRCCOPY);

            SelectObject(hdcSource, bmpWindowBottomLeft);
            BitBlt(hdcDest, 0, (H - 40), 40, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowBottomRight);
            BitBlt(hdcDest, (W - 40), (H - 40), 40, 40, hdcSource, 0, 0, SRCCOPY);

            SelectObject(hdcSource, bmpWindowBottomCenter);
            StretchBlt(hdcDest, 40, (H - 40), (W - 40) - 40, 40, hdcSource, 0, 0, 1, 40, SRCCOPY);

            SelectObject(hdcSource, bmpWindowLeftCenter);
            StretchBlt(hdcDest, 0, 40, 40, (H - 40) - 40, hdcSource, 0, 0, 40, 1, SRCCOPY);

            SelectObject(hdcSource, bmpWindowRightCenter);
            StretchBlt(hdcDest, (W - 40), 40, 40, (H - 40) - 40, hdcSource, 0, 0, 40, 1, SRCCOPY);

            SelectObject(hdcSource, bmpWindowCenter);
            StretchBlt(hdcDest, 40, 40, (W - 40) - 40, (H - 40) - 40, hdcSource, 0, 0, 2, 2, SRCCOPY);

            SelectObject(hdcSource, bmpWindowTitle);
            BitBlt(hdcDest, 5, 5, 102, 20, hdcSource, 0, 0, SRCCOPY);

            EndPaint(MAIN_WINDOW, &ps); // End paint

            DeleteDC(hdcDest);
            DeleteDC(hdcSource);
            DeleteObject(bmpWindowTopLeft);
            DeleteObject(bmpWindowTopRight);
            DeleteObject(bmpWindowBottomLeft);
            DeleteObject(bmpWindowBottomRight);
            DeleteObject(bmpWindowLeftCenter);
            DeleteObject(bmpWindowRightCenter);
            DeleteObject(bmpWindowBottomCenter);
            DeleteObject(bmpWindowTopCenter);
            DeleteObject(bmpWindowTopLeft);
            break;
        }
        case WM_CREATE:
        {
            X_BUTTON = CreateWindow(
                L"BUTTON",
                L"",
                WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
                (W - 30), 5,
                25, 19,
                hWindow,
                (HMENU) ID_X_BUTTON,
                NULL,
                NULL
            );

            X_BUTTON_PROC = (WNDPROC) SetWindowLong(X_BUTTON, GWL_WNDPROC, (LONG) xButtonProc);
            break;
        }
        case WM_CLOSE:
            DestroyWindow(MAIN_WINDOW);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWindow, message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) {
    WNDCLASSEX window;
    MSG message;

    window.cbSize = sizeof(WNDCLASSEX);
    window.cbClsExtra = 0;
    window.cbWndExtra = 0;
    window.hInstance = hInstance;
    window.style = 0;
    window.lpszClassName = L"MAIN_CLASS";
    window.lpfnWndProc = WinProc;
    window.lpszMenuName = NULL;
    window.hbrBackground = (HBRUSH) TRANSPARENT;
    window.hCursor = LoadCursor(hInstance, IDC_ARROW);
    window.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    window.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    if(!RegisterClassEx(&window)) {
        MessageBox(NULL, L"Could not register window class!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    MAIN_WINDOW = CreateWindowEx(
        NULL,
        L"MAIN_CLASS",
        L"STYLING",
        WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN,
        50, 50,
        W, H,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if(MAIN_WINDOW == NULL) {
        MessageBox(NULL, L"Could not create window!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    ShowWindow(MAIN_WINDOW, nCmdShow);

    UpdateWindow(MAIN_WINDOW);

    while(GetMessage(&message, MAIN_WINDOW, 0, 0) > 0) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return (int) message.wParam;
}

Thanks!

Pretty busy at the moment, but I will take a look later this evening to see if I can lend a hand. To sum up, and make sure I understand your problem:

  1. You're trying to override the system menu 'X'?
  2. You want a different image displayed on mouseover of that menu?

Is that correct?

Yes it is, I have gotten it to display the first image, but when I hover over x button I have made, the hover image does not show up, look at my third code update below, and see the code there.

#include <Windows.h>
#include <windowsx.h>
#include "defs.h"
static HWND X_BUTTON;
INT IS_MOUSE_DOWN_HEADER = FALSE;
WNDPROC X_BUTTON_PROC;
static HWND MAIN_WINDOW;
RECT MAIN_WINDOW_CLIENT_RECT;
INT W = 800;
INT H = 400;
INT IS_HOVERERING_X = FALSE;
PAINTSTRUCT ps;
int xSetButtonState(int state) {
    HBITMAP xbmpSource;
    HDC hdcSource;
    HDC hdcDest;
    hdcDest = BeginPaint(X_BUTTON, &ps); // Begin paint
    hdcSource = CreateCompatibleDC(GetDC(0));
    switch(state) {
        case ID_BUTTON_STATE_HOVER:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button_hover.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, 0, 0, 25, 20, hdcSource, 0, 0, SRCCOPY);
            IS_HOVERERING_X = TRUE;
            break;
        case ID_BUTTON_STATE_NORMAL:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, 0, 0, 25, 20, hdcSource, 0, 0, SRCCOPY);
            IS_HOVERERING_X = FALSE;
            break;
        case ID_BUTTON_STATE_PRESSED:
            xbmpSource = (HBITMAP)LoadImage(NULL, L"x_button_pressed.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            SelectObject(hdcSource, xbmpSource);
            BitBlt(hdcDest, 0, 0, 25, 20, hdcSource, 0, 0, SRCCOPY);
            IS_HOVERERING_X = TRUE;
        default:
            return -1;
            break;
    }
    EndPaint(X_BUTTON, &ps);
    DeleteDC(hdcSource);
    DeleteDC(hdcDest);
    DeleteObject(xbmpSource);
    return 0;
}
LRESULT CALLBACK xButtonProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    POINT p;
    GetCursorPos(&p);
    ScreenToClient(MAIN_WINDOW, &p);
    switch(message) {
        case WM_LBUTTONDOWN:
        {
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                xSetButtonState(ID_BUTTON_STATE_PRESSED);
            }
            break;
        }
        case WM_MOUSEMOVE:
        {
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                xSetButtonState(ID_BUTTON_STATE_HOVER);
            } else {
                IS_HOVERERING_X = FALSE;
            }
            break;
        }
        case WM_PAINT:
        {
            if(IS_HOVERERING_X == FALSE) {
                xSetButtonState(ID_BUTTON_STATE_NORMAL);
            }
            break;
        }
        case WM_LBUTTONUP:
        {
            if(p.x > (W - 30) && p.x < (W - 5) && p.y > 5 && p.y < 24) {
                DestroyWindow(MAIN_WINDOW);
            }
            break;
        }
        default:
        {
            return CallWindowProc(X_BUTTON_PROC, hWindow, message, wParam, lParam);
        }
    }
    return 0;
}
LRESULT CALLBACK WinProc(HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_MOUSEMOVE:
        {
            int x = GET_X_LPARAM(lParam);
            int y = GET_Y_LPARAM(lParam);
            if(x > 0 && x < (W - 32) && y > 0 && y < 28) {
                SetCursor(LoadCursor(NULL, IDC_SIZEALL));
                switch(wParam) {
                    case MK_LBUTTON:
                    {
                        POINT p_screen;
                        GetCursorPos(&p_screen);
                        MoveWindow(MAIN_WINDOW, p_screen.x - x, p_screen.y - y, W, H, FALSE);
                        break;
                    }
                }
            } else {
                SetCursor(LoadCursor(NULL, IDC_ARROW));
            }
            break;
        }
        case WM_SIZE:
        {
            GetClientRect(MAIN_WINDOW, &MAIN_WINDOW_CLIENT_RECT);
            W = MAIN_WINDOW_CLIENT_RECT.right - MAIN_WINDOW_CLIENT_RECT.left;
            H = MAIN_WINDOW_CLIENT_RECT.bottom - MAIN_WINDOW_CLIENT_RECT.top;
            break;
        }
        case WM_PAINT:
        {
            W = 800;
            H = 400;
            HBITMAP bmpWindowTopLeft = (HBITMAP)LoadImage(NULL, L"window_top_left_129_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTopRight = (HBITMAP)LoadImage(NULL, L"window_top_right_34_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomLeft = (HBITMAP)LoadImage(NULL, L"window_bottom_left_40_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomRight = (HBITMAP)LoadImage(NULL, L"window_bottom_right_40_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowLeftCenter = (HBITMAP)LoadImage(NULL, L"window_left_center_40_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowRightCenter = (HBITMAP)LoadImage(NULL, L"window_right_center_40_1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowBottomCenter = (HBITMAP)LoadImage(NULL, L"window_bottom_center_1_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTopCenter = (HBITMAP)LoadImage(NULL, L"window_top_center_1_40.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowCenter = (HBITMAP)LoadImage(NULL, L"window_center_2_2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HBITMAP bmpWindowTitle = (HBITMAP)LoadImage(NULL, L"window_title.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            HDC hdcSource;
            HDC hdcDest;
            hdcDest = BeginPaint(MAIN_WINDOW, &ps); // Begin paint
            hdcSource = CreateCompatibleDC(GetDC(0));
            SelectObject(hdcSource, bmpWindowTopLeft);
            BitBlt(hdcDest, 0, 0, 129, 40, hdcSource, 0, 0, SRCCOPY);
            SelectObject(hdcSource, bmpWindowTopRight);
            BitBlt(hdcDest, (W - 34), 0, 34, 40, hdcSource, 0, 0, SRCCOPY);
            SelectObject(hdcSource, bmpWindowTopCenter);
            StretchBlt(hdcDest, 129, 0, (W - 34) - 129, 40, hdcSource, 0, 0, 1, 40, SRCCOPY);
            SelectObject(hdcSource, bmpWindowBottomLeft);
            BitBlt(hdcDest, 0, (H - 40), 40, 40, hdcSource, 0, 0, SRCCOPY);
            SelectObject(hdcSource, bmpWindowBottomRight);
            BitBlt(hdcDest, (W - 40), (H - 40), 40, 40, hdcSource, 0, 0, SRCCOPY);
            SelectObject(hdcSource, bmpWindowBottomCenter);
            StretchBlt(hdcDest, 40, (H - 40), (W - 40) - 40, 40, hdcSource, 0, 0, 1, 40, SRCCOPY);
            SelectObject(hdcSource, bmpWindowLeftCenter);
            StretchBlt(hdcDest, 0, 40, 40, (H - 40) - 40, hdcSource, 0, 0, 40, 1, SRCCOPY);
            SelectObject(hdcSource, bmpWindowRightCenter);
            StretchBlt(hdcDest, (W - 40), 40, 40, (H - 40) - 40, hdcSource, 0, 0, 40, 1, SRCCOPY);
            SelectObject(hdcSource, bmpWindowCenter);
            StretchBlt(hdcDest, 40, 40, (W - 40) - 40, (H - 40) - 40, hdcSource, 0, 0, 2, 2, SRCCOPY);
            SelectObject(hdcSource, bmpWindowTitle);
            BitBlt(hdcDest, 5, 5, 102, 20, hdcSource, 0, 0, SRCCOPY);
            EndPaint(MAIN_WINDOW, &ps); // End paint
            DeleteDC(hdcDest);
            DeleteDC(hdcSource);
            DeleteObject(bmpWindowTopLeft);
            DeleteObject(bmpWindowTopRight);
            DeleteObject(bmpWindowBottomLeft);
            DeleteObject(bmpWindowBottomRight);
            DeleteObject(bmpWindowLeftCenter);
            DeleteObject(bmpWindowRightCenter);
            DeleteObject(bmpWindowBottomCenter);
            DeleteObject(bmpWindowTopCenter);
            DeleteObject(bmpWindowTopLeft);
            break;
        }
        case WM_CREATE:
        {
            X_BUTTON = CreateWindow(
                L"BUTTON",
                L"",
                WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
                (W - 30), 5,
                25, 19,
                hWindow,
                (HMENU) ID_X_BUTTON,
                NULL,
                NULL
            );
            X_BUTTON_PROC = (WNDPROC) SetWindowLong(X_BUTTON, GWL_WNDPROC, (LONG) xButtonProc);
            break;
        }
        case WM_CLOSE:
            DestroyWindow(MAIN_WINDOW);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWindow, message, wParam, lParam);
    }
    return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) {
    WNDCLASSEX window;
    MSG message;
    window.cbSize = sizeof(WNDCLASSEX);
    window.cbClsExtra = 0;
    window.cbWndExtra = 0;
    window.hInstance = hInstance;
    window.style = 0;
    window.lpszClassName = L"MAIN_CLASS";
    window.lpfnWndProc = WinProc;
    window.lpszMenuName = NULL;
    window.hbrBackground = (HBRUSH) TRANSPARENT;
    window.hCursor = LoadCursor(hInstance, IDC_ARROW);
    window.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    window.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
    if(!RegisterClassEx(&window)) {
        MessageBox(NULL, L"Could not register window class!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }
    MAIN_WINDOW = CreateWindowEx(
        NULL,
        L"MAIN_CLASS",
        L"STYLING",
        WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN,
        50, 50,
        W, H,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    if(MAIN_WINDOW == NULL) {
        MessageBox(NULL, L"Could not create window!", L"Error", MB_OK | MB_ICONERROR);
        return 0;
    }
    ShowWindow(MAIN_WINDOW, nCmdShow);
    UpdateWindow(MAIN_WINDOW);
    while(GetMessage(&message, MAIN_WINDOW, 0, 0) > 0) {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
    return (int) message.wParam;
}

Edited 3 Years Ago by Echo89

When debugging, does it actually get into the case for ID_BUTTON_STATE_HOVER? Haven't quite run across that definition before and wondering where it comes from, are you using a special library?

No, It is my own custom definition, so basically, I make a function that accepts an int value. So instead of using numbers I use a definition such as ID_BUTTON_STATE_HOVER as the number 1, ID_BUTTON_STATE_PRESSED as 2 AND ID_BUTTON_STATE_NORMAL as 0.

So it's easier to remember basically. But if you want the whole zip, I can upload one for you.

Could you please? I was searching everywhere for that, but obviously couldn't come up with anything. Does it make it to your case statement?

From just looking at the two images, there really isn't that much of a difference between the two, so is it possible that it "is" loading the image and it's just difficult to tell on your monitor? I had to look at it a couple of times just to make sure they were, in fact, different. Other than a "slightly" lighter shade, and maybe 2 pixel size difference, they're just about twins.

Maybe try a completely different image, just to be 100% sure it isn't loading...

No, I would see the difference, I tried changing it to a darker image, but I still could not see any difference at all.

And anyway, to me, there is quite a noticeable difference.

I noticed the difference as well, but thought I would just put the thought out there, just in case, especially since that's as far as I can go at the moment.

What version of VS did you use to make this solution? I've tried 2008, 2010 & 2012, but none are able to open it....

<EDIT>
Never mind, need to reinstall 2012...
</EDIT>

Edited 3 Years Ago by plenty.groover

From what I've seen, you're not verifying that the image is loaded successfully, which it isn't (as I'm sure you know). I believe you need to get a handle to the original bitmap and then delete it prior to "adding" another, otherwise it will continue to fail. Spare time is difficult for me with grandkids, but I'll do what I can to provide more help.

Hello echo,

I wrote here some notes I hope could help you decrypt your problem.

  1. If you want to create a subclassed button where you want to do the painting yourself through the new WNDPROC address you have given, you do not need to create an owner-drawn button.

  2. When responding to WM_PAINT message, it is always necessary to call the BeginPaint/EndPaint APIs to remove the message from the message queue but in your WM_PAINT label...

    case WM_PAINT:
    {
    if(IS_HOVERERING_X == FALSE) {
    xSetButtonState(ID_BUTTON_STATE_NORMAL);
    }
    break;
    }

... you only called your xSetButtonState which subsequently calls BeginPaint/EndPaint when IS_HOVERERING_X is FALSE. Meaning, when this condition is not satisfied, you are choking your message queue. Try to run Task Manager and run your program and you will see what I mean. However, if you pass this message to DefWindowProc nothing will be seen in your control since you did not completely specify the styles for this button. Hence, when responding to WM_PAINT message, always call BeginPaint/EndPaint and do the painting of your button--in all of its states--yourself.

  1. When DefWindowProc receives a WM_CLOSE message, it automatically destroys the window where the message is sent. You only handle WM_CLOSE if you want to really close your application in a particular condition or let it continue running otherwise.

  2. The way to generate bitmaps during the WM_PAINT message in your main window can cause lags to your application. I suggest you store it in some variables so won't be regenerating it again and again every time WM_PAINT is received. You can destroy those bitmap handles during WM_DESTROY.

That's for now.

Edited 3 Years Ago by RonalBertogi

Just successfully posted a reply to this thread today but I no longer see it when I reopen this thread. Was my post deleted for some reason?

Sorry I couldn't provide better/more timely info, but his advice far exceeds mine. Hope it worked out well. :)

I actually haven't had time to test it recently, I will do it at some point though.

This article has been dead for over six months. Start a new discussion instead.