1 /*
2  * PROJECT:         ReactOS API tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Test for SHELLSTATE
5  * PROGRAMMERS:     Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 #include "shelltest.h"
8 
9 #define NDEBUG
10 #include <debug.h>
11 #include <stdio.h>
12 #include <shellutils.h>
13 #include <strsafe.h>
14 #include <shlwapi.h>
15 
16 /* [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer] */
17 /* The contents of RegValue ShellState. */
18 typedef struct REGSHELLSTATE
19 {
20     DWORD dwSize;
21     SHELLSTATE ss;
22 } REGSHELLSTATE, *PREGSHELLSTATE;
23 
24 static void dump(const char *name, const void *ptr, size_t siz)
25 {
26     char buf[256], sz[16];
27 
28     StringCbCopyA(buf, sizeof(buf), name);
29     StringCbCatA(buf, sizeof(buf), ": ");
30 
31     const BYTE *pb = reinterpret_cast<const BYTE *>(ptr);
32     while (siz--)
33     {
34         StringCbPrintfA(sz, sizeof(sz), "%02X ", *pb++);
35         StringCbCatA(buf, sizeof(buf), sz);
36     }
37 
38     trace("%s\n", buf);
39 }
40 
41 static int read_key(REGSHELLSTATE *prss)
42 {
43     HKEY hKey;
44     LONG result;
45     DWORD cb;
46     static const LPCWSTR s_pszExplorer =
47         L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer";
48 
49     memset(prss, 0, sizeof(*prss));
50 
51     result = RegOpenKeyExW(HKEY_CURRENT_USER, s_pszExplorer, 0, KEY_READ, &hKey);
52     ok(result == ERROR_SUCCESS, "result was %ld\n", result);
53     ok(hKey != NULL, "hKey was NULL\n");
54 
55     if (result != ERROR_SUCCESS || !hKey)
56     {
57         skip("RegOpenKeyEx failed: %ld\n", result);
58         return 1;
59     }
60 
61     cb = sizeof(*prss);
62     result = RegQueryValueExW(hKey, L"ShellState", NULL, NULL, reinterpret_cast<LPBYTE>(prss), &cb);
63     RegCloseKey(hKey);
64 
65     ok(result == ERROR_SUCCESS, "result was %ld\n", result);
66     if (result != ERROR_SUCCESS)
67     {
68         skip("RegQueryValueEx failed: %ld\n", result);
69         return 2;
70     }
71 
72     return 0;
73 }
74 
75 extern "C" HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create);
76 
77 static int read_advanced_key(SHELLSTATE* pss)
78 {
79     HKEY hKey;
80     DWORD dwValue, dwSize;
81 
82     hKey = SHGetShellKey(1, L"Advanced", FALSE);
83     if (hKey == NULL)
84     {
85         return 0;
86     }
87 
88     dwSize = sizeof(dwValue);
89     if (SHQueryValueExW(hKey, L"Hidden", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
90     {
91         pss->fShowAllObjects = (dwValue == 1);
92         pss->fShowSysFiles = (dwValue == 2);
93     }
94 
95     dwSize = sizeof(dwValue);
96     if (SHQueryValueExW(hKey, L"HideFileExt", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
97     {
98         pss->fShowExtensions = (dwValue == 0);
99     }
100 
101     dwSize = sizeof(dwValue);
102     if (SHQueryValueExW(hKey, L"DontPrettyPath", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
103     {
104         pss->fDontPrettyPath = (dwValue != 0);
105     }
106 
107     dwSize = sizeof(dwValue);
108     if (SHQueryValueExW(hKey, L"MapNetDrvBtn", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
109     {
110         pss->fMapNetDrvBtn = (dwValue != 0);
111     }
112 
113     dwSize = sizeof(dwValue);
114     if (SHQueryValueExW(hKey, L"ShowInfoTip", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
115     {
116         pss->fShowInfoTip = (dwValue != 0);
117     }
118 
119     dwSize = sizeof(dwValue);
120     if (SHQueryValueExW(hKey, L"HideIcons", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
121     {
122         pss->fHideIcons = (dwValue != 0);
123     }
124 
125     dwSize = sizeof(dwValue);
126     if (SHQueryValueExW(hKey, L"WebView", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
127     {
128         pss->fWebView = (dwValue != 0);
129     }
130 
131     dwSize = sizeof(dwValue);
132     if (SHQueryValueExW(hKey, L"Filter", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
133     {
134         pss->fFilter = (dwValue != 0);
135     }
136 
137     dwSize = sizeof(dwValue);
138     if (SHQueryValueExW(hKey, L"ShowSuperHidden", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
139     {
140         pss->fShowSuperHidden = (dwValue != 0);
141     }
142 
143     dwSize = sizeof(dwValue);
144     if (SHQueryValueExW(hKey, L"NoNetCrawling", NULL, NULL, &dwValue, &dwSize) == ERROR_SUCCESS)
145     {
146         pss->fNoNetCrawling = (dwValue != 0);
147     }
148 
149     RegCloseKey(hKey);
150     return 0;
151 }
152 
153 static int dump_pss(SHELLSTATE *pss)
154 {
155     dump("SHELLSTATE", pss, sizeof(*pss));
156     return 0;
157 }
158 
159 START_TEST(ShellState)
160 {
161     OSVERSIONINFO osinfo;
162     REGSHELLSTATE rss;
163     SHELLSTATE ss, *pss;
164     SHELLFLAGSTATE FlagState;
165     LPBYTE pb;
166     int ret;
167 
168     trace("GetVersion(): 0x%08lX", GetVersion());
169 
170     osinfo.dwOSVersionInfoSize = sizeof(osinfo);
171     GetVersionEx(&osinfo);
172     trace("osinfo.dwMajorVersion: 0x%08lX\n", osinfo.dwMajorVersion);
173     trace("osinfo.dwMinorVersion: 0x%08lX\n", osinfo.dwMinorVersion);
174     trace("osinfo.dwBuildNumber: 0x%08lX\n", osinfo.dwBuildNumber);
175     trace("osinfo.dwPlatformId: 0x%08lX\n", osinfo.dwPlatformId);
176 
177     trace("WINVER: 0x%04X\n", WINVER);
178     trace("_WIN32_WINNT: 0x%04X\n", _WIN32_WINNT);
179     trace("_WIN32_IE: 0x%04X\n", _WIN32_IE);
180     trace("NTDDI_VERSION: 0x%08X\n", NTDDI_VERSION);
181 
182 #ifdef _MSC_VER
183     trace("_MSC_VER: 0x%08X\n", int(_MSC_VER));
184 #elif defined(__MINGW32__)
185     trace("__MINGW32__: 0x%08X\n", int(__MINGW32__));
186 #elif defined(__clang__)
187     trace("__clang__: 0x%08X\n", int(__clang__));
188 #else
189     #error Unknown compiler.
190 #endif
191 
192     ok(sizeof(REGSHELLSTATE) >= 0x24, "sizeof(REGSHELLSTATE) was %d\n", (int)sizeof(REGSHELLSTATE));
193     trace("sizeof(SHELLSTATE): %d\n", (int)sizeof(SHELLSTATE));
194     trace("__alignof(SHELLSTATE): %d\n", (int)__alignof(SHELLSTATE));
195     trace("sizeof(SHELLFLAGSTATE): %d\n", (int)sizeof(SHELLFLAGSTATE));
196     trace("sizeof(CABINETSTATE): %d\n", (int)sizeof(CABINETSTATE));
197 
198     pss = &rss.ss;
199     pb = reinterpret_cast<LPBYTE>(pss);
200 
201     ret = read_key(&rss);
202     if (ret)
203     {
204         return;
205     }
206 
207     dump_pss(pss);
208     ok(rss.dwSize >= 0x24, "rss.dwSize was %ld (0x%lX).\n", rss.dwSize, rss.dwSize);
209 
210     read_advanced_key(&rss.ss);
211 
212 #define DUMP_LONG(x) trace(#x ": 0x%08X\n", int(x));
213 #define DUMP_BOOL(x) trace(#x ": %d\n", !!int(x));
214     DUMP_BOOL(pss->fShowAllObjects);
215     DUMP_BOOL(pss->fShowExtensions);
216     DUMP_BOOL(pss->fNoConfirmRecycle);
217     DUMP_BOOL(pss->fShowSysFiles);
218     DUMP_BOOL(pss->fShowCompColor);
219     DUMP_BOOL(pss->fDoubleClickInWebView);
220     DUMP_BOOL(pss->fDesktopHTML);
221     DUMP_BOOL(pss->fWin95Classic);
222     DUMP_BOOL(pss->fDontPrettyPath);
223     DUMP_BOOL(pss->fShowAttribCol);
224     DUMP_BOOL(pss->fMapNetDrvBtn);
225     DUMP_BOOL(pss->fShowInfoTip);
226     DUMP_BOOL(pss->fHideIcons);
227     DUMP_BOOL(pss->fWebView);
228     DUMP_BOOL(pss->fFilter);
229     DUMP_BOOL(pss->fShowSuperHidden);
230     DUMP_BOOL(pss->fNoNetCrawling);
231     DUMP_LONG(pss->lParamSort);
232     DUMP_LONG(pss->iSortDirection);
233     DUMP_LONG(pss->version);
234     DUMP_LONG(pss->lParamSort);
235     DUMP_LONG(pss->iSortDirection);
236     DUMP_LONG(pss->version);
237     DUMP_BOOL(pss->fSepProcess);
238     DUMP_BOOL(pss->fStartPanelOn);
239     DUMP_BOOL(pss->fShowStartPage);
240 #if NTDDI_VERSION >= 0x06000000     // for future use
241     DUMP_BOOL(pss->fIconsOnly);
242     DUMP_BOOL(pss->fShowTypeOverlay);
243     DUMP_BOOL(pss->fShowStatusBar);
244 #endif
245 
246 #define SSF_MASK \
247     (SSF_SHOWALLOBJECTS | SSF_SHOWEXTENSIONS | SSF_NOCONFIRMRECYCLE | \
248      SSF_SHOWCOMPCOLOR | SSF_DOUBLECLICKINWEBVIEW | SSF_DESKTOPHTML | \
249      SSF_WIN95CLASSIC | SSF_DONTPRETTYPATH | SSF_SHOWATTRIBCOL | \
250      SSF_MAPNETDRVBUTTON | SSF_SHOWINFOTIP | SSF_HIDEICONS)
251     // For future:
252     // SSF_AUTOCHECKSELECT, SSF_ICONSONLY, SSF_SHOWTYPEOVERLAY, SSF_SHOWSTATUSBAR
253 
254     /* Get the settings */
255     memset(&ss, 0, sizeof(ss));
256     SHGetSetSettings(&ss, SSF_MASK, FALSE);
257 #define CHECK_REG_FLAG(x) ok(pss->x == ss.x, "ss.%s expected %d, was %d\n", #x, (int)pss->x, (int)ss.x)
258     CHECK_REG_FLAG(fShowAllObjects);
259     CHECK_REG_FLAG(fShowExtensions);
260     CHECK_REG_FLAG(fNoConfirmRecycle);
261     CHECK_REG_FLAG(fShowSysFiles);    // No use
262     CHECK_REG_FLAG(fShowCompColor);
263     CHECK_REG_FLAG(fDoubleClickInWebView);
264     CHECK_REG_FLAG(fDesktopHTML);
265     CHECK_REG_FLAG(fWin95Classic);
266     CHECK_REG_FLAG(fDontPrettyPath);
267     CHECK_REG_FLAG(fShowAttribCol);
268     CHECK_REG_FLAG(fMapNetDrvBtn);
269     CHECK_REG_FLAG(fShowInfoTip);
270     CHECK_REG_FLAG(fHideIcons);
271 #if NTDDI_VERSION >= 0x06000000     // for future use
272     CHECK_REG_FLAG(fAutoCheckSelect);
273     CHECK_REG_FLAG(fIconsOnly);
274 #endif
275 
276     /* Get the flag settings */
277     memset(&FlagState, 0, sizeof(FlagState));
278     SHGetSettings(&FlagState, SSF_MASK);
279 #define CHECK_FLAG(x) ok(ss.x == FlagState.x, "FlagState.%s expected %d, was %d\n", #x, (int)ss.x, (int)FlagState.x)
280     CHECK_FLAG(fShowAllObjects);
281     CHECK_FLAG(fShowExtensions);
282     CHECK_FLAG(fNoConfirmRecycle);
283     CHECK_FLAG(fShowSysFiles);    // No use
284     CHECK_FLAG(fShowCompColor);
285     CHECK_FLAG(fDoubleClickInWebView);
286     CHECK_FLAG(fDesktopHTML);
287     CHECK_FLAG(fWin95Classic);
288     CHECK_FLAG(fDontPrettyPath);
289     CHECK_FLAG(fShowAttribCol);
290     CHECK_FLAG(fMapNetDrvBtn);
291     CHECK_FLAG(fShowInfoTip);
292     CHECK_FLAG(fHideIcons);
293 #if NTDDI_VERSION >= 0x06000000     // for future use
294     CHECK_FLAG(fAutoCheckSelect);
295     CHECK_FLAG(fIconsOnly);
296 #endif
297 
298 #if 1
299     #define DO_IT(x) x
300 #else
301     #define DO_IT(x) do { trace(#x ";\n"); x; } while (0)
302 #endif
303 
304     DO_IT(memset(pss, 0, sizeof(*pss)));
305     DO_IT(pss->dwWin95Unused = 1);
306     ok(pb[4] == 0x01 || dump_pss(pss), "Unexpected pss ^\n");
307 
308     DO_IT(memset(pss, 0, sizeof(*pss)));
309     DO_IT(pss->lParamSort = 1);
310     ok(pb[12] == 0x01 || dump_pss(pss), "Unexpected pss ^\n");
311 
312     DO_IT(memset(pss, 0, sizeof(*pss)));
313     DO_IT(pss->iSortDirection = 0xDEADBEEF);
314     ok(*(UNALIGNED DWORD *)(pb + 16) == 0xDEADBEEF || dump_pss(pss), "Unexpected pss ^\n");
315 
316     DO_IT(memset(pss, 0, sizeof(*pss)));
317     DO_IT(pss->version = 0xDEADBEEF);
318     ok(*(UNALIGNED DWORD *)(pb + 20) == 0xDEADBEEF || dump_pss(pss), "Unexpected pss ^\n");
319 
320     DO_IT(memset(pss, 0, sizeof(*pss)));
321     DO_IT(pss->fSepProcess = TRUE);
322     ok(pb[28] == 0x01 || dump_pss(pss), "Unexpected pss ^\n");
323 }
324