From 14599b0a37927355eefd411b444d61bde11b75b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 13 Sep 2020 18:21:29 +0200 Subject: [PATCH] [SHELL32][SHLWAPI] Forward shell32.ShellMessageBoxW directly to shlwapi.ShellMessageBoxWrapW. (#3179) This makes ShellMessageBoxW use the correct implementation where the text buffer size is dynamic, instead of having a too small hardcoded size. Fixes CORE-17271. See also PR #3172 by Kyle Katarn, supplemented with some ideas from Mark Jansen. However we cannot straightforwardly implement ShellMessageBoxA around ShellMessageBoxW, by converting some parameters from ANSI to UNICODE, because there may be some variadic ANSI strings, associated with '%s' printf-like formatters inside the format string, that would also need to be converted; however there is no way for us to find these and perform the conversion ourselves. Therefore, we re-implement ShellMessageBoxA by doing a copy-paste ANSI adaptation of the shlwapi.ShellMessageBoxWrapW function. Note that, on Vista+ onwards, shlwapi implements both ShellMessageBoxA/W, and shell32 directly forwards these exports to shlwapi, thus avoiding these workarounds. [PSDK] Explicily use WINAPIV for the variadic ShellMessageBoxA/W functions. [INCLUDE/REACTOS] Add ShellMessageBoxWrapW in shlwapi_undoc.h . --- dll/win32/shell32/precomp.h | 13 +++++ dll/win32/shell32/shell32.spec | 2 +- dll/win32/shell32/wine/shellord.c | 90 ++++++++++++++++++++++++++++- dll/win32/shlwapi/ordinal.c | 19 +++++- sdk/include/psdk/shellapi.h | 2 + sdk/include/reactos/shlwapi_undoc.h | 10 ++++ 6 files changed, 132 insertions(+), 4 deletions(-) diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h index 84bb7e49dc5..9ae77f4b794 100644 --- a/dll/win32/shell32/precomp.h +++ b/dll/win32/shell32/precomp.h @@ -45,6 +45,19 @@ #undef ShellExecute #include +/* + * For versions < Vista+, redefine ShellMessageBoxW to ShellMessageBoxWrapW + * (this is needed to avoid a linker error). On Vista+ onwards, shell32.ShellMessageBoxW + * redirects to shlwapi.ShellMessageBoxW so the #define should not be needed. + * + * However our shell32 is built with _WIN32_WINNT set to 0x600 (Vista+), + * yet its exports (especially regarding ShellMessageBoxA/W) are Win2003 + * compatible. So the #define is still needed, and the check be disabled. + */ +// #if (_WIN32_WINNT < 0x0600) +#define ShellMessageBoxW ShellMessageBoxWrapW +// #endif + #include #include diff --git a/dll/win32/shell32/shell32.spec b/dll/win32/shell32/shell32.spec index f24256761af..110ac17c69c 100644 --- a/dll/win32/shell32/shell32.spec +++ b/dll/win32/shell32/shell32.spec @@ -178,7 +178,7 @@ 179 stdcall SHGetNewLinkInfoA(str str ptr long long) 180 stdcall SHGetNewLinkInfoW(wstr wstr ptr long long) 181 stdcall -noname RegisterShellHook(long long) -182 varargs ShellMessageBoxW(long long wstr wstr long) +182 varargs ShellMessageBoxW(long long wstr wstr long) shlwapi.ShellMessageBoxWrapW 183 varargs ShellMessageBoxA(long long str str long) 184 stdcall -noname ArrangeWindows(long long long long long) 185 stdcall -noname SHHandleDiskFull(ptr long) diff --git a/dll/win32/shell32/wine/shellord.c b/dll/win32/shell32/wine/shellord.c index 8cbdb2a4da4..ab0969a157b 100644 --- a/dll/win32/shell32/wine/shellord.c +++ b/dll/win32/shell32/wine/shellord.c @@ -331,12 +331,28 @@ BOOL WINAPI RegisterShellHook( * * See ShellMessageBoxA. * + */ +#ifdef __REACTOS__ +/* + * shell32.ShellMessageBoxW directly redirects to shlwapi.ShellMessageBoxWrapW, + * while shell32.ShellMessageBoxA is a copy-paste ANSI adaptation of the + * shlwapi.ShellMessageBoxWrapW function. + * + * From Vista+ onwards, all the implementation of ShellMessageBoxA/W that + * were existing in shell32 has been completely moved to shlwapi, so that + * shell32.ShellMessageBoxA and shell32.ShellMessageBoxW are redirections + * to the corresponding shlwapi functions. + * + */ +#else // !__REACTOS__ +/* * NOTE: * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW * because we can't forward to it in the .spec file since it's exported by * ordinal. If you change the implementation here please update the code in * shlwapi as well. */ +// Wine version, broken. int ShellMessageBoxW( HINSTANCE hInstance, HWND hWnd, @@ -358,12 +374,12 @@ int ShellMessageBoxW( hInstance,hWnd,lpText,lpCaption,uType); if (IS_INTRESOURCE(lpCaption)) - LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0])); + LoadStringW(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle)); else pszTitle = lpCaption; if (IS_INTRESOURCE(lpText)) - LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0])); + LoadStringW(hInstance, LOWORD(lpText), szText, ARRAY_SIZE(szText)); else pszText = lpText; @@ -376,6 +392,7 @@ int ShellMessageBoxW( LocalFree(pszTemp); return ret; } +#endif /************************************************************************* * ShellMessageBoxA [SHELL32.183] @@ -395,6 +412,18 @@ int ShellMessageBoxW( * NOTES * Exported by ordinal */ +#ifdef __REACTOS__ +/* + * Note that we cannot straightforwardly implement ShellMessageBoxA around + * ShellMessageBoxW, by converting some parameters from ANSI to UNICODE, + * because there may be some variadic ANSI strings, associated with '%s' + * printf-like formatters inside the format string, that would also need + * to be converted; however there is no way for us to find these and perform + * the conversion ourselves. + * Therefore, we re-implement ShellMessageBoxA by doing a copy-paste ANSI + * adaptation of the shlwapi.ShellMessageBoxWrapW function. + */ +#endif int ShellMessageBoxA( HINSTANCE hInstance, HWND hWnd, @@ -403,6 +432,62 @@ int ShellMessageBoxA( UINT uType, ...) { +#ifdef __REACTOS__ + CHAR *szText = NULL, szTitle[100]; + LPCSTR pszText, pszTitle = szTitle; + LPSTR pszTemp; + __ms_va_list args; + int ret; + + __ms_va_start(args, uType); + + TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType); + + if (IS_INTRESOURCE(lpCaption)) + LoadStringA(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle)); + else + pszTitle = lpCaption; + + if (IS_INTRESOURCE(lpText)) + { + /* Retrieve the length of the Unicode string and obtain the maximum + * possible length for the corresponding ANSI string (not counting + * any possible NULL-terminator). */ + const WCHAR *ptr; + UINT len = LoadStringW(hInstance, LOWORD(lpText), (LPWSTR)&ptr, 0); + + len = WideCharToMultiByte(CP_ACP, 0, ptr, len, + NULL, 0, NULL, NULL); + + if (len) + { + szText = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(CHAR)); + if (szText) LoadStringA(hInstance, LOWORD(lpText), szText, len + 1); + } + pszText = szText; + if (!pszText) { + WARN("Failed to load id %d\n", LOWORD(lpText)); + __ms_va_end(args); + return 0; + } + } + else + pszText = lpText; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, + pszText, 0, 0, (LPSTR)&pszTemp, 0, &args); + + __ms_va_end(args); + + ret = MessageBoxA(hWnd, pszTemp, pszTitle, uType | MB_SETFOREGROUND); + + HeapFree(GetProcessHeap(), 0, szText); + LocalFree(pszTemp); + return ret; + +#else // __REACTOS__ + +// Wine version, broken. char szText[100],szTitle[100]; LPCSTR pszText = szText, pszTitle = szTitle; LPSTR pszTemp; @@ -433,6 +518,7 @@ int ShellMessageBoxA( ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType); LocalFree(pszTemp); return ret; +#endif } /************************************************************************* diff --git a/dll/win32/shlwapi/ordinal.c b/dll/win32/shlwapi/ordinal.c index 431ec51d2e1..b8b93a60372 100644 --- a/dll/win32/shlwapi/ordinal.c +++ b/dll/win32/shlwapi/ordinal.c @@ -4803,11 +4803,25 @@ DWORD WINAPI GetUIVersion(void) * * See shell32.ShellMessageBoxW * +#ifndef __REACTOS__ + * * NOTE: * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW * because we can't forward to it in the .spec file since it's exported by * ordinal. If you change the implementation here please update the code in * shell32 as well. + * +#else // __REACTOS__ + * + * From Vista+ onwards, all the implementation of ShellMessageBoxA/W that + * were existing in shell32 has been completely moved to shlwapi, so that + * shell32.ShellMessageBoxA and shell32.ShellMessageBoxW are redirections + * to the corresponding shlwapi functions. + * + * For Win2003 compatibility, if you change the implementation here please + * update the code of ShellMessageBoxA in shell32 as well. + * +#endif */ INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, ...) @@ -4823,7 +4837,7 @@ INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText, TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType); if (IS_INTRESOURCE(lpCaption)) - LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0])); + LoadStringW(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle)); else pszTitle = lpCaption; @@ -4852,6 +4866,9 @@ INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText, __ms_va_end(args); +#ifdef __REACTOS__ + uType |= MB_SETFOREGROUND; +#endif ret = MessageBoxW(hWnd, pszTemp, pszTitle, uType); HeapFree(GetProcessHeap(), 0, szText); diff --git a/sdk/include/psdk/shellapi.h b/sdk/include/psdk/shellapi.h index b4a5ecb4f78..77e3fc5b62c 100644 --- a/sdk/include/psdk/shellapi.h +++ b/sdk/include/psdk/shellapi.h @@ -511,6 +511,7 @@ ShellAboutW( _In_opt_ HICON hIcon); int +WINAPIV ShellMessageBoxA( _In_opt_ HINSTANCE hAppInst, _In_opt_ HWND hWnd, @@ -520,6 +521,7 @@ ShellMessageBoxA( ...); int +WINAPIV ShellMessageBoxW( _In_opt_ HINSTANCE hAppInst, _In_opt_ HWND hWnd, diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h index 08af85972d7..a56ed24ed9d 100644 --- a/sdk/include/reactos/shlwapi_undoc.h +++ b/sdk/include/reactos/shlwapi_undoc.h @@ -120,6 +120,16 @@ INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen); PVOID WINAPI SHLockSharedEx(HANDLE hData, DWORD dwProcessId, BOOL bWriteAccess); +int +WINAPIV +ShellMessageBoxWrapW( + _In_opt_ HINSTANCE hAppInst, + _In_opt_ HWND hWnd, + _In_ LPCWSTR lpcText, + _In_opt_ LPCWSTR lpcTitle, + _In_ UINT fuStyle, + ...); + #ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */