Reactos
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Tests for SHGetComputerDisplayNameW
5 * COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8#include "shelltest.h"
9#include <lmserver.h>
10#include <undocshell.h>
11#include <strsafe.h>
12#include <versionhelpers.h>
13
14typedef HRESULT (WINAPI *FN_SHGetComputerDisplayNameW)(PWSTR, DWORD, PWSTR, DWORD);
15typedef NET_API_STATUS (WINAPI *FN_NetServerGetInfo)(LPWSTR, DWORD, PBYTE*);
16typedef NET_API_STATUS (WINAPI *FN_NetApiBufferFree)(PVOID);
17
18static FN_SHGetComputerDisplayNameW s_pSHGetComputerDisplayNameW = NULL;
19static FN_NetServerGetInfo s_pNetServerGetInfo = NULL;
20static FN_NetApiBufferFree s_pNetApiBufferFree = NULL;
21
22#define COMPUTER_DESCRIPTIONS_KEY \
23 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComputerDescriptions"
24
25static PCWSTR
26SHELL_SkipServerSlashes(
27 _In_ PCWSTR pszPath)
28{
29 PCWSTR pch;
30 for (pch = pszPath; *pch == L'\\'; ++pch)
31 ;
32 return pch;
33}
34
35static VOID
36SHELL_CacheComputerDescription(
37 _In_ PCWSTR pszServerName,
38 _In_ PCWSTR pszDesc)
39{
40 if (!pszDesc)
41 return;
42
43 SIZE_T cbDesc = (wcslen(pszDesc) + 1) * sizeof(WCHAR);
44 SHSetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY,
45 SHELL_SkipServerSlashes(pszServerName), REG_SZ, pszDesc, (DWORD)cbDesc);
46}
47
48static HRESULT
49SHELL_GetCachedComputerDescription(
50 _Out_writes_z_(cchDescMax) PWSTR pszDesc,
51 _In_ DWORD cchDescMax,
52 _In_ PCWSTR pszServerName)
53{
54 cchDescMax *= sizeof(WCHAR);
55 DWORD error = SHGetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY,
56 SHELL_SkipServerSlashes(pszServerName), NULL, pszDesc, &cchDescMax);
57 return HRESULT_FROM_WIN32(error);
58}
59
60static HRESULT
61SHELL_BuildDisplayMachineName(
62 _Out_writes_z_(cchNameMax) PWSTR pszName,
63 _In_ DWORD cchNameMax,
64 _In_ PCWSTR pszServerName,
65 _In_ PCWSTR pszDescription)
66{
67 if (!pszDescription || !*pszDescription)
68 return E_FAIL;
69
70 PCWSTR pszFormat = (SHRestricted(REST_ALLOWCOMMENTTOGGLE) ? L"%2 (%1)" : L"%1 (%2)");
71 PCWSTR args[] = { pszDescription , SHELL_SkipServerSlashes(pszServerName) };
72 return (FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING,
73 pszFormat, 0, 0, pszName, cchNameMax, (va_list *)args) ? S_OK : E_FAIL);
74}
75
76static VOID
77TEST_SHGetComputerDisplayNameW(VOID)
78{
79 WCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1], szDesc[256], szDisplayName[MAX_PATH];
80 WCHAR szName[MAX_PATH], szServerName[] = L"DummyServerName";
81
82 DWORD cchCompName = _countof(szCompName);
83 BOOL ret = GetComputerNameW(szCompName, &cchCompName);
84 ok_int(ret, TRUE);
85 trace("%s\n", wine_dbgstr_w(szCompName));
86
87 SHELL_CacheComputerDescription(szServerName, L"DummyDescription");
88
89 HRESULT hr = SHELL_GetCachedComputerDescription(szDesc, _countof(szDesc), szServerName);
90 if (FAILED(hr))
91 szDesc[0] = UNICODE_NULL;
92 trace("%s\n", wine_dbgstr_w(szDesc));
93
94 StringCchCopyW(szDisplayName, _countof(szDisplayName), L"@");
95 hr = s_pSHGetComputerDisplayNameW(NULL, SHGCDN_NOCACHE, szDisplayName, _countof(szDisplayName));
96 ok_hex(hr, S_OK);
97 trace("%s\n", wine_dbgstr_w(szDisplayName));
98 ok_wstr(szDisplayName, szCompName);
99
100 StringCchCopyW(szDisplayName, _countof(szDisplayName), L"@");
101 hr = s_pSHGetComputerDisplayNameW(szServerName, 0, szDisplayName, _countof(szDisplayName));
102 ok_hex(hr, S_OK);
103 trace("%s\n", wine_dbgstr_w(szServerName));
104 ok_wstr(szServerName, L"DummyServerName");
105
106 hr = SHELL_BuildDisplayMachineName(szName, _countof(szName), szServerName, szDesc);
107 ok_hex(hr, S_OK);
108
109 trace("%s\n", wine_dbgstr_w(szDisplayName));
110 trace("%s\n", wine_dbgstr_w(szName));
111 ok_wstr(szDisplayName, szName);
112
113 // Delete registry value
114 HKEY hKey;
115 LSTATUS error = RegOpenKeyExW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY, 0, KEY_WRITE, &hKey);
116 if (error == ERROR_SUCCESS)
117 {
118 RegDeleteValueW(hKey, L"DummyServerName");
119 RegCloseKey(hKey);
120 }
121}
122
123START_TEST(SHGetComputerDisplayNameW)
124{
125 if (IsWindowsVistaOrGreater())
126 {
127 skip("Tests on Vista+ will cause exception\n");
128 return;
129 }
130
131 HINSTANCE hShell32 = GetModuleHandleW(L"shell32.dll");
132 s_pSHGetComputerDisplayNameW =
133 (FN_SHGetComputerDisplayNameW)GetProcAddress(hShell32, MAKEINTRESOURCEA(752));
134 if (!s_pSHGetComputerDisplayNameW)
135 {
136 skip("SHGetComputerDisplayNameW not found\n");
137 return;
138 }
139
140 HINSTANCE hNetApi32 = LoadLibraryW(L"netapi32.dll");
141 if (!hNetApi32)
142 {
143 skip("netapi32.dll not found\n");
144 return;
145 }
146
147 s_pNetServerGetInfo = (FN_NetServerGetInfo)GetProcAddress(hNetApi32, "NetServerGetInfo");
148 s_pNetApiBufferFree = (FN_NetApiBufferFree)GetProcAddress(hNetApi32, "NetApiBufferFree");
149 if (!s_pNetServerGetInfo || !s_pNetApiBufferFree)
150 {
151 skip("NetServerGetInfo or NetApiBufferFree not found\n");
152 FreeLibrary(hNetApi32);
153 return;
154 }
155
156 TEST_SHGetComputerDisplayNameW();
157
158 FreeLibrary(hNetApi32);
159}