subclassing static control to receive WM_CTLCOLORSTATIC - c++

I want to make the background of a static control that displays text transparent. After 2 days of excessive googling i've come up with this:
class TLABEL : public TWINDOW {
private:
HINSTANCE hInst;
public:
static LRESULT CALLBACK SubclassCallback(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR userdata)
{
TLABEL* pThisWindow = (TLABEL*)userdata;
//look for messages that we want to process ourselves
switch (msg)
{
//make background transparent
case WM_CTLCOLORSTATIC:
{
HDC hDC = (HDC)wParam;
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(0, 0, 0)); //text color black
MessageBox(NULL, L"WM_CTLCOLORSTATIC", L"Error!",MB_ICONEXCLAMATION|MB_OK);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_ERASEBKGND:
{
return TRUE;;
}
//remove Subclass if window is destroyed
case WM_NCDESTROY:
{
RemoveWindowSubclass(pThisWindow->handle, &TLABEL::SubclassCallback, uIdSubclass);
return TRUE;
}
}
//deliver all other messages to the original callback-function
return DefSubclassProc(hWnd, msg, wParam, lParam);
}
//standard alignment left
explicit TLABEL(int nx, int ny, int nwidth, int nheight, HWND hParent)
{
hInst = GetModuleHandle(NULL); //i know this is a bad practice
handle = CreateWindowEx(WS_EX_TRANSPARENT, //background transparent
L"STATIC", L"", //class name + text
WS_CHILD | WS_VISIBLE | SS_LEFT, //styles
nx, ny, nwidth, nheight, //dimensions
hParent, NULL, hInst, NULL);
//subclass window to catch messages we want to process ourselves
SetWindowSubclass(this->handle, &TLABEL::SubclassCallback, 0, (DWORD_PTR)this);
}
Somehow the SubclassCallback()-function never receives a WM_CTLCOLORSTATIC message, but i know that the function is called and that it receives WM_ERASEBKGND messages just fine. If i handle the WM_CTLCOLORSTATIC message in the message-handler of the main-window it works, unfortunately that would negate all benefits that come with making a seperate class for such a static control
I have not found any hints why the WM_CTLCOLORSTATIC message is sent to the main window and not my static control since all examples seem to do it just like that.
i have compiled it under VS2010 Express on a WinXP-32 machine

Related

How to use SetWindowPtrLong to set a custom window procedure to a child control?

Now I have a button control to which I want to assign a custom window procedure,
HWND buttonControl = CreateWindow(
L"BUTTON",
L"Click Me!",
WS_VISIBLE | WS_CHILD,
100, 100, 200, 50,
hWnd, //Parent Window,
0,
NULL,
NULL
);
The Window Procedure :
LRESULT CALLBACK customWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
...
return DefWindowProc(hWnd, message, wParam, lParam);
}
I have found some answers that *almost answers my question, such as:
How to change a window procedure at runtime?
Why you have to save the original window procedure of the window.
My question is :
after registering a class like,
WNDCLASS button_wc = { 0 };
button_wc.lpszClassName = L"BUTTON";
button_wc.lpfnWndProc = customWndProc; // Custom window procedure from above.
RegisterClass(&button_wc);
How am I supposed to assign it to the button control?
I know that I have to use SetWindowPtrLong to assign it to the button control, but I don't understand how to do it. In the above link it is also said that I have to save the old window procedure?!
So am I supposed to call SetWindowPtrLong and assign the value when I am creating the WNDCLASS to WNDCLASS::lpfnWndProc like:
button_wc.lpfnWndProc = (WNDPROC)SetWindowPtrLong(buttonControl, GWL_WNDPROC, (LONG_PTR)&customWndProc);
or am I supposed to assign it somewhere else?
EDIT:
This is how I am assigning the custom window procedure:
LRESULT customWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
switch(message) {
case WM_CREATE: {
std::cout << "CREATE" << std::endl;
break;
}
case WM_LBUTTONDOWN: {
std::cout << "LBUTTONDOWN" << std::endl;
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HBRUSH brush = CreateSolidBrush(RGB(20, 140, 240));
FillRect(hdc, &ps.rcPaint, brush);
DeleteObject(brush);
EndPaint(hWnd, &ps);
break;
}
}
return DefSubclassProc(hWnd, message, wParam, lParam);
}
SetWindowSubclass(buttonControl, customWndProc, 17, 0); //Setting the subclass
But the window procedure is not catching the WM_CREATE and WM_LBUTTONDOWN messages but it is catching WM_PAINT messages?! Am I doing something wrong?
Any help is greatly appreciated! Thank you in advance.
So I'm creating a custom window procedure for a child control,
HWND buttonControl = CreateWindow(
L"BUTTON",
L"Click me!",
WS_CHILD | WS_VISIBLE,
100, 100, 200, 50,
hWnd, // Parent Window
0,
NULL,
NULL
);
The custom window procedure :
LRESULT customWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch(message) {
case WM_LBUTTONDOWN : {
std::cout << "Clicked" << std::endl;
break;
}
case WM_LBUTTONUP : {
std::cout << "Un-Clicked" << std::endl;
break;
}
}
return DefSubclassProc(hWnd, message, wParam, lParam); // A "DefWindowPrc" but for subclasses
}
Now I am assigning the custom window procedure to my control using SetWindowSubclass like:
SetWindowSubclass(
buttonControl, // The window we want the subclass to be assigned to
customWndProc, // The custom window procedure we defined above.
17, // Any unique number to identify this subclass with
(DWORD_PTR)nullptr // As we don't want to access data from our subclass we pass a nullptr.
)
This is all defined in commctrl.h.
And that's all I had to do to assign a custom window procedure to a child control.
Thanks to #IInspectable for the answer.

text menu as created window behaviour of highlighting

I have created a Windows application. The elements that I create are using subclassing as I wanted to handle mouse hover events.
DWORD dwStyleOfIcons = SS_BITMAP | SS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER;
img1 = CreateWindow(L"STATIC", NULL, dwStyleOfIcons,
posX, posY, imgWt, imgHt,
hWnd, (HMENU)ICON1_CLICKED, hInst, NULL);
SetWindowSubclass(img1, StaticSubClassWndProc, ICON1_CLICKED, 0);
In my StaticSubClassWndProc(), I handle WM_MOUSEMOVE, WM_MOUSELEAVE, and WM_MOUSEHOVER:
LRESULT CALLBACK StaticSubClassWndProc (HWND hwndsubclass, UINT msg, WPARAM wp, LPARAM lp, UINT_PTR uidsubclass , DWORD_PTR dwrefdata)
{
...
switch(Msg)
{
case WM_MOUSEHOVER: {
if(uidsubclass == ICON1_CLICKED){
texture = "texture2.bmp";
modifyImage(texture);
}
break;
}
case WM_MOUSELEAVE: {
if(uidsubclass == ICON1_CLICKED){
texture = "texture.bmp";
modifyImage(texture);
}
break;
}
There are many STATIC items in my application, which all I wanted the behavior of a pop up context menu, like when I hover over the image it changes to a selected image, and when the cursor is out of view the image changes back to normal. I was able to do that.
I was able to do this for images which act as icons, but how do I do it for static text controls? Essentially, in a pop up menu, the selected text is all highlighted:
Is there no simpler way to make my elements in this window behave like a pop up menu? All I want is this custom structure of pop up menu behavior.
I think you did not handle the TrackMouseEvent function correctly, which caused your child window to be unable to process the WM_MOUSEHOVER and WM_MOUSELEAVE messages.
I tested the following code and it worked for me:
HBITMAP hBmp1 = (HBITMAP)LoadImage(NULL, L"test1.bmp", IMAGE_BITMAP, 200, 300, LR_LOADFROMFILE);
HBITMAP hBmp2 = (HBITMAP)LoadImage(NULL, L"test2.bmp", IMAGE_BITMAP, 200, 300, LR_LOADFROMFILE);
HWND img1;
LRESULT CALLBACK StaticSubClassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uidsubclass, DWORD_PTR dwrefdata)
{
switch (msg)
{
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT lpEventTrack;
lpEventTrack.cbSize = sizeof(TRACKMOUSEEVENT);
lpEventTrack.dwFlags = TME_HOVER | TME_LEAVE;
lpEventTrack.hwndTrack = img1;
lpEventTrack.dwHoverTime = 100;
TrackMouseEvent(&lpEventTrack);
break;
}
case WM_MOUSEHOVER:
{
if (uidsubclass == ICON1_CLICKED) {
SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBmp1);
}
break;
}
case WM_MOUSELEAVE:
{
if (uidsubclass == ICON1_CLICKED) {
SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBmp2);
}
break;
}
default:
return DefSubclassProc(hwnd, msg, wParam, lParam);
}
}
But you need to be aware that WM_MOUSEHOVER and WM_MOUSELEAVE will trigger frequently, so I don't think you should use this method to load pictures when the mouse is hovered or left, which will frequently trigger the loading of pictures.

Rich edit control sends EN_CHANGE when spellcheck underline appears

Let's say you've just set some text in a spellcheck-enabled rich edit control, and the text has some spelling errors. A split second will go by, spellcheck will kick in, and then the misspelled text will get underlined. But guess what: the rich edit control will actually send an EN_CHANGE notification just for the underlining event (this is assuming you've registered for notifications by doing SendMessage(hwnd, EM_SETEVENTMASK, 0, (LPARAM)ENM_CHANGE)).
Is there a workaround to not get this type of behavior? I've got a dialog with some spellcheck-enabled rich edit controls. And I also want to know when an edit event has taken place, so I know when to enable the "Save" button. Getting an EN_CHANGE notification merely for the spellcheck underlining event is thus a problem.
One option I've considered is disabling EN_CHANGE notifications entirely, and then triggering them on my own in a subclassed rich edit control. For example, when there's a WM_CHAR, it would send the EN_CHANGE notification explicitly, etc. But that seems like a problem, because there are many types of events that should trigger changes, like deletes, copy/pastes, etc., and I'd probably not capture all of them correctly.
Another option I've considered is enabling and disabling EN_CHANGE notifications dynamically. For example, enabling them only when there's focus, and disabling when focus is killed. But that also seems problematic, because a rich edit might already have focus when its text is set. Then the spellcheck underline would occur, and the undesirable EN_CHANGE notification would be sent.
I suppose a timer could be used, too, but I think that would be highly error-prone.
Does anybody have any other ideas?
Here's a reproducible example. Simply run it, and it'll say something changed:
#include <Windows.h>
#include <atlbase.h>
#include <atlwin.h>
#include <atltypes.h>
#include <Richedit.h>
class CMyWindow :
public CWindowImpl<CMyWindow, CWindow, CWinTraits<WS_VISIBLE>>
{
public:
CMyWindow()
{
}
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
COMMAND_CODE_HANDLER(EN_CHANGE, OnChange)
END_MSG_MAP()
private:
LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL& bHandled)
{
bHandled = FALSE;
LoadLibrary(L"Msftedit.dll");
CRect rc;
GetClientRect(&rc);
m_wndRichEdit.Create(MSFTEDIT_CLASS, m_hWnd, &rc,
NULL, WS_VISIBLE | WS_CHILD | WS_BORDER);
INT iLangOpts = m_wndRichEdit.SendMessage(EM_GETLANGOPTIONS, NULL, NULL);
iLangOpts |= IMF_SPELLCHECKING;
m_wndRichEdit.SendMessage(EM_SETLANGOPTIONS, NULL, (LPARAM)iLangOpts);
m_wndRichEdit.SetWindowText(L"sdflajlf adlfjldsfklj dfsl");
m_wndRichEdit.SendMessage(EM_SETEVENTMASK, 0, (LPARAM)ENM_CHANGE);
return 0;
}
LRESULT OnChange(WORD, WORD, HWND, BOOL&)
{
MessageBox(L"changed", NULL, NULL);
return 0;
}
private:
CWindow m_wndRichEdit;
};
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
CMyWindow wnd;
CRect rc(0, 0, 200, 200);
wnd.Create(NULL, &rc);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
Also, it appears that using EM_SETMODIFY and EM_GETMODIFY don't help. I guess the spellcheck underlining results in a EM_SETMODIFY, so checking that flag in the handler is of no avail.
because documentation about CHANGENOTIFY ( must contains information that is associated with an EN_CHANGE notification code, but not..) is wrong - only research exist.
in my test i view that EN_CHANGE related to Spellcheck received only when rich edit handle WM_TIMER message. so solution is next - subclass richedit and remember (save in class member variable) - when it inside WM_TIMER. than, when we handle EN_CHANGE - check are richedit inside WM_TIMER.
partial POC code. i special show more complex case - if several (more than one) child richedit`s exist in frame or dialog winndow
#include <richedit.h>
class RichFrame : public ZFrameMultiWnd
{
enum { richIdBase = 0x1234 };
bool _bInTimer[2] = {};
public:
protected:
private:
static LRESULT WINAPI SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if ((uIdSubclass -= richIdBase) >= _countof(_bInTimer))
{
__debugbreak();
}
bool bTimerMessage = uMsg == WM_TIMER;
if (bTimerMessage)
{
reinterpret_cast<RichFrame*>(dwRefData)->_bInTimer[uIdSubclass] = TRUE;
}
lParam = DefSubclassProc(hWnd, uMsg, wParam, lParam);
if (bTimerMessage)
{
reinterpret_cast<RichFrame*>(dwRefData)->_bInTimer[uIdSubclass] = false;
}
return lParam;
}
virtual BOOL CreateClient(HWND hWndParent, int nWidth, int nHeight, PVOID /*lpCreateParams*/)
{
UINT cy = nHeight / _countof(_bInTimer), y = 0;
UINT id = richIdBase;
ULONG n = _countof(_bInTimer);
do
{
if (HWND hwnd = CreateWindowExW(0, MSFTEDIT_CLASS, 0, WS_CHILD|ES_MULTILINE|WS_VISIBLE|WS_BORDER,
0, y, nWidth, cy, hWndParent, (HMENU)id, 0, 0))
{
SendMessage(hwnd, EM_SETLANGOPTIONS, 0,
SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0) | IMF_SPELLCHECKING);
SetWindowText(hwnd, L"sdflajlf adlfjldsfklj d");
SendMessage(hwnd, EM_SETEVENTMASK, 0, ENM_CHANGE);
if (SetWindowSubclass(hwnd, SubclassProc, id, reinterpret_cast<ULONG_PTR>(this)))
{
continue;
}
}
return FALSE;
} while (y += cy, id++, --n);
return TRUE;
}
virtual LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
if (EN_CHANGE == HIWORD(wParam))
{
if ((wParam = LOWORD(wParam) - richIdBase) >= _countof(_bInTimer))
{
__debugbreak();
}
DbgPrint("EN_CHANGE<%x> = %x\n", wParam, _bInTimer[wParam]);
}
break;
case WM_DESTROY:
{
UINT id = richIdBase;
ULONG n = _countof(_bInTimer);
do
{
RemoveWindowSubclass(GetDlgItem(hwnd, id), SubclassProc, id);
} while (id++, --n);
}
break;
case WM_NCDESTROY:
PostQuitMessage(0);
break;
}
return __super::WindowProc(hwnd, uMsg, wParam, lParam);
}
};
Use EM_CANUNDO (maybe also EM_CANREDO) to verify that contents has changed. I hope that spellchecker does't add any undo information.
I recently tried to work around this without subclassing but it was only somewhat successful.
My alternative workaround consists of marking the entire document as CFE_PROTECTED. In the EN_PROTECTED handler ENPROTECTED::msg is WM_NULL when coming from the spell checker and you can set a flag telling yourself to ignore the next EN_CHANGE. To allow actual spelling corrections from the context menu you also need to keep track of menus.
This feels rather fragile but so does tracking WM_TIMER.

How to correctly create push buttons on winApi as well as Handle its messages

So my program works, all apart from one thing, I would like for my button, 'pushBtn' , aka BTN_PUSH_TALK , to send a BN_PUSHED or BN_UNPUSHED message so I can handle it accordingly.
Following steps online, as well as trial and improvement, right now the only response I ever get is once I am done holding / clicking the button.
pushBtn = CreateWindowEx(0, L"BUTTON", L"TALK", WS_CHILD |
WS_VISIBLE |
BS_DEFPUSHBUTTON , 0 , 290 , 50, 50,
hWnd,(HMENU)BTN_PUSH_TALK, GetModuleHandle(NULL), NULL);
Handler (or at least what matters) :
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
bool asd;
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case BTN_PUSH_TALK:
switch (HIWORD(wParam))
{
case BN_UNPUSHED:
if (connected && inputChoiceStr == "Push To Talk") {
tplug->setDuck(false);
}
break;
case BN_PUSHED:
if (connected && inputChoiceStr == "Push To Talk") {
tplug->setDuck(true);
}
break;
}
break;
I expected once i clicked and held down the button , that the BN_PUSHED case would be entered, however it is not.
On letting go, I expect the BN_UNPUSHED case to be entered, but this was not the case either.
case BTN_PUSH_TALK is reached, meaning the button is identifiable, however the switch case within this block of code is never reached.
Buttons send WM_COMMAND on click. To achieve a push/release notification you must subclass the button class (SetWindowLongPtr() with GWLP_WNDPROC) and then handle WM_LBUTTONDOWN and WM_LBUTTONUP in your new Window Proc.
If I'm reading the question right, your goal is to get notifications when a standard push button is initially pushed by the user, whereas standard notification behavior of buttons only posts WM_COMMANDs on "clicks" where a click is the whole mouse down plus mouse up sequence.
Historically in order to get the BN_PUSHED and BN_UNPUSHED notifications in your WM_COMMAND handler you had to use the BS_NOTIFY window style when creating the button. However, if you read the documentation for BN_PUSHED or BN_UNPUSHED you will see
This notification code is provided only for compatibility with 16-bit versions of Windows earlier than version 3.0. Applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.
These were very old notifications that from what I can tell are not just deprecated but no longer even supported. You can do, however, as the documentation suggests: use an owner drawn button i.e. a button created with the BS_OWNERDRAW style.
This turns out to be more difficult than just creating the button with BS_NOTIFY turned on, because the button will no longer perform default painting by itself. Given this added chore, I'd recommend not doing it this way unless you want to custom paint your buttons anyway -- unless you happen to want some nonstandard visual look-and-feel for these buttons as well as nonstandard notification behavior. Otherwise, I would probably just do Win32 subclassing as someone else suggested to trap WM_LBUTTONDOWN etc. and then call the standard button WNDPROC after doing some action on the events i cared about.
Anyway the minimal owner drawn button that reports button down and button up events is like the following. (I post the button events as custom messages but you could do whatever you wish there)
#include <windows.h>
#define BTN_ID 101
#define WM_PUSHBUTTONDOWN WM_APP + 1
#define WM_PUSHBUTTONUP WM_APP + 2
HINSTANCE g_instance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
g_instance = hInstance;
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
wc.lpszClassName = L"owner_draw_btn";
if (!RegisterClass(&wc))
return -1;
if (!CreateWindow(wc.lpszClassName, L"foobar", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL))
return -1;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT HandleDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
auto* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
if (dis->CtlType != ODT_BUTTON)
return 0;
auto style = (dis->itemState & ODS_SELECTED) ?
DFCS_BUTTONPUSH | DFCS_PUSHED :
DFCS_BUTTONPUSH;
auto rect = &dis->rcItem;
DrawFrameControl(dis->hDC, rect, DFC_BUTTON, style);
TCHAR text[512];
auto n = GetWindowText(dis->hwndItem, text, 512);
DrawText(dis->hDC, text, n, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
if (dis->itemAction == ODA_SELECT) {
PostMessage(
hWnd,
(dis->itemState & ODS_SELECTED) ? WM_PUSHBUTTONDOWN : WM_PUSHBUTTONUP,
dis->CtlID,
0
);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
CreateWindow(
L"button", L"foobar",
BS_OWNERDRAW | WS_CHILD | WS_VISIBLE,
10, 10, 150, 35, hWnd,
(HMENU) BTN_ID,
g_instance,
0
);
return 0;
case WM_DRAWITEM:
return HandleDrawItem(hWnd, wParam, lParam);
case WM_PUSHBUTTONDOWN:
OutputDebugString(L"Button down event\n");
break;
case WM_PUSHBUTTONUP:
OutputDebugString(L"Button up event\n");
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}

Changing backgound color of a subclassed button in Win32

I want to change the background color of a button in runtime.
The problem is, the button does not have a black background which is what my code should produce.
Instead, it looks like is has the arrow of a drop-down control on it.
What exactly am I doing wrong here?
First I subclassed the Button:
// HWND hParent is the parent window
// HINSTANCE hInstance is the current module
HWND h = CreateWindow("Button", NULL, WS_CHILD | WS_VISIBLE | SS_OWNERDRAW,
340, 10, 20, 20,
hParent, NULL, hInstance, NULL);
SetWindowSubclass(h, &MyWndProc, MyButtonId, NULL);
The ID is defined as:
enum
{
MyButtonId = 100,
};
And the subclass procedure:
LRESULT CALLBACK MyWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if( uIdSubclass == MyButtonId )
{
switch( msg )
{
case WM_ERASEBKGND:
{
HDC dc = (HDC)wParam;
SetBkColor(dc, RGB(127,127,127));
return 0;
}
}
}
return DefSubclassProc(hWnd, msg, wParam, lParam);
}
You did not pass the button ID to the CreateWindow function, so your button does not have the ID you think it does.
The SetBkColor does not set backgrounds for buttons. It sets backgrounds for subsequent calls to TextOut.
You probably meant to use BS_OWNERDRAW, not SS_OWNERDRAW.
When you use the owner draw style you have to draw the button background and text and border. You do this in the parent window handler for WM_DRAWITEM. So you don't need to subclass the button at all.