[SHELL32][SHLWAPI] Forward shell32.ShellMessageBoxW directly to shlwapi.ShellMessageB... 3179/head
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 13 Sep 2020 16:21:29 +0000 (18:21 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 13 Sep 2020 20:44:58 +0000 (22:44 +0200)
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
dll/win32/shell32/shell32.spec
dll/win32/shell32/wine/shellord.c
dll/win32/shlwapi/ordinal.c
sdk/include/psdk/shellapi.h
sdk/include/reactos/shlwapi_undoc.h

index 84bb7e4..9ae77f4 100644 (file)
 #undef ShellExecute
 #include <undocshell.h>
 
+/*
+ * 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 <browseui_undoc.h>
 
 #include <shellutils.h>
index f242567..110ac17 100644 (file)
 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)
index 8cbdb2a..ab0969a 100644 (file)
@@ -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
 }
 
 /*************************************************************************
index 431ec51..b8b93a6 100644 (file)
@@ -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);
index b4a5ecb..77e3fc5 100644 (file)
@@ -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,
index 08af859..a56ed24 100644 (file)
@@ -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) */