I'm trying to learn how to subclass a GUI control and 'modify' its hdc
.
This is my subclass callback
:
mygui.h
#include <commctrl.h> // SetWindowSubclass
#pragma comment(lib, "Comctl32.lib")
#include <windows.h> // GDI includes.
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
using namespace DllExports;
#pragma comment (lib,"Gdiplus.lib")
typedef UCHAR GuiControls;
enum GuiControlTypes {
GUI_CONTROL_BUTTON
};
struct GuiControlOptionsType
{
int x;
int y;
int width;
int height;
LPCWSTR text;
GuiControlTypes controltype;
bool ERASEDBKGND = false; // Used on the subclass proc.
HDC dc;
};
class Gui
{
public:
std::map<HWND, GuiControlOptionsType> control_list;
HWND GuihWnd;
HWND A_LasthWnd;
LRESULT Create();
LRESULT AddControl(GuiControls aControlType, GuiControlOptionsType opt);
};
LRESULT CALLBACK ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
mygui.cpp
/* Window Procedure. */
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// TODO
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
{
Gui mygui;
mygui.Create();
}
LRESULT Gui::Create()
{
WNDCLASSEX wc{};
MSG Msg;
HWND hWnd = nullptr;
wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0;
wc.hInstance = 0; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW 1); wc.lpszMenuName = NULL;
wc.lpszClassName = L"classname";
if (!RegisterClassEx(&wc))
// TODO
this->GuihWnd = CreateWindowW(
wc.lpszClassName,
L"Title",
WS_EX_COMPOSITED | WS_EX_LAYERED | // Double buffering
WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 200,
nullptr, nullptr, nullptr, nullptr);
DWORD err = GetLastError();
if (this->GuihWnd == NULL)
// TODO
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
GuiControlOptionsType opt;
opt.x = 10; opt.y = 10; opt.width = 100; opt.height = 100; opt.text = L"test";
this->AddControl(GUI_CONTROL_BUTTON, opt);
SetWindowSubclass(this->A_LasthWnd, ButtonProc, 1, (DWORD_PTR)this);
ShowWindow(this->GuihWnd, SW_SHOW);
UpdateWindow(this->GuihWnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0; // Msg.wParam;
}
LRESULT Gui::AddControl(GuiControls aControlType, GuiControlOptionsType opt)
{
switch (aControlType)
{
case GUI_CONTROL_BUTTON:
{
HWND hWnd = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
opt.text, // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
opt.x, // x position
opt.y, // y position
opt.width, // Button width
opt.height, // Button height
this->GuihWnd, // Parent window
NULL, // No menu.
NULL, //(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL); // Pointer not needed.
opt.controltype = GUI_CONTROL_BUTTON;
this->control_list.emplace(hWnd, opt);
this->A_LasthWnd = hWnd;
}
break;
default:
break;
}
return 1;
}
LRESULT CALLBACK ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
Gui* pThis = (Gui*)dwRefData;
switch (uMsg)
{
case WM_ERASEBKGND:
{
if (pThis->control_list[hWnd].ERASEDBKGND)
return 1;
// Create/save the new button dc.
GpBitmap* pBitmap;
GdipCreateBitmapFromScan0(pThis->control_list[hWnd].width, pThis->control_list[hWnd].height, 0, PixelFormat32bppPARGB, 0, &pBitmap);
GpGraphics* g;
GdipGetImageGraphicsContext(pBitmap, &g);
GdipGraphicsClear(g, 0xFF2400ff);
HBITMAP hbm;
GdipCreateHBITMAPFromBitmap(pBitmap, &hbm, 0);
HDC dc = CreateCompatibleDC(NULL);
SelectObject(dc, hbm);
pThis->control_list[hWnd].dc = dc;
GdipDisposeImage(pBitmap);
GdipDeleteGraphics(g);
DeleteObject(hbm);
pThis->control_list[hWnd].ERASEDBKGND = 1;
}
break;
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
{
InvalidateRect(hWnd, 0, 1);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
BLENDFUNCTION bf;
bf.SourceConstantAlpha = 255;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = AC_SRC_ALPHA;
GdiAlphaBlend(hdc, 0, 0, pThis->control_list[hWnd].width, pThis->control_list[hWnd].height,
pThis->control_list[hWnd].dc, 0, 0, pThis->control_list[hWnd].width, pThis->control_list[hWnd].height, bf);
EndPaint(hWnd, &ps);
DeleteObject(hdc);
return TRUE;
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
The problem is... when I click on the button it restores its default hdc
, when I minimize/restore it draws with my 'custom' hdc
.
I tried adding a call to InvalidateRect()
under WM_LBUTTONDOWN
, but it resulted in the same thing.
I also tried creating the Gui
with 'double buffering' adding the styles WS_EX_COMPOSITED | WS_EX_LAYERED
.
What am I missing?
CodePudding user response:
BS_OWNERDRAW
should be "her" style, I think.