https://git.reactos.org/?p=reactos.git;a=commitdiff;h=84df40a128656ff34149f…
commit 84df40a128656ff34149f2e336f1803059b144e7
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Jan 28 23:23:54 2025 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Jan 28 23:23:54 2025 +0900
[SHELL32][SHELL32_APITEST][SDK] SHGetComputerDisplayNameW (#7670)
Implementing missing features...
JIRA issue: CORE-19278
- Modify shell32.spec.
- Move function definition from
stubs.cpp to utils.cpp.
- Implement
SHGetComputerDisplayNameW
function.
- Add prototype to <undocshell.h>.
---
dll/win32/shell32/shell32.spec | 2 +-
dll/win32/shell32/stubs.cpp | 7 -
dll/win32/shell32/utils.cpp | 147 +++++++++++++++++++
modules/rostests/apitests/shell32/CMakeLists.txt | 1 +
.../apitests/shell32/SHGetComputerDisplayNameW.cpp | 159 +++++++++++++++++++++
modules/rostests/apitests/shell32/testlist.c | 2 +
sdk/include/reactos/undocshell.h | 11 ++
7 files changed, 321 insertions(+), 8 deletions(-)
diff --git a/dll/win32/shell32/shell32.spec b/dll/win32/shell32/shell32.spec
index 86a376f49e6..2784c946de8 100644
--- a/dll/win32/shell32/shell32.spec
+++ b/dll/win32/shell32/shell32.spec
@@ -460,7 +460,7 @@
749 stdcall -noname -version=0x501-0x502 SHGetShellStyleHInstance()
750 stdcall -noname SHGetAttributesFromDataObject(ptr long ptr ptr)
751 stub -noname SHSimulateDropOnClsid
-752 stdcall -noname SHGetComputerDisplayNameW(long long long long)
+752 stdcall -noname SHGetComputerDisplayNameW(wstr long ptr long)
753 stdcall -noname CheckStagingArea()
754 stub -noname SHLimitInputEditWithFlags
755 stdcall -noname PathIsEqualOrSubFolder(wstr wstr)
diff --git a/dll/win32/shell32/stubs.cpp b/dll/win32/shell32/stubs.cpp
index 3034c25d9fd..efda8e0864a 100644
--- a/dll/win32/shell32/stubs.cpp
+++ b/dll/win32/shell32/stubs.cpp
@@ -820,10 +820,3 @@ DWORD WINAPI CheckStagingArea(VOID)
/* Called by native explorer */
return 0;
}
-
-EXTERN_C
-DWORD WINAPI SHGetComputerDisplayNameW(DWORD param1, DWORD param2, DWORD param3, DWORD
param4)
-{
- FIXME("SHGetComputerDisplayNameW() stub\n");
- return E_FAIL;
-}
diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp
index 693a8619aff..6a7b139f191 100644
--- a/dll/win32/shell32/utils.cpp
+++ b/dll/win32/shell32/utils.cpp
@@ -9,6 +9,7 @@
#include <lmcons.h>
#include <lmapibuf.h>
#include <lmaccess.h>
+#include <lmserver.h>
#include <secext.h>
WINE_DEFAULT_DEBUG_CHANNEL(shell);
@@ -1893,3 +1894,149 @@ SHGetUserDisplayName(
return hr;
}
+
+// Skip leading backslashes
+static PCWSTR
+SHELL_SkipServerSlashes(
+ _In_ PCWSTR pszPath)
+{
+ PCWSTR pch;
+ for (pch = pszPath; *pch == L'\\'; ++pch)
+ ;
+ return pch;
+}
+
+// The registry key for server computer descriptions cache
+#define COMPUTER_DESCRIPTIONS_KEY \
+
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComputerDescriptions"
+
+// Get server computer description from cache
+static HRESULT
+SHELL_GetCachedComputerDescription(
+ _Out_writes_z_(cchDescMax) PWSTR pszDesc,
+ _In_ DWORD cchDescMax,
+ _In_ PCWSTR pszServerName)
+{
+ cchDescMax *= sizeof(WCHAR);
+ DWORD error = SHGetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY,
+ SHELL_SkipServerSlashes(pszServerName), NULL, pszDesc,
&cchDescMax);
+ return HRESULT_FROM_WIN32(error);
+}
+
+// Do cache a server computer description
+static VOID
+SHELL_CacheComputerDescription(
+ _In_ PCWSTR pszServerName,
+ _In_ PCWSTR pszDesc)
+{
+ if (!pszDesc)
+ return;
+
+ SIZE_T cbDesc = (wcslen(pszDesc) + 1) * sizeof(WCHAR);
+ SHSetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY,
+ SHELL_SkipServerSlashes(pszServerName), REG_SZ, pszDesc, (DWORD)cbDesc);
+}
+
+// Get real server computer description
+static HRESULT
+SHELL_GetComputerDescription(
+ _Out_writes_z_(cchDescMax) PWSTR pszDesc,
+ _In_ SIZE_T cchDescMax,
+ _In_ PWSTR pszServerName)
+{
+ PSERVER_INFO_101 bufptr;
+ NET_API_STATUS error = NetServerGetInfo(pszServerName, 101, (PBYTE*)&bufptr);
+ HRESULT hr = (error > 0) ? HRESULT_FROM_WIN32(error) : error;
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ PCWSTR comment = bufptr->sv101_comment;
+ if (comment && comment[0])
+ StringCchCopyW(pszDesc, cchDescMax, comment);
+ else
+ hr = E_FAIL;
+
+ NetApiBufferFree(bufptr);
+ return hr;
+}
+
+// Build computer display name
+static HRESULT
+SHELL_BuildDisplayMachineName(
+ _Out_writes_z_(cchNameMax) PWSTR pszName,
+ _In_ DWORD cchNameMax,
+ _In_ PCWSTR pszServerName,
+ _In_ PCWSTR pszDescription)
+{
+ if (!pszDescription || !*pszDescription)
+ return E_FAIL;
+
+ PCWSTR pszFormat = (SHRestricted(REST_ALLOWCOMMENTTOGGLE) ? L"%2 (%1)" :
L"%1 (%2)");
+ PCWSTR args[] = { pszDescription , SHELL_SkipServerSlashes(pszServerName) };
+ return (FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING,
+ pszFormat, 0, 0, pszName, cchNameMax, (va_list *)args) ? S_OK
: E_FAIL);
+}
+
+/*************************************************************************
+ * SHGetComputerDisplayNameW [SHELL32.752]
+ */
+EXTERN_C
+HRESULT WINAPI
+SHGetComputerDisplayNameW(
+ _In_opt_ PWSTR pszServerName,
+ _In_ DWORD dwFlags,
+ _Out_writes_z_(cchNameMax) PWSTR pszName,
+ _In_ DWORD cchNameMax)
+{
+ WCHAR szDesc[256], szCompName[MAX_COMPUTERNAME_LENGTH + 1];
+
+ // If no server name is specified, retrieve the local computer name
+ if (!pszServerName)
+ {
+ // Use computer name as server name
+ DWORD cchCompName = _countof(szCompName);
+ if (!GetComputerNameW(szCompName, &cchCompName))
+ return E_FAIL;
+ pszServerName = szCompName;
+
+ // Don't use the cache for the local machine
+ dwFlags |= SHGCDN_NOCACHE;
+ }
+
+ // Get computer description from cache if necessary
+ HRESULT hr = E_FAIL;
+ if (!(dwFlags & SHGCDN_NOCACHE))
+ hr = SHELL_GetCachedComputerDescription(szDesc, _countof(szDesc),
pszServerName);
+
+ // Actually retrieve the computer description if it is not in the cache
+ if (FAILED(hr))
+ {
+ hr = SHELL_GetComputerDescription(szDesc, _countof(szDesc), pszServerName);
+ if (FAILED(hr))
+ szDesc[0] = UNICODE_NULL;
+
+ // Cache the description if necessary
+ if (!(dwFlags & SHGCDN_NOCACHE))
+ SHELL_CacheComputerDescription(pszServerName, szDesc);
+ }
+
+ // If getting the computer description failed, store the server name only
+ if (FAILED(hr) || !szDesc[0])
+ {
+ if (dwFlags & SHGCDN_NOSERVERNAME)
+ return hr; // Bail out if no server name is requested
+
+ StringCchCopyW(pszName, cchNameMax, SHELL_SkipServerSlashes(pszServerName));
+ return S_OK;
+ }
+
+ // If no server name is requested, store the description only
+ if (dwFlags & SHGCDN_NOSERVERNAME)
+ {
+ StringCchCopyW(pszName, cchNameMax, szDesc);
+ return S_OK;
+ }
+
+ // Build a string like "Description (SERVERNAME)"
+ return SHELL_BuildDisplayMachineName(pszName, cchNameMax, pszServerName, szDesc);
+}
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt
b/modules/rostests/apitests/shell32/CMakeLists.txt
index 6f4dfdb00f3..5389915fd87 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
+ SHGetComputerDisplayNameW.cpp
SHGetUnreadMailCountW.cpp
SHIsBadInterfacePtr.cpp
SHParseDisplayName.cpp
diff --git a/modules/rostests/apitests/shell32/SHGetComputerDisplayNameW.cpp
b/modules/rostests/apitests/shell32/SHGetComputerDisplayNameW.cpp
new file mode 100644
index 00000000000..e4d6f49f1b8
--- /dev/null
+++ b/modules/rostests/apitests/shell32/SHGetComputerDisplayNameW.cpp
@@ -0,0 +1,159 @@
+/*
+ * PROJECT: ReactOS API Tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Tests for SHGetComputerDisplayNameW
+ * COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ
<katayama.hirofumi.mz(a)gmail.com>
+ */
+
+#include "shelltest.h"
+#include <lmserver.h>
+#include <undocshell.h>
+#include <strsafe.h>
+#include <versionhelpers.h>
+
+typedef HRESULT (WINAPI *FN_SHGetComputerDisplayNameW)(PWSTR, DWORD, PWSTR, DWORD);
+typedef NET_API_STATUS (WINAPI *FN_NetServerGetInfo)(LPWSTR, DWORD, PBYTE*);
+typedef NET_API_STATUS (WINAPI *FN_NetApiBufferFree)(PVOID);
+
+static FN_SHGetComputerDisplayNameW s_pSHGetComputerDisplayNameW = NULL;
+static FN_NetServerGetInfo s_pNetServerGetInfo = NULL;
+static FN_NetApiBufferFree s_pNetApiBufferFree = NULL;
+
+#define COMPUTER_DESCRIPTIONS_KEY \
+
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComputerDescriptions"
+
+static PCWSTR
+SHELL_SkipServerSlashes(
+ _In_ PCWSTR pszPath)
+{
+ PCWSTR pch;
+ for (pch = pszPath; *pch == L'\\'; ++pch)
+ ;
+ return pch;
+}
+
+static VOID
+SHELL_CacheComputerDescription(
+ _In_ PCWSTR pszServerName,
+ _In_ PCWSTR pszDesc)
+{
+ if (!pszDesc)
+ return;
+
+ SIZE_T cbDesc = (wcslen(pszDesc) + 1) * sizeof(WCHAR);
+ SHSetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY,
+ SHELL_SkipServerSlashes(pszServerName), REG_SZ, pszDesc, (DWORD)cbDesc);
+}
+
+static HRESULT
+SHELL_GetCachedComputerDescription(
+ _Out_writes_z_(cchDescMax) PWSTR pszDesc,
+ _In_ DWORD cchDescMax,
+ _In_ PCWSTR pszServerName)
+{
+ cchDescMax *= sizeof(WCHAR);
+ DWORD error = SHGetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY,
+ SHELL_SkipServerSlashes(pszServerName), NULL, pszDesc,
&cchDescMax);
+ return HRESULT_FROM_WIN32(error);
+}
+
+static HRESULT
+SHELL_BuildDisplayMachineName(
+ _Out_writes_z_(cchNameMax) PWSTR pszName,
+ _In_ DWORD cchNameMax,
+ _In_ PCWSTR pszServerName,
+ _In_ PCWSTR pszDescription)
+{
+ if (!pszDescription || !*pszDescription)
+ return E_FAIL;
+
+ PCWSTR pszFormat = (SHRestricted(REST_ALLOWCOMMENTTOGGLE) ? L"%2 (%1)" :
L"%1 (%2)");
+ PCWSTR args[] = { pszDescription , SHELL_SkipServerSlashes(pszServerName) };
+ return (FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING,
+ pszFormat, 0, 0, pszName, cchNameMax, (va_list *)args) ? S_OK
: E_FAIL);
+}
+
+static VOID
+TEST_SHGetComputerDisplayNameW(VOID)
+{
+ WCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1], szDesc[256], szDisplayName[MAX_PATH];
+ WCHAR szName[MAX_PATH], szServerName[] = L"DummyServerName";
+
+ DWORD cchCompName = _countof(szCompName);
+ BOOL ret = GetComputerNameW(szCompName, &cchCompName);
+ ok_int(ret, TRUE);
+ trace("%s\n", wine_dbgstr_w(szCompName));
+
+ SHELL_CacheComputerDescription(szServerName, L"DummyDescription");
+
+ HRESULT hr = SHELL_GetCachedComputerDescription(szDesc, _countof(szDesc),
szServerName);
+ if (FAILED(hr))
+ szDesc[0] = UNICODE_NULL;
+ trace("%s\n", wine_dbgstr_w(szDesc));
+
+ StringCchCopyW(szDisplayName, _countof(szDisplayName), L"@");
+ hr = s_pSHGetComputerDisplayNameW(NULL, SHGCDN_NOCACHE, szDisplayName,
_countof(szDisplayName));
+ ok_hex(hr, S_OK);
+ trace("%s\n", wine_dbgstr_w(szDisplayName));
+ ok_wstr(szDisplayName, szCompName);
+
+ StringCchCopyW(szDisplayName, _countof(szDisplayName), L"@");
+ hr = s_pSHGetComputerDisplayNameW(szServerName, 0, szDisplayName,
_countof(szDisplayName));
+ ok_hex(hr, S_OK);
+ trace("%s\n", wine_dbgstr_w(szServerName));
+ ok_wstr(szServerName, L"DummyServerName");
+
+ hr = SHELL_BuildDisplayMachineName(szName, _countof(szName), szServerName, szDesc);
+ ok_hex(hr, S_OK);
+
+ trace("%s\n", wine_dbgstr_w(szDisplayName));
+ trace("%s\n", wine_dbgstr_w(szName));
+ ok_wstr(szDisplayName, szName);
+
+ // Delete registry value
+ HKEY hKey;
+ LSTATUS error = RegOpenKeyExW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY, 0,
KEY_WRITE, &hKey);
+ if (error == ERROR_SUCCESS)
+ {
+ RegDeleteValueW(hKey, L"DummyServerName");
+ RegCloseKey(hKey);
+ }
+}
+
+START_TEST(SHGetComputerDisplayNameW)
+{
+ if (IsWindowsVistaOrGreater())
+ {
+ skip("Tests on Vista+ will cause exception\n");
+ return;
+ }
+
+ HINSTANCE hShell32 = GetModuleHandleW(L"shell32.dll");
+ s_pSHGetComputerDisplayNameW =
+ (FN_SHGetComputerDisplayNameW)GetProcAddress(hShell32, MAKEINTRESOURCEA(752));
+ if (!s_pSHGetComputerDisplayNameW)
+ {
+ skip("SHGetComputerDisplayNameW not found\n");
+ return;
+ }
+
+ HINSTANCE hNetApi32 = LoadLibraryW(L"netapi32.dll");
+ if (!hNetApi32)
+ {
+ skip("netapi32.dll not found\n");
+ return;
+ }
+
+ s_pNetServerGetInfo = (FN_NetServerGetInfo)GetProcAddress(hNetApi32,
"NetServerGetInfo");
+ s_pNetApiBufferFree = (FN_NetApiBufferFree)GetProcAddress(hNetApi32,
"NetApiBufferFree");
+ if (!s_pNetServerGetInfo || !s_pNetApiBufferFree)
+ {
+ skip("NetServerGetInfo or NetApiBufferFree not found\n");
+ FreeLibrary(hNetApi32);
+ return;
+ }
+
+ TEST_SHGetComputerDisplayNameW();
+
+ FreeLibrary(hNetApi32);
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c
b/modules/rostests/apitests/shell32/testlist.c
index 91078fb8cc1..1c964c36be4 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -43,6 +43,7 @@ extern void func_ShellExecuteW(void);
extern void func_ShellHook(void);
extern void func_ShellState(void);
extern void func_SHGetAttributesFromDataObject(void);
+extern void func_SHGetComputerDisplayNameW(void);
extern void func_SHGetFileInfo(void);
extern void func_SHGetUnreadMailCountW(void);
extern void func_SHGetUserDisplayName(void);
@@ -97,6 +98,7 @@ const struct test winetest_testlist[] =
{ "ShellHook", func_ShellHook },
{ "ShellState", func_ShellState },
{ "SHGetAttributesFromDataObject", func_SHGetAttributesFromDataObject },
+ { "SHGetComputerDisplayNameW", func_SHGetComputerDisplayNameW },
{ "SHGetFileInfo", func_SHGetFileInfo },
{ "SHGetUnreadMailCountW", func_SHGetUnreadMailCountW },
{ "SHGetUserDisplayName", func_SHGetUserDisplayName },
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index 574f4851e1a..187a74f4d44 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -966,6 +966,17 @@ CopyStreamUI(
_Inout_opt_ IProgressDialog *pProgress,
_In_opt_ DWORDLONG dwlSize);
+// Flags for SHGetComputerDisplayNameW
+#define SHGCDN_NOCACHE 0x1
+#define SHGCDN_NOSERVERNAME 0x10000
+
+HRESULT WINAPI
+SHGetComputerDisplayNameW(
+ _In_opt_ LPWSTR pszServerName,
+ _In_ DWORD dwFlags,
+ _Out_writes_z_(cchNameMax) LPWSTR pszName,
+ _In_ DWORD cchNameMax);
+
/*****************************************************************************
* INVALID_FILETITLE_CHARACTERS
*/