https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6c55a3aa2ad4afb06a931…
commit 6c55a3aa2ad4afb06a931ec648055abf63e42651
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Thu Sep 21 09:14:40 2023 +0900
Commit: GitHub <noreply(a)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.mz(a)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
*/