如何从 WM_CTLCOLORLISTBOX 中检索 Combobox 的 GWLP_USERDATA?
Posted
技术标签:
【中文标题】如何从 WM_CTLCOLORLISTBOX 中检索 Combobox 的 GWLP_USERDATA?【英文标题】:How can I retrieve Combobox's GWLP_USERDATA from WM_CTLCOLORLISTBOX? 【发布时间】:2021-02-25 05:38:54 【问题描述】:到目前为止,我一直在使用的大多数消息都通过 lParam 中的 HWND。所以我使用该值来检索与 GWLP_USERDATA
关联的 hwnd 对象,所以我可以这样做:
case WM_COMMAND:
auto sender = (HWND)lParam;
auto obj = getObj(sender);
obj->myMethod();
并获取与调用的 hwnd 关联的方法。但是,组合框的WM_CTLCOLORLISTBOX
不会在lParam
中发送组合框的HWND
。我必须发送CB_GETCOMBOBOXINFO
消息,但这需要控件的 hwnd,在该设计中,该控件不可用。所以我的问题是:如何从WM_CTLCOLORLISTBOX
检索与组合框关联的对象?我想不出任何其他方法来循环到目前为止创建的所有对象(所以我需要保留它们的数组),以某种方式过滤与组合框控件类型关联的对象,然后在 CB_GETCOMBOBOXINFO
中使用该 hwnd信息。这似乎是一种蛮力。还有比这更好的方法吗?这是我目前的做法:
case WM_CTLCOLORLISTBOX:
auto dc = (HDC) wParam;
SetBkMode(dc, TRANSPARENT);
COMBOBOXINFO info;
for(int i = 0; i < COUNTOF(instances); i++)
auto obj = instances[i];
if(obj->type != ControlType_combobox)
continue;
memset(&info, 0, sizeof(COMBOBOXINFO));
info.cbSize = sizeof(COMBOBOXINFO);
auto hCombo = instances[i];
SendMessage(obj->hwnd, CB_GETCOMBOBOXINFO, 0, (LPARAM) &info);
if((HWND)lParam == info.hwndList)
return (LRESULT) obj->hBrush;
break;
完整代码:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "Comdlg32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <winuser.h>
#include <assert.h>
#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
enum ControlType
ControlType_none,
ControlType_button,
ControlType_combobox
;
class Foo
public:
int n = 0;
const wchar_t *str = nullptr;
HBRUSH hBrush = nullptr;
ControlType type = ControlType_none;
HWND hwnd = nullptr;
void sayHello()
MessageBox(NULL, str, L"", MB_OK);
Foo()
~Foo()
if(hBrush)
DeleteObject(hBrush);
hBrush = nullptr;
;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HFONT getDefaultFont();
void SetDefaultFont(HWND hwnd);
void saveInstance(Foo *f);
void freeInstances();
void associateObj(HWND hwnd, Foo *instance);
Foo* getObj(HWND hwnd);
Foo *instances[12];
int instance_size = 0;
HFONT hDefaultSystemFont;
HINSTANCE g_hinst;
const wchar_t *items[] =
L"Windows", L"Mac",
L"FreeBSD", L"Arch",
;
enum
ID_COMBO = 10,
ID_BTN1,
;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow)
HWND hwnd;
MSG msg ;
WNDCLASSW wc = 0;
wc.lpszClassName = L"Application";
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
wc.hCursor = LoadCursor(0,IDC_ARROW);
g_hinst = hInstance;
RegisterClassW(&wc);
hwnd = CreateWindowW(wc.lpszClassName, L"",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 300, 170, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
DispatchMessage(&msg);
return (int) msg.wParam;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
switch(msg)
case WM_CREATE:
HWND hwndCombo = CreateWindow(L"Combobox", NULL,
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
10, 10, 120, 110, hwnd, (HMENU) ID_COMBO, g_hinst, NULL);
auto f = new Foo;
f->n = 10;
f->str = L"Hello from combo!";
f->hBrush = CreateSolidBrush(RGB(0, 128, 0));
f->type = ControlType_combobox;
associateObj(hwndCombo, f);
for (int i = 0; i < COUNTOF(items); i++)
SendMessageW(hwndCombo, CB_ADDSTRING, 0, (LPARAM) items[i]);
SetDefaultFont(hwndCombo);
HWND btn1 =
CreateWindow(L"Button", L"Click me!",
WS_CHILD | WS_VISIBLE,
5, 40, 90, 25, hwnd, (HMENU) ID_BTN1, g_hinst, NULL);
auto f2 = new Foo;
f2->n = 20;
f2->str = L"Hello from button!";
f2->type = ControlType_button;
associateObj(btn1, f2);
SetDefaultFont(btn1);
break;
case WM_DESTROY:
DeleteObject(hDefaultSystemFont);
hDefaultSystemFont = NULL;
freeInstances();
PostQuitMessage(0);
break;
case WM_COMMAND:
auto sender = (HWND)lParam;
auto o = getObj(sender);
o->sayHello();
break;
case WM_CTLCOLORLISTBOX:
auto dc = (HDC) wParam;
SetBkMode(dc, TRANSPARENT);
COMBOBOXINFO info;
for(int i = 0; i < COUNTOF(instances); i++)
auto obj = instances[i];
if(obj->type != ControlType_combobox)
continue;
memset(&info, 0, sizeof(COMBOBOXINFO));
info.cbSize = sizeof(COMBOBOXINFO);
auto hCombo = instances[i];
SendMessage(obj->hwnd, CB_GETCOMBOBOXINFO, 0, (LPARAM) &info);
if((HWND)lParam == info.hwndList)
return (LRESULT) obj->hBrush;
break;
return DefWindowProcW(hwnd, msg, wParam, lParam);
void associateObj(HWND hwnd, Foo *instance)
instance->hwnd = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)(void*)instance);
saveInstance(instance);
Foo* getObj(HWND hwnd)
return (Foo*)(void*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
void saveInstance(Foo *f)
instances[instance_size++] = f;
void freeInstances()
for(int i = 0; i < COUNTOF(instances); i++)
delete instances[i];
instances[i] = nullptr;
HFONT getDefaultFont()
if(hDefaultSystemFont == NULL)
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
hDefaultSystemFont = CreateFontIndirect(&ncm.lfMessageFont);
return hDefaultSystemFont;
void SetDefaultFont(HWND hwnd)
SendMessage(hwnd, WM_SETFONT, (LPARAM) getDefaultFont(), TRUE);
【问题讨论】:
您可以在列表框HWND
上调用GetParent()
以获取组合的HWND
。
不是解决您当前问题的方法,但请考虑使用SetProp
/GetProp
。由于您正在编写对 Windows 通用控件的抽象,因此您现在不仅要与一方,而且要与两方争夺 GWLP_USERDATA
:第三方应用程序和库的客户端。
@JonathanPotter 喜欢这样吗? auto sender = GetParent((HWND)lParam);
但 `getObj(sender)` 正在返回 NULL
@IInspectable 谢谢你的建议,我会考虑切换到SetProp
/ GetProp
,听起来更合适。
【参考方案1】:
创建 ComboBox 时,使用CB_GETCOMBOBOXINFO
获取其 ListBox 的HWND
,然后使用SetProp()
将对象指针保存在其中。这样,在您的WM_CTLCOLORLISTBOX
处理程序中,您可以在提供的HWND
上使用GetProp()
来访问您的对象。无需狩猎。
更新:如评论中所述,您还可以在WM_CTLCOLORLISTBOX
提供的HWND
上使用GetParent()
来获取其拥有的ComboBox的HWND
,然后您可以从中访问使用 getObj()
的关联对象指针。
【讨论】:
我确实保留了associateObj(hwndCombo, f);
然后auto sender = GetParent((HWND)lParam); assert(sender != NULL); auto obj = getObj(sender);
但我在obj
上收到了NULL
。我错过了什么?以上是关于如何从 WM_CTLCOLORLISTBOX 中检索 Combobox 的 GWLP_USERDATA?的主要内容,如果未能解决你的问题,请参考以下文章
从client(content="<p></p>")中检測到有潜在危急的 Request.Form 值。
唯品会Gucci腰带被得物中检鉴定为假后续:消费者被迫法院维权
Android中检測字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法