https://git.reactos.org/?p=reactos.git;a=commitdiff;h=84df40a128656ff34149f2e336f1803059b144e7

commit 84df40a128656ff34149f2e336f1803059b144e7
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Tue Jan 28 23:23:54 2025 +0900
Commit:     GitHub <nore...@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...@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
  */

Reply via email to