44 * PURPOSE: Test for SHELLSTATE
55 * PROGRAMMERS: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
66 */
7+
78#include " shelltest.h"
9+ #include " shell32_apitest_sub.h"
810
911#define NDEBUG
1012#include < debug.h>
@@ -22,30 +24,37 @@ typedef struct REGSHELLSTATE
2224 SHELLSTATE ss;
2325} REGSHELLSTATE , *PREGSHELLSTATE ;
2426
25- static void dump (const char *name, const void *ptr, size_t siz)
27+ static const LPCWSTR s_pszExplorer =
28+ L" Software\\ Microsoft\\ Windows\\ CurrentVersion\\ Explorer" ;
29+ static const LPCWSTR s_pszShellState =
30+ L" ShellState" ;
31+
32+ static ULONG dump (const char *name, const void *ptr, size_t siz)
2633{
2734 char buf[256 ], sz[16 ];
35+ ULONG ret = 0 ;
2836
2937 StringCbCopyA (buf, sizeof (buf), name);
3038 StringCbCatA (buf, sizeof (buf), " : " );
3139
3240 const BYTE *pb = reinterpret_cast <const BYTE *>(ptr);
3341 while (siz--)
3442 {
43+ if (*pb)
44+ ret++;
3545 StringCbPrintfA (sz, sizeof (sz), " %02X " , *pb++);
3646 StringCbCatA (buf, sizeof (buf), sz);
3747 }
3848
3949 trace (" %s\n " , buf);
50+ return ret;
4051}
4152
4253static int read_key (REGSHELLSTATE *prss)
4354{
4455 HKEY hKey;
4556 LONG result;
4657 DWORD cb;
47- static const LPCWSTR s_pszExplorer =
48- L" Software\\ Microsoft\\ Windows\\ CurrentVersion\\ Explorer" ;
4958
5059 memset (prss, 0 , sizeof (*prss));
5160
@@ -60,7 +69,7 @@ static int read_key(REGSHELLSTATE *prss)
6069 }
6170
6271 cb = sizeof (*prss);
63- result = RegQueryValueExW (hKey, L" ShellState " , NULL , NULL , reinterpret_cast <LPBYTE >(prss), &cb);
72+ result = RegQueryValueExW (hKey, s_pszShellState , NULL , NULL , reinterpret_cast <LPBYTE >(prss), &cb);
6473 RegCloseKey (hKey);
6574
6675 ok (result == ERROR_SUCCESS , " result was %ld\n " , result);
@@ -151,18 +160,204 @@ static int read_advanced_key(SHELLSTATE* pss)
151160
152161static int dump_pss (SHELLSTATE *pss)
153162{
154- dump (" SHELLSTATE" , pss, sizeof (*pss));
163+ dump (" SHELLSTATE KEY " , pss, sizeof (*pss));
155164 return 0 ;
156165}
157166
167+ static HWND start_sub (void )
168+ {
169+ int retries = 50 ;
170+ WCHAR s_szSubProgram[MAX_PATH ]; // shell32_apitest_sub.exe
171+ if (!FindSubProgram (s_szSubProgram, _countof (s_szSubProgram)))
172+ {
173+ skip (" shell32_apitest_sub.exe not found\n " );
174+ return 0 ;
175+ }
176+
177+ // Close the SUB_CLASSNAME windows
178+ DoWaitForWindow (SUB_CLASSNAME , SUB_CLASSNAME , TRUE , TRUE );
179+
180+ // Execute sub program
181+ HINSTANCE hinst = ShellExecuteW (NULL , NULL , s_szSubProgram, L" HIDE" , NULL , SW_SHOWNORMAL );
182+ if ((INT_PTR )hinst <= 32 )
183+ {
184+ skip (" Unable to run shell32_apitest_sub.exe.\n " );
185+ return 0 ;
186+ }
187+
188+ Retry:
189+ HWND s_hSubWnd = DoWaitForWindow (SUB_CLASSNAME , SUB_CLASSNAME , FALSE , FALSE );
190+ if (!s_hSubWnd)
191+ {
192+ if (--retries > 0 )
193+ {
194+ Sleep (100 );
195+ goto Retry;
196+ }
197+ skip (" Unable to find sub-program window.\n " );
198+ return 0 ;
199+ }
200+
201+ return s_hSubWnd;
202+ }
203+
204+ static void stop_sub (HWND s_hSubWnd)
205+ {
206+ PostMessageW (s_hSubWnd, WM_COMMAND , IDNO , 0 ); // Finish
207+ DoWaitForWindow (SUB_CLASSNAME , SUB_CLASSNAME , TRUE , TRUE ); // Close sub-windows
208+ }
209+
210+ static void process_test (SHELLSTATE *pss)
211+ {
212+ SHELLSTATE bak, ss1, ss2;
213+ SHELLSTATE_SUB sub;
214+ HKEY hKey;
215+ LONG result;
216+
217+ memset (&sub, 0 , sizeof (sub));
218+ COPYDATASTRUCT copyData = { ID_SHSTATE , sizeof (sub), &sub };
219+
220+ // Backup current state
221+ memset (&bak, 0 , sizeof (bak));
222+ SHGetSetSettings (&bak, MAXDWORD , FALSE );
223+
224+ HWND s_hSubWnd = start_sub ();
225+ if (!s_hSubWnd)
226+ return ;
227+
228+ memset (&ss1, 0 , sizeof (ss1));
229+ SHGetSetSettings (&ss1, MAXDWORD , FALSE );
230+
231+ // Test 1: Read one field, then write another
232+ sub.dwMask = SSF_DOUBLECLICKINWEBVIEW ;
233+ sub.bSet = FALSE ;
234+ SendMessageW (s_hSubWnd, WM_COPYDATA , 0 , (LPARAM )©Data);
235+
236+ sub.ss .fNoConfirmRecycle = !ss1.fNoConfirmRecycle ;
237+ ss1.fNoConfirmRecycle = sub.ss .fNoConfirmRecycle ;
238+ sub.dwMask = SSF_NOCONFIRMRECYCLE ;
239+ sub.bSet = TRUE ;
240+ SendMessageW (s_hSubWnd, WM_COPYDATA , 0 , (LPARAM )©Data);
241+
242+ memset (&ss2, 0 , sizeof (ss2));
243+ SHGetSetSettings (&ss2, MAXDWORD , FALSE );
244+
245+ #define CHECK_BITS (x ) ok(ss1.x == ss2.x, " ss2.%s expected %d, was %d\n " , #x, (int )ss1.x, (int )ss2.x)
246+ CHECK_BITS (fNoConfirmRecycle );
247+ CHECK_BITS (fDoubleClickInWebView );
248+ CHECK_BITS (fDesktopHTML );
249+ CHECK_BITS (fWin95Classic );
250+ CHECK_BITS (lParamSort);
251+ CHECK_BITS (iSortDirection);
252+ CHECK_BITS (fStartPanelOn );
253+ CHECK_BITS (fShowCompColor );
254+ CHECK_BITS (fShowAttribCol );
255+ CHECK_BITS (fShowInfoTip );
256+
257+ stop_sub (s_hSubWnd);
258+
259+ // Test 2: Only write a field
260+ s_hSubWnd = start_sub ();
261+ if (!s_hSubWnd)
262+ goto Cleanup;
263+
264+ sub.ss .fNoConfirmRecycle = !ss1.fNoConfirmRecycle ;
265+ ss1.fNoConfirmRecycle = sub.ss .fNoConfirmRecycle ;
266+ sub.dwMask = SSF_NOCONFIRMRECYCLE ;
267+ sub.bSet = TRUE ;
268+ SendMessageW (s_hSubWnd, WM_COPYDATA , 0 , (LPARAM )©Data);
269+
270+ memset (&ss2, 0 , sizeof (ss2));
271+ SHGetSetSettings (&ss2, MAXDWORD , FALSE );
272+
273+ CHECK_BITS (fNoConfirmRecycle );
274+ CHECK_BITS (fDoubleClickInWebView );
275+ CHECK_BITS (fDesktopHTML );
276+ CHECK_BITS (fWin95Classic );
277+ CHECK_BITS (lParamSort);
278+ CHECK_BITS (iSortDirection);
279+ CHECK_BITS (fStartPanelOn );
280+ CHECK_BITS (fShowCompColor );
281+ CHECK_BITS (fShowAttribCol );
282+ CHECK_BITS (fShowInfoTip );
283+
284+ stop_sub (s_hSubWnd);
285+
286+ // Test 3: Check default state values
287+ #define FLIP_FLAG (x ) ss1.x = !ss1.x
288+ FLIP_FLAG (fNoConfirmRecycle );
289+ FLIP_FLAG (fDoubleClickInWebView );
290+ FLIP_FLAG (fDesktopHTML );
291+ FLIP_FLAG (fWin95Classic );
292+ FLIP_FLAG (fStartPanelOn );
293+ FLIP_FLAG (fShowCompColor );
294+ FLIP_FLAG (fShowAttribCol );
295+ FLIP_FLAG (fShowInfoTip );
296+ SHGetSetSettings (&ss1, MAXDWORD , TRUE );
297+
298+ result = RegOpenKeyExW (HKEY_CURRENT_USER , s_pszExplorer, 0 , KEY_SET_VALUE , &hKey);
299+ if (result != ERROR_SUCCESS || !hKey)
300+ {
301+ skip (" process_test(): RegOpenKeyEx failed: %ld\n " , result);
302+ goto Cleanup;
303+ }
304+
305+ result = RegDeleteValueW (hKey, s_pszShellState);
306+ RegCloseKey (hKey);
307+
308+ if (result != ERROR_SUCCESS )
309+ {
310+ skip (" process_test(): RegDeleteValueW failed: %ld\n " , result);
311+ goto Cleanup;
312+ }
313+
314+ s_hSubWnd = start_sub ();
315+ if (!s_hSubWnd)
316+ goto Cleanup;
317+
318+ sub.dwMask = SSF_NOCONFIRMRECYCLE ;
319+ sub.bSet = FALSE ;
320+ SendMessageW (s_hSubWnd, WM_COPYDATA , 0 , (LPARAM )©Data);
321+
322+ sub.bSet = TRUE ;
323+ SendMessageW (s_hSubWnd, WM_COPYDATA , 0 , (LPARAM )©Data);
324+
325+ memset (&ss2, 0 , sizeof (ss2));
326+ SHGetSetSettings (&ss2, MAXDWORD , FALSE );
327+
328+ #define CHECK_TRUE (x ) ok(ss2.x, " ss2.%s expected to be TRUE\n " , #x)
329+ #define CHECK_FALSE (x ) ok(!ss2.x, " ss2.%s expected to be FALSE\n " , #x)
330+ if (GetNTVersion () < _WIN32_WINNT_WIN8)
331+ CHECK_FALSE (fNoConfirmRecycle ); // Different between Windows versions
332+ else
333+ CHECK_TRUE (fNoConfirmRecycle );
334+ CHECK_TRUE (fDoubleClickInWebView );
335+ CHECK_FALSE (fDesktopHTML );
336+ CHECK_FALSE (fWin95Classic );
337+ CHECK_TRUE (fStartPanelOn );
338+ CHECK_BITS (fShowCompColor ); // Keeps the state
339+ CHECK_FALSE (fShowAttribCol );
340+ CHECK_BITS (fShowInfoTip ); // Keeps the state
341+
342+ stop_sub (s_hSubWnd);
343+
344+ Cleanup:
345+ // Restore current state
346+ SHGetSetSettings (&bak, MAXDWORD , TRUE );
347+
348+ return ;
349+ }
350+
158351START_TEST (ShellState)
159352{
160353 OSVERSIONINFO osinfo;
161354 REGSHELLSTATE rss;
162355 SHELLSTATE ss, *pss;
163356 SHELLFLAGSTATE FlagState;
357+ BOOL GotReg = TRUE ;
164358 LPBYTE pb;
165359 int ret;
360+ ULONG c1, c2;
166361
167362 trace (" GetVersion(): 0x%08lX\n " , GetVersion ());
168363
@@ -200,7 +395,8 @@ START_TEST(ShellState)
200395 ret = read_key (&rss);
201396 if (ret)
202397 {
203- return ;
398+ GotReg = FALSE ;
399+ goto SkipReg;
204400 }
205401
206402 dump_pss (pss);
@@ -242,6 +438,7 @@ START_TEST(ShellState)
242438 DUMP_BOOL (pss->fShowStatusBar );
243439#endif
244440
441+ SkipReg:
245442#define SSF_MASK \
246443 (SSF_SHOWALLOBJECTS | SSF_SHOWEXTENSIONS | SSF_NOCONFIRMRECYCLE | SSF_SHOWSYSFILES | \
247444 SSF_SHOWCOMPCOLOR | SSF_DOUBLECLICKINWEBVIEW | SSF_DESKTOPHTML | \
@@ -253,6 +450,8 @@ START_TEST(ShellState)
253450 /* Get the settings */
254451 memset (&ss, 0 , sizeof (ss));
255452 SHGetSetSettings (&ss, SSF_MASK , FALSE );
453+ if (GotReg)
454+ {
256455#define CHECK_REG_FLAG (x ) ok(pss->x == ss.x, " ss.%s expected %d, was %d\n " , #x, (int )pss->x, (int )ss.x)
257456 CHECK_REG_FLAG (fShowAllObjects );
258457 CHECK_REG_FLAG (fShowExtensions );
@@ -275,6 +474,14 @@ START_TEST(ShellState)
275474#if NTDDI_VERSION >= NTDDI_WIN8 // for future use
276475 CHECK_REG_FLAG (fShowStatusBar );
277476#endif
477+ }
478+ c1 = dump (" SHELLSTATE SSF_MASK" , &ss, sizeof (ss));
479+
480+ memset (&ss, 0 , sizeof (ss));
481+ SHGetSetSettings (&ss, MAXDWORD , FALSE );
482+ c2 = dump (" SHELLSTATE MAXDWORD" , &ss, sizeof (ss));
483+
484+ ok (c2 >= c1, " Set bytes in MAXDWORD state expected to be greater than %u, was %u\n " , c1, c2);
278485
279486 /* Get the flag settings */
280487 memset (&FlagState, 0 , sizeof (FlagState));
@@ -297,6 +504,16 @@ START_TEST(ShellState)
297504 CHECK_FLAG (fAutoCheckSelect );
298505 CHECK_FLAG (fIconsOnly );
299506#endif
507+ c1 = dump (" SHELLFLAGSTATE SSF_MASK" , &FlagState, sizeof (FlagState));
508+
509+ memset (&FlagState, 0 , sizeof (FlagState));
510+ SHGetSettings (&FlagState, MAXDWORD );
511+ c2 = dump (" SHELLFLAGSTATE MAXDWORD" , &FlagState, sizeof (FlagState));
512+
513+ ok (c2 >= c1, " Set bytes in MAXDWORD flags expected to be greater than %u, was %u\n " , c1, c2);
514+
515+ /* Inter-process tests */
516+ process_test (pss);
300517
301518 /* Structure alignment tests */
302519#if 1
0 commit comments