[PATCH v10 0/3] MR6737: comctl32/toolbar: forward unhandled WM_NOTIFY
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57178 This makes [7-zip file manager](https://www.7-zip.org/) pressing enter while editing path work: * before: * [Icon near path becomes dark (7-zip file manager doesn't go to path).](https://old.reddit.com/r/winehq/comments/16ah3ze/7zip_cant_enter_path_from_p...) * after: * 7-zip file manager goes to path. * Path input displays incorrect path (shouldn't happen, bug in wine's comboboxex unrelated to toolbar). -- v10: comctl32/toolbar: Forward unhandled WM_NOTIFY. comctl32: Move WM_NOTIFY unicode -> ansi conversion code from pager.c to commctrl.c. comctl32/tests: Test WM_NOTIFY forwarding in toolbar. https://gitlab.winehq.org/wine/wine/-/merge_requests/6737
From: Alanas <alanas.00(a)mail.ru> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57178 --- dlls/comctl32/tests/toolbar.c | 100 +++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index 7c886e1f88f..b780cc401f3 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -179,11 +179,47 @@ static BOOL equal_dc(HDC hdc1, HDC hdc2, int width, int height) static void *alloced_str; -static LRESULT parent_wnd_notify(LPARAM lParam) +static NMHDR *test_WM_NOTIFY_nmhdr; +static enum { + TEST_WM_NOTIFY_NONE,/* not testing */ + TEST_WM_NOTIFY_SIMPLE_FORWARD,/* nmhdr.code=0xabcd0004 */ + TEST_WM_NOTIFY_CONVERT_FORWARD,/* nmhdr.code=0xfffffd17=DTN_USERSTRINGW before forwarding, nmhdr.code=0xfffffd0a=DTN_USERSTRINGA after forwarding */ + TEST_WM_NOTIFY_NO_FORWARD,/* nmhdr.code=0xfffffc69 */ + TEST_WM_NOTIFY_SIMPLE_FORWARD_DONE, + TEST_WM_NOTIFY_CONVERT_FORWARD_DONE +} test_WM_NOTIFY_state; +#define TEST_WM_NOTIFY_RETURN ((LRESULT)0xabcd0001) +#define TEST_WM_NOTIFY_HWNDFROM ((HWND)0xabcd0002) +#define TEST_WM_NOTIFY_IDFROM ((UINT_PTR)0xabcd0003) +#define TEST_WM_NOTIFY_SIMPLE_FORWARD_CODE ((UINT)0xabcd0004) +#define TEST_WM_NOTIFY_NO_FORWARD_CODE ((UINT)0xfffffc69) + +static LRESULT parent_wnd_notify(WPARAM wParam, LPARAM lParam) { NMHDR *hdr = (NMHDR *)lParam; NMTBHOTITEM *nmhi; NMTBDISPINFOA *nmdisp; + if (test_WM_NOTIFY_state) + { + ok(hdr == test_WM_NOTIFY_nmhdr, "Got unexpected header.\n"); + ok(wParam == TEST_WM_NOTIFY_IDFROM, "Got unexpected wParam 0x%Ix.\n", wParam); + ok(hdr->hwndFrom == TEST_WM_NOTIFY_HWNDFROM, "hwndFrom changed from 0x%Ix to 0x%Ix.\n", (UINT_PTR)TEST_WM_NOTIFY_HWNDFROM, (UINT_PTR)hdr->hwndFrom); + ok(hdr->idFrom == TEST_WM_NOTIFY_IDFROM, "idFrom changed from 0x%Ix to 0x%Ix.\n", TEST_WM_NOTIFY_IDFROM, hdr->idFrom); + switch (test_WM_NOTIFY_state) { + case TEST_WM_NOTIFY_SIMPLE_FORWARD: + ok(hdr->code == TEST_WM_NOTIFY_SIMPLE_FORWARD_CODE, "code changed from 0x%x to 0x%x.\n", TEST_WM_NOTIFY_SIMPLE_FORWARD_CODE, hdr->code); + test_WM_NOTIFY_state = TEST_WM_NOTIFY_SIMPLE_FORWARD_DONE; + return TEST_WM_NOTIFY_RETURN; + case TEST_WM_NOTIFY_CONVERT_FORWARD: + ok(hdr->code == DTN_USERSTRINGA, "Wrong code 0x%x, should be 0x%x=DTN_USERSTRINGA.\n", hdr->code, DTN_USERSTRINGA); + ok(strcmp("DTN_USERSTRINGW test", ((NMDATETIMESTRINGA *)lParam)->pszUserString) == 0, "pszUserString converted incorrectly.\n"); + test_WM_NOTIFY_state = TEST_WM_NOTIFY_CONVERT_FORWARD_DONE; + return TEST_WM_NOTIFY_RETURN; + default: + ok(FALSE, "Got unexpected WM_NOTIFY.\n"); + return 0; + } + } switch (hdr->code) { case TBN_HOTITEMCHANGE: @@ -428,7 +464,7 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, switch (message) { case WM_NOTIFY: - return parent_wnd_notify(lParam); + return parent_wnd_notify(wParam, lParam); } defwndproc_counter++; @@ -2833,6 +2869,65 @@ static void test_BTNS_SEP(void) DestroyWindow(hwnd); } +static void test_WM_NOTIFY(void) +{ + HWND toolbar = NULL; + LRESULT ret; + + rebuild_toolbar(&toolbar); + + test_WM_NOTIFY_state = TEST_WM_NOTIFY_SIMPLE_FORWARD; + { + NMHDR nm = + { + .hwndFrom = TEST_WM_NOTIFY_HWNDFROM, + .idFrom = TEST_WM_NOTIFY_IDFROM, + .code = TEST_WM_NOTIFY_SIMPLE_FORWARD_CODE + }; + test_WM_NOTIFY_nmhdr = &nm; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&nm); + } + todo_wine ok(ret == TEST_WM_NOTIFY_RETURN, "SendMessageA returned 0x%Ix.\n", ret); + todo_wine ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_SIMPLE_FORWARD_DONE, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + + test_WM_NOTIFY_state = TEST_WM_NOTIFY_CONVERT_FORWARD; + { + NMDATETIMESTRINGW nm = + { + .nmhdr = { + .hwndFrom = TEST_WM_NOTIFY_HWNDFROM, + .idFrom = TEST_WM_NOTIFY_IDFROM, + .code = DTN_USERSTRINGW + }, + .pszUserString = u"DTN_USERSTRINGW test" + /* .st and .dwFlags zero */ + }; + test_WM_NOTIFY_nmhdr = &nm.nmhdr; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&nm); + } + todo_wine ok(ret == TEST_WM_NOTIFY_RETURN, "SendMessageA returned 0x%Ix.\n", ret); + todo_wine ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_CONVERT_FORWARD_DONE, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + + test_WM_NOTIFY_state = TEST_WM_NOTIFY_NO_FORWARD; + { + NMHDR nm = + { + .hwndFrom = TEST_WM_NOTIFY_HWNDFROM, + .idFrom = TEST_WM_NOTIFY_IDFROM, + .code = TEST_WM_NOTIFY_NO_FORWARD_CODE + }; + + test_WM_NOTIFY_nmhdr = &nm; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&nm); + } + ok(ret == 0, "SendMessageA returned 0x%Ix.\n", ret); + ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_NO_FORWARD, "Toolbar forwarded WM_NOTIFY to parent.\n"); + + test_WM_NOTIFY_state = TEST_WM_NOTIFY_NONE; + test_WM_NOTIFY_nmhdr = NULL; + DestroyWindow(toolbar); +} + START_TEST(toolbar) { ULONG_PTR ctx_cookie; @@ -2884,6 +2979,7 @@ START_TEST(toolbar) test_drawtext_flags(); test_imagelist(); test_BTNS_SEP(); + test_WM_NOTIFY(); if (!load_v6_module(&ctx_cookie, &ctx)) return; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6737
From: Alanas <alanas.00(a)mail.ru> It will be needed for toolbar.c. Also rewrite COMCTL32_AdjustUnicodeBuffer (was PAGER_AdjustBuffer): • Multiplication by 2 (also known as sizeof(WCHAR)) happens inside COMCTL32_AdjustUnicodeBuffer. • Use DWORD instead of INT for COMCTL32_UnicodeBuffer.sizeInBytes for consistency with Alloc and negative buffer size doesn't make sense. • Don't forget old COMCTL32_UnicodeBuffer.address when ReAlloc returns NULL. --- dlls/comctl32/comctl32.h | 12 ++ dlls/comctl32/commctrl.c | 439 +++++++++++++++++++++++++++++++++++++++ dlls/comctl32/pager.c | 432 +------------------------------------- 3 files changed, 454 insertions(+), 429 deletions(-) diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index f44b4ae132f..87346a08420 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -216,6 +216,18 @@ typedef struct int running; } SUBCLASS_INFO, *LPSUBCLASS_INFO; +/* WM_NOTIFY unicode -> ansi conversion and forwarding stuff */ + +/* COMCTL32_UnicodeBuffer is for storing result of ansi -> unicode conversion that happens after SendMessageW */ +/* (b.address==NULL)==(b.sizeInBytes==0) && (b.sizeInBytes&1)==0 should always be true (b is COMCTL32_UnicodeBuffer) */ +typedef struct +{ + WCHAR *address; + DWORD sizeInBytes; +} COMCTL32_UnicodeBuffer; + +LRESULT COMCTL32_ForwardNotifyToAnsiWindow(HWND hwndNotify, NMHDR *hdr, COMCTL32_UnicodeBuffer *unicodeBuffer); + /* undocumented functions */ BOOL WINAPI Free (LPVOID); diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index d87e63e813e..44a883d782a 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -2691,3 +2691,442 @@ LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, D return DoNotify(¬ify, code, hdr); } + +/* Text field conversion behavior flags for COMCTL32_SendConvertedNotify() */ +enum conversion_flags +{ + /* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */ + CONVERT_SEND = 0x01, + /* Convert ANSI text from parent back to Unicode for children */ + CONVERT_RECEIVE = 0x02, + /* Send empty text to parent if text is NULL. Original text pointer still remains NULL */ + SEND_EMPTY_IF_NULL = 0x04, + /* Set text to null after parent received the notification if the required mask is not set before sending notification */ + SET_NULL_IF_NO_MASK = 0x08, + /* Zero out the text buffer before sending it to parent */ + ZERO_SEND = 0x10 +}; + +static UINT COMCTL32_GetAnsiNtfCode(UINT code) +{ + switch (code) + { + /* ComboxBoxEx */ + case CBEN_DRAGBEGINW: return CBEN_DRAGBEGINA; + case CBEN_ENDEDITW: return CBEN_ENDEDITA; + case CBEN_GETDISPINFOW: return CBEN_GETDISPINFOA; + /* Date and Time Picker */ + case DTN_FORMATW: return DTN_FORMATA; + case DTN_FORMATQUERYW: return DTN_FORMATQUERYA; + case DTN_USERSTRINGW: return DTN_USERSTRINGA; + case DTN_WMKEYDOWNW: return DTN_WMKEYDOWNA; + /* Header */ + case HDN_BEGINTRACKW: return HDN_BEGINTRACKA; + case HDN_DIVIDERDBLCLICKW: return HDN_DIVIDERDBLCLICKA; + case HDN_ENDTRACKW: return HDN_ENDTRACKA; + case HDN_GETDISPINFOW: return HDN_GETDISPINFOA; + case HDN_ITEMCHANGEDW: return HDN_ITEMCHANGEDA; + case HDN_ITEMCHANGINGW: return HDN_ITEMCHANGINGA; + case HDN_ITEMCLICKW: return HDN_ITEMCLICKA; + case HDN_ITEMDBLCLICKW: return HDN_ITEMDBLCLICKA; + case HDN_TRACKW: return HDN_TRACKA; + /* List View */ + case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA; + case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA; + case LVN_GETDISPINFOW: return LVN_GETDISPINFOA; + case LVN_GETINFOTIPW: return LVN_GETINFOTIPA; + case LVN_INCREMENTALSEARCHW: return LVN_INCREMENTALSEARCHA; + case LVN_ODFINDITEMW: return LVN_ODFINDITEMA; + case LVN_SETDISPINFOW: return LVN_SETDISPINFOA; + /* Toolbar */ + case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA; + case TBN_GETINFOTIPW: return TBN_GETINFOTIPA; + /* Tooltip */ + case TTN_GETDISPINFOW: return TTN_GETDISPINFOA; + /* Tree View */ + case TVN_BEGINDRAGW: return TVN_BEGINDRAGA; + case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA; + case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA; + case TVN_DELETEITEMW: return TVN_DELETEITEMA; + case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA; + case TVN_GETDISPINFOW: return TVN_GETDISPINFOA; + case TVN_GETINFOTIPW: return TVN_GETINFOTIPA; + case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA; + case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA; + case TVN_SELCHANGEDW: return TVN_SELCHANGEDA; + case TVN_SELCHANGINGW: return TVN_SELCHANGINGA; + case TVN_SETDISPINFOW: return TVN_SETDISPINFOA; + } + return code; +} + +/* grow a COMCTL32_UnicodeBuffer if needed so it can hold at least minWChars WCHARs */ +/* return FALSE means failed (unicodeBuffer still valid but too small) */ +/* return TRUE means successful */ +static BOOL COMCTL32_AdjustUnicodeBuffer(COMCTL32_UnicodeBuffer *unicodeBuffer, DWORD minWChars) +{ + WCHAR *address; + DWORD minSizeInBytes; + + if (minWChars > 0x7fffffff) + return FALSE; + minSizeInBytes = minWChars*sizeof(WCHAR); + if (unicodeBuffer->sizeInBytes >= minSizeInBytes) + return TRUE; + address = unicodeBuffer->address; + address = address ? ReAlloc(address, minSizeInBytes) : Alloc(minSizeInBytes); + if (!address) + return FALSE; + *unicodeBuffer = (COMCTL32_UnicodeBuffer) { + .address = address, + .sizeInBytes = minSizeInBytes + }; + return TRUE; +} + +/* Convert text to Unicode and return the original text address */ +static WCHAR *COMCTL32_ConvertText(WCHAR **text) +{ + WCHAR *oldText = *text; + *text = NULL; + Str_SetPtrWtoA((CHAR **)text, oldText); + return oldText; +} + +static void COMCTL32_RestoreText(WCHAR **text, WCHAR *oldText) +{ + if (!oldText) return; + + Free(*text); + *text = oldText; +} + +static LRESULT COMCTL32_SendConvertedNotify(HWND hwndNotify, NMHDR *hdr, UINT *mask, UINT requiredMask, WCHAR **text, + INT *textMax, DWORD flags) +{ + CHAR *sendBuffer = NULL; + CHAR *receiveBuffer; + INT bufferSize; + WCHAR *oldText; + INT oldTextMax; + LRESULT ret = NO_ERROR; + + oldText = *text; + oldTextMax = textMax ? *textMax : 0; + + hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code); + + if (mask && !(*mask & requiredMask)) + { + ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + if (flags & SET_NULL_IF_NO_MASK) oldText = NULL; + goto done; + } + + if (oldTextMax < 0) goto done; + + if ((*text && flags & (CONVERT_SEND | ZERO_SEND)) || (!*text && flags & SEND_EMPTY_IF_NULL)) + { + bufferSize = textMax ? *textMax : lstrlenW(*text) + 1; + sendBuffer = Alloc(bufferSize); + if (!sendBuffer) goto done; + if (!(flags & ZERO_SEND)) WideCharToMultiByte(CP_ACP, 0, *text, -1, sendBuffer, bufferSize, NULL, FALSE); + *text = (WCHAR *)sendBuffer; + } + + ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + + if (*text && oldText && (flags & CONVERT_RECEIVE)) + { + /* MultiByteToWideChar requires that source and destination are not the same buffer */ + if (*text == oldText) + { + bufferSize = lstrlenA((CHAR *)*text) + 1; + receiveBuffer = Alloc(bufferSize); + if (!receiveBuffer) goto done; + memcpy(receiveBuffer, *text, bufferSize); + MultiByteToWideChar(CP_ACP, 0, receiveBuffer, bufferSize, oldText, oldTextMax); + Free(receiveBuffer); + } + else + MultiByteToWideChar(CP_ACP, 0, (CHAR *)*text, -1, oldText, oldTextMax); + } + +done: + Free(sendBuffer); + *text = oldText; + return ret; +} + +LRESULT COMCTL32_ForwardNotifyToAnsiWindow(HWND hwndNotify, NMHDR *hdr, COMCTL32_UnicodeBuffer *unicodeBuffer) +{ + LRESULT ret; + + switch (hdr->code) + { + /* ComboBoxEx */ + case CBEN_GETDISPINFOW: + { + NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmcbe->ceItem.mask, CBEIF_TEXT, &nmcbe->ceItem.pszText, + &nmcbe->ceItem.cchTextMax, ZERO_SEND | SET_NULL_IF_NO_MASK | CONVERT_RECEIVE); + } + case CBEN_DRAGBEGINW: + { + NMCBEDRAGBEGINW *nmdbW = (NMCBEDRAGBEGINW *)hdr; + NMCBEDRAGBEGINA nmdbA = {{0}}; + nmdbA.hdr.code = COMCTL32_GetAnsiNtfCode(nmdbW->hdr.code); + nmdbA.hdr.hwndFrom = nmdbW->hdr.hwndFrom; + nmdbA.hdr.idFrom = nmdbW->hdr.idFrom; + nmdbA.iItemid = nmdbW->iItemid; + WideCharToMultiByte(CP_ACP, 0, nmdbW->szText, ARRAY_SIZE(nmdbW->szText), nmdbA.szText, ARRAY_SIZE(nmdbA.szText), + NULL, FALSE); + return SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmdbA); + } + case CBEN_ENDEDITW: + { + NMCBEENDEDITW *nmedW = (NMCBEENDEDITW *)hdr; + NMCBEENDEDITA nmedA = {{0}}; + nmedA.hdr.code = COMCTL32_GetAnsiNtfCode(nmedW->hdr.code); + nmedA.hdr.hwndFrom = nmedW->hdr.hwndFrom; + nmedA.hdr.idFrom = nmedW->hdr.idFrom; + nmedA.fChanged = nmedW->fChanged; + nmedA.iNewSelection = nmedW->iNewSelection; + nmedA.iWhy = nmedW->iWhy; + WideCharToMultiByte(CP_ACP, 0, nmedW->szText, ARRAY_SIZE(nmedW->szText), nmedA.szText, ARRAY_SIZE(nmedA.szText), + NULL, FALSE); + return SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmedA); + } + /* Date and Time Picker */ + case DTN_FORMATW: + { + NMDATETIMEFORMATW *nmdtf = (NMDATETIMEFORMATW *)hdr; + WCHAR *oldFormat; + DWORD textLength; + + hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code); + oldFormat = COMCTL32_ConvertText((WCHAR **)&nmdtf->pszFormat); + ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)nmdtf); + COMCTL32_RestoreText((WCHAR **)&nmdtf->pszFormat, oldFormat); + + if (nmdtf->pszDisplay) + { + textLength = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, 0, 0); + if (!COMCTL32_AdjustUnicodeBuffer(unicodeBuffer, textLength)) return ret; + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, unicodeBuffer->address, textLength); + if (nmdtf->pszDisplay != nmdtf->szDisplay) + nmdtf->pszDisplay = unicodeBuffer->address; + else + { + textLength = min(textLength, ARRAY_SIZE(nmdtf->szDisplay)); + memcpy(nmdtf->szDisplay, unicodeBuffer->address, textLength * sizeof(WCHAR)); + } + } + + return ret; + } + case DTN_FORMATQUERYW: + { + NMDATETIMEFORMATQUERYW *nmdtfq = (NMDATETIMEFORMATQUERYW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, (WCHAR **)&nmdtfq->pszFormat, NULL, CONVERT_SEND); + } + case DTN_WMKEYDOWNW: + { + NMDATETIMEWMKEYDOWNW *nmdtkd = (NMDATETIMEWMKEYDOWNW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, (WCHAR **)&nmdtkd->pszFormat, NULL, CONVERT_SEND); + } + case DTN_USERSTRINGW: + { + NMDATETIMESTRINGW *nmdts = (NMDATETIMESTRINGW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, (WCHAR **)&nmdts->pszUserString, NULL, CONVERT_SEND); + } + /* Header */ + case HDN_BEGINTRACKW: + case HDN_DIVIDERDBLCLICKW: + case HDN_ENDTRACKW: + case HDN_ITEMCHANGEDW: + case HDN_ITEMCHANGINGW: + case HDN_ITEMCLICKW: + case HDN_ITEMDBLCLICKW: + case HDN_TRACKW: + { + NMHEADERW *nmh = (NMHEADERW *)hdr; + WCHAR *oldText = NULL, *oldFilterText = NULL; + HD_TEXTFILTERW *tf = NULL; + + hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code); + + if (!nmh->pitem) return SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + if (nmh->pitem->mask & HDI_TEXT) oldText = COMCTL32_ConvertText(&nmh->pitem->pszText); + if ((nmh->pitem->mask & HDI_FILTER) && (nmh->pitem->type == HDFT_ISSTRING) && nmh->pitem->pvFilter) + { + tf = (HD_TEXTFILTERW *)nmh->pitem->pvFilter; + oldFilterText = COMCTL32_ConvertText(&tf->pszText); + } + ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + COMCTL32_RestoreText(&nmh->pitem->pszText, oldText); + if (tf) COMCTL32_RestoreText(&tf->pszText, oldFilterText); + return ret; + } + case HDN_GETDISPINFOW: + { + NMHDDISPINFOW *nmhddi = (NMHDDISPINFOW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmhddi->mask, HDI_TEXT, &nmhddi->pszText, &nmhddi->cchTextMax, + SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE); + } + /* List View */ + case LVN_BEGINLABELEDITW: + case LVN_ENDLABELEDITW: + case LVN_SETDISPINFOW: + { + NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText, + &nmlvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE); + } + case LVN_GETDISPINFOW: + { + NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText, + &nmlvdi->item.cchTextMax, CONVERT_RECEIVE); + } + case LVN_GETINFOTIPW: + { + NMLVGETINFOTIPW *nmlvgit = (NMLVGETINFOTIPW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, &nmlvgit->pszText, &nmlvgit->cchTextMax, + CONVERT_SEND | CONVERT_RECEIVE); + } + case LVN_INCREMENTALSEARCHW: + case LVN_ODFINDITEMW: + { + NMLVFINDITEMW *nmlvfi = (NMLVFINDITEMW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmlvfi->lvfi.flags, LVFI_STRING | LVFI_SUBSTRING, + (WCHAR **)&nmlvfi->lvfi.psz, NULL, CONVERT_SEND); + } + /* Toolbar */ + case TBN_GETBUTTONINFOW: + { + NMTOOLBARW *nmtb = (NMTOOLBARW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, &nmtb->pszText, &nmtb->cchText, + SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE); + } + case TBN_GETINFOTIPW: + { + NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, &nmtbgit->pszText, &nmtbgit->cchTextMax, CONVERT_RECEIVE); + } + /* Tooltip */ + case TTN_GETDISPINFOW: + { + NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr; + NMTTDISPINFOA nmttdiA = {{0}}; + DWORD size; + + nmttdiA.hdr.code = COMCTL32_GetAnsiNtfCode(nmttdiW->hdr.code); + nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom; + nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom; + nmttdiA.hinst = nmttdiW->hinst; + nmttdiA.uFlags = nmttdiW->uFlags; + nmttdiA.lParam = nmttdiW->lParam; + nmttdiA.lpszText = nmttdiA.szText; + WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText, + ARRAY_SIZE(nmttdiA.szText), NULL, FALSE); + + ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmttdiA); + + nmttdiW->hinst = nmttdiA.hinst; + nmttdiW->uFlags = nmttdiA.uFlags; + nmttdiW->lParam = nmttdiA.lParam; + + MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText), nmttdiW->szText, + ARRAY_SIZE(nmttdiW->szText)); + if (!nmttdiA.lpszText) + nmttdiW->lpszText = nmttdiW->szText; + else if (!IS_INTRESOURCE(nmttdiA.lpszText)) + { + size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0); + if (size > ARRAY_SIZE(nmttdiW->szText)) + { + if (!COMCTL32_AdjustUnicodeBuffer(unicodeBuffer, size)) return ret; + MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, unicodeBuffer->address, size); + nmttdiW->lpszText = unicodeBuffer->address; + /* Override content in szText */ + memcpy(nmttdiW->szText, nmttdiW->lpszText, min(sizeof(nmttdiW->szText), size * sizeof(WCHAR))); + } + else + { + MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText)); + nmttdiW->lpszText = nmttdiW->szText; + } + } + else + { + nmttdiW->szText[0] = 0; + nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText; + } + + return ret; + } + /* Tree View */ + case TVN_BEGINDRAGW: + case TVN_BEGINRDRAGW: + case TVN_ITEMEXPANDEDW: + case TVN_ITEMEXPANDINGW: + { + NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmtv->itemNew.mask, TVIF_TEXT, &nmtv->itemNew.pszText, NULL, + CONVERT_SEND); + } + case TVN_DELETEITEMW: + { + NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmtv->itemOld.mask, TVIF_TEXT, &nmtv->itemOld.pszText, NULL, + CONVERT_SEND); + } + case TVN_BEGINLABELEDITW: + case TVN_ENDLABELEDITW: + { + NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText, + &nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE); + } + case TVN_SELCHANGINGW: + case TVN_SELCHANGEDW: + { + NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr; + WCHAR *oldItemOldText = NULL; + WCHAR *oldItemNewText = NULL; + + hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code); + + if (!((nmtv->itemNew.mask | nmtv->itemOld.mask) & TVIF_TEXT)) + return SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + + if (nmtv->itemOld.mask & TVIF_TEXT) oldItemOldText = COMCTL32_ConvertText(&nmtv->itemOld.pszText); + if (nmtv->itemNew.mask & TVIF_TEXT) oldItemNewText = COMCTL32_ConvertText(&nmtv->itemNew.pszText); + + ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + COMCTL32_RestoreText(&nmtv->itemOld.pszText, oldItemOldText); + COMCTL32_RestoreText(&nmtv->itemNew.pszText, oldItemNewText); + return ret; + } + case TVN_GETDISPINFOW: + { + NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText, + &nmtvdi->item.cchTextMax, ZERO_SEND | CONVERT_RECEIVE); + } + case TVN_SETDISPINFOW: + { + NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText, + &nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE); + } + case TVN_GETINFOTIPW: + { + NMTVGETINFOTIPW *nmtvgit = (NMTVGETINFOTIPW *)hdr; + return COMCTL32_SendConvertedNotify(hwndNotify, hdr, NULL, 0, &nmtvgit->pszText, &nmtvgit->cchTextMax, CONVERT_RECEIVE); + } + } + /* Other notifications, no need to convert */ + return SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); +} diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c index 07484c6ebf5..cb889177fe4 100644 --- a/dlls/comctl32/pager.c +++ b/dlls/comctl32/pager.c @@ -84,8 +84,7 @@ typedef struct INT TLbtnState; /* state of top or left btn */ INT BRbtnState; /* state of bottom or right btn */ INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */ - WCHAR *pwszBuffer;/* text buffer for converted notifications */ - INT nBufferSize;/* size of the above buffer */ + COMCTL32_UnicodeBuffer unicodeBuffer;/* used in WN_NOTIFY forwarding if bUnicode */ } PAGER_INFO; #define TIMERID1 1 @@ -93,21 +92,6 @@ typedef struct #define INITIAL_DELAY 500 #define REPEAT_DELAY 50 -/* Text field conversion behavior flags for PAGER_SendConvertedNotify() */ -enum conversion_flags -{ - /* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */ - CONVERT_SEND = 0x01, - /* Convert ANSI text from parent back to Unicode for children */ - CONVERT_RECEIVE = 0x02, - /* Send empty text to parent if text is NULL. Original text pointer still remains NULL */ - SEND_EMPTY_IF_NULL = 0x04, - /* Set text to null after parent received the notification if the required mask is not set before sending notification */ - SET_NULL_IF_NO_MASK = 0x08, - /* Zero out the text buffer before sending it to parent */ - ZERO_SEND = 0x10 -}; - static void PAGER_GetButtonRects(const PAGER_INFO* infoPtr, RECT* prcTopLeft, RECT* prcBottomRight, BOOL bClientCoords) { @@ -611,7 +595,7 @@ static LRESULT PAGER_Destroy (PAGER_INFO *infoPtr) { SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); - Free (infoPtr->pwszBuffer); + Free (infoPtr->unicodeBuffer.address); Free (infoPtr); return 0; } @@ -1043,419 +1027,9 @@ static LRESULT PAGER_NotifyFormat(PAGER_INFO *infoPtr, INT command) } } -static UINT PAGER_GetAnsiNtfCode(UINT code) -{ - switch (code) - { - /* ComboxBoxEx */ - case CBEN_DRAGBEGINW: return CBEN_DRAGBEGINA; - case CBEN_ENDEDITW: return CBEN_ENDEDITA; - case CBEN_GETDISPINFOW: return CBEN_GETDISPINFOA; - /* Date and Time Picker */ - case DTN_FORMATW: return DTN_FORMATA; - case DTN_FORMATQUERYW: return DTN_FORMATQUERYA; - case DTN_USERSTRINGW: return DTN_USERSTRINGA; - case DTN_WMKEYDOWNW: return DTN_WMKEYDOWNA; - /* Header */ - case HDN_BEGINTRACKW: return HDN_BEGINTRACKA; - case HDN_DIVIDERDBLCLICKW: return HDN_DIVIDERDBLCLICKA; - case HDN_ENDTRACKW: return HDN_ENDTRACKA; - case HDN_GETDISPINFOW: return HDN_GETDISPINFOA; - case HDN_ITEMCHANGEDW: return HDN_ITEMCHANGEDA; - case HDN_ITEMCHANGINGW: return HDN_ITEMCHANGINGA; - case HDN_ITEMCLICKW: return HDN_ITEMCLICKA; - case HDN_ITEMDBLCLICKW: return HDN_ITEMDBLCLICKA; - case HDN_TRACKW: return HDN_TRACKA; - /* List View */ - case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA; - case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA; - case LVN_GETDISPINFOW: return LVN_GETDISPINFOA; - case LVN_GETINFOTIPW: return LVN_GETINFOTIPA; - case LVN_INCREMENTALSEARCHW: return LVN_INCREMENTALSEARCHA; - case LVN_ODFINDITEMW: return LVN_ODFINDITEMA; - case LVN_SETDISPINFOW: return LVN_SETDISPINFOA; - /* Toolbar */ - case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA; - case TBN_GETINFOTIPW: return TBN_GETINFOTIPA; - /* Tooltip */ - case TTN_GETDISPINFOW: return TTN_GETDISPINFOA; - /* Tree View */ - case TVN_BEGINDRAGW: return TVN_BEGINDRAGA; - case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA; - case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA; - case TVN_DELETEITEMW: return TVN_DELETEITEMA; - case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA; - case TVN_GETDISPINFOW: return TVN_GETDISPINFOA; - case TVN_GETINFOTIPW: return TVN_GETINFOTIPA; - case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA; - case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA; - case TVN_SELCHANGEDW: return TVN_SELCHANGEDA; - case TVN_SELCHANGINGW: return TVN_SELCHANGINGA; - case TVN_SETDISPINFOW: return TVN_SETDISPINFOA; - } - return code; -} - -static BOOL PAGER_AdjustBuffer(PAGER_INFO *infoPtr, INT size) -{ - if (!infoPtr->pwszBuffer) - infoPtr->pwszBuffer = Alloc(size); - else if (infoPtr->nBufferSize < size) - infoPtr->pwszBuffer = ReAlloc(infoPtr->pwszBuffer, size); - - if (!infoPtr->pwszBuffer) return FALSE; - if (infoPtr->nBufferSize < size) infoPtr->nBufferSize = size; - - return TRUE; -} - -/* Convert text to Unicode and return the original text address */ -static WCHAR *PAGER_ConvertText(WCHAR **text) -{ - WCHAR *oldText = *text; - *text = NULL; - Str_SetPtrWtoA((CHAR **)text, oldText); - return oldText; -} - -static void PAGER_RestoreText(WCHAR **text, WCHAR *oldText) -{ - if (!oldText) return; - - Free(*text); - *text = oldText; -} - -static LRESULT PAGER_SendConvertedNotify(PAGER_INFO *infoPtr, NMHDR *hdr, UINT *mask, UINT requiredMask, WCHAR **text, - INT *textMax, DWORD flags) -{ - CHAR *sendBuffer = NULL; - CHAR *receiveBuffer; - INT bufferSize; - WCHAR *oldText; - INT oldTextMax; - LRESULT ret = NO_ERROR; - - oldText = *text; - oldTextMax = textMax ? *textMax : 0; - - hdr->code = PAGER_GetAnsiNtfCode(hdr->code); - - if (mask && !(*mask & requiredMask)) - { - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - if (flags & SET_NULL_IF_NO_MASK) oldText = NULL; - goto done; - } - - if (oldTextMax < 0) goto done; - - if ((*text && flags & (CONVERT_SEND | ZERO_SEND)) || (!*text && flags & SEND_EMPTY_IF_NULL)) - { - bufferSize = textMax ? *textMax : lstrlenW(*text) + 1; - sendBuffer = Alloc(bufferSize); - if (!sendBuffer) goto done; - if (!(flags & ZERO_SEND)) WideCharToMultiByte(CP_ACP, 0, *text, -1, sendBuffer, bufferSize, NULL, FALSE); - *text = (WCHAR *)sendBuffer; - } - - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - - if (*text && oldText && (flags & CONVERT_RECEIVE)) - { - /* MultiByteToWideChar requires that source and destination are not the same buffer */ - if (*text == oldText) - { - bufferSize = lstrlenA((CHAR *)*text) + 1; - receiveBuffer = Alloc(bufferSize); - if (!receiveBuffer) goto done; - memcpy(receiveBuffer, *text, bufferSize); - MultiByteToWideChar(CP_ACP, 0, receiveBuffer, bufferSize, oldText, oldTextMax); - Free(receiveBuffer); - } - else - MultiByteToWideChar(CP_ACP, 0, (CHAR *)*text, -1, oldText, oldTextMax); - } - -done: - Free(sendBuffer); - *text = oldText; - return ret; -} - static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr) { - LRESULT ret; - - if (infoPtr->bUnicode) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - - switch (hdr->code) - { - /* ComboBoxEx */ - case CBEN_GETDISPINFOW: - { - NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmcbe->ceItem.mask, CBEIF_TEXT, &nmcbe->ceItem.pszText, - &nmcbe->ceItem.cchTextMax, ZERO_SEND | SET_NULL_IF_NO_MASK | CONVERT_RECEIVE); - } - case CBEN_DRAGBEGINW: - { - NMCBEDRAGBEGINW *nmdbW = (NMCBEDRAGBEGINW *)hdr; - NMCBEDRAGBEGINA nmdbA = {{0}}; - nmdbA.hdr.code = PAGER_GetAnsiNtfCode(nmdbW->hdr.code); - nmdbA.hdr.hwndFrom = nmdbW->hdr.hwndFrom; - nmdbA.hdr.idFrom = nmdbW->hdr.idFrom; - nmdbA.iItemid = nmdbW->iItemid; - WideCharToMultiByte(CP_ACP, 0, nmdbW->szText, ARRAY_SIZE(nmdbW->szText), nmdbA.szText, ARRAY_SIZE(nmdbA.szText), - NULL, FALSE); - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmdbA); - } - case CBEN_ENDEDITW: - { - NMCBEENDEDITW *nmedW = (NMCBEENDEDITW *)hdr; - NMCBEENDEDITA nmedA = {{0}}; - nmedA.hdr.code = PAGER_GetAnsiNtfCode(nmedW->hdr.code); - nmedA.hdr.hwndFrom = nmedW->hdr.hwndFrom; - nmedA.hdr.idFrom = nmedW->hdr.idFrom; - nmedA.fChanged = nmedW->fChanged; - nmedA.iNewSelection = nmedW->iNewSelection; - nmedA.iWhy = nmedW->iWhy; - WideCharToMultiByte(CP_ACP, 0, nmedW->szText, ARRAY_SIZE(nmedW->szText), nmedA.szText, ARRAY_SIZE(nmedA.szText), - NULL, FALSE); - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmedA); - } - /* Date and Time Picker */ - case DTN_FORMATW: - { - NMDATETIMEFORMATW *nmdtf = (NMDATETIMEFORMATW *)hdr; - WCHAR *oldFormat; - INT textLength; - - hdr->code = PAGER_GetAnsiNtfCode(hdr->code); - oldFormat = PAGER_ConvertText((WCHAR **)&nmdtf->pszFormat); - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)nmdtf); - PAGER_RestoreText((WCHAR **)&nmdtf->pszFormat, oldFormat); - - if (nmdtf->pszDisplay) - { - textLength = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, 0, 0); - if (!PAGER_AdjustBuffer(infoPtr, textLength * sizeof(WCHAR))) return ret; - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, infoPtr->pwszBuffer, textLength); - if (nmdtf->pszDisplay != nmdtf->szDisplay) - nmdtf->pszDisplay = infoPtr->pwszBuffer; - else - { - textLength = min(textLength, ARRAY_SIZE(nmdtf->szDisplay)); - memcpy(nmdtf->szDisplay, infoPtr->pwszBuffer, textLength * sizeof(WCHAR)); - } - } - - return ret; - } - case DTN_FORMATQUERYW: - { - NMDATETIMEFORMATQUERYW *nmdtfq = (NMDATETIMEFORMATQUERYW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR **)&nmdtfq->pszFormat, NULL, CONVERT_SEND); - } - case DTN_WMKEYDOWNW: - { - NMDATETIMEWMKEYDOWNW *nmdtkd = (NMDATETIMEWMKEYDOWNW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR **)&nmdtkd->pszFormat, NULL, CONVERT_SEND); - } - case DTN_USERSTRINGW: - { - NMDATETIMESTRINGW *nmdts = (NMDATETIMESTRINGW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR **)&nmdts->pszUserString, NULL, CONVERT_SEND); - } - /* Header */ - case HDN_BEGINTRACKW: - case HDN_DIVIDERDBLCLICKW: - case HDN_ENDTRACKW: - case HDN_ITEMCHANGEDW: - case HDN_ITEMCHANGINGW: - case HDN_ITEMCLICKW: - case HDN_ITEMDBLCLICKW: - case HDN_TRACKW: - { - NMHEADERW *nmh = (NMHEADERW *)hdr; - WCHAR *oldText = NULL, *oldFilterText = NULL; - HD_TEXTFILTERW *tf = NULL; - - hdr->code = PAGER_GetAnsiNtfCode(hdr->code); - - if (!nmh->pitem) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - if (nmh->pitem->mask & HDI_TEXT) oldText = PAGER_ConvertText(&nmh->pitem->pszText); - if ((nmh->pitem->mask & HDI_FILTER) && (nmh->pitem->type == HDFT_ISSTRING) && nmh->pitem->pvFilter) - { - tf = (HD_TEXTFILTERW *)nmh->pitem->pvFilter; - oldFilterText = PAGER_ConvertText(&tf->pszText); - } - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - PAGER_RestoreText(&nmh->pitem->pszText, oldText); - if (tf) PAGER_RestoreText(&tf->pszText, oldFilterText); - return ret; - } - case HDN_GETDISPINFOW: - { - NMHDDISPINFOW *nmhddi = (NMHDDISPINFOW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmhddi->mask, HDI_TEXT, &nmhddi->pszText, &nmhddi->cchTextMax, - SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE); - } - /* List View */ - case LVN_BEGINLABELEDITW: - case LVN_ENDLABELEDITW: - case LVN_SETDISPINFOW: - { - NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText, - &nmlvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE); - } - case LVN_GETDISPINFOW: - { - NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText, - &nmlvdi->item.cchTextMax, CONVERT_RECEIVE); - } - case LVN_GETINFOTIPW: - { - NMLVGETINFOTIPW *nmlvgit = (NMLVGETINFOTIPW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmlvgit->pszText, &nmlvgit->cchTextMax, - CONVERT_SEND | CONVERT_RECEIVE); - } - case LVN_INCREMENTALSEARCHW: - case LVN_ODFINDITEMW: - { - NMLVFINDITEMW *nmlvfi = (NMLVFINDITEMW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmlvfi->lvfi.flags, LVFI_STRING | LVFI_SUBSTRING, - (WCHAR **)&nmlvfi->lvfi.psz, NULL, CONVERT_SEND); - } - /* Toolbar */ - case TBN_GETBUTTONINFOW: - { - NMTOOLBARW *nmtb = (NMTOOLBARW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmtb->pszText, &nmtb->cchText, - SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE); - } - case TBN_GETINFOTIPW: - { - NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmtbgit->pszText, &nmtbgit->cchTextMax, CONVERT_RECEIVE); - } - /* Tooltip */ - case TTN_GETDISPINFOW: - { - NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr; - NMTTDISPINFOA nmttdiA = {{0}}; - INT size; - - nmttdiA.hdr.code = PAGER_GetAnsiNtfCode(nmttdiW->hdr.code); - nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom; - nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom; - nmttdiA.hinst = nmttdiW->hinst; - nmttdiA.uFlags = nmttdiW->uFlags; - nmttdiA.lParam = nmttdiW->lParam; - nmttdiA.lpszText = nmttdiA.szText; - WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText, - ARRAY_SIZE(nmttdiA.szText), NULL, FALSE); - - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmttdiA); - - nmttdiW->hinst = nmttdiA.hinst; - nmttdiW->uFlags = nmttdiA.uFlags; - nmttdiW->lParam = nmttdiA.lParam; - - MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText), nmttdiW->szText, - ARRAY_SIZE(nmttdiW->szText)); - if (!nmttdiA.lpszText) - nmttdiW->lpszText = nmttdiW->szText; - else if (!IS_INTRESOURCE(nmttdiA.lpszText)) - { - size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0); - if (size > ARRAY_SIZE(nmttdiW->szText)) - { - if (!PAGER_AdjustBuffer(infoPtr, size * sizeof(WCHAR))) return ret; - MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, infoPtr->pwszBuffer, size); - nmttdiW->lpszText = infoPtr->pwszBuffer; - /* Override content in szText */ - memcpy(nmttdiW->szText, nmttdiW->lpszText, min(sizeof(nmttdiW->szText), size * sizeof(WCHAR))); - } - else - { - MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText)); - nmttdiW->lpszText = nmttdiW->szText; - } - } - else - { - nmttdiW->szText[0] = 0; - nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText; - } - - return ret; - } - /* Tree View */ - case TVN_BEGINDRAGW: - case TVN_BEGINRDRAGW: - case TVN_ITEMEXPANDEDW: - case TVN_ITEMEXPANDINGW: - { - NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtv->itemNew.mask, TVIF_TEXT, &nmtv->itemNew.pszText, NULL, - CONVERT_SEND); - } - case TVN_DELETEITEMW: - { - NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtv->itemOld.mask, TVIF_TEXT, &nmtv->itemOld.pszText, NULL, - CONVERT_SEND); - } - case TVN_BEGINLABELEDITW: - case TVN_ENDLABELEDITW: - { - NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText, - &nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE); - } - case TVN_SELCHANGINGW: - case TVN_SELCHANGEDW: - { - NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr; - WCHAR *oldItemOldText = NULL; - WCHAR *oldItemNewText = NULL; - - hdr->code = PAGER_GetAnsiNtfCode(hdr->code); - - if (!((nmtv->itemNew.mask | nmtv->itemOld.mask) & TVIF_TEXT)) - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - - if (nmtv->itemOld.mask & TVIF_TEXT) oldItemOldText = PAGER_ConvertText(&nmtv->itemOld.pszText); - if (nmtv->itemNew.mask & TVIF_TEXT) oldItemNewText = PAGER_ConvertText(&nmtv->itemNew.pszText); - - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); - PAGER_RestoreText(&nmtv->itemOld.pszText, oldItemOldText); - PAGER_RestoreText(&nmtv->itemNew.pszText, oldItemNewText); - return ret; - } - case TVN_GETDISPINFOW: - { - NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText, - &nmtvdi->item.cchTextMax, ZERO_SEND | CONVERT_RECEIVE); - } - case TVN_SETDISPINFOW: - { - NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText, - &nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE); - } - case TVN_GETINFOTIPW: - { - NMTVGETINFOTIPW *nmtvgit = (NMTVGETINFOTIPW *)hdr; - return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmtvgit->pszText, &nmtvgit->cchTextMax, CONVERT_RECEIVE); - } - } - /* Other notifications, no need to convert */ - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr); + return infoPtr->bUnicode ? SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr) : COMCTL32_ForwardNotifyToAnsiWindow(infoPtr->hwndNotify, hdr, &infoPtr->unicodeBuffer); } static LRESULT WINAPI -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6737
From: Alanas <alanas.00(a)mail.ru> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57178 --- dlls/comctl32/tests/toolbar.c | 8 ++++---- dlls/comctl32/toolbar.c | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index b780cc401f3..ddd8c5d1f40 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -2887,8 +2887,8 @@ static void test_WM_NOTIFY(void) test_WM_NOTIFY_nmhdr = &nm; ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&nm); } - todo_wine ok(ret == TEST_WM_NOTIFY_RETURN, "SendMessageA returned 0x%Ix.\n", ret); - todo_wine ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_SIMPLE_FORWARD_DONE, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + ok(ret == TEST_WM_NOTIFY_RETURN, "SendMessageA returned 0x%Ix.\n", ret); + ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_SIMPLE_FORWARD_DONE, "Toolbar didn't forward WM_NOTIFY to parent.\n"); test_WM_NOTIFY_state = TEST_WM_NOTIFY_CONVERT_FORWARD; { @@ -2905,8 +2905,8 @@ static void test_WM_NOTIFY(void) test_WM_NOTIFY_nmhdr = &nm.nmhdr; ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&nm); } - todo_wine ok(ret == TEST_WM_NOTIFY_RETURN, "SendMessageA returned 0x%Ix.\n", ret); - todo_wine ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_CONVERT_FORWARD_DONE, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + ok(ret == TEST_WM_NOTIFY_RETURN, "SendMessageA returned 0x%Ix.\n", ret); + ok(test_WM_NOTIFY_state == TEST_WM_NOTIFY_CONVERT_FORWARD_DONE, "Toolbar didn't forward WM_NOTIFY to parent.\n"); test_WM_NOTIFY_state = TEST_WM_NOTIFY_NO_FORWARD; { diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c index 690a02db6ee..1e198895698 100644 --- a/dlls/comctl32/toolbar.c +++ b/dlls/comctl32/toolbar.c @@ -172,6 +172,7 @@ typedef struct TBUTTON_INFO *buttons; /* pointer to button array */ LPWSTR *strings; /* pointer to string array */ TBITMAP_INFO *bitmaps; + COMCTL32_UnicodeBuffer unicodeBuffer;/* used in WN_NOTIFY forwarding if bUnicode */ } TOOLBAR_INFO, *PTOOLBAR_INFO; @@ -5348,6 +5349,7 @@ TOOLBAR_Destroy (TOOLBAR_INFO *infoPtr) DeleteObject (infoPtr->hDefaultFont); CloseThemeData (infoPtr->hTheme); + Free (infoPtr->unicodeBuffer.address); /* free toolbar info data */ SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); @@ -6357,11 +6359,18 @@ TOOLBAR_Notify (TOOLBAR_INFO *infoPtr, LPNMHDR lpnmh) case TTN_GETDISPINFOA: FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); + break; + } + /* note: PGN_LAST < PGN_FIRST */ + if (lpnmh->code >= PGN_LAST && lpnmh->code <= PGN_FIRST) return 0; - - default: - return 0; + if (infoPtr->bUnicode) + { + TRACE("forwarding 0x%x without unicode -> ansi conversion\n", lpnmh->code); + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->idFrom, (LPARAM)lpnmh); } + TRACE("forwarding 0x%x with unicode -> ansi conversion\n", lpnmh->code); + return COMCTL32_ForwardNotifyToAnsiWindow(infoPtr->hwndNotify, lpnmh, &infoPtr->unicodeBuffer); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6737
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149682 Your paranoid android. === build (build log) === error: patch failed: dlls/comctl32/comctl32.h:216 error: patch failed: dlls/comctl32/commctrl.c:2691 error: patch failed: dlls/comctl32/pager.c:84 Task: Patch failed to apply === debian11 (build log) === error: patch failed: dlls/comctl32/comctl32.h:216 error: patch failed: dlls/comctl32/commctrl.c:2691 error: patch failed: dlls/comctl32/pager.c:84 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/comctl32/comctl32.h:216 error: patch failed: dlls/comctl32/commctrl.c:2691 error: patch failed: dlls/comctl32/pager.c:84 Task: Patch failed to apply
Also add a TRACE() when forwarding notifications to hwndNotify.
OK, but [pager has no `TRACE`](https://gitlab.winehq.org/wine/wine/-/blob/ab40b7fd8686345bf77a27ceb12d4dfba...). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87654
On Fri Nov 15 20:40:35 2024 +0000, Zhiyi Zhang wrote: > I don't see the tests for comctl32 control notification codes. I added 3 tests: - forwarding nmhdr.code=0xabcd0004, not converted - forwarding nmhdr.code=DTN_USERSTRINGW, converted to DTN_USERSTRINGA - not forwarding nmhdr.code=0xfffffc69 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87655
I am not sure Alanas is your real
Yes.
and full
No (missing family name). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87656
Zhiyi Zhang (@zhiyi) commented about dlls/comctl32/toolbar.c:
FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); + break; + } + /* note: PGN_LAST < PGN_FIRST */ + if (lpnmh->code >= PGN_LAST && lpnmh->code <= PGN_FIRST) return 0; - - default: - return 0; + if (infoPtr->bUnicode) + { + TRACE("forwarding 0x%x without unicode -> ansi conversion\n", lpnmh->code); + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->idFrom, (LPARAM)lpnmh); } + TRACE("forwarding 0x%x with unicode -> ansi conversion\n", lpnmh->code); + return COMCTL32_ForwardNotifyToAnsiWindow(infoPtr->hwndNotify, lpnmh, &infoPtr->unicodeBuffer);
I think this is getting too complicated. What notification does 7-zip file manager need to get winehq bug 57178 fixed? It would be best to focus on that first instead of forwarding a bunch of unrelated notifications. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87798
On Fri Nov 15 20:48:01 2024 +0000, Alanas wrote:
I am not sure Alanas is your real Yes. and full No (missing family name). Your family name is still missing.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87799
I think this is getting too complicated.
Windows XP Professional x64 Edition's `comctl32.dll` is more complicated.
What notification does 7-zip file manager need
Forwarding [`CBEN_ENDEDITW`](https://learn.microsoft.com/en-us/windows/win32/controls/cben-endedit) is enough to make pressing enter in 7-zip file manager's path input work. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87804
Forwarding [`CBEN_ENDEDITW`](https://learn.microsoft.com/en-us/windows/win32/controls/cben-endedit) is enough to make pressing enter in 7-zip file manager's path input work.
In that case, add a case in toolbar to handle CBEN_ENDEDITW only. Also, you can test only CBEN_ENDEDITW instead of unrelated notification codes. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87805
In that case, add a case in toolbar to handle CBEN_ENDEDITW only.
7-zip file manager's toolbar's parent is unicode (no unicode -> ansi conversion when forwarding). [`dlls/comctl32/tests/toolbar.c`](https://gitlab.winehq.org/wine/wine/-/blob/ae6366b33c7a6a40802034bc4d12eaf31103e05a/dlls/comctl32/tests/toolbar.c#L435)'s toolbar's parent is ansi (`CBEN_ENDEDITW` converted to `CBEN_ENDEDITA` if running in windows xp professional x64 edition service pack 2). Should wine's `comctl32.dll` toolbar support unicode -> ansi conversion? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87829
`CBEN_ENDEDITW` converted to `CBEN_ENDEDITA` if running in windows xp professional x64 edition service pack 2
Does it happen for other Windows versions as well? If so, then yes, we should support converting CBEN_ENDEDITW to CBEN_ENDEDITA. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87830
Windows XP Professional x64 Edition's `comctl32.dll` is more complicated.
I don't doubt that. But let's focus on getting the bug fixed first. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87831
`CBEN_ENDEDITW` converted to `CBEN_ENDEDITA` if running in windows xp professional x64 edition service pack 2
Does it happen for other Windows versions as well?
Also happens in windows 7 ultimate service pack 1 x64 ([tested both 64 bit program and 32 bit program](/uploads/ae3424dca3c4044ce78a6f2888b4c409/toolbartest1.c)). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87833
In that case, add a case in toolbar to handle CBEN_ENDEDITW only.
Done but [outside this merge request](https://gitlab.winehq.org/BZZZZ/wine/-/compare/master...7zFM?from_project_id...). Should I create another merge request or overwrite this one? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87840
On Mon Nov 18 13:43:45 2024 +0000, Alanas wrote:
In that case, add a case in toolbar to handle CBEN_ENDEDITW only. Done but [outside this merge request](https://gitlab.winehq.org/BZZZZ/wine/-/compare/master...7zFM?from_project_id...). Should I create another merge request or overwrite this one? You should push to this one since it's for fixing the 7-zip bug.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_87850
participants (4)
-
Alanas -
Alanas (@BZZZZ) -
Marvin -
Zhiyi Zhang (@zhiyi)