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:
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