https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6c55a3aa2ad4afb06a931ec648055abf63e42651

commit 6c55a3aa2ad4afb06a931ec648055abf63e42651
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Thu Sep 21 09:14:40 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Thu Sep 21 09:14:40 2023 +0900

    [SHELL32][SHELL32_APITEST][SDK] Implement Int64ToString (#5706)
    
    - Implement Int64ToString and LargeIntegerToString functions.
    - Add Int64ToString and LargeIntegerToString prototypes to <shellundoc.h>.
    - Add Int64ToString testcase.
    - I found a bug in GetNumberFormat.LeadingZero.
    
    http://undoc.airesoft.co.uk/shell32.dll/Int64ToString.php
    http://undoc.airesoft.co.uk/shell32.dll/LargeIntegerToString.php
---
 dll/win32/shell32/stubs.cpp                        |  32 ----
 dll/win32/shell32/utils.cpp                        | 156 +++++++++++++++++
 modules/rostests/apitests/shell32/CMakeLists.txt   |   1 +
 .../rostests/apitests/shell32/Int64ToString.cpp    | 194 +++++++++++++++++++++
 modules/rostests/apitests/shell32/testlist.c       |   2 +
 sdk/include/reactos/undocshell.h                   |  26 +++
 6 files changed, 379 insertions(+), 32 deletions(-)

diff --git a/dll/win32/shell32/stubs.cpp b/dll/win32/shell32/stubs.cpp
index 4c019e9b031..a49a506928e 100644
--- a/dll/win32/shell32/stubs.cpp
+++ b/dll/win32/shell32/stubs.cpp
@@ -949,38 +949,6 @@ Printers_GetPidl(LPCITEMIDLIST pidl, LPCWSTR lpName, DWORD 
dwUnknown1, DWORD dwU
     return NULL;
 }
 
-/*
- * Unimplemented
- */
-EXTERN_C INT
-WINAPI
-Int64ToString(LONGLONG llInt64,
-              LPWSTR lpOut,
-              UINT uSize,
-              BOOL bUseFormat,
-              NUMBERFMT *pNumberFormat,
-              DWORD dwNumberFlags)
-{
-    FIXME("Int64ToString() stub\n");
-    return 0;
-}
-
-/*
- * Unimplemented
- */
-EXTERN_C INT
-WINAPI
-LargeIntegerToString(LARGE_INTEGER *pLargeInt,
-                     LPWSTR lpOut,
-                     UINT uSize,
-                     BOOL bUseFormat,
-                     NUMBERFMT *pNumberFormat,
-                     DWORD dwNumberFlags)
-{
-    FIXME("LargeIntegerToString() stub\n");
-    return 0;
-}
-
 /*
  * Unimplemented
  */
diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp
index c21e679a07b..4140fcaa274 100644
--- a/dll/win32/shell32/utils.cpp
+++ b/dll/win32/shell32/utils.cpp
@@ -99,3 +99,159 @@ SHFindComputer(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST 
pidlSavedSearch)
 
     return SUCCEEDED(hr);
 }
+
+static HRESULT
+Int64ToStr(
+    _In_ LONGLONG llValue,
+    _Out_writes_z_(cchValue) LPWSTR pszValue,
+    _In_ UINT cchValue)
+{
+    WCHAR szBuff[40];
+    UINT ich = 0, ichValue;
+#if (WINVER >= _WIN32_WINNT_VISTA)
+    BOOL bMinus = (llValue < 0);
+
+    if (bMinus)
+        llValue = -llValue;
+#endif
+
+    if (cchValue <= 0)
+        return E_FAIL;
+
+    do
+    {
+        szBuff[ich++] = (WCHAR)(L'0' + (llValue % 10));
+        llValue /= 10;
+    } while (llValue != 0 && ich < _countof(szBuff) - 1);
+
+#if (WINVER >= _WIN32_WINNT_VISTA)
+    if (bMinus && ich < _countof(szBuff))
+        szBuff[ich++] = '-';
+#endif
+
+    for (ichValue = 0; ich > 0 && ichValue < cchValue; ++ichValue)
+    {
+        --ich;
+        pszValue[ichValue] = szBuff[ich];
+    }
+
+    if (ichValue >= cchValue)
+    {
+        pszValue[cchValue - 1] = UNICODE_NULL;
+        return E_FAIL;
+    }
+
+    pszValue[ichValue] = UNICODE_NULL;
+    return S_OK;
+}
+
+static VOID
+Int64GetNumFormat(
+    _Out_ NUMBERFMTW *pDest,
+    _In_opt_ const NUMBERFMTW *pSrc,
+    _In_ DWORD dwNumberFlags,
+    _Out_writes_z_(cchDecimal) LPWSTR pszDecimal,
+    _In_ INT cchDecimal,
+    _Out_writes_z_(cchThousand) LPWSTR pszThousand,
+    _In_ INT cchThousand)
+{
+    WCHAR szBuff[20];
+
+    if (pSrc)
+        *pDest = *pSrc;
+    else
+        dwNumberFlags = 0;
+
+    if (!(dwNumberFlags & FMT_USE_NUMDIGITS))
+    {
+        GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szBuff, 
_countof(szBuff));
+        pDest->NumDigits = StrToIntW(szBuff);
+    }
+
+    if (!(dwNumberFlags & FMT_USE_LEADZERO))
+    {
+        GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szBuff, 
_countof(szBuff));
+        pDest->LeadingZero = StrToIntW(szBuff);
+    }
+
+    if (!(dwNumberFlags & FMT_USE_GROUPING))
+    {
+        GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szBuff, 
_countof(szBuff));
+        pDest->Grouping = StrToIntW(szBuff);
+    }
+
+    if (!(dwNumberFlags & FMT_USE_DECIMAL))
+    {
+        GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, pszDecimal, 
cchDecimal);
+        pDest->lpDecimalSep = pszDecimal;
+    }
+
+    if (!(dwNumberFlags & FMT_USE_THOUSAND))
+    {
+        GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, pszThousand, 
cchThousand);
+        pDest->lpThousandSep = pszThousand;
+    }
+
+    if (!(dwNumberFlags & FMT_USE_NEGNUMBER))
+    {
+        GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER, szBuff, 
_countof(szBuff));
+        pDest->NegativeOrder = StrToIntW(szBuff);
+    }
+}
+
+/*************************************************************************
+ *  Int64ToString [SHELL32.209]
+ *
+ * @see http://undoc.airesoft.co.uk/shell32.dll/Int64ToString.php
+ */
+EXTERN_C
+INT WINAPI
+Int64ToString(
+    _In_ LONGLONG llValue,
+    _Out_writes_z_(cchOut) LPWSTR pszOut,
+    _In_ UINT cchOut,
+    _In_ BOOL bUseFormat,
+    _In_opt_ const NUMBERFMTW *pNumberFormat,
+    _In_ DWORD dwNumberFlags)
+{
+    INT ret;
+    NUMBERFMTW NumFormat;
+    WCHAR szValue[80], szDecimalSep[6], szThousandSep[6];
+
+    Int64ToStr(llValue, szValue, _countof(szValue));
+
+    if (bUseFormat)
+    {
+        Int64GetNumFormat(&NumFormat, pNumberFormat, dwNumberFlags,
+                          szDecimalSep, _countof(szDecimalSep),
+                          szThousandSep, _countof(szThousandSep));
+        ret = GetNumberFormatW(LOCALE_USER_DEFAULT, 0, szValue, &NumFormat, 
pszOut, cchOut);
+        if (ret)
+            --ret;
+        return ret;
+    }
+
+    if (FAILED(StringCchCopyW(pszOut, cchOut, szValue)))
+        return 0;
+
+    return lstrlenW(pszOut);
+}
+
+/*************************************************************************
+ *  LargeIntegerToString [SHELL32.210]
+ *
+ * @see http://undoc.airesoft.co.uk/shell32.dll/LargeIntegerToString.php
+ */
+EXTERN_C
+INT WINAPI
+LargeIntegerToString(
+    _In_ const LARGE_INTEGER *pLargeInt,
+    _Out_writes_z_(cchOut) LPWSTR pszOut,
+    _In_ UINT cchOut,
+    _In_ BOOL bUseFormat,
+    _In_opt_ const NUMBERFMTW *pNumberFormat,
+    _In_ DWORD dwNumberFlags)
+{
+    return Int64ToString(pLargeInt->QuadPart, pszOut, cchOut, bUseFormat,
+                         pNumberFormat, dwNumberFlags);
+}
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt 
b/modules/rostests/apitests/shell32/CMakeLists.txt
index 602e25ad199..07ba4a96ca6 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -16,6 +16,7 @@ list(APPEND SOURCE
     ExtractIconEx.cpp
     FindExecutable.cpp
     GetDisplayNameOf.cpp
+    Int64ToString.cpp
     IShellFolderViewCB.cpp
     OpenAs_RunDLL.cpp
     PathResolve.cpp
diff --git a/modules/rostests/apitests/shell32/Int64ToString.cpp 
b/modules/rostests/apitests/shell32/Int64ToString.cpp
new file mode 100644
index 00000000000..19ff028db6f
--- /dev/null
+++ b/modules/rostests/apitests/shell32/Int64ToString.cpp
@@ -0,0 +1,194 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Tests for Int64ToString
+ * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
+ */
+
+#include "shelltest.h"
+#include <undocshell.h>
+#include <versionhelpers.h>
+
+typedef struct tagTEST_RETURN
+{
+    INT ret;
+    LPCWSTR text;
+} TEST_RETURN, *PTEST_RETURN;
+
+typedef struct tagTEST_ENTRY
+{
+    INT lineno;
+    LONGLONG value;
+
+    UINT NumDigits;
+    UINT LeadingZero;
+    UINT Grouping;
+    LPCWSTR pszDecimalSep;
+    LPCWSTR pszThousandSep;
+    UINT NegativeOrder;
+
+    TEST_RETURN NonVista;
+    TEST_RETURN Vista;
+} TEST_ENTRY, *PTEST_ENTRY;
+
+#define DATA0 2, FALSE, 3, L".", L",", 0
+#define DATA1 3, TRUE, 3, L"<>", L":", 1
+
+static const TEST_ENTRY s_Entries[] =
+{
+    { __LINE__, 0, DATA0, { 3, L".00" }, { 3, L".00" } },
+    { __LINE__, 0, DATA1, { 6, L"0<>000" }, { 6, L"0<>000" } },
+    { __LINE__, 1, DATA0, { 4, L"1.00" }, { 4, L"1.00" } },
+    { __LINE__, 1, DATA1, { 6, L"1<>000" }, { 6, L"1<>000" } },
+    { __LINE__, -999, DATA0, { 0, L"#####" }, { 8, L"(999.00)" } },
+    { __LINE__, -999, DATA1, { 0, L"#####" }, { 9, L"-999<>000" } },
+    { __LINE__, 100000, DATA0, { 10, L"100,000.00" }, { 10, L"100,000.00" } },
+    { __LINE__, 100000, DATA1, { 12, L"100:000<>000" }, { 12, L"100:000<>000" 
} },
+    { __LINE__, 0xE8D4A51000LL, DATA0, { 20, L"1,000,000,000,000.00" }, { 20, 
L"1,000,000,000,000.00" } },
+    { __LINE__, 0xE8D4A51000LL, DATA1, { 22, L"1:000:000:000:000<>000" }, { 
22, L"1:000:000:000:000<>000" } },
+    { __LINE__, 0x7FFFFFFFFFFFFFFFLL, DATA0, { 28, 
L"9,223,372,036,854,775,807.00" }, { 28, L"9,223,372,036,854,775,807.00" } },
+    { __LINE__, 0x7FFFFFFFFFFFFFFFLL, DATA1, { 30, 
L"9:223:372:036:854:775:807<>000" }, { 30, L"9:223:372:036:854:775:807<>000" } 
},
+};
+static const SIZE_T s_cEntries = _countof(s_Entries);
+
+static void DoTestEntry(BOOL bVista, const TEST_ENTRY *pEntry)
+{
+    INT lineno = pEntry->lineno;
+
+    WCHAR szDecimalSep[10], szThousandSep[10];
+    lstrcpynW(szDecimalSep, pEntry->pszDecimalSep, _countof(szDecimalSep));
+    lstrcpynW(szThousandSep, pEntry->pszThousandSep, _countof(szThousandSep));
+
+    NUMBERFMTW format =
+    {
+        pEntry->NumDigits, pEntry->LeadingZero, pEntry->Grouping,
+        szDecimalSep, szThousandSep, pEntry->NegativeOrder
+    };
+
+    WCHAR szBuff[64];
+    lstrcpynW(szBuff, L"#####", _countof(szBuff));
+
+    INT ret = Int64ToString(pEntry->value, szBuff, _countof(szBuff), TRUE, 
&format, -1);
+    if (bVista)
+    {
+        ok(pEntry->Vista.ret == ret, "Line %d: %d vs %d\n", lineno, 
pEntry->Vista.ret, ret);
+        ok(lstrcmpW(pEntry->Vista.text, szBuff) == 0, "Line %d: %ls vs %ls\n",
+           lineno, pEntry->Vista.text, szBuff);
+    }
+    else
+    {
+        ok(pEntry->NonVista.ret == ret, "Line %d: %d vs %d\n", lineno, 
pEntry->NonVista.ret, ret);
+        ok(lstrcmpW(pEntry->NonVista.text, szBuff) == 0, "Line %d: %ls vs 
%ls\n",
+           lineno, pEntry->NonVista.text, szBuff);
+    }
+
+    lstrcpynW(szBuff, L"#####", _countof(szBuff));
+
+    LARGE_INTEGER LInt;
+    LInt.QuadPart = pEntry->value;
+    ret = LargeIntegerToString(&LInt, szBuff, _countof(szBuff), TRUE, &format, 
-1);
+    if (bVista)
+    {
+        ok(pEntry->Vista.ret == ret, "Line %d: %d vs %d\n", lineno, 
pEntry->Vista.ret, ret);
+        ok(lstrcmpW(pEntry->Vista.text, szBuff) == 0, "Line %d: %ls vs %ls\n",
+           lineno, pEntry->Vista.text, szBuff);
+    }
+    else
+    {
+        ok(pEntry->NonVista.ret == ret, "Line %d: %d vs %d\n", lineno, 
pEntry->NonVista.ret, ret);
+        ok(lstrcmpW(pEntry->NonVista.text, szBuff) == 0, "Line %d: %ls vs 
%ls\n",
+           lineno, pEntry->NonVista.text, szBuff);
+    }
+}
+
+static void Test_EntryTest(BOOL bVista)
+{
+    for (SIZE_T i = 0; i < s_cEntries; ++i)
+    {
+        DoTestEntry(bVista, &s_Entries[i]);
+    }
+}
+
+static void Test_Int64ToString(BOOL bVista)
+{
+    WCHAR szBuff[64];
+    INT ret;
+
+    ret = Int64ToString(0, szBuff, _countof(szBuff), FALSE, NULL, 0);
+    ok_int(ret, 1);
+    ok_wstr(szBuff, L"0");
+
+    ret = Int64ToString(1, szBuff, _countof(szBuff), FALSE, NULL, 0);
+    ok_int(ret, 1);
+    ok_wstr(szBuff, L"1");
+
+    ret = Int64ToString(-9999, szBuff, _countof(szBuff), FALSE, NULL, 0);
+    if (bVista)
+    {
+        ok_int(ret, 5);
+        ok_wstr(szBuff, L"-9999");
+    }
+    else
+    {
+        ok_int(ret, 4);
+        ok_wstr(szBuff, L"''''");
+    }
+
+    ret = Int64ToString(10000, szBuff, _countof(szBuff), FALSE, NULL, 0);
+    ok_int(ret, 5);
+    ok_wstr(szBuff, L"10000");
+
+    ret = Int64ToString(0xE8D4A51000LL, szBuff, _countof(szBuff), FALSE, NULL, 
0);
+    ok_int(ret, 13);
+    ok_wstr(szBuff, L"1000000000000");
+}
+
+static void Test_LargeIntegerToString(BOOL bVista)
+{
+    LARGE_INTEGER LInt;
+    WCHAR szBuff[64];
+    INT ret;
+
+    LInt.QuadPart = 0;
+    ret = LargeIntegerToString(&LInt, szBuff, _countof(szBuff), FALSE, NULL, 
0);
+    ok_int(ret, 1);
+    ok_wstr(szBuff, L"0");
+
+    LInt.QuadPart = 1;
+    ret = LargeIntegerToString(&LInt, szBuff, _countof(szBuff), FALSE, NULL, 
0);
+    ok_int(ret, 1);
+    ok_wstr(szBuff, L"1");
+
+    LInt.QuadPart = -9999;
+    ret = LargeIntegerToString(&LInt, szBuff, _countof(szBuff), FALSE, NULL, 
0);
+    if (bVista)
+    {
+        ok_int(ret, 5);
+        ok_wstr(szBuff, L"-9999");
+    }
+    else
+    {
+        ok_int(ret, 4);
+        ok_wstr(szBuff, L"''''");
+    }
+
+    LInt.QuadPart = 10000;
+    ret = LargeIntegerToString(&LInt, szBuff, _countof(szBuff), FALSE, NULL, 
0);
+    ok_int(ret, 5);
+    ok_wstr(szBuff, L"10000");
+
+    LInt.QuadPart = 0xE8D4A51000LL;
+    ret = LargeIntegerToString(&LInt, szBuff, _countof(szBuff), FALSE, NULL, 
0);
+    ok_int(ret, 13);
+    ok_wstr(szBuff, L"1000000000000");
+}
+
+START_TEST(Int64ToString)
+{
+    BOOL bVista = IsWindowsVistaOrGreater();
+    trace("bVista: %d\n", bVista);
+
+    Test_EntryTest(bVista);
+    Test_Int64ToString(bVista);
+    Test_LargeIntegerToString(bVista);
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c 
b/modules/rostests/apitests/shell32/testlist.c
index 2d364f19770..424e878d3b9 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -17,6 +17,7 @@ extern void func_DragDrop(void);
 extern void func_ExtractIconEx(void);
 extern void func_FindExecutable(void);
 extern void func_GetDisplayNameOf(void);
+extern void func_Int64ToString(void);
 extern void func_IShellFolderViewCB(void);
 extern void func_menu(void);
 extern void func_OpenAs_RunDLL(void);
@@ -52,6 +53,7 @@ const struct test winetest_testlist[] =
     { "ExtractIconEx", func_ExtractIconEx },
     { "FindExecutable", func_FindExecutable },
     { "GetDisplayNameOf", func_GetDisplayNameOf },
+    { "Int64ToString", func_Int64ToString },
     { "IShellFolderViewCB", func_IShellFolderViewCB },
     { "menu", func_menu },
     { "OpenAs_RunDLL", func_OpenAs_RunDLL },
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index 370fef7377e..93fc4201d8c 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -658,6 +658,32 @@ BOOL WINAPI GUIDFromStringW(
 LPSTR WINAPI SheRemoveQuotesA(LPSTR psz);
 LPWSTR WINAPI SheRemoveQuotesW(LPWSTR psz);
 
+/* Flags for Int64ToString and LargeIntegerToString */
+#define FMT_USE_NUMDIGITS 0x01
+#define FMT_USE_LEADZERO  0x02
+#define FMT_USE_GROUPING  0x04
+#define FMT_USE_DECIMAL   0x08
+#define FMT_USE_THOUSAND  0x10
+#define FMT_USE_NEGNUMBER 0x20
+
+INT WINAPI
+Int64ToString(
+    _In_ LONGLONG llValue,
+    _Out_writes_z_(cchOut) LPWSTR pszOut,
+    _In_ UINT cchOut,
+    _In_ BOOL bUseFormat,
+    _In_opt_ const NUMBERFMTW *pNumberFormat,
+    _In_ DWORD dwNumberFlags);
+
+INT WINAPI
+LargeIntegerToString(
+    _In_ const LARGE_INTEGER *pLargeInt,
+    _Out_writes_z_(cchOut) LPWSTR pszOut,
+    _In_ UINT cchOut,
+    _In_ BOOL bUseFormat,
+    _In_opt_ const NUMBERFMTW *pNumberFormat,
+    _In_ DWORD dwNumberFlags);
+
 /*****************************************************************************
  * Shell32 resources
  */

Reply via email to