https://git.reactos.org/?p=reactos.git;a=commitdiff;h=84607161b4701bc7eb89e443eff6c6f484247184

commit 84607161b4701bc7eb89e443eff6c6f484247184
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Mon Jan 20 09:51:27 2025 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Mon Jan 20 09:51:27 2025 +0900

    [SHELL32][SHELL32_APITEST][SDK] Implement SHGetUnreadMailCountW (#7622)
    
    Implementing missing features...
    JIRA issue: CORE-19278
    - Modify shell32.spec.
    - Move function definition from stubs.cpp into utils.cpp.
    - Add SHELL_ReadSingleUnreadMailCount helper function.
    - Add prototype to <shellapi.h>.
---
 dll/win32/shell32/shell32.spec                     |   2 +-
 dll/win32/shell32/stubs.cpp                        |  16 ---
 dll/win32/shell32/utils.cpp                        | 117 +++++++++++++++++++++
 modules/rostests/apitests/shell32/CMakeLists.txt   |   1 +
 .../apitests/shell32/SHGetUnreadMailCountW.cpp     |  81 ++++++++++++++
 modules/rostests/apitests/shell32/testlist.c       |   2 +
 sdk/include/psdk/shellapi.h                        |   9 ++
 7 files changed, 211 insertions(+), 17 deletions(-)

diff --git a/dll/win32/shell32/shell32.spec b/dll/win32/shell32/shell32.spec
index 9a4f8b07c43..86a376f49e6 100644
--- a/dll/win32/shell32/shell32.spec
+++ b/dll/win32/shell32/shell32.spec
@@ -317,7 +317,7 @@
 317 stdcall SHGetSpecialFolderLocation(long long ptr)
 318 stdcall SHGetSpecialFolderPathA(long ptr long long)
 319 stdcall SHGetSpecialFolderPathW(long ptr long long)
-320 stdcall SHGetUnreadMailCountW (long wstr long ptr wstr long)
+320 stdcall SHGetUnreadMailCountW(ptr wstr ptr ptr ptr long)
 321 stdcall SHHelpShortcuts_RunDLL(long long long long) SHHelpShortcuts_RunDLLA
 322 stdcall SHHelpShortcuts_RunDLLA(long long long long)
 323 stdcall SHHelpShortcuts_RunDLLW(long long long long)
diff --git a/dll/win32/shell32/stubs.cpp b/dll/win32/shell32/stubs.cpp
index 5698b7dc0c8..f9ef73a2d7e 100644
--- a/dll/win32/shell32/stubs.cpp
+++ b/dll/win32/shell32/stubs.cpp
@@ -14,22 +14,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
-/*
- * Unimplemented
- */
-EXTERN_C HRESULT
-WINAPI
-SHGetUnreadMailCountW(HKEY hKeyUser,
-                      LPCWSTR pszMailAddress,
-                      DWORD *pdwCount,
-                      FILETIME *pFileTime,
-                      LPWSTR pszShellExecuteCommand,
-                      int cchShellExecuteCommand)
-{
-    FIXME("SHGetUnreadMailCountW() stub\n");
-    return E_FAIL;
-}
-
 /*
  * Unimplemented
  */
diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp
index 831d52d3c1e..4e0949eb2bb 100644
--- a/dll/win32/shell32/utils.cpp
+++ b/dll/win32/shell32/utils.cpp
@@ -878,6 +878,123 @@ SHCreatePropertyBag(_In_ REFIID riid, _Out_ void **ppvObj)
     return SHCreatePropertyBagOnMemory(STGM_READWRITE, riid, ppvObj);
 }
 
+// The helper function for SHGetUnreadMailCountW
+static DWORD
+SHELL_ReadSingleUnreadMailCount(
+    _In_ HKEY hKey,
+    _Out_opt_ PDWORD pdwCount,
+    _Out_opt_ PFILETIME pFileTime,
+    _Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand,
+    _In_ INT cchShellExecuteCommand)
+{
+    DWORD dwType, dwCount, cbSize = sizeof(dwCount);
+    DWORD error = SHQueryValueExW(hKey, L"MessageCount", 0, &dwType, &dwCount, 
&cbSize);
+    if (error)
+        return error;
+    if (pdwCount && dwType == REG_DWORD)
+        *pdwCount = dwCount;
+
+    FILETIME FileTime;
+    cbSize = sizeof(FileTime);
+    error = SHQueryValueExW(hKey, L"TimeStamp", 0, &dwType, &FileTime, 
&cbSize);
+    if (error)
+        return error;
+    if (pFileTime && dwType == REG_BINARY)
+        *pFileTime = FileTime;
+
+    WCHAR szName[2 * MAX_PATH];
+    cbSize = sizeof(szName);
+    error = SHQueryValueExW(hKey, L"Application", 0, &dwType, szName, &cbSize);
+    if (error)
+        return error;
+
+    if (pszShellExecuteCommand && dwType == REG_SZ &&
+        FAILED(StringCchCopyW(pszShellExecuteCommand, cchShellExecuteCommand, 
szName)))
+    {
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ *  SHGetUnreadMailCountW [SHELL32.320]
+ *
+ * @see 
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetunreadmailcountw
+ */
+EXTERN_C
+HRESULT WINAPI
+SHGetUnreadMailCountW(
+    _In_opt_ HKEY hKeyUser,
+    _In_opt_ LPCWSTR pszMailAddress,
+    _Out_opt_ PDWORD pdwCount,
+    _Inout_opt_ PFILETIME pFileTime,
+    _Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand,
+    _In_ INT cchShellExecuteCommand)
+{
+    LSTATUS error;
+    HKEY hKey;
+
+    if (!hKeyUser)
+        hKeyUser = HKEY_CURRENT_USER;
+
+    if (pszMailAddress)
+    {
+        CStringW strKey = 
L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail";
+        strKey += L'\\';
+        strKey += pszMailAddress;
+
+        error = RegOpenKeyExW(hKeyUser, strKey, 0, KEY_QUERY_VALUE, &hKey);
+        if (error)
+            return HRESULT_FROM_WIN32(error);
+
+        error = SHELL_ReadSingleUnreadMailCount(hKey, pdwCount, pFileTime,
+                                                pszShellExecuteCommand, 
cchShellExecuteCommand);
+    }
+    else
+    {
+        if (pszShellExecuteCommand || cchShellExecuteCommand)
+            return E_INVALIDARG;
+
+        *pdwCount = 0;
+
+        error = RegOpenKeyExW(hKeyUser, 
L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail",
+                              0, KEY_ENUMERATE_SUB_KEYS, &hKey);
+        if (error)
+            return HRESULT_FROM_WIN32(error);
+
+        for (DWORD dwIndex = 0; !error; ++dwIndex)
+        {
+            WCHAR Name[2 * MAX_PATH];
+            DWORD cchName = _countof(Name);
+            FILETIME LastWritten;
+            error = RegEnumKeyExW(hKey, dwIndex, Name, &cchName, NULL, NULL, 
NULL, &LastWritten);
+            if (error)
+                break;
+
+            HKEY hSubKey;
+            error = RegOpenKeyExW(hKey, Name, 0, KEY_QUERY_VALUE, &hSubKey);
+            if (error)
+                break;
+
+            FILETIME FileTime;
+            DWORD dwCount;
+            error = SHELL_ReadSingleUnreadMailCount(hSubKey, &dwCount, 
&FileTime, NULL, 0);
+            if (!error && (!pFileTime || CompareFileTime(&FileTime, pFileTime) 
>= 0))
+                *pdwCount += dwCount;
+
+            RegCloseKey(hSubKey);
+        }
+
+        if (error == ERROR_NO_MORE_ITEMS)
+            error = ERROR_SUCCESS;
+    }
+
+    RegCloseKey(hKey);
+
+    return error ? HRESULT_FROM_WIN32(error) : S_OK;
+}
+
 /*************************************************************************
  *  SHSetUnreadMailCountW [SHELL32.336]
  *
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt 
b/modules/rostests/apitests/shell32/CMakeLists.txt
index cb6c11bcf8e..3c9a2e73dcf 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -31,6 +31,7 @@ list(APPEND SOURCE
     SHCreateDataObject.cpp
     SHCreateFileDataObject.cpp
     SHCreateFileExtractIconW.cpp
+    SHGetUnreadMailCountW.cpp
     SHParseDisplayName.cpp
     SHRestricted.cpp
     SHShouldShowWizards.cpp
diff --git a/modules/rostests/apitests/shell32/SHGetUnreadMailCountW.cpp 
b/modules/rostests/apitests/shell32/SHGetUnreadMailCountW.cpp
new file mode 100644
index 00000000000..a669cbe1269
--- /dev/null
+++ b/modules/rostests/apitests/shell32/SHGetUnreadMailCountW.cpp
@@ -0,0 +1,81 @@
+/*
+ * PROJECT:     ReactOS API tests
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Test for SHGetUnreadMailCountW
+ * COPYRIGHT:   Copyright 2025 Katayama Hirofumi MZ 
(katayama.hirofumi...@gmail.com)
+ */
+
+#include "shelltest.h"
+
+static VOID SetUnreadMailInfo(PDWORD pdwDisposition)
+{
+    HKEY hKey;
+    LSTATUS error = RegCreateKeyExW(
+        HKEY_CURRENT_USER, 
L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\example.com",
+        0, NULL, 0, KEY_WRITE, NULL, &hKey, pdwDisposition);
+    ok_long(error, ERROR_SUCCESS);
+
+    DWORD dwCount = 1;
+    error = SHSetValueW(hKey, NULL, L"MessageCount", REG_DWORD, &dwCount, 
sizeof(dwCount));
+    ok_long(error, ERROR_SUCCESS);
+
+    FILETIME FileTime;
+    GetSystemTimeAsFileTime(&FileTime);
+    error = SHSetValueW(hKey, NULL, L"TimeStamp", REG_BINARY, &FileTime, 
sizeof(FileTime));
+    ok_long(error, ERROR_SUCCESS);
+
+    LPCWSTR pszApp = L"MyMailerApp";
+    DWORD cbValue = (lstrlenW(pszApp) + 1) * sizeof(WCHAR);
+    error = SHSetValueW(hKey, NULL, L"Application", REG_SZ, pszApp, cbValue);
+    ok_long(error, ERROR_SUCCESS);
+
+    RegCloseKey(hKey);
+}
+
+START_TEST(SHGetUnreadMailCountW)
+{
+    HRESULT hr;
+
+    DWORD dwDisposition;
+    SetUnreadMailInfo(&dwDisposition);
+
+    hr = SHGetUnreadMailCountW(NULL, L"example.com", NULL, NULL, NULL, 0);
+    ok_hex(hr, S_OK);
+
+    FILETIME FileTime;
+    ZeroMemory(&FileTime, sizeof(FileTime));
+    hr = SHGetUnreadMailCountW(HKEY_CURRENT_USER, L"example.com", NULL, 
&FileTime, NULL, 0);
+    ok_hex(hr, S_OK);
+    ok(FileTime.dwHighDateTime != 0, "FileTime.dwHighDateTime was zero\n");
+
+    DWORD dwCount = 0;
+    ZeroMemory(&FileTime, sizeof(FileTime));
+    hr = SHGetUnreadMailCountW(NULL, NULL, &dwCount, &FileTime, NULL, 0);
+    ok_hex(hr, S_OK);
+    ok_long(dwCount, 1);
+    ok_long(FileTime.dwHighDateTime, 0);
+
+    dwCount = 0;
+    hr = SHGetUnreadMailCountW(NULL, L"example.com", &dwCount, NULL, NULL, 0);
+    ok_hex(hr, S_OK);
+    ok_long(dwCount, 1);
+
+    hr = SHGetUnreadMailCountW(NULL, NULL, &dwCount, NULL, NULL, 0);
+    ok_hex(hr, S_OK);
+
+    WCHAR szAppName[MAX_PATH];
+    dwCount = 0;
+    hr = SHGetUnreadMailCountW(NULL, NULL, &dwCount, NULL, szAppName, 
_countof(szAppName));
+    ok_hex(hr, E_INVALIDARG);
+    ok_long(dwCount, 0);
+
+    hr = SHGetUnreadMailCountW(NULL, L"example.com", NULL, NULL, szAppName, 
_countof(szAppName));
+    ok_hex(hr, S_OK);
+    ok_wstr(szAppName, L"MyMailerApp");
+
+    if (dwDisposition == REG_CREATED_NEW_KEY)
+    {
+        RegDeleteKeyW(HKEY_CURRENT_USER,
+                      
L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\example.com");
+    }
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c 
b/modules/rostests/apitests/shell32/testlist.c
index fc879889ebe..3c1cbd7e045 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -44,6 +44,7 @@ extern void func_ShellHook(void);
 extern void func_ShellState(void);
 extern void func_SHGetAttributesFromDataObject(void);
 extern void func_SHGetFileInfo(void);
+extern void func_SHGetUnreadMailCountW(void);
 extern void func_SHGetUserDisplayName(void);
 extern void func_SHLimitInputEdit(void);
 extern void func_SHParseDisplayName(void);
@@ -96,6 +97,7 @@ const struct test winetest_testlist[] =
     { "ShellState", func_ShellState },
     { "SHGetAttributesFromDataObject", func_SHGetAttributesFromDataObject },
     { "SHGetFileInfo", func_SHGetFileInfo },
+    { "SHGetUnreadMailCountW", func_SHGetUnreadMailCountW },
     { "SHGetUserDisplayName", func_SHGetUserDisplayName },
     { "SHLimitInputEdit", func_SHLimitInputEdit },
     { "SHParseDisplayName", func_SHParseDisplayName },
diff --git a/sdk/include/psdk/shellapi.h b/sdk/include/psdk/shellapi.h
index b707d6d41df..f343928aa62 100644
--- a/sdk/include/psdk/shellapi.h
+++ b/sdk/include/psdk/shellapi.h
@@ -659,6 +659,15 @@ SHEnumerateUnreadMailAccountsW(
     _Out_writes_(cchMailAddress) PWSTR pszMailAddress,
     _In_ INT cchMailAddress);
 
+HRESULT WINAPI
+SHGetUnreadMailCountW(
+    _In_opt_ HKEY hKeyUser,
+    _In_opt_ LPCWSTR pszMailAddress,
+    _Out_opt_ PDWORD pdwCount,
+    _Inout_opt_ PFILETIME pFileTime,
+    _Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand,
+    _In_ INT cchShellExecuteCommand);
+
 #ifdef UNICODE
 #define NOTIFYICONDATA_V1_SIZE NOTIFYICONDATAW_V1_SIZE
 #define NOTIFYICONDATA_V2_SIZE NOTIFYICONDATAW_V2_SIZE

Reply via email to