Skip to content

Commit 8460716

Browse files
authored
[SHELL32][SHELL32_APITEST][SDK] Implement SHGetUnreadMailCountW (reactos#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>.
1 parent 157e18b commit 8460716

File tree

7 files changed

+211
-17
lines changed

7 files changed

+211
-17
lines changed

dll/win32/shell32/shell32.spec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@
317317
317 stdcall SHGetSpecialFolderLocation(long long ptr)
318318
318 stdcall SHGetSpecialFolderPathA(long ptr long long)
319319
319 stdcall SHGetSpecialFolderPathW(long ptr long long)
320-
320 stdcall SHGetUnreadMailCountW (long wstr long ptr wstr long)
320+
320 stdcall SHGetUnreadMailCountW(ptr wstr ptr ptr ptr long)
321321
321 stdcall SHHelpShortcuts_RunDLL(long long long long) SHHelpShortcuts_RunDLLA
322322
322 stdcall SHHelpShortcuts_RunDLLA(long long long long)
323323
323 stdcall SHHelpShortcuts_RunDLLW(long long long long)

dll/win32/shell32/stubs.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,6 @@
1414

1515
WINE_DEFAULT_DEBUG_CHANNEL(shell);
1616

17-
/*
18-
* Unimplemented
19-
*/
20-
EXTERN_C HRESULT
21-
WINAPI
22-
SHGetUnreadMailCountW(HKEY hKeyUser,
23-
LPCWSTR pszMailAddress,
24-
DWORD *pdwCount,
25-
FILETIME *pFileTime,
26-
LPWSTR pszShellExecuteCommand,
27-
int cchShellExecuteCommand)
28-
{
29-
FIXME("SHGetUnreadMailCountW() stub\n");
30-
return E_FAIL;
31-
}
32-
3317
/*
3418
* Unimplemented
3519
*/

dll/win32/shell32/utils.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,123 @@ SHCreatePropertyBag(_In_ REFIID riid, _Out_ void **ppvObj)
878878
return SHCreatePropertyBagOnMemory(STGM_READWRITE, riid, ppvObj);
879879
}
880880

881+
// The helper function for SHGetUnreadMailCountW
882+
static DWORD
883+
SHELL_ReadSingleUnreadMailCount(
884+
_In_ HKEY hKey,
885+
_Out_opt_ PDWORD pdwCount,
886+
_Out_opt_ PFILETIME pFileTime,
887+
_Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand,
888+
_In_ INT cchShellExecuteCommand)
889+
{
890+
DWORD dwType, dwCount, cbSize = sizeof(dwCount);
891+
DWORD error = SHQueryValueExW(hKey, L"MessageCount", 0, &dwType, &dwCount, &cbSize);
892+
if (error)
893+
return error;
894+
if (pdwCount && dwType == REG_DWORD)
895+
*pdwCount = dwCount;
896+
897+
FILETIME FileTime;
898+
cbSize = sizeof(FileTime);
899+
error = SHQueryValueExW(hKey, L"TimeStamp", 0, &dwType, &FileTime, &cbSize);
900+
if (error)
901+
return error;
902+
if (pFileTime && dwType == REG_BINARY)
903+
*pFileTime = FileTime;
904+
905+
WCHAR szName[2 * MAX_PATH];
906+
cbSize = sizeof(szName);
907+
error = SHQueryValueExW(hKey, L"Application", 0, &dwType, szName, &cbSize);
908+
if (error)
909+
return error;
910+
911+
if (pszShellExecuteCommand && dwType == REG_SZ &&
912+
FAILED(StringCchCopyW(pszShellExecuteCommand, cchShellExecuteCommand, szName)))
913+
{
914+
return ERROR_INSUFFICIENT_BUFFER;
915+
}
916+
917+
return ERROR_SUCCESS;
918+
}
919+
920+
/*************************************************************************
921+
* SHGetUnreadMailCountW [SHELL32.320]
922+
*
923+
* @see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetunreadmailcountw
924+
*/
925+
EXTERN_C
926+
HRESULT WINAPI
927+
SHGetUnreadMailCountW(
928+
_In_opt_ HKEY hKeyUser,
929+
_In_opt_ LPCWSTR pszMailAddress,
930+
_Out_opt_ PDWORD pdwCount,
931+
_Inout_opt_ PFILETIME pFileTime,
932+
_Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand,
933+
_In_ INT cchShellExecuteCommand)
934+
{
935+
LSTATUS error;
936+
HKEY hKey;
937+
938+
if (!hKeyUser)
939+
hKeyUser = HKEY_CURRENT_USER;
940+
941+
if (pszMailAddress)
942+
{
943+
CStringW strKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail";
944+
strKey += L'\\';
945+
strKey += pszMailAddress;
946+
947+
error = RegOpenKeyExW(hKeyUser, strKey, 0, KEY_QUERY_VALUE, &hKey);
948+
if (error)
949+
return HRESULT_FROM_WIN32(error);
950+
951+
error = SHELL_ReadSingleUnreadMailCount(hKey, pdwCount, pFileTime,
952+
pszShellExecuteCommand, cchShellExecuteCommand);
953+
}
954+
else
955+
{
956+
if (pszShellExecuteCommand || cchShellExecuteCommand)
957+
return E_INVALIDARG;
958+
959+
*pdwCount = 0;
960+
961+
error = RegOpenKeyExW(hKeyUser, L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail",
962+
0, KEY_ENUMERATE_SUB_KEYS, &hKey);
963+
if (error)
964+
return HRESULT_FROM_WIN32(error);
965+
966+
for (DWORD dwIndex = 0; !error; ++dwIndex)
967+
{
968+
WCHAR Name[2 * MAX_PATH];
969+
DWORD cchName = _countof(Name);
970+
FILETIME LastWritten;
971+
error = RegEnumKeyExW(hKey, dwIndex, Name, &cchName, NULL, NULL, NULL, &LastWritten);
972+
if (error)
973+
break;
974+
975+
HKEY hSubKey;
976+
error = RegOpenKeyExW(hKey, Name, 0, KEY_QUERY_VALUE, &hSubKey);
977+
if (error)
978+
break;
979+
980+
FILETIME FileTime;
981+
DWORD dwCount;
982+
error = SHELL_ReadSingleUnreadMailCount(hSubKey, &dwCount, &FileTime, NULL, 0);
983+
if (!error && (!pFileTime || CompareFileTime(&FileTime, pFileTime) >= 0))
984+
*pdwCount += dwCount;
985+
986+
RegCloseKey(hSubKey);
987+
}
988+
989+
if (error == ERROR_NO_MORE_ITEMS)
990+
error = ERROR_SUCCESS;
991+
}
992+
993+
RegCloseKey(hKey);
994+
995+
return error ? HRESULT_FROM_WIN32(error) : S_OK;
996+
}
997+
881998
/*************************************************************************
882999
* SHSetUnreadMailCountW [SHELL32.336]
8831000
*

modules/rostests/apitests/shell32/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ list(APPEND SOURCE
3131
SHCreateDataObject.cpp
3232
SHCreateFileDataObject.cpp
3333
SHCreateFileExtractIconW.cpp
34+
SHGetUnreadMailCountW.cpp
3435
SHParseDisplayName.cpp
3536
SHRestricted.cpp
3637
SHShouldShowWizards.cpp
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* PROJECT: ReactOS API tests
3+
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4+
* PURPOSE: Test for SHGetUnreadMailCountW
5+
* COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ ([email protected])
6+
*/
7+
8+
#include "shelltest.h"
9+
10+
static VOID SetUnreadMailInfo(PDWORD pdwDisposition)
11+
{
12+
HKEY hKey;
13+
LSTATUS error = RegCreateKeyExW(
14+
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\example.com",
15+
0, NULL, 0, KEY_WRITE, NULL, &hKey, pdwDisposition);
16+
ok_long(error, ERROR_SUCCESS);
17+
18+
DWORD dwCount = 1;
19+
error = SHSetValueW(hKey, NULL, L"MessageCount", REG_DWORD, &dwCount, sizeof(dwCount));
20+
ok_long(error, ERROR_SUCCESS);
21+
22+
FILETIME FileTime;
23+
GetSystemTimeAsFileTime(&FileTime);
24+
error = SHSetValueW(hKey, NULL, L"TimeStamp", REG_BINARY, &FileTime, sizeof(FileTime));
25+
ok_long(error, ERROR_SUCCESS);
26+
27+
LPCWSTR pszApp = L"MyMailerApp";
28+
DWORD cbValue = (lstrlenW(pszApp) + 1) * sizeof(WCHAR);
29+
error = SHSetValueW(hKey, NULL, L"Application", REG_SZ, pszApp, cbValue);
30+
ok_long(error, ERROR_SUCCESS);
31+
32+
RegCloseKey(hKey);
33+
}
34+
35+
START_TEST(SHGetUnreadMailCountW)
36+
{
37+
HRESULT hr;
38+
39+
DWORD dwDisposition;
40+
SetUnreadMailInfo(&dwDisposition);
41+
42+
hr = SHGetUnreadMailCountW(NULL, L"example.com", NULL, NULL, NULL, 0);
43+
ok_hex(hr, S_OK);
44+
45+
FILETIME FileTime;
46+
ZeroMemory(&FileTime, sizeof(FileTime));
47+
hr = SHGetUnreadMailCountW(HKEY_CURRENT_USER, L"example.com", NULL, &FileTime, NULL, 0);
48+
ok_hex(hr, S_OK);
49+
ok(FileTime.dwHighDateTime != 0, "FileTime.dwHighDateTime was zero\n");
50+
51+
DWORD dwCount = 0;
52+
ZeroMemory(&FileTime, sizeof(FileTime));
53+
hr = SHGetUnreadMailCountW(NULL, NULL, &dwCount, &FileTime, NULL, 0);
54+
ok_hex(hr, S_OK);
55+
ok_long(dwCount, 1);
56+
ok_long(FileTime.dwHighDateTime, 0);
57+
58+
dwCount = 0;
59+
hr = SHGetUnreadMailCountW(NULL, L"example.com", &dwCount, NULL, NULL, 0);
60+
ok_hex(hr, S_OK);
61+
ok_long(dwCount, 1);
62+
63+
hr = SHGetUnreadMailCountW(NULL, NULL, &dwCount, NULL, NULL, 0);
64+
ok_hex(hr, S_OK);
65+
66+
WCHAR szAppName[MAX_PATH];
67+
dwCount = 0;
68+
hr = SHGetUnreadMailCountW(NULL, NULL, &dwCount, NULL, szAppName, _countof(szAppName));
69+
ok_hex(hr, E_INVALIDARG);
70+
ok_long(dwCount, 0);
71+
72+
hr = SHGetUnreadMailCountW(NULL, L"example.com", NULL, NULL, szAppName, _countof(szAppName));
73+
ok_hex(hr, S_OK);
74+
ok_wstr(szAppName, L"MyMailerApp");
75+
76+
if (dwDisposition == REG_CREATED_NEW_KEY)
77+
{
78+
RegDeleteKeyW(HKEY_CURRENT_USER,
79+
L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\example.com");
80+
}
81+
}

modules/rostests/apitests/shell32/testlist.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern void func_ShellHook(void);
4444
extern void func_ShellState(void);
4545
extern void func_SHGetAttributesFromDataObject(void);
4646
extern void func_SHGetFileInfo(void);
47+
extern void func_SHGetUnreadMailCountW(void);
4748
extern void func_SHGetUserDisplayName(void);
4849
extern void func_SHLimitInputEdit(void);
4950
extern void func_SHParseDisplayName(void);
@@ -96,6 +97,7 @@ const struct test winetest_testlist[] =
9697
{ "ShellState", func_ShellState },
9798
{ "SHGetAttributesFromDataObject", func_SHGetAttributesFromDataObject },
9899
{ "SHGetFileInfo", func_SHGetFileInfo },
100+
{ "SHGetUnreadMailCountW", func_SHGetUnreadMailCountW },
99101
{ "SHGetUserDisplayName", func_SHGetUserDisplayName },
100102
{ "SHLimitInputEdit", func_SHLimitInputEdit },
101103
{ "SHParseDisplayName", func_SHParseDisplayName },

sdk/include/psdk/shellapi.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,15 @@ SHEnumerateUnreadMailAccountsW(
659659
_Out_writes_(cchMailAddress) PWSTR pszMailAddress,
660660
_In_ INT cchMailAddress);
661661

662+
HRESULT WINAPI
663+
SHGetUnreadMailCountW(
664+
_In_opt_ HKEY hKeyUser,
665+
_In_opt_ LPCWSTR pszMailAddress,
666+
_Out_opt_ PDWORD pdwCount,
667+
_Inout_opt_ PFILETIME pFileTime,
668+
_Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand,
669+
_In_ INT cchShellExecuteCommand);
670+
662671
#ifdef UNICODE
663672
#define NOTIFYICONDATA_V1_SIZE NOTIFYICONDATAW_V1_SIZE
664673
#define NOTIFYICONDATA_V2_SIZE NOTIFYICONDATAW_V2_SIZE

0 commit comments

Comments
 (0)