Commit 4c5de640 authored by Mikołaj Zalewski's avatar Mikołaj Zalewski Committed by Alexandre Julliard

comctl32: header: Test and improve the custom draw and owner draw code.

parent b182950b
......@@ -23,7 +23,6 @@
* TODO:
* - Imagelist support (completed?)
* - Hottrack support (completed?)
* - Custom draw support (completed?)
* - Filters support (HDS_FILTER, HDI_FILTER, HDM_*FILTER*, HDN_*FILTER*)
* - New Windows Vista features
*/
......@@ -108,6 +107,8 @@ typedef struct
static BOOL HEADER_PrepareCallbackItems(HWND hwnd, INT iItem, INT reqMask);
static void HEADER_FreeCallbackItems(HEADER_ITEM *lpItem);
static LRESULT HEADER_SendNotify(HWND hwnd, UINT code, NMHDR *hdr);
static LRESULT HEADER_SendCtrlCustomDraw(HWND hwnd, DWORD dwDrawStage, HDC hdc, RECT *rect);
static const WCHAR themeClass[] = {'H','e','a','d','e','r',0};
static WCHAR emptyString[] = {0};
......@@ -300,12 +301,12 @@ static void HEADER_GetHotDividerRect(HWND hwnd, HEADER_INFO *infoPtr, RECT *r)
static INT
HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack, LRESULT lCDFlags)
{
HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
HEADER_ITEM *phdi = &infoPtr->items[iItem];
RECT r;
INT oldBkMode, cxEdge = GetSystemMetrics(SM_CXEDGE);
INT oldBkMode;
HTHEME theme = GetWindowTheme (hwnd);
NMCUSTOMDRAW nmcd;
......@@ -315,6 +316,26 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
if (r.right - r.left == 0)
return phdi->rect.right;
/* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
SetTextColor(hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
if (lCDFlags & CDRF_NOTIFYITEMDRAW && !(phdi->fmt & HDF_OWNERDRAW))
{
LRESULT lCDItemFlags;
nmcd.dwDrawStage = CDDS_PREPAINT | CDDS_ITEM;
nmcd.hdc = hdc;
nmcd.dwItemSpec = iItem;
nmcd.rc = r;
nmcd.uItemState = phdi->bDown ? CDIS_SELECTED : 0;
nmcd.lItemlParam = phdi->lParam;
lCDItemFlags = HEADER_SendNotify(hwnd, NM_CUSTOMDRAW, (NMHDR *)&nmcd);
if (lCDItemFlags & CDRF_SKIPDEFAULT)
return phdi->rect.right;
}
if (theme != NULL) {
int state = (phdi->bDown) ? HIS_PRESSED :
(bHotTrack ? HIS_HOT : HIS_NORMAL);
......@@ -324,6 +345,8 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
&r, &r);
}
else {
HBRUSH hbr;
if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) {
if (phdi->bDown) {
DrawEdge (hdc, &r, BDR_RAISEDOUTER,
......@@ -335,31 +358,16 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
}
else
DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
hbr = CreateSolidBrush(GetBkColor(hdc));
FillRect(hdc, &r, hbr);
DeleteObject(hbr);
}
if (phdi->bDown) {
r.left += 2;
r.top += 2;
}
r.left -= cxEdge;
r.right += cxEdge;
/* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
SetTextColor (hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
nmcd.hdr.hwndFrom = hwnd;
nmcd.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID);
nmcd.hdr.code = NM_CUSTOMDRAW;
nmcd.dwDrawStage = CDDS_PREPAINT | CDDS_ITEM | CDDS_ITEMPOSTERASE;
nmcd.hdc = hdc;
nmcd.dwItemSpec = iItem;
nmcd.rc = r;
nmcd.uItemState = phdi->bDown ? CDIS_SELECTED : 0;
nmcd.lItemlParam = phdi->lParam;
SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
if (phdi->fmt & HDF_OWNERDRAW) {
DRAWITEMSTRUCT dis;
......@@ -370,7 +378,7 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
dis.itemState = phdi->bDown ? ODS_SELECTED : 0;
dis.hwndItem = hwnd;
dis.hDC = hdc;
dis.rcItem = r;
dis.rcItem = phdi->rect;
dis.itemData = phdi->lParam;
oldBkMode = SetBkMode(hdc, TRANSPARENT);
SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM,
......@@ -391,15 +399,6 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
rw = r.right - r.left;
rh = r.bottom - r.top;
if (theme == NULL) {
HBRUSH hbr = CreateSolidBrush(GetBkColor(hdc));
RECT rcBackground = r;
rcBackground.right -= cxEdge;
rcBackground.left += cxEdge;
FillRect(hdc, &rcBackground, hbr);
DeleteObject(hbr);
}
if (phdi->fmt & HDF_STRING) {
RECT textRect;
......@@ -526,10 +525,11 @@ HEADER_Refresh (HWND hwnd, HDC hdc)
{
HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
HFONT hFont, hOldFont;
RECT rect;
RECT rect, rcRest;
HBRUSH hbrBk;
UINT i;
INT x;
LRESULT lCDFlags;
HTHEME theme = GetWindowTheme (hwnd);
if (!infoPtr->bRectsValid)
......@@ -537,6 +537,7 @@ HEADER_Refresh (HWND hwnd, HDC hdc)
/* get rect for the bar, adjusted for the border */
GetClientRect (hwnd, &rect);
lCDFlags = HEADER_SendCtrlCustomDraw(hwnd, CDDS_PREPAINT, hdc, &rect);
if (infoPtr->bDragging)
ImageList_DragShowNolock(FALSE);
......@@ -554,21 +555,21 @@ HEADER_Refresh (HWND hwnd, HDC hdc)
for (i = 0; x <= rect.right && i < infoPtr->uNumItem; i++) {
int idx = HEADER_OrderToIndex(hwnd,i);
if (RectVisible(hdc, &infoPtr->items[idx].rect))
HEADER_DrawItem(hwnd, hdc, idx, infoPtr->iHotItem == idx);
HEADER_DrawItem(hwnd, hdc, idx, infoPtr->iHotItem == idx, lCDFlags);
x = infoPtr->items[idx].rect.right;
}
rect.left = x;
if ((x <= rect.right) && RectVisible(hdc, &rect) && (infoPtr->uNumItem > 0)) {
rcRest = rect;
rcRest.left = x;
if ((x <= rect.right) && RectVisible(hdc, &rcRest) && (infoPtr->uNumItem > 0)) {
if (theme != NULL) {
DrawThemeBackground (theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rect,
NULL);
DrawThemeBackground(theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rcRest, NULL);
}
else {
if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS)
DrawEdge (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE);
DrawEdge (hdc, &rcRest, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE);
else
DrawEdge (hdc, &rect, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE);
DrawEdge (hdc, &rcRest, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE);
}
}
......@@ -578,6 +579,9 @@ HEADER_Refresh (HWND hwnd, HDC hdc)
if (infoPtr->bDragging)
ImageList_DragShowNolock(TRUE);
SelectObject (hdc, hOldFont);
if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
HEADER_SendCtrlCustomDraw(hwnd, CDDS_POSTPAINT, hdc, &rect);
}
......@@ -779,18 +783,38 @@ static UINT HEADER_NotifyCodeWtoA(UINT code)
return code;
}
static LRESULT
HEADER_SendNotify(HWND hwnd, UINT code, NMHDR *nmhdr)
{
HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
nmhdr->hwndFrom = hwnd;
nmhdr->idFrom = GetWindowLongPtrW (hwnd, GWLP_ID);
nmhdr->code = code;
return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
(WPARAM)nmhdr->idFrom, (LPARAM)nmhdr);
}
static BOOL
HEADER_SendSimpleNotify (HWND hwnd, UINT code)
{
HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
NMHDR nmhdr;
return (BOOL)HEADER_SendNotify(hwnd, code, &nmhdr);
}
nmhdr.hwndFrom = hwnd;
nmhdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID);
nmhdr.code = code;
return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
(WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
static LRESULT
HEADER_SendCtrlCustomDraw(HWND hwnd, DWORD dwDrawStage, HDC hdc, RECT *rect)
{
NMCUSTOMDRAW nm;
nm.dwDrawStage = dwDrawStage;
nm.hdc = hdc;
nm.rc = *rect;
nm.dwItemSpec = 0;
nm.uItemState = 0;
nm.lItemlParam = 0;
return HEADER_SendNotify(hwnd, NM_CUSTOMDRAW, (NMHDR *)&nm);
}
static BOOL
......@@ -799,15 +823,13 @@ HEADER_SendNotifyWithHDItemT(HWND hwnd, UINT code, INT iItem, HDITEMW *lpItem)
HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
NMHEADERW nmhdr;
nmhdr.hdr.hwndFrom = hwnd;
nmhdr.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID);
nmhdr.hdr.code = (infoPtr->nNotifyFormat == NFR_UNICODE ? code : HEADER_NotifyCodeWtoA(code));
if (infoPtr->nNotifyFormat != NFR_UNICODE)
code = HEADER_NotifyCodeWtoA(code);
nmhdr.iItem = iItem;
nmhdr.iButton = 0;
nmhdr.pitem = lpItem;
return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
(WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
return (BOOL)HEADER_SendNotify(hwnd, code, (NMHDR *)&nmhdr);
}
static BOOL
......@@ -962,6 +984,8 @@ HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
HEADER_ITEM *lpItem;
HIMAGELIST himl;
HBITMAP hMemory, hOldBitmap;
LRESULT lCDFlags;
RECT rc;
HDC hMemoryDC;
HDC hDeviceDC;
int height, width;
......@@ -982,7 +1006,13 @@ HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
ReleaseDC(NULL, hDeviceDC);
hOldBitmap = SelectObject(hMemoryDC, hMemory);
SetViewportOrgEx(hMemoryDC, -lpItem->rect.left, -lpItem->rect.top, NULL);
HEADER_DrawItem(hwnd, hMemoryDC, wParam, FALSE);
GetClientRect(hwnd, &rc);
lCDFlags = HEADER_SendCtrlCustomDraw(hwnd, CDDS_PREPAINT, hMemoryDC, &rc);
HEADER_DrawItem(hwnd, hMemoryDC, wParam, FALSE, lCDFlags);
if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
HEADER_SendCtrlCustomDraw(hwnd, CDDS_POSTPAINT, hMemoryDC, &rc);
hMemory = SelectObject(hMemoryDC, hOldBitmap);
DeleteDC(hMemoryDC);
......
......@@ -31,6 +31,13 @@ typedef struct tagEXPECTEDNOTIFY
HDITEMA hdItem;
} EXPECTEDNOTIFY;
typedef LRESULT (*CUSTOMDRAWPROC)(int n, NMCUSTOMDRAW *nm);
CUSTOMDRAWPROC g_CustomDrawProc;
int g_CustomDrawCount;
DRAWITEMSTRUCT g_DrawItem;
BOOL g_DrawItemReceived;
EXPECTEDNOTIFY expectedNotify[10];
INT nExpectedNotify = 0;
INT nReceivedNotify = 0;
......@@ -41,6 +48,8 @@ static HWND hHeaderParentWnd;
static HWND hWndHeader;
#define MAX_CHARS 100
#define compare(val, exp, fmt) ok((val) == (exp), #val " value: " fmt ", expected: " fmt "\n", (val), (exp))
static void expect_notify(INT iCode, BOOL fUnicode, HDITEMA *lpItem)
{
assert(nExpectedNotify < 10);
......@@ -479,6 +488,173 @@ static void test_header_control (void)
}
#define TEST_NMCUSTOMDRAW(draw_stage, item_spec, lparam, _left, _top, _right, _bottom) \
ok(nm->dwDrawStage == draw_stage, "Invalid dwDrawStage %d vs %d\n", draw_stage, nm->dwDrawStage); \
if (item_spec != -1) \
ok(nm->dwItemSpec == item_spec, "Invalid dwItemSpec %d vs %ld\n", item_spec, nm->dwItemSpec); \
ok(nm->lItemlParam == lparam, "Invalid lItemlParam %d vs %ld\n", lparam, nm->lItemlParam); \
ok(nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right, \
"Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", _left, _top, _right, _bottom, \
nm->rc.left, nm->rc.top, nm->rc.right, nm->rc.bottom);
static LRESULT customdraw_1(int n, NMCUSTOMDRAW *nm)
{
if (nm == NULL) { /* test ended */
ok(n==1, "NM_CUSTOMDRAW messages: %d, expected: 1\n", n);
return 0;
}
switch (n)
{
case 0:
/* don't test dwItemSpec - it's 0 no comctl5 but 1308756 on comctl6 */
TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
return 0;
}
ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
return -1;
}
static LRESULT customdraw_2(int n, NMCUSTOMDRAW *nm)
{
if (nm == NULL) { /* test ended */
ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n);
return 0;
}
switch (n)
{
case 0:
TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
return CDRF_NOTIFYITEMDRAW;
case 1:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18);
return 0;
case 2:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18);
return 0;
case 3:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18);
return 0;
}
ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
return 0;
}
static LRESULT customdraw_3(int n, NMCUSTOMDRAW *nm)
{
if (nm == NULL) { /* test ended */
ok(n==5, "NM_CUSTOMDRAW messages: %d, expected: 5\n", n);
return 0;
}
switch (n)
{
case 0:
TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTERASE|CDRF_NOTIFYPOSTPAINT|CDRF_SKIPDEFAULT;
case 1:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18);
return 0;
case 2:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18);
return 0;
case 3:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18);
return 0;
case 4:
TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18);
return 0;
}
ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
return 0;
}
static LRESULT customdraw_4(int n, NMCUSTOMDRAW *nm)
{
if (nm == NULL) { /* test ended */
ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n);
return 0;
}
switch (n)
{
case 0:
TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
case 1:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18);
return 0;
case 2:
TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18);
return 0;
case 3:
TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18);
return 0;
}
ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
return 0;
}
static void run_customdraw_scenario(CUSTOMDRAWPROC proc)
{
g_CustomDrawProc = proc;
g_CustomDrawCount = 0;
InvalidateRect(hWndHeader, NULL, TRUE);
UpdateWindow(hWndHeader);
proc(g_CustomDrawCount, NULL);
g_CustomDrawProc = NULL;
}
void test_customdraw()
{
int i;
HDITEM item;
RECT rect;
CHAR name[] = "Test";
hWndHeader = create_header_control();
GetClientRect(hWndHeader, &rect);
ok(rect.right - rect.left == 670 && rect.bottom - rect.top == 18,
"Tests will fail as header size is %dx%d instead of 670x18\n",
rect.right - rect.left == 670, rect.bottom - rect.top == 18);
for (i = 0; i < 3; i++)
{
ZeroMemory(&item, sizeof(item));
item.mask = HDI_TEXT|HDI_WIDTH;
item.cxy = 50*(i+1);
item.pszText = name;
item.lParam = i*5;
SendMessage(hWndHeader, HDM_INSERTITEM, i, (LPARAM)&item);
}
run_customdraw_scenario(customdraw_1);
run_customdraw_scenario(customdraw_2);
run_customdraw_scenario(customdraw_3);
ZeroMemory(&item, sizeof(item));
item.mask = HDI_FORMAT;
item.fmt = HDF_OWNERDRAW;
SendMessage(hWndHeader, HDM_SETITEM, 1, (LPARAM)&item);
g_DrawItem.CtlID = 0;
g_DrawItem.CtlType = ODT_HEADER;
g_DrawItem.hwndItem = hWndHeader;
g_DrawItem.itemID = 1;
g_DrawItem.itemState = 0;
SendMessage(hWndHeader, HDM_GETITEMRECT, 1, (LPARAM)&g_DrawItem.rcItem);
run_customdraw_scenario(customdraw_4);
ok(g_DrawItemReceived, "WM_DRAWITEM not received\n");
DestroyWindow(hWndHeader);
hWndHeader = NULL;
g_DrawItem.CtlType = 0;
g_DrawItemReceived = FALSE;
}
static void check_order(const int expected_id[], const int expected_order[],
int count, const char *type)
{
......@@ -561,6 +737,7 @@ static void test_header_order (void)
LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
DRAWITEMSTRUCT *di;
switch(msg) {
case WM_NOTIFY:
......@@ -568,7 +745,11 @@ LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
NMHEADERA *hdr = (NMHEADER *)lParam;
EXPECTEDNOTIFY *expected;
int i;
if (hdr->hdr.code == NM_CUSTOMDRAW)
if (g_CustomDrawProc)
return g_CustomDrawProc(g_CustomDrawCount++, (NMCUSTOMDRAW*)hdr);
for (i=0; i<nUnexpectedNotify; i++)
ok(hdr->hdr.code != unexpectedNotify[i], "Received invalid notify %d\n", hdr->hdr.code);
......@@ -583,7 +764,23 @@ LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
compare_items(hdr->hdr.code, &expected->hdItem, hdr->pitem, expected->fUnicode);
break;
}
case WM_DRAWITEM:
di = (DRAWITEMSTRUCT *)lParam;
ok(g_DrawItem.CtlType != 0, "Unexpected WM_DRAWITEM\n");
if (g_DrawItem.CtlType == 0) return 0;
g_DrawItemReceived = TRUE;
compare(di->CtlType, g_DrawItem.CtlType, "%d");
compare(di->CtlID, g_DrawItem.CtlID, "%d");
compare(di->hwndItem, g_DrawItem.hwndItem, "%p");
compare(di->itemID, g_DrawItem.itemID, "%d");
compare(di->itemState, g_DrawItem.itemState, "%d");
compare(di->rcItem.left, g_DrawItem.rcItem.left, "%d");
compare(di->rcItem.top, g_DrawItem.rcItem.top, "%d");
compare(di->rcItem.right, g_DrawItem.rcItem.right, "%d");
compare(di->rcItem.bottom, g_DrawItem.rcItem.bottom, "%d");
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
......@@ -618,6 +815,7 @@ static void init(void) {
hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
assert(hHeaderParentWnd != NULL);
ShowWindow(hHeaderParentWnd, SW_SHOW);
}
START_TEST(header)
......@@ -626,6 +824,7 @@ START_TEST(header)
test_header_control();
test_header_order();
test_customdraw();
DestroyWindow(hHeaderParentWnd);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment