https://git.reactos.org/?p=reactos.git;a=commitdiff;h=84607161b4701bc7eb89e…
commit 84607161b4701bc7eb89e443eff6c6f484247184
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Mon Jan 20 09:51:27 2025 +0900
Commit: GitHub <noreply(a)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-sh…
+ */
+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.mz(a)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