[PATCH v14 0/3] MR6737: comctl32/toolbar: forward WM_NOTIFY CBEN_ENDEDITW
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). -- v14: comctl32/toolbar: Forward WM_NOTIFY CBEN_ENDEDITW. comctl32: Move WM_NOTIFY unicode to ansi conversion code from pager.c to commctrl.c. comctl32/tests: Test WM_NOTIFY CBEN_ENDEDITW conversion and forwarding in toolbar. https://gitlab.winehq.org/wine/wine/-/merge_requests/6737
From: Alanas Tebuev <alanas.00(a)mail.ru> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57178 --- dlls/comctl32/tests/toolbar.c | 80 ++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index 7c886e1f88f..e57635f30a9 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -179,13 +179,62 @@ static BOOL equal_dc(HDC hdc1, HDC hdc2, int width, int height) static void *alloced_str; -static LRESULT parent_wnd_notify(LPARAM lParam) +static const NMCBEENDEDITW test_WM_NOTIFY_NMCBEENDEDITW = +{ + .hdr.hwndFrom = (HWND)0xabcd0001, + .hdr.idFrom = 0xabcd0002, + .hdr.code = CBEN_ENDEDITW, + .fChanged = 0xabcd0003, + .iNewSelection = 0xabcd0004, + .szText = {'L','o','r','e','m',' ','i','p','s','u','m',' ','d','o','l','o','r',' ','s','i','t',' ','a','m','e','t',0}, + .iWhy = 0xabcd0005 +}; + +static const NMCBEENDEDITA test_WM_NOTIFY_NMCBEENDEDITA = +{ + .hdr.hwndFrom = (HWND)0xabcd0001, + .hdr.idFrom = 0xabcd0002, + .hdr.code = CBEN_ENDEDITA, + .fChanged = 0xabcd0003, + .iNewSelection = 0xabcd0004, + .szText = {'L','o','r','e','m',' ','i','p','s','u','m',' ','d','o','l','o','r',' ','s','i','t',' ','a','m','e','t',0}, + .iWhy = 0xabcd0005 +}; + +static BOOL test_WM_NOTIFY_expect_CBEN_ENDEDITW; +static BOOL test_WM_NOTIFY_expect_CBEN_ENDEDITA; + +static LRESULT parent_wnd_notify(WPARAM wParam, LPARAM lParam) { NMHDR *hdr = (NMHDR *)lParam; NMTBHOTITEM *nmhi; NMTBDISPINFOA *nmdisp; switch (hdr->code) { + case CBEN_ENDEDITW: + if (test_WM_NOTIFY_expect_CBEN_ENDEDITW) + { + test_WM_NOTIFY_expect_CBEN_ENDEDITW = FALSE; + ok(hdr == &test_WM_NOTIFY_NMCBEENDEDITW.hdr, "Got unexpected header.\n"); + ok(wParam == 0xabcd0002, "Got unexpected wParam 0x%Ix.\n", wParam); + } + else + { + ok(FALSE, "Got unexpected WM_NOTIFY.\n"); + } + return 0xabcd0006; + case CBEN_ENDEDITA: + if (test_WM_NOTIFY_expect_CBEN_ENDEDITA) + { + test_WM_NOTIFY_expect_CBEN_ENDEDITA = FALSE; + ok(!memcmp(hdr, &test_WM_NOTIFY_NMCBEENDEDITA, sizeof(NMCBEENDEDITA)), "Incorrectly converted NMCBEENDEDITW to NMCBEENDEDITA.\n"); + ok(wParam == 0xabcd0002, "Got unexpected wParam 0x%Ix.\n", wParam); + } + else + { + ok(FALSE, "Got unexpected WM_NOTIFY.\n"); + } + return 0xabcd0007; case TBN_HOTITEMCHANGE: nmhi = (NMTBHOTITEM *)lParam; g_fReceivedHotItemChange = TRUE; @@ -375,6 +424,8 @@ static LRESULT parent_wnd_notify(LPARAM lParam) return 0; } +static LRESULT parent_WM_NOTIFYFORMAT_return = NFR_ANSI; + static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static LONG defwndproc_counter = 0; @@ -428,7 +479,9 @@ 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); + case WM_NOTIFYFORMAT: + return parent_WM_NOTIFYFORMAT_return; } defwndproc_counter++; @@ -2833,6 +2886,28 @@ static void test_BTNS_SEP(void) DestroyWindow(hwnd); } +static void test_WM_NOTIFY(void) +{ + HWND toolbar = NULL; + LRESULT ret; + + parent_WM_NOTIFYFORMAT_return = NFR_UNICODE; + rebuild_toolbar(&toolbar); + parent_WM_NOTIFYFORMAT_return = NFR_ANSI; + test_WM_NOTIFY_expect_CBEN_ENDEDITW = TRUE; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); + todo_wine ok(ret == 0xabcd0006, "SendMessageA returned 0x%Ix.\n", ret); + todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITW, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + test_WM_NOTIFY_expect_CBEN_ENDEDITW = FALSE; + rebuild_toolbar(&toolbar); + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TRUE; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); + todo_wine ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); + todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't convert and forward WM_NOTIFY to parent.\n"); + test_WM_NOTIFY_expect_CBEN_ENDEDITA = FALSE; + DestroyWindow(toolbar); +} + START_TEST(toolbar) { ULONG_PTR ctx_cookie; @@ -2884,6 +2959,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 Tebuev <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..1bb1f8d0461 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 to ansi conversion and forwarding stuff */ + +/* COMCTL32_UnicodeBuffer is for storing result of ansi to 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..7e17d994ad8 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 Tebuev <alanas.00(a)mail.ru> This makes 7-Zip File Manager press enter in path input work. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57178 --- dlls/comctl32/tests/toolbar.c | 8 ++++---- dlls/comctl32/toolbar.c | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index e57635f30a9..2c71a0885d7 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -2896,14 +2896,14 @@ static void test_WM_NOTIFY(void) parent_WM_NOTIFYFORMAT_return = NFR_ANSI; test_WM_NOTIFY_expect_CBEN_ENDEDITW = TRUE; ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); - todo_wine ok(ret == 0xabcd0006, "SendMessageA returned 0x%Ix.\n", ret); - todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITW, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + ok(ret == 0xabcd0006, "SendMessageA returned 0x%Ix.\n", ret); + ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITW, "Toolbar didn't forward WM_NOTIFY to parent.\n"); test_WM_NOTIFY_expect_CBEN_ENDEDITW = FALSE; rebuild_toolbar(&toolbar); test_WM_NOTIFY_expect_CBEN_ENDEDITA = TRUE; ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); - todo_wine ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); - todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't convert and forward WM_NOTIFY to parent.\n"); + ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); + ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't convert and forward WM_NOTIFY to parent.\n"); test_WM_NOTIFY_expect_CBEN_ENDEDITA = FALSE; DestroyWindow(toolbar); } diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c index 690a02db6ee..1f4b6d84c3f 100644 --- a/dlls/comctl32/toolbar.c +++ b/dlls/comctl32/toolbar.c @@ -6359,7 +6359,17 @@ TOOLBAR_Notify (TOOLBAR_INFO *infoPtr, LPNMHDR lpnmh) FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); return 0; + case CBEN_ENDEDITW: + if (infoPtr->bUnicode) + { + TRACE("Forwarding CBEN_ENDEDITW (no conversion).\n"); + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->idFrom, (LPARAM)lpnmh); + } + TRACE("Converting CBEN_ENDEDITW to CBEN_ENDEDITA and forwarding.\n"); + return COMCTL32_ForwardNotifyToAnsiWindow(infoPtr->hwndNotify, lpnmh, NULL); + default: + WARN("Should WM_NOTIFY NMHDR code 0x%x be forwarded?\n", lpnmh->code); return 0; } } -- 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=150044 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
On Fri Nov 15 20:32:16 2024 +0000, Alanas Tebuev wrote:
Also add a TRACE() when forwarding notifications to hwndNotify. OK, but [pager has no `TRACE`](https://gitlab.winehq.org/wine/wine/-/blob/ab40b7fd8686345bf77a27ceb12d4dfba...). Only explanation of nmhdr.code=0xffffff60=LVN_FIRST-60 I found is https://narkive.com/VaroOjWB.6:<blockquote cite="https://narkive.com/VaroOjWB.6">Google for LVN_FIRST-60 and you'll find out that it's LVN_GETEMPTYTEXTA.<br>Google for LVN_GETEMPTYTEXTA and you'll find out that the lParam<br>parameter points to a NMLVDISPINFOA struct.<br><br>Regards<br>Timo</blockquote>
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_89362
Zhiyi Zhang (@zhiyi) commented about dlls/comctl32/tests/toolbar.c:
DestroyWindow(hwnd); }
+static void test_WM_NOTIFY(void) +{ + HWND toolbar = NULL; + LRESULT ret; + + parent_WM_NOTIFYFORMAT_return = NFR_UNICODE; + rebuild_toolbar(&toolbar); + parent_WM_NOTIFYFORMAT_return = NFR_ANSI;
This is not clear. NFR_UNICODE only takes effect when creating a new toolbar. So setting parent_WM_NOTIFYFORMAT_return to NFR_ANSI is actually for the rebuild_toolbar() at line 2902. What you should do is create a toolbar expecting Unicode notifications, send CBEN_ENDEDITW and CBEN_ENDEDITA, and then create a new toolbar expecting ASCII notifications, then send CBEN_ENDEDITW and CBEN_ENDEDITA. And let's send CBEN_ENDEDITW with SendMessageW() instead of SendMessageA(). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6737#note_89425
participants (4)
-
Alanas Tebuev -
Alanas Tebuev (@BZZZZ) -
Marvin -
Zhiyi Zhang (@zhiyi)