Problem with subclasing Win32 control

user42 121 Reputation points
2021-01-13T15:58:48.313+00:00

Here is dll code I use:

#include "stdafx.h"  
  
#include <string>  
#include <commctrl.h>  
#pragma comment( lib, "comctl32.lib")  
  
#pragma data_seg("SHARED")  
  
HWND hWndComp[128] = { nullptr };  
HFONT font = CreateFont(18, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,  
	CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, "DejaVu Sans Mono");  
  
#pragma data_seg()  
#pragma comment(linker, "/section:SHARED,RWS")  
  
HINSTANCE hInst;  
HHOOK hGetMsgHook;  
BOOL bSubclassed = FALSE;  
  
#define WM_NOTEPADMESSAGE WM_USER + 10  
  
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);  
LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);  
  
BOOL APIENTRY DllMain(HMODULE hModule,  
	DWORD  ul_reason_for_call,  
	LPVOID lpReserved  
)  
{  
	switch (ul_reason_for_call)  
	{  
	case DLL_PROCESS_ATTACH:  
	{  
		hInst = (HINSTANCE)hModule;  
	}  
	case DLL_THREAD_ATTACH:  
		break;  
	case DLL_THREAD_DETACH:  
	case DLL_PROCESS_DETACH:  
	{  
		char out[64] = { 0 };  
		sprintf_s(out, 63, "DLL_PROCESS_DETACH, bSubclassed: %i", (int)bSubclassed);  
		OutputDebugStringA(out);  
  
		if (bSubclassed)  
		{  
			RemoveWindowSubclass(hWndComp[0], SubclassProc, 0);  
			bSubclassed = FALSE;  
			hWndComp[0] = nullptr;  
		}  
	}  
	break;  
	}  
	return TRUE;  
}  
  
int cnt = 0;  
BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam)  
{  
	char wclass[64] = { 0 };  
	if (RealGetWindowClassA(hWnd, wclass, 63) != 0) {  
		if (strcmp(wclass, "SysListView32") == 0)  
		{  
			hWndComp[cnt] = hWnd;  
			cnt++;  
  
			char out[128] = { 0 };  
			sprintf_s(out, 127, "child - hWnd : %08X, class: '%s'", (UINT)hWnd, wclass);  
			OutputDebugStringA(out);  
		}  
	}  
	return TRUE;  
}  
  
extern "C" __declspec(dllexport) BOOL CALLBACK SetHook(BOOL bInstall)  
{  
	if (bInstall)  
	{  
		char out[256] = { 0 };  
		  
		HWND main_window = FindWindowA("wxWindowNR", "FileZilla");  
  
		if (main_window)  
		{  
			EnumChildWindows(main_window, EnumChildProc, NULL);  
  
			if (!hWndComp[0]) {  
				sprintf_s(out, 255, "No listview components found");  
				OutputDebugStringA(out);  
				return FALSE;  
			}  
  
			hGetMsgHook = SetWindowsHookExA(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, hInst, 0);  
			if (hGetMsgHook)  
			{  
				DWORD dwThreadId = GetWindowThreadProcessId(hWndComp[0], NULL);  
				PostThreadMessageA(dwThreadId, WM_NOTEPADMESSAGE, 0, (LPARAM)hWndComp[0]);  
  
				sprintf_s(out, 255, "hWndComp: %08X - Thread Id : %08X", (UINT)hWndComp[0], dwThreadId);  
			}  
			else {  
				sprintf_s(out, 255, "Error SetWindowsHookEx: %d", GetLastError());  
			}  
  
			OutputDebugStringA(out);  
		}  
		else  
		{  
			sprintf_s(out, 255, "Main window not found");  
			OutputDebugStringA(out);  
  
			return FALSE;  
		}  
	}  
	else  
	{  
		if (hGetMsgHook)  
			UnhookWindowsHookEx(hGetMsgHook);  
	}  
	return TRUE;  
}  
  
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)  
{  
	MSG* lpMsg;  
	if (nCode >= 0)  
	{  
		lpMsg = (MSG*)lParam;  
		if (lpMsg->message == WM_NOTEPADMESSAGE)  
		{  
			char out[128] = { 0 };  
			sprintf_s(out, 127, "WM_NOTEPADMESSAGE - hWndComp : %08X", (UINT)hWndComp[0]);  
			OutputDebugStringA(out);  
  
			bSubclassed = SetWindowSubclass((HWND)hWndComp[0], SubclassProc, 0, 0);  
  
			if (!bSubclassed) {  
				sprintf_s(out, 127, "Error SetWindowSubclass : %d", GetLastError());  
				OutputDebugStringA(out);  
			}  
		}  
	}  
	return CallNextHookEx(hGetMsgHook, nCode, wParam, lParam);  
}  
  
LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)  
{  
	NMHDR* hdr;  
	char out[256] = { 0 };  
  
	switch (uMsg)  
	{  
	case WM_NOTIFY:  
		hdr = (NMHDR*)lParam;  
		if (hdr->code == NM_CUSTOMDRAW) {  
			LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;  
			if (lplvcd) {  
  
				sprintf_s(out, 255, "dwDrawStage: %08X", lplvcd->nmcd.dwDrawStage);  
				OutputDebugStringA(out);  
  
				switch (lplvcd->nmcd.dwDrawStage)   
				{  
				case CDDS_PREPAINT:  
					return CDRF_NOTIFYITEMDRAW;  
  
				case CDDS_ITEMPREPAINT:  
  
					if (font)  
						SelectObject(lplvcd->nmcd.hdc, font);  
					else {  
						sprintf_s(out, 255, "'font' creation failed");  
						OutputDebugStringA(out);  
					}  
  
					RECT r = lplvcd->nmcd.rc;  
  
					sprintf_s(out, 255,  
						"hWnd: %08X, subItem: %i, draw: %08X, rect: (%li, %li)-(%li, %li), txt: %08X, txtBg: %08X\n",  
						(UINT)hWnd, lplvcd->iSubItem, lplvcd->nmcd.dwDrawStage, r.left, r.top, r.right, r.bottom,  
						lplvcd->clrText, lplvcd->clrTextBk);  
					OutputDebugStringA(out);  
  
					lplvcd->clrText = RGB(100, 0, 100);  
					lplvcd->clrTextBk = RGB(33, 44, 55);  
					//lplvcd->clrFace = RGB(0, 100, 100);  
					  
					return CDRF_NEWFONT;  
					  
				default:  
					break;  
				}  
			}  
		}  
	  
	break;  
  
	default:  
		break;  
	}  
	return DefSubclassProc(hWnd, uMsg, wParam, lParam);  

The problem is that changing clrText and clrTextBk as well as font has no effect on the control.
If I change clrFace then control painting glitches like so:
56234-dll-hhok.png

The output I get from the dll:

[17072] child - hWnd : 00650B72, class: 'SysListView32'  
[17072] hWndComp: 00650B72 - Thread Id : 00003ECC  
[1428] WM_NOTEPADMESSAGE - hWndComp : 00650B72  
[1428] dwDrawStage: 00000001  
[1428] dwDrawStage: 00010001  
[1428] hWnd: 00650B72, subItem: 0, draw: 00010001, rect: (0, 0)-(182, 24), txt: 247FF410, txtBg: 00000014  
[1428] dwDrawStage: 00010001  
[1428] hWnd: 00650B72, subItem: 182, draw: 00010001, rect: (182, 0)-(257, 24), txt: 00646400, txtBg: 00000000  
[1428] dwDrawStage: 00010001  
[1428] hWnd: 00650B72, subItem: 257, draw: 00010001, rect: (257, 0)-(358, 24), txt: 00646400, txtBg: 00000000  
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,443 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 82,031 Reputation points
    2021-01-14T09:47:49.557+00:00

    In one of my old codes, I did this for Header painting =>

    List-View-Header.jpg

    LRESULT CALLBACK ListViewSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        static HFONT hNewFont = NULL;
        switch (uMsg)
        {
        case WM_NOTIFY:
        {
            LPNMHDR pnmhdr = (LPNMHDR)lParam;
            switch (pnmhdr->code)
            {
            case NM_CUSTOMDRAW:
            {
                LPNMCUSTOMDRAW pNMCustomDraw = (LPNMCUSTOMDRAW)lParam;
                switch (pNMCustomDraw->dwDrawStage)
                {
                case CDDS_PREPAINT:
                {
                    return CDRF_NOTIFYITEMDRAW; //| CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYSUBITEMDRAW;
                }
                break;
                case CDDS_ITEMPREPAINT:
                {
                    if (pNMCustomDraw->dwItemSpec == 0)
                        SetTextColor(pNMCustomDraw->hdc, RGB(255, 0, 0));
                    else if (pNMCustomDraw->dwItemSpec == 1)
                        SetTextColor(pNMCustomDraw->hdc, RGB(0, 0, 255));
    
                    HFONT hFont = (HFONT)GetStockObject(SYSTEM_FONT);
                    LOGFONT lf;
                    GetObject(hFont, sizeof(LOGFONT), (PVOID)&lf);
                    lf.lfWeight = FW_BOLD;
                    lf.lfItalic = 1;            
                    if (!hNewFont)
                    {
                        hNewFont = CreateFontIndirect(&lf);
                    }
                    SelectObject(pNMCustomDraw->hdc, hNewFont);
                    return CDRF_NEWFONT;
                }
                break;
                }
                break;
            }
            break;
            }
        }
        break;
        }
        return DefSubclassProc(hWnd, uMsg, wParam, lParam);
    }
    

1 additional answer

Sort by: Most helpful
  1. Viorel 112.9K Reputation points
    2021-01-13T16:47:26.347+00:00

    Maybe the font cannot be shared. Did you try creating the font inside the CDDS_ITEMPREPAINT handler?