[TASKMGR] Fix number formatting to respect NLS Number format settings (#4657)
authorKyle Katarn <contact@kcsoftwares.com>
Sun, 4 Sep 2022 17:10:11 +0000 (19:10 +0200)
committerGitHub <noreply@github.com>
Sun, 4 Sep 2022 17:10:11 +0000 (19:10 +0200)
TaskMgr currently does not respect local NLS settings and forces 3 digits + comma (US convention) formatting.
Fix this with a direct reuse of SH_FormatInteger() as already implemented in other places
(dll/win32/shell32/dialogs/filedefext.cpp ...)

- Removal of CommaSeparateNumberString() and replace with SH_FormatInteger().
- PerfDataGetText(): Use a switch structure.  Return TRUE iftext could be retrieved; FALSE if not.

Co-authored-by: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito@reactos.org>
Co-authored-by: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
base/applications/taskmgr/precomp.h
base/applications/taskmgr/procpage.c

index d54dcb3..5593f40 100644 (file)
@@ -14,6 +14,7 @@
 #include <windef.h>
 #include <winbase.h>
 #include <wingdi.h>
+#include <winnls.h>
 #include <winuser.h>
 #include <winreg.h>
 #include <commctrl.h>
index 6145a28..e916cae 100644 (file)
@@ -58,7 +58,6 @@ void AddProcess(ULONG Index);
 void UpdateProcesses();
 void gethmsfromlargeint(LARGE_INTEGER largeint, DWORD *dwHours, DWORD *dwMinutes, DWORD *dwSeconds);
 void ProcessPageOnNotify(WPARAM wParam, LPARAM lParam);
-void CommaSeparateNumberString(LPWSTR strNumber, ULONG nMaxCount);
 void ProcessPageShowContextMenu(DWORD dwProcessId);
 BOOL PerfDataGetText(ULONG Index, ULONG ColumnIndex, LPTSTR lpText, ULONG nMaxCount);
 DWORD WINAPI ProcessPageRefreshThread(void *lpParameter);
@@ -324,20 +323,68 @@ void ProcessPageOnNotify(WPARAM wParam, LPARAM lParam)
     }
 }
 
-void CommaSeparateNumberString(LPWSTR strNumber, ULONG nMaxCount)
+/*
+ * Adapted from SH_FormatInteger in dll/win32/shell32/dialogs/filedefext.cpp.
+ */
+UINT
+SH_FormatInteger(
+    _In_ LONGLONG Num,
+    _Out_writes_z_(cchResultMax) LPWSTR pwszResult,
+    _In_ UINT cchResultMax)
 {
-    WCHAR  temp[260];
-    UINT   i, j, k;
-
-    for (i=0,j=0; i<(wcslen(strNumber) % 3); i++, j++)
-        temp[j] = strNumber[i];
-    for (k=0; i<wcslen(strNumber); i++,j++,k++) {
-        if ((k % 3 == 0) && (j > 0))
-            temp[j++] = L',';
-        temp[j] = strNumber[i];
+    NUMBERFMTW nf;
+    INT i;
+    INT cchGrouping, cchResult;
+    WCHAR wszNumber[24];
+    WCHAR wszDecimalSep[8], wszThousandSep[8];
+    WCHAR wszGrouping[12];
+
+    /* Print the number in uniform mode */
+    StringCchPrintfW(wszNumber, _countof(wszNumber), L"%I64u", Num);
+
+    /* Get system strings for decimal and thousand separators */
+    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, wszDecimalSep, _countof(wszDecimalSep));
+    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, wszThousandSep, _countof(wszThousandSep));
+
+    /* Initialize format for printing the number in bytes */
+    ZeroMemory(&nf, sizeof(nf));
+    nf.lpDecimalSep = wszDecimalSep;
+    nf.lpThousandSep = wszThousandSep;
+
+    /* Get system string for groups separator */
+    cchGrouping = GetLocaleInfoW(LOCALE_USER_DEFAULT,
+                                 LOCALE_SGROUPING,
+                                 wszGrouping,
+                                 _countof(wszGrouping));
+
+    /* Convert grouping specs from string to integer */
+    for (i = 0; i < cchGrouping; i++)
+    {
+        WCHAR wch = wszGrouping[i];
+
+        if (wch >= L'0' && wch <= L'9')
+            nf.Grouping = nf.Grouping * 10 + (wch - L'0');
+        else if (wch != L';')
+            break;
     }
-    temp[j] = L'\0';
-    wcsncpy(strNumber, temp, nMaxCount);
+
+    if ((nf.Grouping % 10) == 0)
+        nf.Grouping /= 10;
+    else
+        nf.Grouping *= 10;
+
+    /* Format the number */
+    cchResult = GetNumberFormatW(LOCALE_USER_DEFAULT,
+                                 0,
+                                 wszNumber,
+                                 &nf,
+                                 pwszResult,
+                                 cchResultMax);
+    if (!cchResult)
+        return 0;
+
+    /* GetNumberFormatW returns number of characters including UNICODE_NULL */
+    return cchResult - 1;
 }
 
 void ProcessPageShowContextMenu(DWORD dwProcessId)
@@ -561,140 +608,134 @@ void AddProcess(ULONG Index)
 
 BOOL PerfDataGetText(ULONG Index, ULONG ColumnIndex, LPTSTR lpText, ULONG nMaxCount)
 {
-    IO_COUNTERS    iocounters;
-    LARGE_INTEGER  time;
-
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IMAGENAME)
-        PerfDataGetImageName(Index, lpText, nMaxCount);
-    if (ColumnDataHints[ColumnIndex] == COLUMN_PID)
-        wsprintfW(lpText, L"%lu", PerfDataGetProcessId(Index));
-    if (ColumnDataHints[ColumnIndex] == COLUMN_USERNAME)
-        PerfDataGetUserName(Index, lpText, nMaxCount);
-    if (ColumnDataHints[ColumnIndex] == COLUMN_COMMANDLINE)
-        PerfDataGetCommandLine(Index, lpText, nMaxCount);
-    if (ColumnDataHints[ColumnIndex] == COLUMN_SESSIONID)
-        wsprintfW(lpText, L"%lu", PerfDataGetSessionId(Index));
-    if (ColumnDataHints[ColumnIndex] == COLUMN_CPUUSAGE)
-        wsprintfW(lpText, L"%02lu", PerfDataGetCPUUsage(Index));
-    if (ColumnDataHints[ColumnIndex] == COLUMN_CPUTIME)
-    {
-        DWORD dwHours;
-        DWORD dwMinutes;
-        DWORD dwSeconds;
+    IO_COUNTERS iocounters;
 
-        time = PerfDataGetCPUTime(Index);
-        gethmsfromlargeint(time, &dwHours, &dwMinutes, &dwSeconds);
-        wsprintfW(lpText, L"%lu:%02lu:%02lu", dwHours, dwMinutes, dwSeconds);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_MEMORYUSAGE)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetWorkingSetSizeBytes(Index) / 1024);
-        CommaSeparateNumberString(lpText, nMaxCount);
-        wcscat(lpText, L" K");
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_PEAKMEMORYUSAGE)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetPeakWorkingSetSizeBytes(Index) / 1024);
-        CommaSeparateNumberString(lpText, nMaxCount);
-        wcscat(lpText, L" K");
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_MEMORYUSAGEDELTA)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetWorkingSetSizeDelta(Index) / 1024);
-        CommaSeparateNumberString(lpText, nMaxCount);
-        wcscat(lpText, L" K");
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_PAGEFAULTS)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetPageFaultCount(Index));
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_PAGEFAULTSDELTA)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetPageFaultCountDelta(Index));
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_VIRTUALMEMORYSIZE)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetVirtualMemorySizeBytes(Index) / 1024);
-        CommaSeparateNumberString(lpText, nMaxCount);
-        wcscat(lpText, L" K");
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_PAGEDPOOL)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetPagedPoolUsagePages(Index) / 1024);
-        CommaSeparateNumberString(lpText, nMaxCount);
-        wcscat(lpText, L" K");
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_NONPAGEDPOOL)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetNonPagedPoolUsagePages(Index) / 1024);
-        CommaSeparateNumberString(lpText, nMaxCount);
-        wcscat(lpText, L" K");
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_BASEPRIORITY)
-        wsprintfW(lpText, L"%lu", PerfDataGetBasePriority(Index));
-    if (ColumnDataHints[ColumnIndex] == COLUMN_HANDLECOUNT)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetHandleCount(Index));
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_THREADCOUNT)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetThreadCount(Index));
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_USEROBJECTS)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetUSERObjectCount(Index));
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_GDIOBJECTS)
-    {
-        wsprintfW(lpText, L"%lu", PerfDataGetGDIObjectCount(Index));
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IOREADS)
-    {
-        PerfDataGetIOCounters(Index, &iocounters);
-        /* wsprintfW(pnmdi->item.pszText, L"%d", iocounters.ReadOperationCount); */
-        _ui64tow(iocounters.ReadOperationCount, lpText, 10);
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IOWRITES)
-    {
-        PerfDataGetIOCounters(Index, &iocounters);
-        /* wsprintfW(pnmdi->item.pszText, L"%d", iocounters.WriteOperationCount); */
-        _ui64tow(iocounters.WriteOperationCount, lpText, 10);
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IOOTHER)
-    {
-        PerfDataGetIOCounters(Index, &iocounters);
-        /* wsprintfW(pnmdi->item.pszText, L"%d", iocounters.OtherOperationCount); */
-        _ui64tow(iocounters.OtherOperationCount, lpText, 10);
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IOREADBYTES)
+    switch (ColumnDataHints[ColumnIndex])
     {
-        PerfDataGetIOCounters(Index, &iocounters);
-        /* wsprintfW(pnmdi->item.pszText, L"%d", iocounters.ReadTransferCount); */
-        _ui64tow(iocounters.ReadTransferCount, lpText, 10);
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IOWRITEBYTES)
-    {
-        PerfDataGetIOCounters(Index, &iocounters);
-        /* wsprintfW(pnmdi->item.pszText, L"%d", iocounters.WriteTransferCount); */
-        _ui64tow(iocounters.WriteTransferCount, lpText, 10);
-        CommaSeparateNumberString(lpText, nMaxCount);
-    }
-    if (ColumnDataHints[ColumnIndex] == COLUMN_IOOTHERBYTES)
-    {
-        PerfDataGetIOCounters(Index, &iocounters);
-        /* wsprintfW(pnmdi->item.pszText, L"%d", iocounters.OtherTransferCount); */
-        _ui64tow(iocounters.OtherTransferCount, lpText, 10);
-        CommaSeparateNumberString(lpText, nMaxCount);
+        case COLUMN_IMAGENAME:
+            PerfDataGetImageName(Index, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_PID:
+            StringCchPrintfW(lpText, nMaxCount, L"%lu", PerfDataGetProcessId(Index));
+            return TRUE;
+
+        case COLUMN_USERNAME:
+            PerfDataGetUserName(Index, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_COMMANDLINE:
+            PerfDataGetCommandLine(Index, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_SESSIONID:
+            StringCchPrintfW(lpText, nMaxCount, L"%lu", PerfDataGetSessionId(Index));
+            return TRUE;
+
+        case COLUMN_CPUUSAGE:
+            StringCchPrintfW(lpText, nMaxCount, L"%02lu", PerfDataGetCPUUsage(Index));
+            return TRUE;
+
+        case COLUMN_CPUTIME:
+        {
+            LARGE_INTEGER time;
+            DWORD dwHours;
+            DWORD dwMinutes;
+            DWORD dwSeconds;
+
+            time = PerfDataGetCPUTime(Index);
+            gethmsfromlargeint(time, &dwHours, &dwMinutes, &dwSeconds);
+            StringCchPrintfW(lpText, nMaxCount, L"%lu:%02lu:%02lu", dwHours, dwMinutes, dwSeconds);
+            return TRUE;
+        }
+
+        case COLUMN_MEMORYUSAGE:
+            SH_FormatInteger(PerfDataGetWorkingSetSizeBytes(Index) / 1024, lpText, nMaxCount);
+            StringCchCatW(lpText, nMaxCount, L" K");
+            return TRUE;
+
+        case COLUMN_PEAKMEMORYUSAGE:
+            SH_FormatInteger(PerfDataGetPeakWorkingSetSizeBytes(Index) / 1024, lpText, nMaxCount);
+            StringCchCatW(lpText, nMaxCount, L" K");
+            return TRUE;
+
+        case COLUMN_MEMORYUSAGEDELTA:
+            SH_FormatInteger(PerfDataGetWorkingSetSizeDelta(Index) / 1024, lpText, nMaxCount);
+            StringCchCatW(lpText, nMaxCount, L" K");
+            return TRUE;
+
+        case COLUMN_PAGEFAULTS:
+            SH_FormatInteger(PerfDataGetPageFaultCount(Index), lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_PAGEFAULTSDELTA:
+            SH_FormatInteger(PerfDataGetPageFaultCountDelta(Index), lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_VIRTUALMEMORYSIZE:
+            SH_FormatInteger(PerfDataGetVirtualMemorySizeBytes(Index) / 1024, lpText, nMaxCount);
+            StringCchCatW(lpText, nMaxCount, L" K");
+            return TRUE;
+
+        case COLUMN_PAGEDPOOL:
+            SH_FormatInteger(PerfDataGetPagedPoolUsagePages(Index) / 1024, lpText, nMaxCount);
+            StringCchCatW(lpText, nMaxCount, L" K");
+            return TRUE;
+
+        case COLUMN_NONPAGEDPOOL:
+            SH_FormatInteger(PerfDataGetNonPagedPoolUsagePages(Index) / 1024, lpText, nMaxCount);
+            StringCchCatW(lpText, nMaxCount, L" K");
+            return TRUE;
+
+        case COLUMN_BASEPRIORITY:
+            StringCchPrintfW(lpText, nMaxCount, L"%lu", PerfDataGetBasePriority(Index));
+            return TRUE;
+
+        case COLUMN_HANDLECOUNT:
+            SH_FormatInteger(PerfDataGetHandleCount(Index), lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_THREADCOUNT:
+            SH_FormatInteger(PerfDataGetThreadCount(Index), lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_USEROBJECTS:
+            SH_FormatInteger(PerfDataGetUSERObjectCount(Index), lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_GDIOBJECTS:
+            SH_FormatInteger(PerfDataGetGDIObjectCount(Index), lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_IOREADS:
+            PerfDataGetIOCounters(Index, &iocounters);
+            SH_FormatInteger(iocounters.ReadOperationCount, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_IOWRITES:
+            PerfDataGetIOCounters(Index, &iocounters);
+            SH_FormatInteger(iocounters.WriteOperationCount, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_IOOTHER:
+            PerfDataGetIOCounters(Index, &iocounters);
+            SH_FormatInteger(iocounters.OtherOperationCount, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_IOREADBYTES:
+            PerfDataGetIOCounters(Index, &iocounters);
+            SH_FormatInteger(iocounters.ReadTransferCount, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_IOWRITEBYTES:
+            PerfDataGetIOCounters(Index, &iocounters);
+            SH_FormatInteger(iocounters.WriteTransferCount, lpText, nMaxCount);
+            return TRUE;
+
+        case COLUMN_IOOTHERBYTES:
+            PerfDataGetIOCounters(Index, &iocounters);
+            SH_FormatInteger(iocounters.OtherTransferCount, lpText, nMaxCount);
+            return TRUE;
     }
 
     return FALSE;