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).
-- v17: comctl32/toolbar: Forward WM_NOTIFY CBEN_ENDEDITW and CBEN_ENDEDITA. 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.
From: Alanas Tebuev alanas.00@mail.ru
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57178 --- dlls/comctl32/tests/toolbar.c | 112 +++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-)
diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index ebeb49fe8d4..df322dcd6da 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -179,13 +179,79 @@ 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 enum +{ + TEST_WM_NOTIFY_NO_FORWARD, + TEST_WM_NOTIFY_FORWARD_NO_CONVERT, + TEST_WM_NOTIFY_FORWARD_CONVERT +} test_WM_NOTIFY_expect_CBEN_ENDEDITW, 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: + switch (test_WM_NOTIFY_expect_CBEN_ENDEDITW) + { + case TEST_WM_NOTIFY_NO_FORWARD: + ok(FALSE, "Got unexpected WM_NOTIFY.\n"); + break; + case TEST_WM_NOTIFY_FORWARD_NO_CONVERT: + test_WM_NOTIFY_expect_CBEN_ENDEDITW = TEST_WM_NOTIFY_NO_FORWARD; + ok(hdr == &test_WM_NOTIFY_NMCBEENDEDITW.hdr, "Got unexpected header.\n"); + ok(wParam == 0xabcd0002, "Got unexpected wParam 0x%Ix.\n", wParam); + break; + default: + ok(FALSE, "This testing code is broken.\n"); + break; + } + return 0xabcd0006; + case CBEN_ENDEDITA: + switch (test_WM_NOTIFY_expect_CBEN_ENDEDITA) + { + case TEST_WM_NOTIFY_NO_FORWARD: + ok(FALSE, "Got unexpected WM_NOTIFY.\n"); + break; + case TEST_WM_NOTIFY_FORWARD_NO_CONVERT: + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_NO_FORWARD; + ok(hdr == &test_WM_NOTIFY_NMCBEENDEDITA.hdr, "Got unexpected header.\n"); + ok(wParam == 0xabcd0002, "Got unexpected wParam 0x%Ix.\n", wParam); + break; + case TEST_WM_NOTIFY_FORWARD_CONVERT: + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_NO_FORWARD; + 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); + break; + default: + ok(FALSE, "This testing code is broken.\n"); + break; + } + return 0xabcd0007; case TBN_HOTITEMCHANGE: nmhi = (NMTBHOTITEM *)lParam; g_fReceivedHotItemChange = TRUE; @@ -375,6 +441,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 +496,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 +2903,43 @@ 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); + + test_WM_NOTIFY_expect_CBEN_ENDEDITW = TEST_WM_NOTIFY_FORWARD_NO_CONVERT; + ret = SendMessageW(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); + todo_wine ok(ret == 0xabcd0006, "SendMessageW 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 = TEST_WM_NOTIFY_NO_FORWARD; + + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_FORWARD_NO_CONVERT; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITA); + todo_wine ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); + todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_NO_FORWARD; + + parent_WM_NOTIFYFORMAT_return = NFR_ANSI; + rebuild_toolbar(&toolbar); + + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_FORWARD_CONVERT; + ret = SendMessageW(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); + todo_wine ok(ret == 0xabcd0007, "SendMessageW 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 = TEST_WM_NOTIFY_FORWARD_NO_CONVERT; + ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITA); + todo_wine ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); + todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't forward WM_NOTIFY to parent.\n"); + test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_NO_FORWARD; + + DestroyWindow(toolbar); +} + START_TEST(toolbar) { ULONG_PTR ctx_cookie; @@ -2884,6 +2991,7 @@ START_TEST(toolbar) test_drawtext_flags(); test_imagelist(); test_BTNS_SEP(); + test_WM_NOTIFY();
if (!load_v6_module(&ctx_cookie, &ctx)) return;
From: Alanas Tebuev alanas.00@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..e0d64ff0c6b 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 > (DWORD)-1 / sizeof(WCHAR)) + 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
From: Alanas Tebuev alanas.00@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 | 16 ++++++++-------- dlls/comctl32/toolbar.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index df322dcd6da..4c11cdbab96 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -2913,14 +2913,14 @@ static void test_WM_NOTIFY(void)
test_WM_NOTIFY_expect_CBEN_ENDEDITW = TEST_WM_NOTIFY_FORWARD_NO_CONVERT; ret = SendMessageW(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); - todo_wine ok(ret == 0xabcd0006, "SendMessageW 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, "SendMessageW 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 = TEST_WM_NOTIFY_NO_FORWARD;
test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_FORWARD_NO_CONVERT; ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITA); - todo_wine ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); - todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't 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 forward WM_NOTIFY to parent.\n"); test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_NO_FORWARD;
parent_WM_NOTIFYFORMAT_return = NFR_ANSI; @@ -2928,13 +2928,13 @@ static void test_WM_NOTIFY(void)
test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_FORWARD_CONVERT; ret = SendMessageW(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITW); - todo_wine ok(ret == 0xabcd0007, "SendMessageW 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, "SendMessageW 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 = TEST_WM_NOTIFY_FORWARD_NO_CONVERT; ret = SendMessageA(toolbar, WM_NOTIFY, 0, (LPARAM)&test_WM_NOTIFY_NMCBEENDEDITA); - todo_wine ok(ret == 0xabcd0007, "SendMessageA returned 0x%Ix.\n", ret); - todo_wine ok(!test_WM_NOTIFY_expect_CBEN_ENDEDITA, "Toolbar didn't 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 forward WM_NOTIFY to parent.\n"); test_WM_NOTIFY_expect_CBEN_ENDEDITA = TEST_WM_NOTIFY_NO_FORWARD;
DestroyWindow(toolbar); diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c index 690a02db6ee..84aaf648141 100644 --- a/dlls/comctl32/toolbar.c +++ b/dlls/comctl32/toolbar.c @@ -6359,7 +6359,21 @@ 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); + + case CBEN_ENDEDITA: + TRACE("Forwarding CBEN_ENDEDITA (no conversion).\n"); + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->idFrom, (LPARAM)lpnmh); + default: + WARN("Should WM_NOTIFY NMHDR code 0x%x be forwarded?\n", lpnmh->code); return 0; } }
Zhiyi Zhang (@zhiyi) commented about dlls/comctl32/comctl32.h:
int running;
} SUBCLASS_INFO, *LPSUBCLASS_INFO;
Regarding "comctl32: Move WM_NOTIFY unicode to ansi conversion code from pager.c to commctrl.c.". Let's split this commit into two commits. First, move the code for conversion from pager.c to commctrl.c. Then, made the changes for COMCTL32_AdjustUnicodeBuffer() in a second commit.