1 /* Unit test suite for functions SystemParametersInfo and GetSystemMetrics.
2  *
3  * Copyright 2002 Andriy Palamarchuk
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #ifndef __REACTOS__
21 #define _WIN32_WINNT 0x0600 /* For SPI_GETMOUSEHOVERWIDTH and more */
22 #define _WIN32_IE 0x0700
23 #define WINVER 0x0600 /* For COLOR_MENUBAR, NONCLIENTMETRICS with padding */
24 #endif
25 
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 
31 #include "wine/test.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winreg.h"
36 #include "winuser.h"
37 #include "winnls.h"
38 
39 #ifndef SPI_GETDESKWALLPAPER
40 # define SPI_GETDESKWALLPAPER 0x0073
41 #endif
42 
43 static LONG (WINAPI *pChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID);
44 static BOOL (WINAPI *pIsProcessDPIAware)(void);
45 static BOOL (WINAPI *pSetProcessDPIAware)(void);
46 static BOOL (WINAPI *pSetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
47 static BOOL (WINAPI *pGetProcessDpiAwarenessInternal)(HANDLE,DPI_AWARENESS*);
48 static BOOL (WINAPI *pSetProcessDpiAwarenessInternal)(DPI_AWARENESS);
49 static UINT (WINAPI *pGetDpiForSystem)(void);
50 static UINT (WINAPI *pGetDpiForWindow)(HWND);
51 static BOOL (WINAPI *pGetDpiForMonitorInternal)(HMONITOR,UINT,UINT*,UINT*);
52 static DPI_AWARENESS_CONTEXT (WINAPI *pGetThreadDpiAwarenessContext)(void);
53 static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
54 static DPI_AWARENESS_CONTEXT (WINAPI *pGetWindowDpiAwarenessContext)(HWND);
55 static DPI_AWARENESS (WINAPI *pGetAwarenessFromDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
56 static BOOL (WINAPI *pIsValidDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
57 static INT (WINAPI *pGetSystemMetricsForDpi)(INT,UINT);
58 static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT);
59 static BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
60 static BOOL (WINAPI *pLogicalToPhysicalPointForPerMonitorDPI)(HWND,POINT*);
61 static BOOL (WINAPI *pPhysicalToLogicalPointForPerMonitorDPI)(HWND,POINT*);
62 static LONG (WINAPI *pGetAutoRotationState)(PAR_STATE);
63 
64 static BOOL strict;
65 static int dpi, real_dpi;
66 
67 #define eq(received, expected, label, type) \
68         ok((received) == (expected), "%s: got " type " instead of " type "\n", (label),(received),(expected))
69 
70 
71 #define SPI_SETBEEP_REGKEY                      "Control Panel\\Sound"
72 #define SPI_SETBEEP_VALNAME                     "Beep"
73 #define SPI_SETMOUSE_REGKEY                     "Control Panel\\Mouse"
74 #define SPI_SETMOUSE_VALNAME1                   "MouseThreshold1"
75 #define SPI_SETMOUSE_VALNAME2                   "MouseThreshold2"
76 #define SPI_SETMOUSE_VALNAME3                   "MouseSpeed"
77 #define SPI_SETBORDER_REGKEY                    "Control Panel\\Desktop\\WindowMetrics"
78 #define SPI_SETBORDER_REGKEY2                   "Control Panel\\Desktop"
79 #define SPI_SETBORDER_VALNAME                   "BorderWidth"
80 #define SPI_METRIC_REGKEY                       "Control Panel\\Desktop\\WindowMetrics"
81 #define SPI_SCROLLWIDTH_VALNAME                 "ScrollWidth"
82 #define SPI_SCROLLHEIGHT_VALNAME                "ScrollHeight"
83 #define SPI_CAPTIONWIDTH_VALNAME                "CaptionWidth"
84 #define SPI_CAPTIONHEIGHT_VALNAME               "CaptionHeight"
85 #define SPI_CAPTIONFONT_VALNAME                 "CaptionFont"
86 #define SPI_SMCAPTIONWIDTH_VALNAME              "SmCaptionWidth"
87 #define SPI_SMCAPTIONHEIGHT_VALNAME             "SmCaptionHeight"
88 #define SPI_SMCAPTIONFONT_VALNAME               "SmCaptionFont"
89 #define SPI_MENUWIDTH_VALNAME                   "MenuWidth"
90 #define SPI_MENUHEIGHT_VALNAME                  "MenuHeight"
91 #define SPI_MENUFONT_VALNAME                    "MenuFont"
92 #define SPI_STATUSFONT_VALNAME                  "StatusFont"
93 #define SPI_MESSAGEFONT_VALNAME                 "MessageFont"
94 
95 #define SPI_SETKEYBOARDSPEED_REGKEY             "Control Panel\\Keyboard"
96 #define SPI_SETKEYBOARDSPEED_VALNAME            "KeyboardSpeed"
97 #define SPI_ICONHORIZONTALSPACING_REGKEY        "Control Panel\\Desktop\\WindowMetrics"
98 #define SPI_ICONHORIZONTALSPACING_REGKEY2       "Control Panel\\Desktop"
99 #define SPI_ICONHORIZONTALSPACING_VALNAME       "IconSpacing"
100 #define SPI_ICONVERTICALSPACING_REGKEY          "Control Panel\\Desktop\\WindowMetrics"
101 #define SPI_ICONVERTICALSPACING_REGKEY2         "Control Panel\\Desktop"
102 #define SPI_ICONVERTICALSPACING_VALNAME         "IconVerticalSpacing"
103 #define SPI_MINIMIZEDMETRICS_REGKEY             "Control Panel\\Desktop\\WindowMetrics"
104 #define SPI_MINWIDTH_VALNAME                    "MinWidth"
105 #define SPI_MINHORZGAP_VALNAME                  "MinHorzGap"
106 #define SPI_MINVERTGAP_VALNAME                  "MinVertGap"
107 #define SPI_MINARRANGE_VALNAME                  "MinArrange"
108 #define SPI_SETSCREENSAVETIMEOUT_REGKEY         "Control Panel\\Desktop"
109 #define SPI_SETSCREENSAVETIMEOUT_VALNAME        "ScreenSaveTimeOut"
110 #define SPI_SETSCREENSAVEACTIVE_REGKEY          "Control Panel\\Desktop"
111 #define SPI_SETSCREENSAVEACTIVE_VALNAME         "ScreenSaveActive"
112 #define SPI_SETGRIDGRANULARITY_REGKEY           "Control Panel\\Desktop"
113 #define SPI_SETGRIDGRANULARITY_VALNAME          "GridGranularity"
114 #define SPI_SETKEYBOARDDELAY_REGKEY             "Control Panel\\Keyboard"
115 #define SPI_SETKEYBOARDDELAY_VALNAME            "KeyboardDelay"
116 #define SPI_SETICONTITLEWRAP_REGKEY1            "Control Panel\\Desktop\\WindowMetrics"
117 #define SPI_SETICONTITLEWRAP_REGKEY2            "Control Panel\\Desktop"
118 #define SPI_SETICONTITLEWRAP_VALNAME            "IconTitleWrap"
119 #define SPI_SETMENUDROPALIGNMENT_REGKEY1        "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"
120 #define SPI_SETMENUDROPALIGNMENT_REGKEY2        "Control Panel\\Desktop"
121 #define SPI_SETMENUDROPALIGNMENT_VALNAME        "MenuDropAlignment"
122 #define SPI_SETDOUBLECLKWIDTH_REGKEY1           "Control Panel\\Mouse"
123 #define SPI_SETDOUBLECLKWIDTH_REGKEY2           "Control Panel\\Desktop"
124 #define SPI_SETDOUBLECLKWIDTH_VALNAME           "DoubleClickWidth"
125 #define SPI_SETDOUBLECLKHEIGHT_REGKEY1          "Control Panel\\Mouse"
126 #define SPI_SETDOUBLECLKHEIGHT_REGKEY2          "Control Panel\\Desktop"
127 #define SPI_SETDOUBLECLKHEIGHT_VALNAME          "DoubleClickHeight"
128 #define SPI_SETDOUBLECLICKTIME_REGKEY           "Control Panel\\Mouse"
129 #define SPI_SETDOUBLECLICKTIME_VALNAME          "DoubleClickSpeed"
130 #define SPI_SETMOUSEBUTTONSWAP_REGKEY           "Control Panel\\Mouse"
131 #define SPI_SETMOUSEBUTTONSWAP_VALNAME          "SwapMouseButtons"
132 #define SPI_SETWORKAREA_REGKEY                  "Control Panel\\Desktop"
133 #define SPI_SETWORKAREA_VALNAME                 "WINE_WorkArea"
134 #define SPI_SETSHOWSOUNDS_REGKEY                "Control Panel\\Accessibility\\ShowSounds"
135 #define SPI_SETSHOWSOUNDS_VALNAME               "On"
136 #define SPI_SETKEYBOARDPREF_REGKEY              "Control Panel\\Accessibility\\Keyboard Preference"
137 #define SPI_SETKEYBOARDPREF_VALNAME             "On"
138 #define SPI_SETKEYBOARDPREF_REGKEY_LEGACY       "Control Panel\\Accessibility"
139 #define SPI_SETKEYBOARDPREF_VALNAME_LEGACY      "Keyboard Preference"
140 #define SPI_SETSCREENREADER_REGKEY              "Control Panel\\Accessibility\\Blind Access"
141 #define SPI_SETSCREENREADER_VALNAME             "On"
142 #define SPI_SETSCREENREADER_REGKEY_LEGACY       "Control Panel\\Accessibility"
143 #define SPI_SETSCREENREADER_VALNAME_LEGACY      "Blind Access"
144 #define SPI_SETFONTSMOOTHING_REGKEY             "Control Panel\\Desktop"
145 #define SPI_SETFONTSMOOTHING_VALNAME            "FontSmoothing"
146 #define SPI_SETFONTSMOOTHINGTYPE_VALNAME        "FontSmoothingType"
147 #define SPI_SETFONTSMOOTHINGCONTRAST_VALNAME    "FontSmoothingGamma"
148 #define SPI_SETFONTSMOOTHINGORIENTATION_VALNAME "FontSmoothingOrientation"
149 #define SPI_SETLOWPOWERACTIVE_REGKEY            "Control Panel\\Desktop"
150 #define SPI_SETLOWPOWERACTIVE_VALNAME           "LowPowerActive"
151 #define SPI_SETPOWEROFFACTIVE_REGKEY            "Control Panel\\Desktop"
152 #define SPI_SETPOWEROFFACTIVE_VALNAME           "PowerOffActive"
153 #define SPI_SETDRAGFULLWINDOWS_REGKEY           "Control Panel\\Desktop"
154 #define SPI_SETDRAGFULLWINDOWS_VALNAME          "DragFullWindows"
155 #define SPI_SETSNAPTODEFBUTTON_REGKEY           "Control Panel\\Mouse"
156 #define SPI_SETSNAPTODEFBUTTON_VALNAME          "SnapToDefaultButton"
157 #define SPI_SETMOUSEHOVERWIDTH_REGKEY           "Control Panel\\Mouse"
158 #define SPI_SETMOUSEHOVERWIDTH_VALNAME          "MouseHoverWidth"
159 #define SPI_SETMOUSEHOVERHEIGHT_REGKEY          "Control Panel\\Mouse"
160 #define SPI_SETMOUSEHOVERHEIGHT_VALNAME         "MouseHoverHeight"
161 #define SPI_SETMOUSEHOVERTIME_REGKEY            "Control Panel\\Mouse"
162 #define SPI_SETMOUSEHOVERTIME_VALNAME           "MouseHoverTime"
163 #define SPI_SETMOUSESCROLLCHARS_REGKEY          "Control Panel\\Desktop"
164 #define SPI_SETMOUSESCROLLCHARS_VALNAME         "WheelScrollChars"
165 #define SPI_SETMOUSESCROLLLINES_REGKEY          "Control Panel\\Desktop"
166 #define SPI_SETMOUSESCROLLLINES_VALNAME         "WheelScrollLines"
167 #define SPI_SETMENUSHOWDELAY_REGKEY             "Control Panel\\Desktop"
168 #define SPI_SETMENUSHOWDELAY_VALNAME            "MenuShowDelay"
169 #define SPI_SETDESKWALLPAPER_REGKEY             "Control Panel\\Desktop"
170 #define SPI_SETDESKWALLPAPER_VALNAME            "Wallpaper"
171 
172 /* volatile registry branch under CURRENT_USER_REGKEY for temporary values storage */
173 #define WINE_CURRENT_USER_REGKEY     "Wine"
174 
175 static HWND ghTestWnd;
176 
177 static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam );
178 static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam,
179                                               LPARAM lParam );
180 static int change_counter;
181 static int change_setworkarea_param, change_iconverticalspacing_param;
182 static int change_last_param;
183 static int last_bpp;
184 static BOOL displaychange_ok = FALSE, displaychange_test_active = FALSE;
185 static HANDLE displaychange_sem = 0;
186 
187 static BOOL get_reg_dword(HKEY base, const char *key_name, const char *value_name, DWORD *value)
188 {
189     HKEY key;
190     DWORD type, data, size = sizeof(data);
191     BOOL ret = FALSE;
192 
193     if (RegOpenKeyA(base, key_name, &key) == ERROR_SUCCESS)
194     {
195         if (RegQueryValueExA(key, value_name, NULL, &type, (void *)&data, &size) == ERROR_SUCCESS &&
196             type == REG_DWORD)
197         {
198             *value = data;
199             ret = TRUE;
200         }
201         RegCloseKey(key);
202     }
203     return ret;
204 }
205 
206 static DWORD get_real_dpi(void)
207 {
208     DWORD dpi;
209 
210     if (pSetThreadDpiAwarenessContext)
211     {
212         DPI_AWARENESS_CONTEXT context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE );
213         dpi = pGetDpiForSystem();
214         pSetThreadDpiAwarenessContext( context );
215         return dpi;
216     }
217     if (get_reg_dword(HKEY_CURRENT_USER, "Control Panel\\Desktop", "LogPixels", &dpi))
218         return dpi;
219     if (get_reg_dword(HKEY_CURRENT_CONFIG, "Software\\Fonts", "LogPixels", &dpi))
220         return dpi;
221     return USER_DEFAULT_SCREEN_DPI;
222 }
223 
224 static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam,
225                                               LPARAM lParam )
226 {
227     switch (msg) {
228 
229     case WM_DISPLAYCHANGE:
230         ok(displaychange_ok, "Unexpected WM_DISPLAYCHANGE message\n");
231         last_bpp = wParam;
232         displaychange_ok = FALSE;
233         ReleaseSemaphore(displaychange_sem, 1, 0);
234         break;
235 
236     case WM_SETTINGCHANGE:
237         if (change_counter>0) {
238             /* ignore these messages caused by resizing of toolbars */
239             if( wParam == SPI_SETWORKAREA){
240                 change_setworkarea_param = 1;
241                 break;
242             } else if( wParam == SPI_ICONVERTICALSPACING) {
243                 change_iconverticalspacing_param = 1;
244                 break;
245             } else if( displaychange_test_active)
246                 break;
247             if( !change_last_param){
248                 change_last_param = wParam;
249                 break;
250             }
251             ok(0,"too many changes counter=%d last change=%d\n",
252                change_counter,change_last_param);
253             change_counter++;
254             change_last_param = wParam;
255             break;
256         }
257         change_counter++;
258         change_last_param = change_setworkarea_param = change_iconverticalspacing_param =0;
259         if( wParam == SPI_SETWORKAREA)
260             change_setworkarea_param = 1;
261         else if( wParam == SPI_ICONVERTICALSPACING)
262             change_iconverticalspacing_param = 1;
263         else
264             change_last_param = wParam;
265         break;
266 
267     case WM_DESTROY:
268         PostQuitMessage( 0 );
269         break;
270 
271     /* drop through */
272     default:
273         return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
274     }
275 
276     return 0;
277 }
278 
279 /*
280 Performs testing for system parameters messages
281 params:
282  - system parameter id
283  - supposed value of the registry key
284 */
285 static void test_change_message( int action, int optional )
286 {
287     if (change_counter==0 && optional==1)
288         return;
289     ok( 1 == change_counter,
290         "Missed a message: change_counter=%d\n", change_counter );
291     change_counter = 0;
292     ok( action == change_last_param ||
293         ( change_setworkarea_param && action == SPI_SETWORKAREA) ||
294         ( change_iconverticalspacing_param && action == SPI_ICONVERTICALSPACING),
295         "Wrong action got %d expected %d\n", change_last_param, action );
296     change_last_param = 0;
297 }
298 
299 static BOOL test_error_msg ( int rc, const char *name )
300 {
301     DWORD last_error = GetLastError();
302 
303     if (rc==0)
304     {
305         if (last_error==0xdeadbeef || last_error==ERROR_INVALID_SPI_VALUE || last_error==ERROR_INVALID_PARAMETER)
306         {
307             skip("%s not supported on this platform\n", name);
308         }
309         else if (last_error==ERROR_ACCESS_DENIED)
310         {
311             skip("%s does not have privileges to run\n", name);
312         }
313         else
314         {
315             trace("%s failed for reason: %d. Indicating test failure and skipping remainder of test\n",name,last_error);
316             ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,last_error);
317         }
318         return FALSE;
319     }
320     else
321     {
322         ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,last_error);
323         return TRUE;
324     }
325 }
326 
327 /*
328  * Tests the HKEY_CURRENT_USER subkey value.
329  * The value should contain string value.
330  */
331 static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCSTR valName2,
332                            const void *exp_value, DWORD exp_type, BOOL optional )
333 {
334     CHAR  value[MAX_PATH];
335     DWORD valueLen;
336     DWORD type;
337     HKEY hKey;
338     LONG rc;
339     int found=0;
340 
341     *value='\0';
342     valueLen=sizeof(value);
343     RegOpenKeyA( HKEY_CURRENT_USER, subKey1, &hKey );
344     rc=RegQueryValueExA( hKey, valName1, NULL, &type, (LPBYTE)value, &valueLen );
345     RegCloseKey( hKey );
346     if (rc==ERROR_SUCCESS)
347     {
348         ok( type == exp_type, "wrong type %u/%u\n", type, exp_type );
349         switch (exp_type)
350         {
351         case REG_DWORD:
352             ok( *(DWORD *)value == *(DWORD *)exp_value,
353                 "Wrong value in registry: %s %s %08x/%08x\n",
354                 subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value );
355             break;
356         case REG_SZ:
357             ok( !strcmp( exp_value, value ),
358                 "Wrong value in registry: %s %s '%s' instead of '%s'\n",
359                 subKey1, valName1, value, (const char *)exp_value );
360             break;
361         }
362         found++;
363     }
364     else if (strict)
365     {
366         ok(0,"Missing registry entry: subKey=%s, valName=%s\n",
367            subKey1, valName1);
368     }
369     if (valName2)
370     {
371         *value='\0';
372         valueLen=sizeof(value);
373         RegOpenKeyA( HKEY_CURRENT_USER, subKey1, &hKey );
374         rc=RegQueryValueExA( hKey, valName2, NULL, &type, (LPBYTE)value, &valueLen );
375         RegCloseKey( hKey );
376         if (rc==ERROR_SUCCESS)
377         {
378             ok( type == exp_type, "wrong type %u/%u\n", type, exp_type );
379             switch (exp_type)
380             {
381             case REG_DWORD:
382                 ok( *(DWORD *)value == *(DWORD *)exp_value,
383                     "Wrong value in registry: %s %s %08x/%08x\n",
384                     subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value );
385                 break;
386             case REG_SZ:
387                 ok( !strcmp( exp_value, value ),
388                     "Wrong value in registry: %s %s '%s' instead of '%s'\n",
389                     subKey1, valName1, value, (const char *)exp_value );
390                 break;
391             }
392             found++;
393         }
394         else if (strict)
395         {
396             ok( 0,"Missing registry entry: subKey=%s, valName=%s\n",
397                 subKey1, valName2 );
398         }
399     }
400     if (subKey2 && !strict)
401     {
402         *value='\0';
403         valueLen=sizeof(value);
404         RegOpenKeyA( HKEY_CURRENT_USER, subKey2, &hKey );
405         rc=RegQueryValueExA( hKey, valName1, NULL, &type, (LPBYTE)value, &valueLen );
406         RegCloseKey( hKey );
407         if (rc==ERROR_SUCCESS)
408         {
409             ok( type == exp_type, "wrong type %u/%u\n", type, exp_type );
410             switch (exp_type)
411             {
412             case REG_DWORD:
413                 ok( *(DWORD *)value == *(DWORD *)exp_value,
414                     "Wrong value in registry: %s %s %08x/%08x\n",
415                     subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value );
416                 break;
417             case REG_SZ:
418                 ok( !strcmp( exp_value, value ),
419                     "Wrong value in registry: %s %s '%s' instead of '%s'\n",
420                     subKey1, valName1, value, (const char *)exp_value );
421                 break;
422             }
423             found++;
424         }
425         else if (strict)
426         {
427             ok( 0,"Missing registry entry: subKey=%s, valName=%s\n",
428                 subKey2, valName1 );
429         }
430         if (valName2)
431         {
432             *value='\0';
433             valueLen=sizeof(value);
434             RegOpenKeyA( HKEY_CURRENT_USER, subKey2, &hKey );
435             rc=RegQueryValueExA( hKey, valName2, NULL, &type, (LPBYTE)value, &valueLen );
436             RegCloseKey( hKey );
437             if (rc==ERROR_SUCCESS)
438             {
439                 ok( type == exp_type, "wrong type %u/%u\n", type, exp_type );
440                 switch (exp_type)
441                 {
442                 case REG_DWORD:
443                     ok( *(DWORD *)value == *(DWORD *)exp_value,
444                         "Wrong value in registry: %s %s %08x/%08x\n",
445                         subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value );
446                     break;
447                 case REG_SZ:
448                     ok( !strcmp( exp_value, value ),
449                         "Wrong value in registry: %s %s '%s' instead of '%s'\n",
450                         subKey1, valName1, value, (const char *)exp_value );
451                     break;
452                 }
453                 found++;
454             }
455             else if (strict)
456             {
457                 ok( 0,"Missing registry entry: subKey=%s, valName=%s\n",
458                     subKey2, valName2 );
459             }
460          }
461     }
462     ok(found || optional,
463        "Missing registry values: %s or %s in keys: %s or %s\n",
464        valName1, (valName2?valName2:"<n/a>"), subKey1, (subKey2?subKey2:"<n/a>") );
465 }
466 
467 #define test_reg_key( subKey, valName, testValue ) \
468     _test_reg_key( subKey, NULL, valName, NULL, testValue, REG_SZ, FALSE )
469 #define test_reg_key_optional( subKey, valName, testValue ) \
470     _test_reg_key( subKey, NULL, valName, NULL, testValue, REG_SZ, TRUE )
471 #define test_reg_key_ex( subKey1, subKey2, valName, testValue ) \
472     _test_reg_key( subKey1, subKey2, valName, NULL, testValue, REG_SZ, FALSE )
473 #define test_reg_key_ex2( subKey1, subKey2, valName1, valName2, testValue ) \
474     _test_reg_key( subKey1, subKey2, valName1, valName2, testValue, REG_SZ, FALSE )
475 #define test_reg_key_ex2_optional( subKey1, subKey2, valName1, valName2, testValue ) \
476     _test_reg_key( subKey1, subKey2, valName1, valName2, testValue, REG_SZ, TRUE )
477 #define test_reg_key_dword( subKey, valName, testValue ) \
478     _test_reg_key( subKey, NULL, valName, NULL, testValue, REG_DWORD, FALSE )
479 
480 /* get a metric from the registry. If the value is negative
481  * it is assumed to be in twips and converted to pixels */
482 static UINT metricfromreg( const char *keyname, const char *valname, int dpi)
483 {
484     HKEY hkey;
485     char buf[64];
486     DWORD ret;
487     DWORD size, type;
488     int value;
489 
490     RegOpenKeyA( HKEY_CURRENT_USER, keyname, &hkey );
491     size = sizeof(buf);
492     ret=RegQueryValueExA( hkey, valname, NULL, &type, (LPBYTE)buf, &size );
493     RegCloseKey( hkey );
494     if( ret != ERROR_SUCCESS) return -1;
495     value = atoi( buf);
496     if( value < 0)
497         value = ( -value * dpi + 720) / 1440;
498     return value;
499 }
500 
501 typedef struct
502 {
503     INT16  lfHeight;
504     INT16  lfWidth;
505     INT16  lfEscapement;
506     INT16  lfOrientation;
507     INT16  lfWeight;
508     BYTE   lfItalic;
509     BYTE   lfUnderline;
510     BYTE   lfStrikeOut;
511     BYTE   lfCharSet;
512     BYTE   lfOutPrecision;
513     BYTE   lfClipPrecision;
514     BYTE   lfQuality;
515     BYTE   lfPitchAndFamily;
516     CHAR   lfFaceName[LF_FACESIZE];
517 } LOGFONT16, *LPLOGFONT16;
518 
519 /* get logfont from the registry */
520 static int lffromreg( const char *keyname, const char *valname, LOGFONTA *plf)
521 {
522     HKEY hkey;
523     LOGFONTW lfw;
524     DWORD ret, size, type;
525 
526     RegOpenKeyA( HKEY_CURRENT_USER, keyname, &hkey );
527     size = sizeof( lfw);
528     ret=RegQueryValueExA( hkey, valname, NULL, &type, (LPBYTE)&lfw, &size );
529     RegCloseKey( hkey );
530     ok( ret == ERROR_SUCCESS, "Key \"%s\" value \"%s\" not found\n", keyname, valname);
531     if( ret != ERROR_SUCCESS)
532         return FALSE;
533     if( size <= sizeof( LOGFONT16)) {
534         LOGFONT16 *plf16 = (LOGFONT16*) &lfw;
535         plf->lfHeight = plf16->lfHeight;
536         plf->lfWidth = plf16->lfWidth;
537         plf->lfEscapement = plf16->lfEscapement;
538         plf->lfOrientation = plf16->lfOrientation;
539         plf->lfWeight = plf16->lfWeight;
540         plf->lfItalic = plf16->lfItalic;
541         plf->lfUnderline = plf16->lfUnderline;
542         plf->lfStrikeOut = plf16->lfStrikeOut;
543         plf->lfCharSet = plf16->lfCharSet;
544         plf->lfOutPrecision = plf16->lfOutPrecision;
545         plf->lfClipPrecision = plf16->lfClipPrecision;
546         plf->lfQuality = plf16->lfQuality;
547         plf->lfPitchAndFamily = plf16->lfPitchAndFamily;
548         memcpy( plf->lfFaceName, plf16->lfFaceName, LF_FACESIZE );
549     } else if( size <= sizeof( LOGFONTA)) {
550         plf = (LOGFONTA*) &lfw;
551     } else {
552         plf->lfHeight = lfw.lfHeight;
553         plf->lfWidth = lfw.lfWidth;
554         plf->lfEscapement = lfw.lfEscapement;
555         plf->lfOrientation = lfw.lfOrientation;
556         plf->lfWeight = lfw.lfWeight;
557         plf->lfItalic = lfw.lfItalic;
558         plf->lfUnderline = lfw.lfUnderline;
559         plf->lfStrikeOut = lfw.lfStrikeOut;
560         plf->lfCharSet = lfw.lfCharSet;
561         plf->lfOutPrecision = lfw.lfOutPrecision;
562         plf->lfClipPrecision = lfw.lfClipPrecision;
563         plf->lfQuality = lfw.lfQuality;
564         plf->lfPitchAndFamily = lfw.lfPitchAndFamily;
565         WideCharToMultiByte( CP_ACP, 0, lfw.lfFaceName, -1, plf->lfFaceName,
566             LF_FACESIZE, NULL, NULL);
567 
568     }
569     return TRUE;
570 }
571 
572 static void test_SPI_SETBEEP( void )                   /*      2 */
573 {
574     BOOL rc;
575     BOOL old_b;
576     BOOL b;
577     BOOL curr_val;
578 
579     trace("testing SPI_{GET,SET}BEEP\n");
580     SetLastError(0xdeadbeef);
581     rc=SystemParametersInfoA( SPI_GETBEEP, 0, &old_b, 0 );
582     if (!test_error_msg(rc,"SPI_{GET,SET}BEEP"))
583         return;
584 
585     curr_val = TRUE;
586     rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
587     if (!test_error_msg(rc,"SPI_SETBEEP")) return;
588     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
589     test_change_message( SPI_SETBEEP, 0 );
590     test_reg_key( SPI_SETBEEP_REGKEY,
591                   SPI_SETBEEP_VALNAME,
592                   curr_val ? "Yes" : "No" );
593     rc=SystemParametersInfoA( SPI_GETBEEP, 0, &b, 0 );
594     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
595     eq( b, curr_val, "SPI_{GET,SET}BEEP", "%d" );
596     rc=SystemParametersInfoW( SPI_GETBEEP, 0, &b, 0 );
597     if (rc || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
598     {
599         ok(rc, "SystemParametersInfoW: rc=%d err=%d\n", rc, GetLastError());
600         eq( b, curr_val, "SystemParametersInfoW", "%d" );
601     }
602 
603     /* is a message sent for the second change? */
604     rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
605     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
606     test_change_message( SPI_SETBEEP, 0 );
607 
608     curr_val = FALSE;
609     rc=SystemParametersInfoW( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
610     if (rc == FALSE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
611         rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
612     ok(rc, "SystemParametersInfo: rc=%d err=%d\n", rc, GetLastError());
613     test_change_message( SPI_SETBEEP, 0 );
614     test_reg_key( SPI_SETBEEP_REGKEY,
615                   SPI_SETBEEP_VALNAME,
616                   curr_val ? "Yes" : "No" );
617     rc=SystemParametersInfoA( SPI_GETBEEP, 0, &b, 0 );
618     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
619     eq( b, curr_val, "SPI_{GET,SET}BEEP", "%d" );
620     rc=SystemParametersInfoW( SPI_GETBEEP, 0, &b, 0 );
621     if (rc || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
622     {
623         ok(rc, "SystemParametersInfoW: rc=%d err=%d\n", rc, GetLastError());
624         eq( b, curr_val, "SystemParametersInfoW", "%d" );
625     }
626     ok( MessageBeep( MB_OK ), "Return value of MessageBeep when sound is disabled\n" );
627 
628     rc=SystemParametersInfoA( SPI_SETBEEP, old_b, 0, SPIF_UPDATEINIFILE );
629     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
630 }
631 
632 static const char *setmouse_valuenames[3] = {
633     SPI_SETMOUSE_VALNAME1,
634     SPI_SETMOUSE_VALNAME2,
635     SPI_SETMOUSE_VALNAME3
636 };
637 
638 /*
639  * Runs check for one setting of spi_setmouse.
640  */
641 static BOOL run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *proj_change, int nchange )
642 {
643     BOOL rc;
644     INT mi[3];
645     static int aw_turn = 0;
646 
647     char buf[20];
648     int i;
649 
650     aw_turn++;
651     rc = FALSE;
652     SetLastError(0xdeadbeef);
653     if (aw_turn % 2)  /* call unicode on odd (non even) calls */
654         rc=SystemParametersInfoW( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
655     else
656         rc=SystemParametersInfoA( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
657     if (!test_error_msg(rc,"SPI_SETMOUSE")) return FALSE;
658 
659     ok(rc, "SystemParametersInfo: rc=%d err=%d\n", rc, GetLastError());
660     test_change_message( SPI_SETMOUSE, 0 );
661     for (i = 0; i < 3; i++)
662     {
663         sprintf( buf, "%d", curr_val[i] );
664         test_reg_key( SPI_SETMOUSE_REGKEY, setmouse_valuenames[i], buf );
665     }
666 
667     rc=SystemParametersInfoA( SPI_GETMOUSE, 0, mi, 0 );
668     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
669     for (i = 0; i < 3; i++)
670     {
671         ok(mi[i] == curr_val[i],
672            "incorrect value for %d: %d != %d\n", i, mi[i], curr_val[i]);
673     }
674 
675     rc=SystemParametersInfoW( SPI_GETMOUSE, 0, mi, 0 );
676     ok(rc, "SystemParametersInfoW: rc=%d err=%d\n", rc, GetLastError());
677     for (i = 0; i < 3; i++)
678     {
679         ok(mi[i] == curr_val[i],
680            "incorrect value for %d: %d != %d\n", i, mi[i], curr_val[i]);
681     }
682 
683     if (0)
684     {
685     /* FIXME: this always fails for me  - AJ */
686     for (i = 0; i < nchange; i++)
687     {
688         POINT mv;
689         mouse_event( MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, 0, 0, 0, 0 );
690         mouse_event( MOUSEEVENTF_MOVE, req_change[i].x, req_change[i].y, 0, 0 );
691         GetCursorPos( &mv );
692         ok( proj_change[i].x == mv.x, "Projected dx and real dx comparison. May fail under high load.\n" );
693         ok( proj_change[i].y == mv.y, "Projected dy equals real dy. May fail under high load.\n" );
694     }
695     }
696     return TRUE;
697 }
698 
699 static void test_SPI_SETMOUSE( void )                  /*      4 */
700 {
701     BOOL rc;
702     INT old_mi[3];
703 
704     /* win nt default values - 6, 10, 1 */
705     INT curr_val[3] = {6, 10, 1};
706 
707     /* requested and projected mouse movements */
708     POINT req_change[] =   { {6, 6}, { 7, 6}, { 8, 6}, {10, 10}, {11, 10}, {100, 100} };
709     POINT proj_change1[] = { {6, 6}, {14, 6}, {16, 6}, {20, 20}, {22, 20}, {200, 200} };
710     POINT proj_change2[] = { {6, 6}, {14, 6}, {16, 6}, {20, 20}, {44, 20}, {400, 400} };
711     POINT proj_change3[] = { {6, 6}, {14, 6}, {16, 6}, {20, 20}, {22, 20}, {200, 200} };
712     POINT proj_change4[] = { {6, 6}, { 7, 6}, { 8, 6}, {10, 10}, {11, 10}, {100, 100} };
713     POINT proj_change5[] = { {6, 6}, { 7, 6}, {16, 6}, {20, 20}, {22, 20}, {200, 200} };
714     POINT proj_change6[] = { {6, 6}, {28, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} };
715     POINT proj_change7[] = { {6, 6}, {14, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} };
716     POINT proj_change8[] = { {6, 6}, {28, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} };
717 
718     int nchange = ARRAY_SIZE(req_change);
719 
720     trace("testing SPI_{GET,SET}MOUSE\n");
721     SetLastError(0xdeadbeef);
722     rc=SystemParametersInfoA( SPI_GETMOUSE, 0, old_mi, 0 );
723     if (!test_error_msg(rc,"SPI_{GET,SET}MOUSE"))
724         return;
725 
726     if (!run_spi_setmouse_test( curr_val, req_change, proj_change1, nchange )) return;
727 
728     /* acceleration change */
729     curr_val[2] = 2;
730     run_spi_setmouse_test( curr_val, req_change, proj_change2, nchange );
731 
732     /* acceleration change */
733     curr_val[2] = 3;
734     run_spi_setmouse_test( curr_val, req_change, proj_change3, nchange );
735 
736     /* acceleration change */
737     curr_val[2] = 0;
738     run_spi_setmouse_test( curr_val, req_change, proj_change4, nchange );
739 
740     /* threshold change */
741     curr_val[2] = 1;
742     curr_val[0] = 7;
743     run_spi_setmouse_test( curr_val, req_change, proj_change5, nchange );
744 
745     /* threshold change */
746     curr_val[2] = 2;
747     curr_val[0] = 6;
748     curr_val[1] = 6;
749     run_spi_setmouse_test( curr_val, req_change, proj_change6, nchange );
750 
751     /* threshold change */
752     curr_val[1] = 7;
753     run_spi_setmouse_test( curr_val, req_change, proj_change7, nchange );
754 
755     /* threshold change */
756     curr_val[1] = 5;
757     run_spi_setmouse_test( curr_val, req_change, proj_change8, nchange );
758 
759     rc=SystemParametersInfoA( SPI_SETMOUSE, 0, old_mi, SPIF_UPDATEINIFILE );
760     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
761 }
762 
763 static BOOL test_setborder(UINT curr_val, int usesetborder, int dpi)
764 {
765     BOOL rc;
766     UINT border, regval;
767     INT frame;
768     NONCLIENTMETRICSA ncm;
769 
770     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
771     rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
772     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
773     if( usesetborder) {
774         rc=SystemParametersInfoA( SPI_SETBORDER, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
775         if (!test_error_msg(rc,"SPI_SETBORDER")) return FALSE;
776         ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
777         test_change_message( SPI_SETBORDER, 1 );
778     } else { /* set non client metrics */
779         ncm.iBorderWidth = curr_val;
780         rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &ncm, SPIF_UPDATEINIFILE|
781                 SPIF_SENDCHANGE);
782         if (!test_error_msg(rc,"SPI_SETNONCLIENTMETRICS")) return FALSE;
783         ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
784         test_change_message( SPI_SETNONCLIENTMETRICS, 1 );
785     }
786     if( curr_val) { /* skip if 0, some windows versions return 0 others 1 */
787         regval = metricfromreg( SPI_SETBORDER_REGKEY2, SPI_SETBORDER_VALNAME, dpi);
788         if( regval != curr_val)
789             regval = metricfromreg( SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME, dpi);
790         ok( regval==curr_val, "wrong value in registry %d, expected %d\n", regval, curr_val);
791     }
792     /* minimum border width is 1 */
793     if (curr_val == 0) curr_val = 1;
794     /* should be the same as the non client metrics */
795     rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
796     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
797     eq( (UINT)ncm.iBorderWidth, curr_val, "NonClientMetric.iBorderWidth", "%d");
798     /* and from SPI_GETBORDER */
799     rc=SystemParametersInfoA( SPI_GETBORDER, 0, &border, 0 );
800     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
801     eq( border, curr_val, "SPI_{GET,SET}BORDER", "%d");
802     /* test some SystemMetrics */
803     frame = curr_val + GetSystemMetrics( SM_CXDLGFRAME );
804     eq( frame, GetSystemMetrics( SM_CXFRAME ), "SM_CXFRAME", "%d" );
805     eq( frame, GetSystemMetrics( SM_CYFRAME ), "SM_CYFRAME", "%d" );
806     eq( frame, GetSystemMetrics( SM_CXSIZEFRAME ), "SM_CXSIZEFRAME", "%d" );
807     eq( frame, GetSystemMetrics( SM_CYSIZEFRAME ), "SM_CYSIZEFRAME", "%d" );
808     return TRUE;
809 }
810 
811 static void test_SPI_SETBORDER( void )                 /*      6 */
812 {
813     BOOL rc;
814     UINT old_border;
815     NONCLIENTMETRICSA ncmsave;
816     INT CaptionWidth,
817         PaddedBorderWidth;
818 
819     ncmsave.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
820     rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, 0, &ncmsave, 0);
821     if( !rc) {
822         win_skip("SPI_GETNONCLIENTMETRICS is not available\n");
823         return;
824     }
825     /* CaptionWidth from the registry may have different value of iCaptionWidth
826      * from the non client metrics (observed on WinXP).
827      * Fix this so we can safely restore settings with the nonclientmetrics */
828     CaptionWidth = metricfromreg(
829             "Control Panel\\Desktop\\WindowMetrics","CaptionWidth", dpi);
830     ncmsave.iCaptionWidth = CaptionWidth;
831 
832     /* These tests hang when XFree86 4.0 for Windows is running (tested on
833      *  WinNT, SP2, Cygwin/XFree 4.1.0. Skip the test when XFree86 is
834      * running.
835      */
836     if (FindWindowA( NULL, "Cygwin/XFree86" ))
837         return;
838 
839     trace("testing SPI_{GET,SET}BORDER\n");
840 
841     SetLastError(0xdeadbeef);
842     rc=SystemParametersInfoA( SPI_GETBORDER, 0, &old_border, 0 );
843     if (!test_error_msg(rc,"SPI_{GET,SET}BORDER"))
844         return;
845     /* FIXME: include new PaddedBorderWidth parameter */
846     PaddedBorderWidth = ncmsave.iBorderWidth - old_border;
847     if( PaddedBorderWidth){
848         win_skip( "Cannot reliably restore border width yet (PaddedBorderWidth = %d)\n",
849                 PaddedBorderWidth);
850         return;
851     }
852     /* This will restore sane values if the test hang previous run. */
853     if ( old_border == 7 || old_border == 20 )
854         old_border = 1;
855 
856     /* win2k3 fails if you set the same border twice, or if size is 0 */
857     if (!test_setborder(2,  1, dpi)) return;
858     test_setborder(1,  1, dpi);
859     test_setborder(3,  1, dpi);
860     if (!test_setborder(1, 0, dpi)) return;
861     test_setborder(0, 0, dpi);
862     test_setborder(3, 0, dpi);
863 
864     rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &ncmsave,
865             SPIF_UPDATEINIFILE| SPIF_SENDCHANGE);
866     test_change_message( SPI_SETNONCLIENTMETRICS, 1 );
867     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
868 }
869 
870 static void test_SPI_SETKEYBOARDSPEED( void )          /*     10 */
871 {
872     BOOL rc;
873     UINT old_speed;
874     const UINT vals[]={0,20,31};
875     unsigned int i;
876 
877     trace("testing SPI_{GET,SET}KEYBOARDSPEED\n");
878     SetLastError(0xdeadbeef);
879     rc=SystemParametersInfoA( SPI_GETKEYBOARDSPEED, 0, &old_speed, 0 );
880     if (!test_error_msg(rc,"SPI_{GET,SET}KEYBOARDSPEED"))
881         return;
882 
883     for (i=0;i<ARRAY_SIZE(vals);i++)
884     {
885         UINT v;
886         char buf[10];
887 
888         rc=SystemParametersInfoA( SPI_SETKEYBOARDSPEED, vals[i], 0,
889                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
890         if (!test_error_msg(rc,"SPI_SETKEYBOARDSPEED")) return;
891         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
892         test_change_message( SPI_SETKEYBOARDSPEED, 0 );
893         sprintf( buf, "%d", vals[i] );
894         test_reg_key( SPI_SETKEYBOARDSPEED_REGKEY, SPI_SETKEYBOARDSPEED_VALNAME, buf );
895 
896         rc=SystemParametersInfoA( SPI_GETKEYBOARDSPEED, 0, &v, 0 );
897         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
898         eq( v, vals[i], "SPI_{GET,SET}KEYBOARDSPEED", "%d" );
899     }
900 
901     rc=SystemParametersInfoA( SPI_SETKEYBOARDSPEED, old_speed, 0, SPIF_UPDATEINIFILE );
902     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
903 }
904 
905 /* test_SPI_ICONHORIZONTALSPACING helper */
906 static BOOL dotest_spi_iconhorizontalspacing( INT curr_val)
907 {
908     BOOL rc;
909     INT spacing, regval, min_val = MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI );
910     ICONMETRICSA im;
911 
912     rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, curr_val, 0,
913                               SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
914     if (!test_error_msg(rc,"SPI_ICONHORIZONTALSPACING")) return FALSE;
915     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
916     test_change_message( SPI_ICONHORIZONTALSPACING, 0 );
917     curr_val = max( curr_val, min_val );
918     /* The registry keys depend on the Windows version and the values too
919      * let's test (works on win95,ME,NT4,2k,XP)
920      */
921     regval = metricfromreg( SPI_ICONHORIZONTALSPACING_REGKEY2, SPI_ICONHORIZONTALSPACING_VALNAME, dpi);
922     if( regval != curr_val)
923         regval = metricfromreg( SPI_ICONHORIZONTALSPACING_REGKEY, SPI_ICONHORIZONTALSPACING_VALNAME, dpi);
924     ok( curr_val == regval,
925         "wrong value in registry %d, expected %d\n", regval, curr_val);
926     /* compare with what SPI_ICONHORIZONTALSPACING returns */
927     rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &spacing, 0 );
928     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
929     eq( spacing, curr_val, "ICONHORIZONTALSPACING", "%d");
930     /* and with a system metrics */
931     eq( GetSystemMetrics( SM_CXICONSPACING ), curr_val, "SM_CXICONSPACING", "%d" );
932     /* and with what SPI_GETICONMETRICS returns */
933     im.cbSize = sizeof(ICONMETRICSA);
934     rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE );
935     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
936     eq( im.iHorzSpacing, curr_val, "SPI_GETICONMETRICS", "%d" );
937     return TRUE;
938 }
939 
940 static void test_SPI_ICONHORIZONTALSPACING( void )     /*     13 */
941 {
942     BOOL rc;
943     INT old_spacing;
944 
945     trace("testing SPI_ICONHORIZONTALSPACING\n");
946     SetLastError(0xdeadbeef);
947     /* default value: 75 */
948     rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &old_spacing, 0 );
949     if (!test_error_msg(rc,"SPI_ICONHORIZONTALSPACING"))
950         return;
951     /* do not increase the value as it would upset the user's icon layout */
952     if (!dotest_spi_iconhorizontalspacing( old_spacing - 1)) return;
953     dotest_spi_iconhorizontalspacing( 10); /* minimum is 32 */
954     /* restore */
955     rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, old_spacing, 0, SPIF_UPDATEINIFILE );
956     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
957 }
958 
959 static void test_SPI_SETSCREENSAVETIMEOUT( void )      /*     14 */
960 {
961     BOOL rc;
962     UINT old_timeout;
963     const UINT vals[]={0,32767};
964     unsigned int i;
965 
966     trace("testing SPI_{GET,SET}SCREENSAVETIMEOUT\n");
967     SetLastError(0xdeadbeef);
968     rc=SystemParametersInfoA( SPI_GETSCREENSAVETIMEOUT, 0, &old_timeout, 0 );
969     if (!test_error_msg(rc,"SPI_{GET,SET}SCREENSAVETIMEOUT"))
970         return;
971 
972     for (i=0;i<ARRAY_SIZE(vals);i++)
973     {
974         UINT v;
975         char buf[10];
976 
977         rc=SystemParametersInfoA( SPI_SETSCREENSAVETIMEOUT, vals[i], 0,
978                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
979         if (!test_error_msg(rc,"SPI_SETSCREENSAVETIMEOUT")) return;
980         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
981         test_change_message( SPI_SETSCREENSAVETIMEOUT, 0 );
982         sprintf( buf, "%d", vals[i] );
983         test_reg_key( SPI_SETSCREENSAVETIMEOUT_REGKEY,
984                       SPI_SETSCREENSAVETIMEOUT_VALNAME, buf );
985 
986         rc = SystemParametersInfoA( SPI_GETSCREENSAVETIMEOUT, 0, &v, 0 );
987         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
988         eq( v, vals[i], "SPI_{GET,SET}SCREENSAVETIMEOUT", "%d" );
989     }
990 
991     rc=SystemParametersInfoA( SPI_SETSCREENSAVETIMEOUT, old_timeout, 0,
992                               SPIF_UPDATEINIFILE );
993     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
994 }
995 
996 static void test_SPI_SETSCREENSAVEACTIVE( void )       /*     17 */
997 {
998     BOOL rc;
999     BOOL old_b;
1000     const UINT vals[]={TRUE,FALSE};
1001     unsigned int i;
1002 
1003     trace("testing SPI_{GET,SET}SCREENSAVEACTIVE\n");
1004     SetLastError(0xdeadbeef);
1005     rc=SystemParametersInfoA( SPI_GETSCREENSAVEACTIVE, 0, &old_b, 0 );
1006     if (!test_error_msg(rc,"SPI_{GET,SET}SCREENSAVEACTIVE"))
1007         return;
1008 
1009     for (i=0;i<ARRAY_SIZE(vals);i++)
1010     {
1011         UINT v;
1012 
1013         rc=SystemParametersInfoA( SPI_SETSCREENSAVEACTIVE, vals[i], 0,
1014                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1015         if (!test_error_msg(rc,"SPI_SETSCREENSAVEACTIVE")) return;
1016         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1017         test_change_message( SPI_SETSCREENSAVEACTIVE, 0 );
1018         test_reg_key( SPI_SETSCREENSAVEACTIVE_REGKEY,
1019                       SPI_SETSCREENSAVEACTIVE_VALNAME,
1020                       vals[i] ? "1" : "0" );
1021 
1022         rc=SystemParametersInfoA( SPI_GETSCREENSAVEACTIVE, 0, &v, 0 );
1023         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1024         ok(v == vals[i] || broken(! v) /* Win 7 */,
1025            "SPI_{GET,SET}SCREENSAVEACTIVE: got %d instead of %d\n", v, vals[i]);
1026     }
1027 
1028     rc=SystemParametersInfoA( SPI_SETSCREENSAVEACTIVE, old_b, 0, SPIF_UPDATEINIFILE );
1029     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1030 }
1031 
1032 static void test_SPI_SETGRIDGRANULARITY( void )        /*     19 */
1033 {
1034     /* ??? */;
1035 }
1036 
1037 static void test_SPI_SETKEYBOARDDELAY( void )          /*     23 */
1038 {
1039     BOOL rc;
1040     UINT old_delay;
1041     const UINT vals[]={0,3};
1042     unsigned int i;
1043 
1044     trace("testing SPI_{GET,SET}KEYBOARDDELAY\n");
1045     SetLastError(0xdeadbeef);
1046     rc=SystemParametersInfoA( SPI_GETKEYBOARDDELAY, 0, &old_delay, 0 );
1047     if (!test_error_msg(rc,"SPI_{GET,SET}KEYBOARDDELAY"))
1048         return;
1049 
1050     for (i=0;i<ARRAY_SIZE(vals);i++)
1051     {
1052         UINT delay;
1053         char buf[10];
1054 
1055         rc=SystemParametersInfoA( SPI_SETKEYBOARDDELAY, vals[i], 0,
1056                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1057         if (!test_error_msg(rc,"SPI_SETKEYBOARDDELAY")) return;
1058         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1059         test_change_message( SPI_SETKEYBOARDDELAY, 0 );
1060         sprintf( buf, "%d", vals[i] );
1061         test_reg_key( SPI_SETKEYBOARDDELAY_REGKEY,
1062                       SPI_SETKEYBOARDDELAY_VALNAME, buf );
1063 
1064         rc=SystemParametersInfoA( SPI_GETKEYBOARDDELAY, 0, &delay, 0 );
1065         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1066         eq( delay, vals[i], "SPI_{GET,SET}KEYBOARDDELAY", "%d" );
1067     }
1068 
1069     rc=SystemParametersInfoA( SPI_SETKEYBOARDDELAY, old_delay, 0, SPIF_UPDATEINIFILE );
1070     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1071 }
1072 
1073 
1074 /* test_SPI_ICONVERTICALSPACING helper */
1075 static BOOL dotest_spi_iconverticalspacing( INT curr_val)
1076 {
1077     BOOL rc;
1078     INT spacing, regval, min_val = MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI );
1079     ICONMETRICSA im;
1080 
1081     rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, curr_val, 0,
1082                               SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
1083     if (!test_error_msg(rc,"SPI_ICONVERTICALSPACING")) return FALSE;
1084     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1085     test_change_message( SPI_ICONVERTICALSPACING, 0 );
1086     curr_val = max( curr_val, min_val );
1087     /* The registry keys depend on the Windows version and the values too
1088      * let's test (works on win95,ME,NT4,2k,XP)
1089      */
1090     regval = metricfromreg( SPI_ICONVERTICALSPACING_REGKEY2, SPI_ICONVERTICALSPACING_VALNAME, dpi);
1091     if( regval != curr_val)
1092         regval = metricfromreg( SPI_ICONVERTICALSPACING_REGKEY, SPI_ICONVERTICALSPACING_VALNAME, dpi);
1093     ok( curr_val == regval,
1094         "wrong value in registry %d, expected %d\n", regval, curr_val);
1095     /* compare with what SPI_ICONVERTICALSPACING returns */
1096     rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &spacing, 0 );
1097     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1098     eq( spacing, curr_val, "ICONVERTICALSPACING", "%d" );
1099     /* and with a system metrics */
1100     eq( GetSystemMetrics( SM_CYICONSPACING ), curr_val, "SM_CYICONSPACING", "%d" );
1101     /* and with what SPI_GETICONMETRICS returns */
1102     im.cbSize = sizeof(ICONMETRICSA);
1103     rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE );
1104     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1105     eq( im.iVertSpacing, curr_val, "SPI_GETICONMETRICS", "%d" );
1106     return TRUE;
1107 }
1108 
1109 static void test_SPI_ICONVERTICALSPACING( void )       /*     24 */
1110 {
1111     BOOL rc;
1112     INT old_spacing;
1113 
1114     trace("testing SPI_ICONVERTICALSPACING\n");
1115     SetLastError(0xdeadbeef);
1116     /* default value: 75 */
1117     rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &old_spacing, 0 );
1118     if (!test_error_msg(rc,"SPI_ICONVERTICALSPACING"))
1119         return;
1120     /* do not increase the value as it would upset the user's icon layout */
1121     if (!dotest_spi_iconverticalspacing( old_spacing - 1)) return;
1122     /* same tests with a value less than the minimum 32 */
1123     dotest_spi_iconverticalspacing( 10);
1124     /* restore */
1125     rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, old_spacing, 0,
1126                               SPIF_UPDATEINIFILE );
1127     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1128 }
1129 
1130 static void test_SPI_SETICONTITLEWRAP( void )          /*     26 */
1131 {
1132     BOOL rc;
1133     BOOL old_b;
1134     const UINT vals[]={TRUE,FALSE};
1135     unsigned int i;
1136     ICONMETRICSA im;
1137 
1138     /* These tests hang when XFree86 4.0 for Windows is running (tested on
1139      * WinNT, SP2, Cygwin/XFree 4.1.0. Skip the test when XFree86 is
1140      * running.
1141      */
1142     if (FindWindowA( NULL, "Cygwin/XFree86" ))
1143         return;
1144 
1145     trace("testing SPI_{GET,SET}ICONTITLEWRAP\n");
1146     SetLastError(0xdeadbeef);
1147     rc=SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &old_b, 0 );
1148     if (!test_error_msg(rc,"SPI_{GET,SET}ICONTITLEWRAP"))
1149         return;
1150 
1151     for (i=0;i<ARRAY_SIZE(vals);i++)
1152     {
1153         UINT v;
1154         UINT regval;
1155 
1156         rc=SystemParametersInfoA( SPI_SETICONTITLEWRAP, vals[i], 0,
1157                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1158         if (!test_error_msg(rc,"SPI_SETICONTITLEWRAP")) return;
1159         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1160         test_change_message( SPI_SETICONTITLEWRAP, 1 );
1161         regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY2,
1162                 SPI_SETICONTITLEWRAP_VALNAME, dpi);
1163         if( regval != vals[i])
1164             regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY1,
1165                     SPI_SETICONTITLEWRAP_VALNAME, dpi);
1166         ok( regval == vals[i], "wrong value in registry %d, expected %d\n", regval, vals[i] );
1167 
1168         rc=SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &v, 0 );
1169         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1170         eq( v, vals[i], "SPI_{GET,SET}ICONTITLEWRAP", "%d" );
1171         /* and test with what SPI_GETICONMETRICS returns */
1172         im.cbSize = sizeof(ICONMETRICSA);
1173         rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE );
1174         ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1175         eq( im.iTitleWrap, (BOOL)vals[i], "SPI_GETICONMETRICS", "%d" );
1176     }
1177 
1178     rc=SystemParametersInfoA( SPI_SETICONTITLEWRAP, old_b, 0, SPIF_UPDATEINIFILE );
1179     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1180 }
1181 
1182 static void test_SPI_SETMENUDROPALIGNMENT( void )      /*     28 */
1183 {
1184     BOOL rc;
1185     BOOL old_b;
1186     const UINT vals[]={TRUE,FALSE};
1187     unsigned int i;
1188 
1189     trace("testing SPI_{GET,SET}MENUDROPALIGNMENT\n");
1190     SetLastError(0xdeadbeef);
1191     rc=SystemParametersInfoA( SPI_GETMENUDROPALIGNMENT, 0, &old_b, 0 );
1192     if (!test_error_msg(rc,"SPI_{GET,SET}MENUDROPALIGNMENT"))
1193         return;
1194 
1195     for (i=0;i<ARRAY_SIZE(vals);i++)
1196     {
1197         UINT v;
1198 
1199         rc=SystemParametersInfoA( SPI_SETMENUDROPALIGNMENT, vals[i], 0,
1200                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1201         if (!test_error_msg(rc,"SPI_SETMENUDROPALIGNMENT")) return;
1202         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1203         test_change_message( SPI_SETMENUDROPALIGNMENT, 0 );
1204         test_reg_key_ex( SPI_SETMENUDROPALIGNMENT_REGKEY1,
1205                          SPI_SETMENUDROPALIGNMENT_REGKEY2,
1206                          SPI_SETMENUDROPALIGNMENT_VALNAME,
1207                          vals[i] ? "1" : "0" );
1208 
1209         rc=SystemParametersInfoA( SPI_GETMENUDROPALIGNMENT, 0, &v, 0 );
1210         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1211         eq( v, vals[i], "SPI_{GET,SET}MENUDROPALIGNMENT", "%d" );
1212         eq( GetSystemMetrics( SM_MENUDROPALIGNMENT ), (int)vals[i],
1213             "SM_MENUDROPALIGNMENT", "%d" );
1214     }
1215 
1216     rc=SystemParametersInfoA( SPI_SETMENUDROPALIGNMENT, old_b, 0,
1217                               SPIF_UPDATEINIFILE );
1218     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1219 }
1220 
1221 static void test_SPI_SETDOUBLECLKWIDTH( void )         /*     29 */
1222 {
1223     BOOL rc;
1224     INT old_width;
1225     const UINT vals[]={0,10000};
1226     unsigned int i;
1227 
1228     trace("testing SPI_{GET,SET}DOUBLECLKWIDTH\n");
1229     old_width = GetSystemMetrics( SM_CXDOUBLECLK );
1230 
1231     for (i=0;i<ARRAY_SIZE(vals);i++)
1232     {
1233         char buf[10];
1234 
1235         SetLastError(0xdeadbeef);
1236         rc=SystemParametersInfoA( SPI_SETDOUBLECLKWIDTH, vals[i], 0,
1237                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1238         if (!test_error_msg(rc,"SPI_{GET,SET}DOUBLECLKWIDTH"))
1239             return;
1240 
1241         test_change_message( SPI_SETDOUBLECLKWIDTH, 0 );
1242         sprintf( buf, "%d", vals[i] );
1243         test_reg_key_ex( SPI_SETDOUBLECLKWIDTH_REGKEY1,
1244                          SPI_SETDOUBLECLKWIDTH_REGKEY2,
1245                          SPI_SETDOUBLECLKWIDTH_VALNAME, buf );
1246         eq( GetSystemMetrics( SM_CXDOUBLECLK ), (int)vals[i],
1247             "SM_CXDOUBLECLK", "%d" );
1248     }
1249 
1250     rc=SystemParametersInfoA( SPI_SETDOUBLECLKWIDTH, old_width, 0,
1251                               SPIF_UPDATEINIFILE );
1252     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1253 }
1254 
1255 static void test_SPI_SETDOUBLECLKHEIGHT( void )        /*     30 */
1256 {
1257     BOOL rc;
1258     INT old_height;
1259     const UINT vals[]={0,10000};
1260     unsigned int i;
1261 
1262     trace("testing SPI_{GET,SET}DOUBLECLKHEIGHT\n");
1263     old_height = GetSystemMetrics( SM_CYDOUBLECLK );
1264 
1265     for (i=0;i<ARRAY_SIZE(vals);i++)
1266     {
1267         char buf[10];
1268 
1269         SetLastError(0xdeadbeef);
1270         rc=SystemParametersInfoA( SPI_SETDOUBLECLKHEIGHT, vals[i], 0,
1271                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1272         if (!test_error_msg(rc,"SPI_{GET,SET}DOUBLECLKHEIGHT"))
1273             return;
1274 
1275         test_change_message( SPI_SETDOUBLECLKHEIGHT, 0 );
1276         sprintf( buf, "%d", vals[i] );
1277         test_reg_key_ex( SPI_SETDOUBLECLKHEIGHT_REGKEY1,
1278                          SPI_SETDOUBLECLKHEIGHT_REGKEY2,
1279                          SPI_SETDOUBLECLKHEIGHT_VALNAME, buf );
1280         eq( GetSystemMetrics( SM_CYDOUBLECLK ), (int)vals[i],
1281             "SM_CYDOUBLECLK", "%d" );
1282     }
1283 
1284     rc=SystemParametersInfoA( SPI_SETDOUBLECLKHEIGHT, old_height, 0,
1285                               SPIF_UPDATEINIFILE );
1286     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1287 }
1288 
1289 static void test_SPI_SETDOUBLECLICKTIME( void )        /*     32 */
1290 {
1291     BOOL rc;
1292     UINT curr_val;
1293     UINT saved_val;
1294     UINT old_time;
1295     char buf[10];
1296 
1297     trace("testing SPI_{GET,SET}DOUBLECLICKTIME\n");
1298     old_time = GetDoubleClickTime();
1299 
1300     curr_val = 0;
1301     SetLastError(0xdeadbeef);
1302     rc=SystemParametersInfoA( SPI_SETDOUBLECLICKTIME, curr_val, 0,
1303                               SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1304     if (!test_error_msg(rc,"SPI_{GET,SET}DOUBLECLICKTIME"))
1305         return;
1306 
1307     test_change_message( SPI_SETDOUBLECLICKTIME, 0 );
1308     sprintf( buf, "%d", curr_val );
1309     test_reg_key( SPI_SETDOUBLECLICKTIME_REGKEY,
1310                   SPI_SETDOUBLECLICKTIME_VALNAME, buf );
1311     curr_val = 500; /* used value for 0 */
1312     eq( GetDoubleClickTime(), curr_val, "GetDoubleClickTime", "%d" );
1313 
1314     curr_val = 1000;
1315     rc=SystemParametersInfoA( SPI_SETDOUBLECLICKTIME, curr_val, 0,
1316                              SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1317     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1318     test_change_message( SPI_SETDOUBLECLICKTIME, 0 );
1319     sprintf( buf, "%d", curr_val );
1320     test_reg_key( SPI_SETDOUBLECLICKTIME_REGKEY,
1321                   SPI_SETDOUBLECLICKTIME_VALNAME, buf );
1322     eq( GetDoubleClickTime(), curr_val, "GetDoubleClickTime", "%d" );
1323 
1324     saved_val = curr_val;
1325 
1326     curr_val = 0;
1327     SetDoubleClickTime( curr_val );
1328     sprintf( buf, "%d", saved_val );
1329     test_reg_key( SPI_SETDOUBLECLICKTIME_REGKEY,
1330                   SPI_SETDOUBLECLICKTIME_VALNAME, buf );
1331     curr_val = 500; /* used value for 0 */
1332     eq( GetDoubleClickTime(), curr_val, "GetDoubleClickTime", "%d" );
1333 
1334     curr_val = 1000;
1335     SetDoubleClickTime( curr_val );
1336     sprintf( buf, "%d", saved_val );
1337     test_reg_key( SPI_SETDOUBLECLICKTIME_REGKEY,
1338                   SPI_SETDOUBLECLICKTIME_VALNAME, buf );
1339     eq( GetDoubleClickTime(), curr_val, "GetDoubleClickTime", "%d" );
1340 
1341     rc=SystemParametersInfoA(SPI_SETDOUBLECLICKTIME, old_time, 0, SPIF_UPDATEINIFILE);
1342     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1343 }
1344 
1345 static void test_SPI_SETMOUSEBUTTONSWAP( void )        /*     33 */
1346 {
1347     BOOL rc;
1348     BOOL old_b;
1349     const UINT vals[]={TRUE,FALSE};
1350     unsigned int i;
1351 
1352     trace("testing SPI_{GET,SET}MOUSEBUTTONSWAP\n");
1353     old_b = GetSystemMetrics( SM_SWAPBUTTON );
1354 
1355     for (i=0;i<ARRAY_SIZE(vals);i++)
1356     {
1357         SetLastError(0xdeadbeef);
1358         rc=SystemParametersInfoA( SPI_SETMOUSEBUTTONSWAP, vals[i], 0,
1359                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1360         if (!test_error_msg(rc,"SPI_SETMOUSEBUTTONSWAP")) return;
1361 
1362         test_change_message( SPI_SETMOUSEBUTTONSWAP, 0 );
1363         test_reg_key( SPI_SETMOUSEBUTTONSWAP_REGKEY,
1364                       SPI_SETMOUSEBUTTONSWAP_VALNAME,
1365                       vals[i] ? "1" : "0" );
1366         eq( GetSystemMetrics( SM_SWAPBUTTON ), (int)vals[i],
1367             "SM_SWAPBUTTON", "%d" );
1368         rc=SwapMouseButton((BOOL)vals[i^1]);
1369         eq( GetSystemMetrics( SM_SWAPBUTTON ), (int)vals[i^1],
1370             "SwapMouseButton", "%d" );
1371         ok( rc==(BOOL)vals[i], "SwapMouseButton does not return previous state (really %d)\n", rc );
1372     }
1373 
1374     rc=SystemParametersInfoA( SPI_SETMOUSEBUTTONSWAP, old_b, 0,
1375                               SPIF_UPDATEINIFILE );
1376     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1377 }
1378 
1379 static void test_SPI_SETFASTTASKSWITCH( void )         /*     36 */
1380 {
1381     BOOL rc;
1382     BOOL v;
1383 
1384     trace("testing SPI_GETFASTTASKSWITCH\n");
1385     SetLastError(0xdeadbeef);
1386     rc=SystemParametersInfoA( SPI_GETFASTTASKSWITCH, 0, &v, 0 );
1387     if (!test_error_msg(rc,"SPI_{GET,SET}FASTTASKSWITCH"))
1388         return;
1389 
1390     /* there is not a single Windows platform on which SPI_GETFASTTASKSWITCH
1391      * works. That sure simplifies testing!
1392      */
1393 }
1394 
1395 static void test_SPI_SETDRAGFULLWINDOWS( void )        /*     37 */
1396 {
1397     BOOL rc;
1398     BOOL old_b;
1399     const UINT vals[]={TRUE,FALSE};
1400     unsigned int i;
1401 
1402     trace("testing SPI_{GET,SET}DRAGFULLWINDOWS\n");
1403     SetLastError(0xdeadbeef);
1404     rc=SystemParametersInfoA( SPI_GETDRAGFULLWINDOWS, 0, &old_b, 0 );
1405 
1406     /* SPI_{GET,SET}DRAGFULLWINDOWS is not implemented on Win95 */
1407     if (!test_error_msg(rc,"SPI_{GET,SET}DRAGFULLWINDOWS"))
1408         return;
1409 
1410     for (i=0;i<ARRAY_SIZE(vals);i++)
1411     {
1412         UINT v;
1413 
1414         rc=SystemParametersInfoA( SPI_SETDRAGFULLWINDOWS, vals[i], 0,
1415                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1416         if (!test_error_msg(rc,"SPI_SETDRAGFULLWINDOWS")) return;
1417         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1418         test_change_message( SPI_SETDRAGFULLWINDOWS, 0 );
1419         test_reg_key( SPI_SETDRAGFULLWINDOWS_REGKEY,
1420                       SPI_SETDRAGFULLWINDOWS_VALNAME,
1421                       vals[i] ? "1" : "0" );
1422 
1423         rc=SystemParametersInfoA( SPI_GETDRAGFULLWINDOWS, 0, &v, 0 );
1424         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1425         eq( v, vals[i], "SPI_{GET,SET}DRAGFULLWINDOWS", "%d" );
1426     }
1427 
1428     rc=SystemParametersInfoA( SPI_SETDRAGFULLWINDOWS, old_b, 0, SPIF_UPDATEINIFILE );
1429     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1430 }
1431 
1432 #define test_reg_metric( KEY, VAL, val) do { \
1433     INT regval;\
1434     regval = metricfromreg( KEY, VAL, dpi);\
1435     ok( regval==val, "wrong value \"%s\" in registry %d, expected %d\n", VAL, regval, val);\
1436 } while(0)
1437 
1438 #define test_reg_metric2( KEY1, KEY2, VAL, val) do { \
1439     INT regval;\
1440     regval = metricfromreg( KEY1, VAL, dpi);\
1441     if( regval != val) regval = metricfromreg( KEY2, VAL, dpi);\
1442     ok( regval==val, "wrong value \"%s\" in registry %d, expected %d\n", VAL, regval, val);\
1443 } while(0)
1444 
1445 #define test_reg_font( KEY, VAL, LF) do { \
1446     LOGFONTA lfreg;\
1447     lffromreg( KEY, VAL, &lfreg);\
1448     ok( (lfreg.lfHeight < 0 ? (LF).lfHeight == MulDiv( lfreg.lfHeight, dpi, real_dpi ) : \
1449                 MulDiv( -(LF).lfHeight , 72, dpi) == lfreg.lfHeight )&&\
1450         (LF).lfWidth == lfreg.lfWidth &&\
1451         (LF).lfWeight == lfreg.lfWeight &&\
1452         !strcmp( (LF).lfFaceName, lfreg.lfFaceName)\
1453         , "wrong value \"%s\" in registry %d, %d\n", VAL, (LF).lfHeight, lfreg.lfHeight);\
1454 } while(0)
1455 
1456 #define TEST_NONCLIENTMETRICS_REG( ncm) do { \
1457 /*FIXME: test_reg_metric2( SPI_SETBORDER_REGKEY2, SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME, (ncm).iBorderWidth);*/\
1458 test_reg_metric( SPI_METRIC_REGKEY, SPI_SCROLLWIDTH_VALNAME, (ncm).iScrollWidth);\
1459 test_reg_metric( SPI_METRIC_REGKEY, SPI_SCROLLHEIGHT_VALNAME, (ncm).iScrollHeight);\
1460 /*FIXME: test_reg_metric( SPI_METRIC_REGKEY, SPI_CAPTIONWIDTH_VALNAME, (ncm).iCaptionWidth);*/\
1461 test_reg_metric( SPI_METRIC_REGKEY, SPI_CAPTIONHEIGHT_VALNAME, (ncm).iCaptionHeight);\
1462 test_reg_metric( SPI_METRIC_REGKEY, SPI_SMCAPTIONWIDTH_VALNAME, (ncm).iSmCaptionWidth);\
1463 test_reg_metric( SPI_METRIC_REGKEY, SPI_SMCAPTIONHEIGHT_VALNAME, (ncm).iSmCaptionHeight);\
1464 test_reg_metric( SPI_METRIC_REGKEY, SPI_MENUWIDTH_VALNAME, (ncm).iMenuWidth);\
1465 test_reg_metric( SPI_METRIC_REGKEY, SPI_MENUHEIGHT_VALNAME, (ncm).iMenuHeight);\
1466 test_reg_font( SPI_METRIC_REGKEY, SPI_MENUFONT_VALNAME, (ncm).lfMenuFont);\
1467 test_reg_font( SPI_METRIC_REGKEY, SPI_CAPTIONFONT_VALNAME, (ncm).lfCaptionFont);\
1468 test_reg_font( SPI_METRIC_REGKEY, SPI_SMCAPTIONFONT_VALNAME, (ncm).lfSmCaptionFont);\
1469 test_reg_font( SPI_METRIC_REGKEY, SPI_STATUSFONT_VALNAME, (ncm).lfStatusFont);\
1470 test_reg_font( SPI_METRIC_REGKEY, SPI_MESSAGEFONT_VALNAME, (ncm).lfMessageFont); } while(0)
1471 
1472 /* get text metric height value for the specified logfont */
1473 static int get_tmheight( LOGFONTA *plf, int flag)
1474 {
1475     TEXTMETRICA tm;
1476     HDC hdc = GetDC(0);
1477     HFONT hfont = CreateFontIndirectA( plf);
1478     hfont = SelectObject( hdc, hfont);
1479     GetTextMetricsA( hdc, &tm);
1480     hfont = SelectObject( hdc, hfont);
1481     ReleaseDC( 0, hdc );
1482     return tm.tmHeight + (flag ? tm.tmExternalLeading : 0);
1483 }
1484 
1485 static int get_tmheightW( LOGFONTW *plf, int flag)
1486 {
1487     TEXTMETRICW tm;
1488     HDC hdc = GetDC(0);
1489     HFONT hfont = CreateFontIndirectW( plf);
1490     hfont = SelectObject( hdc, hfont);
1491     GetTextMetricsW( hdc, &tm);
1492     hfont = SelectObject( hdc, hfont);
1493     ReleaseDC( 0, hdc );
1494     return tm.tmHeight + (flag ? tm.tmExternalLeading : 0);
1495 }
1496 
1497 static void test_GetSystemMetrics( void);
1498 static UINT smcxsmsize = 999999999;
1499 
1500 static void test_SPI_SETNONCLIENTMETRICS( void )               /*     44 */
1501 {
1502     BOOL rc;
1503     INT expect;
1504     NONCLIENTMETRICSA Ncmorig;
1505     NONCLIENTMETRICSA Ncmnew;
1506     NONCLIENTMETRICSA Ncmcur;
1507     NONCLIENTMETRICSA Ncmstart;
1508 
1509     Ncmorig.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
1510     Ncmnew.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
1511     Ncmcur.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
1512     Ncmstart.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
1513 
1514     trace("testing SPI_{GET,SET}NONCLIENTMETRICS\n");
1515     change_counter = 0;
1516     SetLastError(0xdeadbeef);
1517     rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &Ncmorig, FALSE );
1518     if (!test_error_msg(rc,"SPI_{GET,SET}NONCLIENTMETRICS"))
1519         return;
1520     Ncmstart = Ncmorig;
1521     smcxsmsize = Ncmstart.iSmCaptionWidth;
1522     /* SPI_GETNONCLIENTMETRICS returns some "cooked" values. For instance if
1523        the caption font height is higher than the CaptionHeight field,
1524        the latter is adjusted accordingly. To be able to restore these setting
1525        accurately be restore the raw values. */
1526     Ncmorig.iCaptionWidth = metricfromreg( SPI_METRIC_REGKEY, SPI_CAPTIONWIDTH_VALNAME, real_dpi);
1527     Ncmorig.iCaptionHeight = metricfromreg( SPI_METRIC_REGKEY, SPI_CAPTIONHEIGHT_VALNAME, dpi);
1528     Ncmorig.iSmCaptionHeight = metricfromreg( SPI_METRIC_REGKEY, SPI_SMCAPTIONHEIGHT_VALNAME, dpi);
1529     Ncmorig.iMenuHeight = metricfromreg( SPI_METRIC_REGKEY, SPI_MENUHEIGHT_VALNAME, dpi);
1530     /* test registry entries */
1531     TEST_NONCLIENTMETRICS_REG( Ncmorig);
1532 
1533     /* make small changes */
1534     Ncmnew = Ncmstart;
1535     Ncmnew.iBorderWidth += 1;
1536     Ncmnew.iScrollWidth += 1;
1537     Ncmnew.iScrollHeight -= 1;
1538     Ncmnew.iCaptionWidth -= 2;
1539     Ncmnew.iCaptionHeight += 2;
1540     Ncmnew.lfCaptionFont.lfHeight +=1;
1541     Ncmnew.lfCaptionFont.lfWidth +=2;
1542     Ncmnew.lfCaptionFont.lfWeight +=1;
1543     Ncmnew.iSmCaptionWidth += 1;
1544     Ncmnew.iSmCaptionHeight += 2;
1545     Ncmnew.lfSmCaptionFont.lfHeight +=3;
1546     Ncmnew.lfSmCaptionFont.lfWidth -=1;
1547     Ncmnew.lfSmCaptionFont.lfWeight +=3;
1548     Ncmnew.iMenuWidth += 1;
1549     Ncmnew.iMenuHeight += 2;
1550     Ncmnew.lfMenuFont.lfHeight +=1;
1551     Ncmnew.lfMenuFont.lfWidth +=1;
1552     Ncmnew.lfMenuFont.lfWeight +=2;
1553     Ncmnew.lfStatusFont.lfHeight -=1;
1554     Ncmnew.lfStatusFont.lfWidth -=1;
1555     Ncmnew.lfStatusFont.lfWeight +=3;
1556     Ncmnew.lfMessageFont.lfHeight -=2;
1557     Ncmnew.lfMessageFont.lfWidth -=1;
1558     Ncmnew.lfMessageFont.lfWeight +=4;
1559 
1560     rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &Ncmnew, SPIF_UPDATEINIFILE|
1561             SPIF_SENDCHANGE);
1562     if (!test_error_msg(rc,"SPI_SETNONCLIENTMETRICS")) return;
1563     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1564     test_change_message( SPI_SETNONCLIENTMETRICS, 1 );
1565     /* get them back */
1566     rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &Ncmcur, FALSE );
1567     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1568     /* test registry entries */
1569     TEST_NONCLIENTMETRICS_REG( Ncmcur );
1570     /* test the system metrics with these settings */
1571     test_GetSystemMetrics();
1572     /* now for something invalid: increase the {menu|caption|smcaption} fonts
1573        by a large amount will increase the {menu|caption|smcaption} height*/
1574     Ncmnew = Ncmstart;
1575     Ncmnew.lfMenuFont.lfHeight -= 8;
1576     Ncmnew.lfCaptionFont.lfHeight =-4;
1577     Ncmnew.lfSmCaptionFont.lfHeight -=10;
1578     /* also show that a few values are lo limited */
1579     Ncmnew.iCaptionWidth = 0;
1580     Ncmnew.iCaptionHeight = 0;
1581     Ncmnew.iScrollHeight = 0;
1582     Ncmnew.iScrollWidth  = 0;
1583 
1584     rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &Ncmnew, SPIF_UPDATEINIFILE|
1585             SPIF_SENDCHANGE);
1586     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1587     test_change_message( SPI_SETNONCLIENTMETRICS, 1 );
1588     /* raw values are in registry */
1589     TEST_NONCLIENTMETRICS_REG( Ncmnew );
1590     /* get them back */
1591     rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &Ncmcur, FALSE );
1592     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1593     /* cooked values are returned */
1594     expect = max( Ncmnew.iMenuHeight, 2 + get_tmheight( &Ncmnew.lfMenuFont, 1));
1595     ok( Ncmcur.iMenuHeight == expect,
1596         "MenuHeight: %d expected %d\n", Ncmcur.iMenuHeight, expect);
1597     expect = max( Ncmnew.iCaptionHeight, 2 + get_tmheight(&Ncmnew.lfCaptionFont, 0));
1598     ok( Ncmcur.iCaptionHeight == expect,
1599         "CaptionHeight: %d expected %d\n", Ncmcur.iCaptionHeight, expect);
1600     expect = max( Ncmnew.iSmCaptionHeight, 2 + get_tmheight( &Ncmnew.lfSmCaptionFont, 0));
1601     ok( Ncmcur.iSmCaptionHeight == expect,
1602         "SmCaptionHeight: %d expected %d\n", Ncmcur.iSmCaptionHeight, expect);
1603 
1604     /* iCaptionWidth depends on a version, could be 8, 12 (Vista, Win7), 13 */
1605     ok( (Ncmcur.iCaptionWidth >= 8 && Ncmcur.iCaptionWidth <= 13) ||
1606         Ncmcur.iCaptionWidth == Ncmstart.iCaptionWidth, /* with windows XP theme,  the value never changes */
1607         "CaptionWidth: %d expected from [8, 13] or %d\n", Ncmcur.iCaptionWidth, Ncmstart.iCaptionWidth);
1608     ok( Ncmcur.iScrollWidth == 8,
1609         "ScrollWidth: %d expected 8\n", Ncmcur.iScrollWidth);
1610     ok( Ncmcur.iScrollHeight == 8,
1611         "ScrollHeight: %d expected 8\n", Ncmcur.iScrollHeight);
1612     /* test the system metrics with these settings */
1613     test_GetSystemMetrics();
1614     /* restore */
1615     rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA),
1616         &Ncmorig, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
1617     test_change_message( SPI_SETNONCLIENTMETRICS, 0 );
1618     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1619     /* test the system metrics with these settings */
1620     test_GetSystemMetrics();
1621 }
1622 
1623 static void test_SPI_SETMINIMIZEDMETRICS( void )               /*     44 */
1624 {
1625     BOOL rc;
1626     INT regval;
1627     MINIMIZEDMETRICS lpMm_orig;
1628     MINIMIZEDMETRICS lpMm_new;
1629     MINIMIZEDMETRICS lpMm_cur;
1630 
1631     lpMm_orig.cbSize = sizeof(MINIMIZEDMETRICS);
1632     lpMm_new.cbSize = sizeof(MINIMIZEDMETRICS);
1633     lpMm_cur.cbSize = sizeof(MINIMIZEDMETRICS);
1634 
1635     trace("testing SPI_{GET,SET}MINIMIZEDMETRICS\n");
1636     SetLastError(0xdeadbeef);
1637     rc=SystemParametersInfoA( SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &lpMm_orig, FALSE );
1638     if (!test_error_msg(rc,"SPI_{GET,SET}MINIMIZEDMETRICS"))
1639         return;
1640     /* Test registry. Note that it is perfectly valid for some fields to
1641      * not be set.
1642      */
1643     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINWIDTH_VALNAME, dpi);
1644     ok( regval == -1 || regval == lpMm_orig.iWidth, "wrong value in registry %d, expected %d\n",
1645         regval, lpMm_orig.iWidth);
1646     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINHORZGAP_VALNAME, dpi);
1647     ok( regval == -1 || regval == lpMm_orig.iHorzGap, "wrong value in registry %d, expected %d\n",
1648         regval, lpMm_orig.iHorzGap);
1649     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINVERTGAP_VALNAME, dpi);
1650     ok( regval == -1 || regval == lpMm_orig.iVertGap, "wrong value in registry %d, expected %d\n",
1651         regval, lpMm_orig.iVertGap);
1652     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINARRANGE_VALNAME, dpi);
1653     ok( regval == -1 || regval == lpMm_orig.iArrange, "wrong value in registry %d, expected %d\n",
1654         regval, lpMm_orig.iArrange);
1655     /* set some new values */
1656     lpMm_cur.iWidth = 180;
1657     lpMm_cur.iHorzGap = 1;
1658     lpMm_cur.iVertGap = 1;
1659     lpMm_cur.iArrange = 5;
1660     rc=SystemParametersInfoA( SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS),
1661         &lpMm_cur, SPIF_UPDATEINIFILE );
1662     if (!test_error_msg(rc,"SPI_SETMINIMIZEDMETRICS")) return;
1663     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1664     /* read them back */
1665     rc=SystemParametersInfoA( SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &lpMm_new, FALSE );
1666     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1667     /* and compare */
1668     eq( lpMm_new.iWidth,   lpMm_cur.iWidth,   "iWidth",   "%d" );
1669     eq( lpMm_new.iHorzGap, lpMm_cur.iHorzGap, "iHorzGap", "%d" );
1670     eq( lpMm_new.iVertGap, lpMm_cur.iVertGap, "iVertGap", "%d" );
1671     eq( lpMm_new.iArrange, lpMm_cur.iArrange, "iArrange", "%d" );
1672     /* test registry */
1673     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINWIDTH_VALNAME, dpi);
1674     ok( regval == lpMm_new.iWidth, "wrong value in registry %d, expected %d\n",
1675         regval, lpMm_new.iWidth);
1676     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINHORZGAP_VALNAME, dpi);
1677     ok( regval == lpMm_new.iHorzGap, "wrong value in registry %d, expected %d\n",
1678         regval, lpMm_new.iHorzGap);
1679     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINVERTGAP_VALNAME, dpi);
1680     ok( regval == lpMm_new.iVertGap, "wrong value in registry %d, expected %d\n",
1681         regval, lpMm_new.iVertGap);
1682     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINARRANGE_VALNAME, dpi);
1683     ok( regval == lpMm_new.iArrange, "wrong value in registry %d, expected %d\n",
1684         regval, lpMm_new.iArrange);
1685     /* test some system metrics */
1686     eq( GetSystemMetrics( SM_CXMINIMIZED ) - 6,
1687         lpMm_new.iWidth,   "iWidth",   "%d" );
1688     eq( GetSystemMetrics( SM_CXMINSPACING ) - GetSystemMetrics( SM_CXMINIMIZED ),
1689         lpMm_new.iHorzGap, "iHorzGap", "%d" );
1690     eq( GetSystemMetrics( SM_CYMINSPACING ) - GetSystemMetrics( SM_CYMINIMIZED ),
1691         lpMm_new.iVertGap, "iVertGap", "%d" );
1692     eq( GetSystemMetrics( SM_ARRANGE ),
1693         lpMm_new.iArrange, "iArrange", "%d" );
1694     /* now some really invalid settings */
1695     lpMm_cur.iWidth = -1;
1696     lpMm_cur.iHorzGap = -1;
1697     lpMm_cur.iVertGap = -1;
1698     lpMm_cur.iArrange = - 1;
1699     rc=SystemParametersInfoA( SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS),
1700         &lpMm_cur, SPIF_UPDATEINIFILE );
1701     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1702     /* read back */
1703     rc=SystemParametersInfoA( SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &lpMm_new, FALSE );
1704     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1705     /* the width and H/V gaps have minimum 0, arrange is and'd with 0xf */
1706     eq( lpMm_new.iWidth,   0,   "iWidth",   "%d" );
1707     eq( lpMm_new.iHorzGap, 0, "iHorzGap", "%d" );
1708     eq( lpMm_new.iVertGap, 0, "iVertGap", "%d" );
1709     eq( lpMm_new.iArrange, 0xf & lpMm_cur.iArrange, "iArrange", "%d" );
1710     /* test registry */
1711     if (0)
1712     {
1713     /* FIXME: cannot understand the results of this (11, 11, 11, 0) */
1714     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINWIDTH_VALNAME, dpi);
1715     ok( regval == lpMm_new.iWidth, "wrong value in registry %d, expected %d\n",
1716         regval, lpMm_new.iWidth);
1717     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINHORZGAP_VALNAME, dpi);
1718     ok( regval == lpMm_new.iHorzGap, "wrong value in registry %d, expected %d\n",
1719         regval, lpMm_new.iHorzGap);
1720     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINVERTGAP_VALNAME, dpi);
1721     ok( regval == lpMm_new.iVertGap, "wrong value in registry %d, expected %d\n",
1722         regval, lpMm_new.iVertGap);
1723     regval = metricfromreg( SPI_MINIMIZEDMETRICS_REGKEY, SPI_MINARRANGE_VALNAME, dpi);
1724     ok( regval == lpMm_new.iArrange, "wrong value in registry %d, expected %d\n",
1725         regval, lpMm_new.iArrange);
1726     }
1727     /* test some system metrics */
1728     eq( GetSystemMetrics( SM_CXMINIMIZED ) - 6,
1729         lpMm_new.iWidth,   "iWidth",   "%d" );
1730     eq( GetSystemMetrics( SM_CXMINSPACING ) - GetSystemMetrics( SM_CXMINIMIZED ),
1731         lpMm_new.iHorzGap, "iHorzGap", "%d" );
1732     eq( GetSystemMetrics( SM_CYMINSPACING ) - GetSystemMetrics( SM_CYMINIMIZED ),
1733         lpMm_new.iVertGap, "iVertGap", "%d" );
1734     eq( GetSystemMetrics( SM_ARRANGE ),
1735         lpMm_new.iArrange, "iArrange", "%d" );
1736     /* restore */
1737     rc=SystemParametersInfoA( SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS),
1738         &lpMm_orig, SPIF_UPDATEINIFILE );
1739     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1740     /* check that */
1741     rc=SystemParametersInfoA( SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &lpMm_new, FALSE );
1742     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1743     eq( lpMm_new.iWidth,   lpMm_orig.iWidth,   "iWidth",   "%d" );
1744     eq( lpMm_new.iHorzGap, lpMm_orig.iHorzGap, "iHorzGap", "%d" );
1745     eq( lpMm_new.iVertGap, lpMm_orig.iVertGap, "iVertGap", "%d" );
1746     eq( lpMm_new.iArrange, lpMm_orig.iArrange, "iArrange", "%d" );
1747 }
1748 
1749 static void test_SPI_SETICONMETRICS( void )               /*     46 */
1750 {
1751     BOOL rc, wrap;
1752     INT spacing;
1753     ICONMETRICSA im_orig;
1754     ICONMETRICSA im_new;
1755     ICONMETRICSA im_cur;
1756     INT regval;
1757 
1758     im_orig.cbSize = sizeof(ICONMETRICSA);
1759     im_new.cbSize = sizeof(ICONMETRICSA);
1760     im_cur.cbSize = sizeof(ICONMETRICSA);
1761 
1762     trace("testing SPI_{GET,SET}ICONMETRICS\n");
1763     SetLastError(0xdeadbeef);
1764     rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im_orig, FALSE );
1765     if (!test_error_msg(rc,"SPI_{GET,SET}ICONMETRICS"))
1766         return;
1767    /* check some registry values */
1768     regval = metricfromreg( SPI_ICONHORIZONTALSPACING_REGKEY, SPI_ICONHORIZONTALSPACING_VALNAME, dpi);
1769     ok( regval==im_orig.iHorzSpacing,
1770         "wrong value in registry %d, expected %d\n", regval, im_orig.iHorzSpacing);
1771     regval = metricfromreg( SPI_ICONVERTICALSPACING_REGKEY, SPI_ICONVERTICALSPACING_VALNAME, dpi);
1772     ok( regval==im_orig.iVertSpacing,
1773         "wrong value in registry %d, expected %d\n", regval, im_orig.iVertSpacing);
1774     regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY2, SPI_SETICONTITLEWRAP_VALNAME, dpi);
1775     if( regval != im_orig.iTitleWrap)
1776         regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY1, SPI_SETICONTITLEWRAP_VALNAME, dpi);
1777     ok( regval==im_orig.iTitleWrap, "wrong value in registry %d, expected %d\n", regval, im_orig.iTitleWrap);
1778 
1779     /* change everything without creating something invalid ( Win9x would ignore
1780      * an invalid font for instance) */
1781     im_cur = im_orig;
1782     im_cur.iHorzSpacing += 10;
1783     im_cur.iVertSpacing += 6;
1784     im_cur.iTitleWrap = !im_cur.iTitleWrap;
1785     im_cur.lfFont.lfHeight += 1;
1786     im_cur.lfFont.lfWidth += 2;
1787     im_cur.lfFont.lfEscapement = 1;
1788     im_cur.lfFont.lfWeight = im_cur.lfFont.lfWeight > 100 ? 1 : 314;
1789     im_cur.lfFont.lfItalic = !im_cur.lfFont.lfItalic;
1790     im_cur.lfFont.lfStrikeOut = !im_cur.lfFont.lfStrikeOut;
1791     im_cur.lfFont.lfUnderline = !im_cur.lfFont.lfUnderline;
1792     im_cur.lfFont.lfCharSet = im_cur.lfFont.lfCharSet ? 0 : 1;
1793     im_cur.lfFont.lfOutPrecision = im_cur.lfFont.lfOutPrecision == OUT_DEFAULT_PRECIS ?
1794                                 OUT_TT_PRECIS : OUT_DEFAULT_PRECIS;
1795     im_cur.lfFont.lfClipPrecision ^= CLIP_LH_ANGLES;
1796     im_cur.lfFont.lfPitchAndFamily = im_cur.lfFont.lfPitchAndFamily ? 0 : 1;
1797     im_cur.lfFont.lfQuality = im_cur.lfFont.lfQuality == DEFAULT_QUALITY ?
1798                                 DRAFT_QUALITY : DEFAULT_QUALITY;
1799     if( strcmp( im_cur.lfFont.lfFaceName, "MS Serif"))
1800         strcpy( im_cur.lfFont.lfFaceName, "MS Serif");
1801     else
1802         strcpy( im_cur.lfFont.lfFaceName, "MS Sans Serif");
1803 
1804     rc=SystemParametersInfoA( SPI_SETICONMETRICS, sizeof(ICONMETRICSA), &im_cur, SPIF_UPDATEINIFILE );
1805     if (!test_error_msg(rc,"SPI_SETICONMETRICS")) return;
1806     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1807 
1808     rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im_new, FALSE );
1809     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1810     /* test GET <-> SETICONMETRICS */
1811     eq( im_new.iHorzSpacing, im_cur.iHorzSpacing, "iHorzSpacing", "%d" );
1812     eq( im_new.iVertSpacing, im_cur.iVertSpacing, "iVertSpacing", "%d" );
1813     eq( im_new.iTitleWrap,   im_cur.iTitleWrap,   "iTitleWrap",   "%d" );
1814     eq( im_new.lfFont.lfHeight,         im_cur.lfFont.lfHeight,         "lfHeight",         "%d" );
1815     eq( im_new.lfFont.lfWidth,          im_cur.lfFont.lfWidth,          "lfWidth",          "%d" );
1816     eq( im_new.lfFont.lfEscapement,     im_cur.lfFont.lfEscapement,     "lfEscapement",     "%d" );
1817     eq( im_new.lfFont.lfWeight,         im_cur.lfFont.lfWeight,         "lfWeight",         "%d" );
1818     eq( im_new.lfFont.lfItalic,         im_cur.lfFont.lfItalic,         "lfItalic",         "%d" );
1819     eq( im_new.lfFont.lfStrikeOut,      im_cur.lfFont.lfStrikeOut,      "lfStrikeOut",      "%d" );
1820     eq( im_new.lfFont.lfUnderline,      im_cur.lfFont.lfUnderline,      "lfUnderline",      "%d" );
1821     eq( im_new.lfFont.lfCharSet,        im_cur.lfFont.lfCharSet,        "lfCharSet",        "%d" );
1822     eq( im_new.lfFont.lfOutPrecision,   im_cur.lfFont.lfOutPrecision,   "lfOutPrecision",   "%d" );
1823     eq( im_new.lfFont.lfClipPrecision,  im_cur.lfFont.lfClipPrecision,  "lfClipPrecision",  "%d" );
1824     eq( im_new.lfFont.lfPitchAndFamily, im_cur.lfFont.lfPitchAndFamily, "lfPitchAndFamily", "%d" );
1825     eq( im_new.lfFont.lfQuality,        im_cur.lfFont.lfQuality,        "lfQuality",        "%d" );
1826     ok( !strcmp( im_new.lfFont.lfFaceName, im_cur.lfFont.lfFaceName),
1827         "wrong facename \"%s\", should be \"%s\"\n", im_new.lfFont.lfFaceName,
1828         im_cur.lfFont.lfFaceName);
1829     /* test some system metrics */
1830     eq( GetSystemMetrics( SM_CXICONSPACING ),
1831         im_new.iHorzSpacing, "iHorzSpacing", "%d" );
1832     eq( GetSystemMetrics( SM_CYICONSPACING ),
1833         im_new.iVertSpacing, "iVertSpacing", "%d" );
1834    /* check some registry values */
1835     regval = metricfromreg( SPI_ICONHORIZONTALSPACING_REGKEY, SPI_ICONHORIZONTALSPACING_VALNAME, dpi);
1836     ok( regval==im_cur.iHorzSpacing, "wrong value in registry %d, expected %d\n", regval, im_cur.iHorzSpacing);
1837     regval = metricfromreg( SPI_ICONVERTICALSPACING_REGKEY, SPI_ICONVERTICALSPACING_VALNAME, dpi);
1838     ok( regval==im_cur.iVertSpacing, "wrong value in registry %d, expected %d\n", regval, im_cur.iVertSpacing);
1839     regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY2, SPI_SETICONTITLEWRAP_VALNAME, dpi);
1840     if( regval != im_cur.iTitleWrap)
1841         regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY1, SPI_SETICONTITLEWRAP_VALNAME, dpi);
1842     ok( regval==im_cur.iTitleWrap, "wrong value in registry %d, expected %d\n", regval, im_cur.iTitleWrap);
1843     /* test some values from other SPI_GETxxx calls */
1844     rc = SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &spacing, 0 );
1845     ok( rc && spacing == im_cur.iHorzSpacing,
1846         "SystemParametersInfoA( SPI_ICONHORIZONTALSPACING...) failed or returns wrong value %d instead of %d\n",
1847         spacing, im_cur.iHorzSpacing);
1848     rc = SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &spacing, 0 );
1849     ok( rc && spacing == im_cur.iVertSpacing,
1850         "SystemParametersInfoA( SPI_ICONVERTICALSPACING...) failed or returns wrong value %d instead of %d\n",
1851         spacing, im_cur.iVertSpacing);
1852     rc = SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &wrap, 0 );
1853     ok( rc && wrap == im_cur.iTitleWrap,
1854         "SystemParametersInfoA( SPI_GETICONTITLEWRAP...) failed or returns wrong value %d instead of %d\n",
1855         wrap, im_cur.iTitleWrap);
1856     /* restore old values */
1857     rc=SystemParametersInfoA( SPI_SETICONMETRICS, sizeof(ICONMETRICSA), &im_orig,SPIF_UPDATEINIFILE );
1858     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1859 
1860     rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im_new, FALSE );
1861     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1862 
1863     eq( im_new.iHorzSpacing, im_orig.iHorzSpacing, "iHorzSpacing", "%d" );
1864     eq( im_new.iVertSpacing, im_orig.iVertSpacing, "iVertSpacing", "%d" );
1865     eq( im_new.iTitleWrap,   im_orig.iTitleWrap,   "iTitleWrap",   "%d" );
1866 }
1867 
1868 static void test_SPI_SETWORKAREA( void )               /*     47 */
1869 {
1870     BOOL rc;
1871     RECT old_area;
1872     RECT area;
1873     RECT curr_val;
1874 
1875     trace("testing SPI_{GET,SET}WORKAREA\n");
1876     SetLastError(0xdeadbeef);
1877     rc=SystemParametersInfoA(SPI_GETWORKAREA, 0, &old_area, 0);
1878     if (!test_error_msg(rc,"SPI_{GET,SET}WORKAREA"))
1879         return;
1880 
1881     /* Modify the work area only minimally as this causes the icons that
1882      * fall outside it to be moved around thus requiring the user to
1883      * reposition them manually one by one.
1884      * Changing the work area by just one pixel should make this occurrence
1885      * reasonably unlikely.
1886      */
1887     SetRect(&curr_val, old_area.left, old_area.top, old_area.right - 1, old_area.bottom - 1);
1888     rc=SystemParametersInfoA( SPI_SETWORKAREA, 0, &curr_val,
1889                               SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1890     if (!test_error_msg(rc,"SPI_SETWORKAREA")) return;
1891     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1892     rc=SystemParametersInfoA( SPI_GETWORKAREA, 0, &area, 0 );
1893     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1894     if( !EqualRect( &area, &curr_val)) /* no message if rect has not changed */
1895         test_change_message( SPI_SETWORKAREA, 0);
1896     eq( area.left,   curr_val.left,   "left",   "%d" );
1897     eq( area.top,    curr_val.top,    "top",    "%d" );
1898     /* size may be rounded */
1899     ok( area.right >= curr_val.right - 16 && area.right < curr_val.right + 16,
1900         "right: got %d instead of %d\n", area.right, curr_val.right );
1901     ok( area.bottom >= curr_val.bottom - 16 && area.bottom < curr_val.bottom + 16,
1902         "bottom: got %d instead of %d\n", area.bottom, curr_val.bottom );
1903     curr_val = area;
1904     rc=SystemParametersInfoA( SPI_SETWORKAREA, 0, &old_area,
1905                               SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1906     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1907     rc=SystemParametersInfoA( SPI_GETWORKAREA, 0, &area, 0 );
1908     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
1909     if( !EqualRect( &area, &curr_val)) /* no message if rect has not changed */
1910         test_change_message( SPI_SETWORKAREA, 0 );
1911     eq( area.left,   old_area.left,   "left",   "%d" );
1912     eq( area.top,    old_area.top,    "top",    "%d" );
1913     /* size may be rounded */
1914     ok( area.right >= old_area.right - 16 && area.right < old_area.right + 16,
1915         "right: got %d instead of %d\n", area.right, old_area.right );
1916     ok( area.bottom >= old_area.bottom - 16 && area.bottom < old_area.bottom + 16,
1917         "bottom: got %d instead of %d\n", area.bottom, old_area.bottom );
1918 }
1919 
1920 static void test_SPI_SETSHOWSOUNDS( void )             /*     57 */
1921 {
1922     BOOL rc;
1923     BOOL old_b;
1924     const UINT vals[]={TRUE,FALSE};
1925     unsigned int i;
1926 
1927     trace("testing SPI_{GET,SET}SHOWSOUNDS\n");
1928     SetLastError(0xdeadbeef);
1929     rc=SystemParametersInfoA( SPI_GETSHOWSOUNDS, 0, &old_b, 0 );
1930     if (!test_error_msg(rc,"SPI_{GET,SET}SHOWSOUNDS"))
1931         return;
1932 
1933     for (i=0;i<ARRAY_SIZE(vals);i++)
1934     {
1935         UINT v;
1936 
1937         rc=SystemParametersInfoA( SPI_SETSHOWSOUNDS, vals[i], 0,
1938                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1939         if (!test_error_msg(rc,"SPI_SETSHOWSOUNDS")) return;
1940         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1941         test_change_message( SPI_SETSHOWSOUNDS, 1 );
1942         test_reg_key( SPI_SETSHOWSOUNDS_REGKEY,
1943                       SPI_SETSHOWSOUNDS_VALNAME,
1944                       vals[i] ? "1" : "0" );
1945 
1946         rc=SystemParametersInfoA( SPI_GETSHOWSOUNDS, 0, &v, 0 );
1947         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1948         eq( v, vals[i], "SPI_GETSHOWSOUNDS", "%d" );
1949         eq( GetSystemMetrics( SM_SHOWSOUNDS ), (int)vals[i],
1950             "SM_SHOWSOUNDS", "%d" );
1951     }
1952 
1953     rc=SystemParametersInfoA( SPI_SETSHOWSOUNDS, old_b, 0, SPIF_UPDATEINIFILE );
1954     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1955 }
1956 
1957 static void test_SPI_SETKEYBOARDPREF( void )           /*     69 */
1958 {
1959     BOOL rc;
1960     BOOL old_b;
1961     const UINT vals[]={TRUE,FALSE};
1962     unsigned int i;
1963 
1964     trace("testing SPI_{GET,SET}KEYBOARDPREF\n");
1965     SetLastError(0xdeadbeef);
1966     rc=SystemParametersInfoA( SPI_GETKEYBOARDPREF, 0, &old_b, 0 );
1967     if (!test_error_msg(rc,"SPI_{GET,SET}KEYBOARDPREF"))
1968         return;
1969 
1970     for (i=0;i<ARRAY_SIZE(vals);i++)
1971     {
1972         BOOL v;
1973 
1974         rc=SystemParametersInfoA( SPI_SETKEYBOARDPREF, vals[i], 0,
1975                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
1976         if (!test_error_msg(rc,"SPI_SETKEYBOARDPREF")) return;
1977         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1978         test_change_message( SPI_SETKEYBOARDPREF, 1 );
1979         test_reg_key_ex2( SPI_SETKEYBOARDPREF_REGKEY, SPI_SETKEYBOARDPREF_REGKEY_LEGACY,
1980                           SPI_SETKEYBOARDPREF_VALNAME, SPI_SETKEYBOARDPREF_VALNAME_LEGACY,
1981                           vals[i] ? "1" : "0" );
1982 
1983         rc=SystemParametersInfoA( SPI_GETKEYBOARDPREF, 0, &v, 0 );
1984         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
1985         eq( v, (BOOL)vals[i], "SPI_GETKEYBOARDPREF", "%d" );
1986     }
1987 
1988     rc=SystemParametersInfoA( SPI_SETKEYBOARDPREF, old_b, 0, SPIF_UPDATEINIFILE );
1989     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
1990 }
1991 
1992 static void test_SPI_SETSCREENREADER( void )           /*     71 */
1993 {
1994     BOOL rc;
1995     BOOL old_b;
1996     const UINT vals[]={TRUE,FALSE};
1997     unsigned int i;
1998 
1999     trace("testing SPI_{GET,SET}SCREENREADER\n");
2000     SetLastError(0xdeadbeef);
2001     rc=SystemParametersInfoA( SPI_GETSCREENREADER, 0, &old_b, 0 );
2002     if (!test_error_msg(rc,"SPI_{GET,SET}SCREENREADER"))
2003         return;
2004 
2005     for (i=0;i<ARRAY_SIZE(vals);i++)
2006     {
2007         BOOL v;
2008 
2009         rc=SystemParametersInfoA( SPI_SETSCREENREADER, vals[i], 0,
2010                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2011         if (!test_error_msg(rc,"SPI_SETSCREENREADER")) return;
2012         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2013         test_change_message( SPI_SETSCREENREADER, 1 );
2014         test_reg_key_ex2_optional( SPI_SETSCREENREADER_REGKEY, SPI_SETSCREENREADER_REGKEY_LEGACY,
2015                                    SPI_SETSCREENREADER_VALNAME, SPI_SETSCREENREADER_VALNAME_LEGACY,
2016                                    vals[i] ? "1" : "0" );
2017 
2018         rc=SystemParametersInfoA( SPI_GETSCREENREADER, 0, &v, 0 );
2019         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2020         eq( v, (BOOL)vals[i], "SPI_GETSCREENREADER", "%d" );
2021     }
2022 
2023     rc=SystemParametersInfoA( SPI_SETSCREENREADER, old_b, 0, SPIF_UPDATEINIFILE );
2024     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2025 }
2026 
2027 static void test_SPI_SETFONTSMOOTHING( void )         /*     75 */
2028 {
2029     BOOL rc;
2030     BOOL old_b;
2031     DWORD old_type, old_contrast, old_orient;
2032     const UINT vals[]={0xffffffff,0,1,2};
2033     unsigned int i;
2034 
2035     trace("testing SPI_{GET,SET}FONTSMOOTHING\n");
2036     SetLastError(0xdeadbeef);
2037     rc=SystemParametersInfoA( SPI_GETFONTSMOOTHING, 0, &old_b, 0 );
2038     if (!test_error_msg(rc,"SPI_{GET,SET}FONTSMOOTHING"))
2039         return;
2040     SystemParametersInfoA( SPI_GETFONTSMOOTHINGTYPE, 0, &old_type, 0 );
2041     SystemParametersInfoA( SPI_GETFONTSMOOTHINGCONTRAST, 0, &old_contrast, 0 );
2042     SystemParametersInfoA( SPI_GETFONTSMOOTHINGORIENTATION, 0, &old_orient, 0 );
2043 
2044     for (i=0;i<ARRAY_SIZE(vals);i++)
2045     {
2046         UINT v;
2047 
2048         rc=SystemParametersInfoA( SPI_SETFONTSMOOTHING, vals[i], 0,
2049                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2050         if (!test_error_msg(rc,"SPI_SETFONTSMOOTHING")) return;
2051         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2052         test_change_message( SPI_SETFONTSMOOTHING, 0 );
2053         test_reg_key( SPI_SETFONTSMOOTHING_REGKEY,
2054                       SPI_SETFONTSMOOTHING_VALNAME,
2055                       vals[i] ? "2" : "0" );
2056 
2057         rc=SystemParametersInfoA( SPI_SETFONTSMOOTHINGTYPE, 0, UlongToPtr(vals[i]),
2058                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2059         if (!test_error_msg(rc,"SPI_SETFONTSMOOTHINGTYPE")) return;
2060         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2061         test_change_message( SPI_SETFONTSMOOTHINGTYPE, 0 );
2062         test_reg_key_dword( SPI_SETFONTSMOOTHING_REGKEY,
2063                             SPI_SETFONTSMOOTHINGTYPE_VALNAME, &vals[i] );
2064 
2065         rc=SystemParametersInfoA( SPI_SETFONTSMOOTHINGCONTRAST, 0, UlongToPtr(vals[i]),
2066                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2067         if (!test_error_msg(rc,"SPI_SETFONTSMOOTHINGCONTRAST")) return;
2068         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2069         test_change_message( SPI_SETFONTSMOOTHINGCONTRAST, 0 );
2070         test_reg_key_dword( SPI_SETFONTSMOOTHING_REGKEY,
2071                             SPI_SETFONTSMOOTHINGCONTRAST_VALNAME, &vals[i] );
2072 
2073         rc=SystemParametersInfoA( SPI_SETFONTSMOOTHINGORIENTATION, 0, UlongToPtr(vals[i]),
2074                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2075         if (!test_error_msg(rc,"SPI_SETFONTSMOOTHINGORIENTATION")) return;
2076         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2077         test_change_message( SPI_SETFONTSMOOTHINGORIENTATION, 0 );
2078         test_reg_key_dword( SPI_SETFONTSMOOTHING_REGKEY,
2079                             SPI_SETFONTSMOOTHINGORIENTATION_VALNAME, &vals[i] );
2080 
2081         rc=SystemParametersInfoA( SPI_GETFONTSMOOTHING, 0, &v, 0 );
2082         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2083         eq( v, vals[i] ? 1 : 0, "SPI_GETFONTSMOOTHING", "%d" );
2084 
2085         rc=SystemParametersInfoA( SPI_GETFONTSMOOTHINGTYPE, 0, &v, 0 );
2086         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2087         ok( v == vals[i], "wrong value %x/%x\n", v, vals[i] );
2088 
2089         rc=SystemParametersInfoA( SPI_GETFONTSMOOTHINGCONTRAST, 0, &v, 0 );
2090         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2091         ok( v == vals[i], "wrong value %x/%x\n", v, vals[i] );
2092 
2093         rc=SystemParametersInfoA( SPI_GETFONTSMOOTHINGORIENTATION, 0, &v, 0 );
2094         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2095         ok( v == vals[i], "wrong value %x/%x\n", v, vals[i] );
2096     }
2097 
2098     rc=SystemParametersInfoA( SPI_SETFONTSMOOTHING, old_b, 0, SPIF_UPDATEINIFILE );
2099     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2100     rc=SystemParametersInfoA( SPI_SETFONTSMOOTHINGTYPE, old_type, 0, SPIF_UPDATEINIFILE );
2101     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2102     rc=SystemParametersInfoA( SPI_SETFONTSMOOTHINGCONTRAST, old_contrast, 0, SPIF_UPDATEINIFILE );
2103     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2104     rc=SystemParametersInfoA( SPI_SETFONTSMOOTHINGORIENTATION, old_orient, 0, SPIF_UPDATEINIFILE );
2105     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2106 }
2107 
2108 static void test_SPI_SETLOWPOWERACTIVE( void )         /*     85 */
2109 {
2110     BOOL rc;
2111     BOOL old_b;
2112     const UINT vals[]={TRUE,FALSE};
2113     unsigned int i;
2114 
2115     trace("testing SPI_{GET,SET}LOWPOWERACTIVE\n");
2116     SetLastError(0xdeadbeef);
2117     rc=SystemParametersInfoA( SPI_GETLOWPOWERACTIVE, 0, &old_b, 0 );
2118     if (!test_error_msg(rc,"SPI_{GET,SET}LOWPOWERACTIVE"))
2119         return;
2120 
2121     for (i=0;i<ARRAY_SIZE(vals);i++)
2122     {
2123         UINT v;
2124 
2125         rc=SystemParametersInfoA( SPI_SETLOWPOWERACTIVE, vals[i], 0,
2126                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2127         if (!test_error_msg(rc,"SPI_SETLOWPOWERACTIVE")) return;
2128         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2129         test_change_message( SPI_SETLOWPOWERACTIVE, 1 );
2130         test_reg_key_optional( SPI_SETLOWPOWERACTIVE_REGKEY,
2131                                SPI_SETLOWPOWERACTIVE_VALNAME,
2132                                vals[i] ? "1" : "0" );
2133 
2134         /* SPI_SETLOWPOWERACTIVE is not persistent in win2k3 and above */
2135         v = 0xdeadbeef;
2136         rc=SystemParametersInfoA( SPI_GETLOWPOWERACTIVE, 0, &v, 0 );
2137         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2138         ok(v == vals[i] || v == 0, /* win2k3 */
2139            "SPI_GETLOWPOWERACTIVE: got %d instead of 0 or %d\n", v, vals[i]);
2140     }
2141 
2142     rc=SystemParametersInfoA( SPI_SETLOWPOWERACTIVE, old_b, 0, SPIF_UPDATEINIFILE );
2143     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2144 }
2145 
2146 static void test_SPI_SETPOWEROFFACTIVE( void )         /*     86 */
2147 {
2148     BOOL rc;
2149     BOOL old_b;
2150     const UINT vals[]={TRUE,FALSE};
2151     unsigned int i;
2152 
2153     trace("testing SPI_{GET,SET}POWEROFFACTIVE\n");
2154     SetLastError(0xdeadbeef);
2155     rc=SystemParametersInfoA( SPI_GETPOWEROFFACTIVE, 0, &old_b, 0 );
2156     if (!test_error_msg(rc,"SPI_{GET,SET}POWEROFFACTIVE"))
2157         return;
2158 
2159     for (i=0;i<ARRAY_SIZE(vals);i++)
2160     {
2161         UINT v;
2162 
2163         rc=SystemParametersInfoA( SPI_SETPOWEROFFACTIVE, vals[i], 0,
2164                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2165         if (!test_error_msg(rc,"SPI_SETPOWEROFFACTIVE")) return;
2166         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2167         test_change_message( SPI_SETPOWEROFFACTIVE, 1 );
2168         test_reg_key_optional( SPI_SETPOWEROFFACTIVE_REGKEY,
2169                                SPI_SETPOWEROFFACTIVE_VALNAME,
2170                                vals[i] ? "1" : "0" );
2171 
2172         /* SPI_SETPOWEROFFACTIVE is not persistent in win2k3 and above */
2173         v = 0xdeadbeef;
2174         rc=SystemParametersInfoA( SPI_GETPOWEROFFACTIVE, 0, &v, 0 );
2175         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2176         ok(v == vals[i] || v == 0, /* win2k3 */
2177            "SPI_GETPOWEROFFACTIVE: got %d instead of 0 or %d\n", v, vals[i]);
2178     }
2179 
2180     rc=SystemParametersInfoA( SPI_SETPOWEROFFACTIVE, old_b, 0, SPIF_UPDATEINIFILE );
2181     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2182 }
2183 
2184 static void test_SPI_SETSNAPTODEFBUTTON( void )         /*     95 */
2185 {
2186     BOOL rc;
2187     BOOL old_b;
2188     const UINT vals[]={TRUE,FALSE};
2189     unsigned int i;
2190 
2191     trace("testing SPI_{GET,SET}SNAPTODEFBUTTON\n");
2192     SetLastError(0xdeadbeef);
2193     rc=SystemParametersInfoA( SPI_GETSNAPTODEFBUTTON, 0, &old_b, 0 );
2194     if (!test_error_msg(rc,"SPI_GETSNAPTODEFBUTTON"))
2195         return;
2196 
2197     for (i=0;i<ARRAY_SIZE(vals);i++)
2198     {
2199         UINT v;
2200 
2201         rc=SystemParametersInfoA( SPI_SETSNAPTODEFBUTTON, vals[i], 0,
2202                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2203         if (!test_error_msg(rc,"SPI_SETSNAPTODEFBUTTON")) return;
2204         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2205         test_change_message( SPI_SETSNAPTODEFBUTTON, 0 );
2206         test_reg_key_optional( SPI_SETSNAPTODEFBUTTON_REGKEY,
2207                                SPI_SETSNAPTODEFBUTTON_VALNAME,
2208                                vals[i] ? "1" : "0" );
2209 
2210         rc=SystemParametersInfoA( SPI_GETSNAPTODEFBUTTON, 0, &v, 0 );
2211         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2212         eq( v, vals[i], "SPI_GETSNAPTODEFBUTTON", "%d" );
2213     }
2214 
2215     rc=SystemParametersInfoA( SPI_SETSNAPTODEFBUTTON, old_b, 0, SPIF_UPDATEINIFILE );
2216     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2217 }
2218 
2219 static void test_SPI_SETMOUSEHOVERWIDTH( void )      /*     99 */
2220 {
2221     BOOL rc;
2222     UINT old_width;
2223     const UINT vals[]={0,32767};
2224     unsigned int i;
2225 
2226     trace("testing SPI_{GET,SET}MOUSEHOVERWIDTH\n");
2227     SetLastError(0xdeadbeef);
2228     rc=SystemParametersInfoA( SPI_GETMOUSEHOVERWIDTH, 0, &old_width, 0 );
2229     if (!test_error_msg(rc,"SPI_{GET,SET}MOUSEHOVERWIDTH"))
2230         return;
2231 
2232     for (i=0;i<ARRAY_SIZE(vals);i++)
2233     {
2234         UINT v;
2235         char buf[10];
2236 
2237         rc=SystemParametersInfoA( SPI_SETMOUSEHOVERWIDTH, vals[i], 0,
2238                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2239         if (!test_error_msg(rc,"SPI_SETMOUSEHOVERWIDTH")) return;
2240         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2241         test_change_message( SPI_SETMOUSEHOVERWIDTH, 0 );
2242         sprintf( buf, "%d", vals[i] );
2243         test_reg_key( SPI_SETMOUSEHOVERWIDTH_REGKEY,
2244                       SPI_SETMOUSEHOVERWIDTH_VALNAME, buf );
2245 
2246         SystemParametersInfoA( SPI_GETMOUSEHOVERWIDTH, 0, &v, 0 );
2247         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2248         eq( v, vals[i], "SPI_{GET,SET}MOUSEHOVERWIDTH", "%d" );
2249     }
2250 
2251     rc=SystemParametersInfoA( SPI_SETMOUSEHOVERWIDTH, old_width, 0,
2252                               SPIF_UPDATEINIFILE );
2253     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2254 }
2255 
2256 static void test_SPI_SETMOUSEHOVERHEIGHT( void )      /*     101 */
2257 {
2258     BOOL rc;
2259     UINT old_height;
2260     const UINT vals[]={0,32767};
2261     unsigned int i;
2262 
2263     trace("testing SPI_{GET,SET}MOUSEHOVERHEIGHT\n");
2264     SetLastError(0xdeadbeef);
2265     rc=SystemParametersInfoA( SPI_GETMOUSEHOVERHEIGHT, 0, &old_height, 0 );
2266     if (!test_error_msg(rc,"SPI_{GET,SET}MOUSEHOVERHEIGHT"))
2267         return;
2268 
2269     for (i=0;i<ARRAY_SIZE(vals);i++)
2270     {
2271         UINT v;
2272         char buf[10];
2273 
2274         rc=SystemParametersInfoA( SPI_SETMOUSEHOVERHEIGHT, vals[i], 0,
2275                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2276         if (!test_error_msg(rc,"SPI_SETMOUSEHOVERHEIGHT")) return;
2277         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2278         test_change_message( SPI_SETMOUSEHOVERHEIGHT, 0 );
2279         sprintf( buf, "%d", vals[i] );
2280         test_reg_key( SPI_SETMOUSEHOVERHEIGHT_REGKEY,
2281                       SPI_SETMOUSEHOVERHEIGHT_VALNAME, buf );
2282 
2283         SystemParametersInfoA( SPI_GETMOUSEHOVERHEIGHT, 0, &v, 0 );
2284         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2285         eq( v, vals[i], "SPI_{GET,SET}MOUSEHOVERHEIGHT", "%d" );
2286     }
2287 
2288     rc=SystemParametersInfoA( SPI_SETMOUSEHOVERHEIGHT, old_height, 0,
2289                               SPIF_UPDATEINIFILE );
2290     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2291 }
2292 
2293 static void test_SPI_SETMOUSEHOVERTIME( void )      /*     103 */
2294 {
2295     BOOL rc;
2296     UINT old_time;
2297 
2298     /* Windows XP accepts 10 as the minimum hover time. Any value below will be
2299      * defaulted to a value of 10 automatically.
2300      */
2301     const UINT vals[]={10,32767};
2302     unsigned int i;
2303 
2304     trace("testing SPI_{GET,SET}MOUSEHOVERTIME\n");
2305     SetLastError(0xdeadbeef);
2306     rc=SystemParametersInfoA( SPI_GETMOUSEHOVERTIME, 0, &old_time, 0 );
2307     if (!test_error_msg(rc,"SPI_{GET,SET}MOUSEHOVERTIME"))
2308         return;
2309 
2310     for (i=0;i<ARRAY_SIZE(vals);i++)
2311     {
2312         UINT v;
2313         char buf[10];
2314 
2315         rc=SystemParametersInfoA( SPI_SETMOUSEHOVERTIME, vals[i], 0,
2316                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2317         if (!test_error_msg(rc,"SPI_SETMOUSEHOVERTIME")) return;
2318         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2319         test_change_message( SPI_SETMOUSEHOVERTIME, 0 );
2320         sprintf( buf, "%d", vals[i] );
2321         test_reg_key( SPI_SETMOUSEHOVERTIME_REGKEY,
2322                       SPI_SETMOUSEHOVERTIME_VALNAME, buf );
2323 
2324         SystemParametersInfoA( SPI_GETMOUSEHOVERTIME, 0, &v, 0 );
2325         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2326         eq( v, vals[i], "SPI_{GET,SET}MOUSEHOVERTIME", "%d" );
2327     }
2328 
2329     rc=SystemParametersInfoA( SPI_SETMOUSEHOVERTIME, old_time, 0,
2330                               SPIF_UPDATEINIFILE );
2331     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2332 }
2333 
2334 static void test_SPI_SETWHEELSCROLLLINES( void )      /*     105 */
2335 {
2336     BOOL rc;
2337     UINT old_lines;
2338     const UINT vals[]={0,32767};
2339     unsigned int i;
2340 
2341     trace("testing SPI_{GET,SET}WHEELSCROLLLINES\n");
2342     SetLastError(0xdeadbeef);
2343     rc=SystemParametersInfoA( SPI_GETWHEELSCROLLLINES, 0, &old_lines, 0 );
2344 
2345     /* SPI_{GET,SET}WHEELSCROLLLINES not supported on Windows 95 */
2346     if (!test_error_msg(rc,"SPI_{GET,SET}WHEELSCROLLLINES"))
2347         return;
2348 
2349     for (i=0;i<ARRAY_SIZE(vals);i++)
2350     {
2351         UINT v;
2352         char buf[10];
2353 
2354         rc=SystemParametersInfoA( SPI_SETWHEELSCROLLLINES, vals[i], 0,
2355                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2356         if (!test_error_msg(rc,"SPI_SETWHEELSCROLLLINES")) return;
2357         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2358         test_change_message( SPI_SETWHEELSCROLLLINES, 0 );
2359         sprintf( buf, "%d", vals[i] );
2360         test_reg_key( SPI_SETMOUSESCROLLLINES_REGKEY,
2361                       SPI_SETMOUSESCROLLLINES_VALNAME, buf );
2362 
2363         SystemParametersInfoA( SPI_GETWHEELSCROLLLINES, 0, &v, 0 );
2364         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2365         eq( v, vals[i], "SPI_{GET,SET}WHEELSCROLLLINES", "%d" );
2366     }
2367 
2368     rc=SystemParametersInfoA( SPI_SETWHEELSCROLLLINES, old_lines, 0,
2369                               SPIF_UPDATEINIFILE );
2370     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2371 }
2372 
2373 static void test_SPI_SETMENUSHOWDELAY( void )      /*     107 */
2374 {
2375     BOOL rc;
2376     UINT old_delay;
2377     const UINT vals[]={0,32767};
2378     unsigned int i;
2379 
2380     trace("testing SPI_{GET,SET}MENUSHOWDELAY\n");
2381     SetLastError(0xdeadbeef);
2382     rc=SystemParametersInfoA( SPI_GETMENUSHOWDELAY, 0, &old_delay, 0 );
2383 
2384     /* SPI_{GET,SET}MENUSHOWDELAY not supported on Windows 95 */
2385     if (!test_error_msg(rc,"SPI_{GET,SET}MENUSHOWDELAY"))
2386         return;
2387 
2388     for (i=0;i<ARRAY_SIZE(vals);i++)
2389     {
2390         UINT v;
2391         char buf[10];
2392 
2393         rc=SystemParametersInfoA( SPI_SETMENUSHOWDELAY, vals[i], 0,
2394                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2395         if (!test_error_msg(rc,"SPI_SETMENUSHOWDELAY")) return;
2396         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2397         test_change_message( SPI_SETMENUSHOWDELAY, 0 );
2398         sprintf( buf, "%d", vals[i] );
2399         test_reg_key( SPI_SETMENUSHOWDELAY_REGKEY,
2400                       SPI_SETMENUSHOWDELAY_VALNAME, buf );
2401 
2402         SystemParametersInfoA( SPI_GETMENUSHOWDELAY, 0, &v, 0 );
2403         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2404         eq( v, vals[i], "SPI_{GET,SET}MENUSHOWDELAY", "%d" );
2405     }
2406 
2407     rc=SystemParametersInfoA( SPI_SETMENUSHOWDELAY, old_delay, 0,
2408                               SPIF_UPDATEINIFILE );
2409     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2410 }
2411 
2412 static void test_SPI_SETWHEELSCROLLCHARS( void )      /*     108 */
2413 {
2414     BOOL rc;
2415     UINT old_chars;
2416     const UINT vals[]={32767,0};
2417     unsigned int i;
2418 
2419     trace("testing SPI_{GET,SET}WHEELSCROLLCHARS\n");
2420     SetLastError(0xdeadbeef);
2421     rc=SystemParametersInfoA( SPI_GETWHEELSCROLLCHARS, 0, &old_chars, 0 );
2422 
2423     /* SPI_{GET,SET}WHEELSCROLLCHARS not supported on Windows 95 */
2424     if (!test_error_msg(rc,"SPI_{GET,SET}WHEELSCROLLCHARS"))
2425         return;
2426 
2427     for (i=0;i<ARRAY_SIZE(vals);i++)
2428     {
2429         UINT v;
2430         char buf[10];
2431 
2432         rc=SystemParametersInfoA( SPI_SETWHEELSCROLLCHARS, vals[i], 0,
2433                                SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
2434         if (!test_error_msg(rc,"SPI_SETWHEELSCROLLCHARS")) return;
2435         test_change_message( SPI_SETWHEELSCROLLCHARS, 0 );
2436         sprintf( buf, "%d", vals[i] );
2437         test_reg_key( SPI_SETMOUSESCROLLCHARS_REGKEY,
2438                       SPI_SETMOUSESCROLLCHARS_VALNAME, buf );
2439 
2440         SystemParametersInfoA( SPI_GETWHEELSCROLLCHARS, 0, &v, 0 );
2441         ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError());
2442         eq( v, vals[i], "SPI_{GET,SET}WHEELSCROLLCHARS", "%d" );
2443     }
2444 
2445     rc=SystemParametersInfoA( SPI_SETWHEELSCROLLCHARS, old_chars, 0,
2446                               SPIF_UPDATEINIFILE );
2447     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2448 }
2449 
2450 static void test_SPI_SETWALLPAPER( void )              /*   115 */
2451 {
2452     BOOL rc;
2453     char oldval[260];
2454     char newval[260];
2455 
2456     trace("testing SPI_{GET,SET}DESKWALLPAPER\n");
2457     SetLastError(0xdeadbeef);
2458     rc=SystemParametersInfoA(SPI_GETDESKWALLPAPER, 260, oldval, 0);
2459     if (!test_error_msg(rc,"SPI_{GET,SET}DESKWALLPAPER"))
2460         return;
2461 
2462     strcpy(newval, "");
2463     rc=SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, newval, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
2464     if (!test_error_msg(rc,"SPI_SETDESKWALLPAPER")) return;
2465     ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError());
2466     test_change_message(SPI_SETDESKWALLPAPER, 0);
2467 
2468     rc=SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, oldval, SPIF_UPDATEINIFILE);
2469     ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError());
2470 
2471     test_reg_key(SPI_SETDESKWALLPAPER_REGKEY, SPI_SETDESKWALLPAPER_VALNAME, oldval);
2472 }
2473 
2474 static void test_WM_DISPLAYCHANGE(void)
2475 {
2476     DEVMODEA mode, startmode;
2477     int start_bpp, last_set_bpp = 0;
2478     int test_bpps[] = {8, 16, 24, 32}, i;
2479     LONG change_ret;
2480     DWORD wait_ret;
2481 
2482     if (!pChangeDisplaySettingsExA)
2483     {
2484         win_skip("ChangeDisplaySettingsExA is not available\n");
2485         return;
2486     }
2487 
2488     displaychange_test_active = TRUE;
2489 
2490     memset(&startmode, 0, sizeof(startmode));
2491     startmode.dmSize = sizeof(startmode);
2492     EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &startmode);
2493     start_bpp = startmode.dmBitsPerPel;
2494 
2495     displaychange_sem = CreateSemaphoreW(NULL, 0, 1, NULL);
2496 
2497     for(i = 0; i < ARRAY_SIZE(test_bpps); i++) {
2498         last_bpp = -1;
2499 
2500         memset(&mode, 0, sizeof(mode));
2501         mode.dmSize = sizeof(mode);
2502         mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2503         mode.dmBitsPerPel = test_bpps[i];
2504         mode.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN);
2505         mode.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN);
2506 
2507         change_counter = 0; /* This sends a SETTINGSCHANGE message as well in which we aren't interested */
2508         displaychange_ok = TRUE;
2509         change_ret = pChangeDisplaySettingsExA(NULL, &mode, NULL, 0, NULL);
2510         /* Wait quite long for the message, screen setting changes can take some time */
2511         if(change_ret == DISP_CHANGE_SUCCESSFUL) {
2512             wait_ret = WaitForSingleObject(displaychange_sem, 10000);
2513             /* we may not get a notification if nothing changed */
2514             if (wait_ret == WAIT_TIMEOUT && !last_set_bpp && start_bpp == test_bpps[i])
2515                 continue;
2516             ok(wait_ret == WAIT_OBJECT_0, "Waiting for the WM_DISPLAYCHANGE message timed out\n");
2517         }
2518         displaychange_ok = FALSE;
2519 
2520         if(change_ret != DISP_CHANGE_SUCCESSFUL) {
2521             skip("Setting depth %d failed(ret = %d)\n", test_bpps[i], change_ret);
2522             ok(last_bpp == -1, "WM_DISPLAYCHANGE was sent with wParam %d despite mode change failure\n", last_bpp);
2523             continue;
2524         }
2525 
2526         todo_wine_if(start_bpp != test_bpps[i]) {
2527             ok(last_bpp == test_bpps[i], "Set bpp %d, but WM_DISPLAYCHANGE reported bpp %d\n", test_bpps[i], last_bpp);
2528         }
2529         last_set_bpp = test_bpps[i];
2530     }
2531 
2532     if(start_bpp != last_set_bpp && last_set_bpp != 0) {
2533         memset(&mode, 0, sizeof(mode));
2534         mode.dmSize = sizeof(mode);
2535         mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2536         mode.dmBitsPerPel = start_bpp;
2537         mode.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN);
2538         mode.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN);
2539 
2540         displaychange_ok = TRUE;
2541         change_ret = pChangeDisplaySettingsExA(NULL, &mode, NULL, 0, NULL);
2542         WaitForSingleObject(displaychange_sem, 10000);
2543         displaychange_ok = FALSE;
2544         CloseHandle(displaychange_sem);
2545         displaychange_sem = 0;
2546     }
2547 
2548     displaychange_test_active = FALSE;
2549 }
2550 
2551 /*
2552  * Registry entries for the system parameters.
2553  * Names are created by 'SET' flags names.
2554  * We assume that corresponding 'GET' entries use the same registry keys.
2555  */
2556 static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam )
2557 {
2558     test_SPI_SETBEEP();                         /*      1 */
2559     test_SPI_SETMOUSE();                        /*      4 */
2560     test_SPI_SETBORDER();                       /*      6 */
2561     test_SPI_SETKEYBOARDSPEED();                /*     10 */
2562     test_SPI_ICONHORIZONTALSPACING();           /*     13 */
2563     test_SPI_SETSCREENSAVETIMEOUT();            /*     14 */
2564     test_SPI_SETSCREENSAVEACTIVE();             /*     17 */
2565     test_SPI_SETGRIDGRANULARITY();              /*     19 */
2566     test_SPI_SETKEYBOARDDELAY();                /*     23 */
2567     test_SPI_ICONVERTICALSPACING();             /*     24 */
2568     test_SPI_SETICONTITLEWRAP();                /*     26 */
2569     test_SPI_SETMENUDROPALIGNMENT();            /*     28 */
2570     test_SPI_SETDOUBLECLKWIDTH();               /*     29 */
2571     test_SPI_SETDOUBLECLKHEIGHT();              /*     30 */
2572     test_SPI_SETDOUBLECLICKTIME();              /*     32 */
2573     test_SPI_SETMOUSEBUTTONSWAP();              /*     33 */
2574     test_SPI_SETFASTTASKSWITCH();               /*     36 */
2575     test_SPI_SETDRAGFULLWINDOWS();              /*     37 */
2576     /* test_WM_DISPLAYCHANGE seems to be somewhat buggy on
2577      * some versions of Windows (Vista, Win2k8, Win7B) in that
2578      * not all metrics are properly restored. Problems are
2579      * SM_CXMAXTRACK, SM_CYMAXTRACK
2580      * Fortunately setting the Non-Client metrics like in
2581      * test_SPI_SETNONCLIENTMETRICS will correct this. That is why
2582      * we do the DISPLAY change now... */
2583     test_WM_DISPLAYCHANGE();
2584     test_SPI_SETNONCLIENTMETRICS();             /*     42 */
2585     test_SPI_SETMINIMIZEDMETRICS();             /*     44 */
2586     test_SPI_SETICONMETRICS();                  /*     46 */
2587     test_SPI_SETWORKAREA();                     /*     47 */
2588     test_SPI_SETSHOWSOUNDS();                   /*     57 */
2589     test_SPI_SETKEYBOARDPREF();                 /*     69 */
2590     test_SPI_SETSCREENREADER();                 /*     71 */
2591     test_SPI_SETFONTSMOOTHING();                /*     75 */
2592     test_SPI_SETLOWPOWERACTIVE();               /*     85 */
2593     test_SPI_SETPOWEROFFACTIVE();               /*     86 */
2594     test_SPI_SETSNAPTODEFBUTTON();              /*     95 */
2595     test_SPI_SETMOUSEHOVERWIDTH();              /*     99 */
2596     test_SPI_SETMOUSEHOVERHEIGHT();             /*    101 */
2597     test_SPI_SETMOUSEHOVERTIME();               /*    103 */
2598     test_SPI_SETWHEELSCROLLLINES();             /*    105 */
2599     test_SPI_SETMENUSHOWDELAY();                /*    107 */
2600     test_SPI_SETWHEELSCROLLCHARS();             /*    108 */
2601     test_SPI_SETWALLPAPER();                    /*    115 */
2602 
2603 
2604     SendMessageA( ghTestWnd, WM_DESTROY, 0, 0 );
2605     return 0;
2606 }
2607 
2608 /* test calculation of GetSystemMetrics values (mostly) from non client metrics,
2609  * icon metrics and minimized metrics.
2610  */
2611 
2612 /* copied from wine's GdiGetCharDimensions, which is not available on most
2613  * windows versions */
2614 static LONG _GdiGetCharDimensions(HDC hdc, LPTEXTMETRICA lptm, LONG *height)
2615 {
2616     SIZE sz;
2617     static const CHAR alphabet[] = {
2618         'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
2619         'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
2620         'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
2621 
2622     if(lptm && !GetTextMetricsA(hdc, lptm)) return 0;
2623 
2624     if(!GetTextExtentPointA(hdc, alphabet, 52, &sz)) return 0;
2625 
2626     if (height) *height = sz.cy;
2627     return (sz.cx / 26 + 1) / 2;
2628 }
2629 
2630 /* get text metrics and/or "average" char width of the specified logfont
2631  * for the specified dc */
2632 static void get_text_metr_size( HDC hdc, LOGFONTA *plf, TEXTMETRICA * ptm, UINT *psz)
2633 {
2634     HFONT hfont, hfontsav;
2635     TEXTMETRICA tm;
2636     if( !ptm) ptm = &tm;
2637     hfont = CreateFontIndirectA( plf);
2638     if( !hfont || ( hfontsav = SelectObject( hdc, hfont)) == NULL ) {
2639         ptm->tmHeight = -1;
2640         if( psz) *psz = 10;
2641         if( hfont) DeleteObject( hfont);
2642         return;
2643     }
2644     GetTextMetricsA( hdc, ptm);
2645     if( psz)
2646         if( !(*psz = _GdiGetCharDimensions( hdc, ptm, NULL)))
2647             *psz = 10;
2648     SelectObject( hdc, hfontsav);
2649     DeleteObject( hfont);
2650 }
2651 
2652 static int gsm_error_ctr;
2653 
2654 #define ok_gsm( i, e)\
2655 {\
2656     int exp = (e);\
2657     int act = GetSystemMetrics( (i));\
2658     if( exp != act) gsm_error_ctr++;\
2659     ok( !( exp != act),"GetSystemMetrics(%s): expected %d actual %d\n", #i, exp,act);\
2660 }
2661 #define ok_gsm_2( i, e1, e2)\
2662 {\
2663     int exp1 = (e1);\
2664     int exp2 = (e2);\
2665     int act = GetSystemMetrics( (i));\
2666     if( exp1 != act && exp2 != act) gsm_error_ctr++;\
2667     ok( !( exp1 != act && exp2 != act), "GetSystemMetrics(%s): expected %d or %d actual %d\n", #i, exp1, exp2, act);\
2668 }
2669 #define ok_gsm_3( i, e1, e2, e3)\
2670 {\
2671     int exp1 = (e1);\
2672     int exp2 = (e2);\
2673     int exp3 = (e3);\
2674     int act = GetSystemMetrics( (i));\
2675     if( exp1 != act && exp2 != act && exp3 != act) gsm_error_ctr++;\
2676     ok( !( exp1 != act && exp2 != act && exp3 != act),"GetSystemMetrics(%s): expected %d or %d or %d actual %d\n", #i, exp1, exp2, exp3, act);\
2677 }
2678 
2679 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
2680 {
2681     return lstrcmpiA(elf->lfFaceName, (const char *)lparam);
2682 }
2683 
2684 static BOOL is_font_enumerated(const char *name)
2685 {
2686     HDC hdc = CreateCompatibleDC(0);
2687     BOOL ret = FALSE;
2688 
2689     if (!EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)name))
2690         ret = TRUE;
2691 
2692     DeleteDC(hdc);
2693     return ret;
2694 }
2695 
2696 static int get_cursor_size( int size )
2697 {
2698     /* only certain sizes are allowed for cursors */
2699     if (size >= 64) return 64;
2700     if (size >= 48) return 48;
2701     return 32;
2702 }
2703 
2704 static void test_GetSystemMetrics( void)
2705 {
2706     TEXTMETRICA tmMenuFont;
2707     UINT IconSpacing, IconVerticalSpacing;
2708     BOOL rc;
2709 
2710     HDC hdc = CreateICA( "Display", 0, 0, 0);
2711     UINT avcwCaption;
2712     INT CaptionWidthfromreg, smicon, broken_val;
2713     MINIMIZEDMETRICS minim;
2714     NONCLIENTMETRICSA ncm;
2715     SIZE screen;
2716 
2717     assert(sizeof(ncm) == 344);
2718 
2719     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
2720     rc = SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
2721     ok(rc, "SystemParametersInfoA failed\n");
2722 
2723     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth) - 1;
2724     rc = SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
2725     ok(!rc, "SystemParametersInfoA should fail\n");
2726 
2727     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth) + 1;
2728     SetLastError(0xdeadbeef);
2729     rc = SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
2730     ok(!rc, "SystemParametersInfoA should fail\n");
2731 
2732     ncm.cbSize = sizeof(ncm); /* Vista added padding */
2733     SetLastError(0xdeadbeef);
2734     ncm.iPaddedBorderWidth = 0xcccc;
2735     rc = SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
2736     ok(rc || broken(!rc) /* before Vista */, "SystemParametersInfoA failed\n");
2737     if (rc) ok( ncm.iPaddedBorderWidth == 0, "wrong iPaddedBorderWidth %u\n", ncm.iPaddedBorderWidth );
2738 
2739     minim.cbSize = sizeof( minim);
2740     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth);
2741     SystemParametersInfoA( SPI_GETMINIMIZEDMETRICS, 0, &minim, 0);
2742     rc = SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
2743     if( !rc) {
2744         win_skip("SPI_GETNONCLIENTMETRICS is not available\n");
2745         return;
2746     }
2747 
2748     ok(is_font_enumerated(ncm.lfCaptionFont.lfFaceName), "font %s should be enumerated\n", ncm.lfCaptionFont.lfFaceName);
2749     ok(is_font_enumerated(ncm.lfSmCaptionFont.lfFaceName), "font %s should be enumerated\n", ncm.lfSmCaptionFont.lfFaceName);
2750     ok(is_font_enumerated(ncm.lfMenuFont.lfFaceName), "font %s should be enumerated\n", ncm.lfMenuFont.lfFaceName);
2751     ok(is_font_enumerated(ncm.lfStatusFont.lfFaceName), "font %s should be enumerated\n", ncm.lfStatusFont.lfFaceName);
2752     ok(is_font_enumerated(ncm.lfMessageFont.lfFaceName), "font %s should be enumerated\n", ncm.lfMessageFont.lfFaceName);
2753 
2754     /* CaptionWidth from the registry may have different value of iCaptionWidth
2755      * from the non client metrics (observed on WinXP) */
2756     CaptionWidthfromreg = metricfromreg(
2757             "Control Panel\\Desktop\\WindowMetrics","CaptionWidth", dpi);
2758     get_text_metr_size( hdc, &ncm.lfMenuFont, &tmMenuFont, NULL);
2759     get_text_metr_size( hdc, &ncm.lfCaptionFont, NULL, &avcwCaption);
2760     /* FIXME: use icon metric */
2761     if( !SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &IconVerticalSpacing, 0))
2762         IconVerticalSpacing = 0;
2763     if( !SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &IconSpacing, 0 ))
2764         IconSpacing = 0;
2765     /* reset error counters */
2766     gsm_error_ctr = 0;
2767 
2768     /* the tests: */
2769 
2770     /* SM_CXSCREEN, cannot test these two */
2771     /* SM_CYSCREEN */
2772     ok_gsm( SM_CXVSCROLL,  ncm.iScrollWidth);
2773     ok_gsm( SM_CYHSCROLL,  ncm.iScrollWidth);
2774     ok_gsm( SM_CYCAPTION, ncm.iCaptionHeight+1);
2775     ok_gsm( SM_CXBORDER, 1);
2776     ok_gsm( SM_CYBORDER, 1);
2777     ok_gsm( SM_CXDLGFRAME, 3);
2778     ok_gsm( SM_CYDLGFRAME, 3);
2779     ok_gsm( SM_CYVTHUMB,  ncm.iScrollHeight);
2780     ok_gsm( SM_CXHTHUMB,  ncm.iScrollHeight);
2781     /* These don't depend on the Shell Icon Size registry value */
2782     ok_gsm( SM_CXICON, MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI ) );
2783     ok_gsm( SM_CYICON, MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI ) );
2784     ok_gsm( SM_CXCURSOR, get_cursor_size( MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI )));
2785     ok_gsm( SM_CYCURSOR, get_cursor_size( MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI )));
2786     ok_gsm( SM_CYMENU, ncm.iMenuHeight + 1);
2787     ok_gsm( SM_CXFULLSCREEN,
2788             GetSystemMetrics( SM_CXMAXIMIZED) - 2 * GetSystemMetrics( SM_CXFRAME));
2789     ok_gsm( SM_CYFULLSCREEN,
2790             GetSystemMetrics( SM_CYMAXIMIZED) - GetSystemMetrics( SM_CYMIN));
2791     /* SM_CYKANJIWINDOW */
2792     /* SM_MOUSEPRESENT */
2793     ok_gsm( SM_CYVSCROLL, ncm.iScrollHeight);
2794     ok_gsm( SM_CXHSCROLL, ncm.iScrollHeight);
2795     /* SM_DEBUG */
2796     /* SM_SWAPBUTTON */
2797     /* SM_RESERVED1 */
2798     /* SM_RESERVED2 */
2799     /* SM_RESERVED3 */
2800     /* SM_RESERVED4 */
2801     ok_gsm( SM_CXMIN, 3 * max( CaptionWidthfromreg >= 0 ? CaptionWidthfromreg : ncm.iCaptionWidth, 8) +
2802             GetSystemMetrics( SM_CYSIZE) + 4 + 4 * avcwCaption + 2 * GetSystemMetrics( SM_CXFRAME));
2803     ok_gsm( SM_CYMIN, GetSystemMetrics( SM_CYCAPTION) +
2804             2 * GetSystemMetrics( SM_CYFRAME));
2805     ok_gsm_2( SM_CXSIZE,
2806         ncm.iCaptionWidth,  /* classic/standard windows style */
2807         GetSystemMetrics( SM_CYCAPTION) - 1 /* WinXP style */
2808         );
2809     ok_gsm( SM_CYSIZE,  ncm.iCaptionHeight);
2810     ok_gsm( SM_CXFRAME, ncm.iBorderWidth + 3);
2811     ok_gsm( SM_CYFRAME, ncm.iBorderWidth + 3);
2812     ok_gsm( SM_CXMINTRACK,  GetSystemMetrics( SM_CXMIN));
2813     ok_gsm( SM_CYMINTRACK,  GetSystemMetrics( SM_CYMIN));
2814     /* SM_CXDOUBLECLK */
2815     /* SM_CYDOUBLECLK */
2816     if( IconSpacing) ok_gsm( SM_CXICONSPACING, IconSpacing);
2817     if( IconVerticalSpacing) ok_gsm( SM_CYICONSPACING, IconVerticalSpacing);
2818     /* SM_MENUDROPALIGNMENT */
2819     /* SM_PENWINDOWS */
2820     /* SM_DBCSENABLED */
2821     /* SM_CMOUSEBUTTONS */
2822     /* SM_SECURE */
2823     ok_gsm( SM_CXEDGE, 2);
2824     ok_gsm( SM_CYEDGE, 2);
2825     /* sign-extension for iHorzGap/iVertGap is broken on Win9x */
2826     ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + (short)minim.iHorzGap );
2827     ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + (short)minim.iVertGap );
2828 
2829     smicon = MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI );
2830     if (!pIsProcessDPIAware || pIsProcessDPIAware())
2831         smicon = max( min( smicon, CaptionWidthfromreg - 2), 4 ) & ~1;
2832     todo_wine_if( real_dpi == dpi && smicon != (MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI) & ~1) )
2833     {
2834         broken_val = (min( ncm.iCaptionHeight, CaptionWidthfromreg ) - 2) & ~1;
2835         broken_val = min( broken_val, 20 );
2836 
2837         if (smicon == 4)
2838         {
2839             ok_gsm_2( SM_CXSMICON, smicon, 6 );
2840             ok_gsm_2( SM_CYSMICON, smicon, 6 );
2841         }
2842         else if (smicon < broken_val)
2843         {
2844             ok_gsm_2( SM_CXSMICON, smicon, broken_val );
2845             ok_gsm_2( SM_CYSMICON, smicon, broken_val );
2846         }
2847         else
2848         {
2849             ok_gsm( SM_CXSMICON, smicon );
2850             ok_gsm( SM_CYSMICON, smicon );
2851         }
2852     }
2853 
2854     ok_gsm( SM_CYSMCAPTION, ncm.iSmCaptionHeight + 1);
2855     ok_gsm_3( SM_CXSMSIZE,
2856         ncm.iSmCaptionWidth, /* classic/standard windows style */
2857         GetSystemMetrics( SM_CYSMCAPTION) - 1, /* WinXP style */
2858         smcxsmsize /* winXP seems to cache this value: setnonclientmetric
2859                       does not change it */
2860         );
2861     ok_gsm( SM_CYSMSIZE, GetSystemMetrics( SM_CYSMCAPTION) - 1);
2862     ok_gsm( SM_CXMENUSIZE, ncm.iMenuWidth);
2863     ok_gsm( SM_CYMENUSIZE, ncm.iMenuHeight);
2864     /* SM_ARRANGE */
2865     ok_gsm( SM_CXMINIMIZED, minim.iWidth + 6);
2866     ok_gsm( SM_CYMINIMIZED, GetSystemMetrics( SM_CYCAPTION) + 5);
2867     screen.cx = GetSystemMetrics( SM_CXVIRTUALSCREEN );
2868     screen.cy = GetSystemMetrics( SM_CYVIRTUALSCREEN );
2869     if (!screen.cx || !screen.cy)  /* not supported on NT4 */
2870     {
2871         screen.cx = GetSystemMetrics( SM_CXSCREEN );
2872         screen.cy = GetSystemMetrics( SM_CYSCREEN );
2873     }
2874     ok_gsm_3( SM_CXMAXTRACK, screen.cx + 4 + 2 * GetSystemMetrics(SM_CXFRAME),
2875               screen.cx - 4 + 2 * GetSystemMetrics(SM_CXFRAME), /* Vista */
2876               screen.cx + 2 * GetSystemMetrics(SM_CXFRAME)); /* Win8 */
2877     ok_gsm_3( SM_CYMAXTRACK, screen.cy + 4 + 2 * GetSystemMetrics(SM_CYFRAME),
2878               screen.cy - 4 + 2 * GetSystemMetrics(SM_CYFRAME), /* Vista */
2879               screen.cy + 2 * GetSystemMetrics(SM_CYFRAME)); /* Win8 */
2880     /* the next two cannot really be tested as they depend on (application)
2881      * toolbars */
2882     /* SM_CXMAXIMIZED */
2883     /* SM_CYMAXIMIZED */
2884     /* SM_NETWORK */
2885     /* */
2886     /* */
2887     /* */
2888     /* SM_CLEANBOOT */
2889     /* SM_CXDRAG */
2890     /* SM_CYDRAG */
2891     /* SM_SHOWSOUNDS */
2892     ok_gsm( SM_CXMENUCHECK,
2893             ((tmMenuFont.tmHeight + tmMenuFont.tmExternalLeading+1)/2)*2-1);
2894     ok_gsm( SM_CYMENUCHECK,
2895             ((tmMenuFont.tmHeight + tmMenuFont.tmExternalLeading+1)/2)*2-1);
2896     /* SM_SLOWMACHINE */
2897     /* SM_MIDEASTENABLED */
2898     /* SM_MOUSEWHEELPRESENT */
2899     /* SM_XVIRTUALSCREEN */
2900     /* SM_YVIRTUALSCREEN */
2901     /* SM_CXVIRTUALSCREEN */
2902     /* SM_CYVIRTUALSCREEN */
2903     /* SM_CMONITORS */
2904     /* SM_SAMEDISPLAYFORMAT */
2905     /* SM_IMMENABLED */
2906     /* SM_CXFOCUSBORDER */
2907     /* SM_CYFOCUSBORDER */
2908     /* SM_TABLETPC */
2909     /* SM_MEDIACENTER */
2910     /* SM_CMETRICS */
2911     /* end of tests */
2912     if( gsm_error_ctr ) { /* if any errors where found */
2913         trace( "BorderWidth %d CaptionWidth %d CaptionHeight %d IconSpacing %d IconVerticalSpacing %d\n",
2914                 ncm.iBorderWidth, ncm.iCaptionWidth, ncm.iCaptionHeight, IconSpacing, IconVerticalSpacing);
2915         trace( "MenuHeight %d MenuWidth %d ScrollHeight %d ScrollWidth %d SmCaptionHeight %d SmCaptionWidth %d\n",
2916                 ncm.iMenuHeight, ncm.iMenuWidth, ncm.iScrollHeight, ncm.iScrollWidth, ncm.iSmCaptionHeight, ncm.iSmCaptionWidth);
2917         trace( "Captionfontchar width %d  MenuFont %d,%d CaptionWidth from registry: %d screen %d,%d\n",
2918                 avcwCaption, tmMenuFont.tmHeight, tmMenuFont.tmExternalLeading, CaptionWidthfromreg, screen.cx, screen.cy);
2919     }
2920 
2921     DeleteDC(hdc);
2922 }
2923 
2924 static void compare_font( const LOGFONTW *lf1, const LOGFONTW *lf2, int dpi, int custom_dpi, int line )
2925 {
2926     ok_(__FILE__,line)( lf1->lfHeight == MulDiv( lf2->lfHeight, dpi, custom_dpi ),
2927                         "wrong lfHeight %d vs %d\n", lf1->lfHeight, lf2->lfHeight );
2928     ok_(__FILE__,line)( abs( lf1->lfWidth - MulDiv( lf2->lfWidth, dpi, custom_dpi )) <= 1,
2929                         "wrong lfWidth %d vs %d\n", lf1->lfWidth, lf2->lfWidth );
2930     ok_(__FILE__,line)( !memcmp( &lf1->lfEscapement, &lf2->lfEscapement,
2931                                  offsetof( LOGFONTW, lfFaceName ) - offsetof( LOGFONTW, lfEscapement )),
2932                         "font differs\n" );
2933     ok_(__FILE__,line)( !lstrcmpW( lf1->lfFaceName, lf2->lfFaceName ), "wrong face name %s vs %s\n",
2934                         wine_dbgstr_w( lf1->lfFaceName ), wine_dbgstr_w( lf2->lfFaceName ));
2935 }
2936 
2937 static void test_metrics_for_dpi( int custom_dpi )
2938 {
2939     int i, val;
2940     NONCLIENTMETRICSW ncm1, ncm2;
2941     ICONMETRICSW im1, im2;
2942     LOGFONTW lf1, lf2;
2943     BOOL ret;
2944 
2945     if (!pSystemParametersInfoForDpi)
2946     {
2947         win_skip( "custom dpi metrics not supported\n" );
2948         return;
2949     }
2950 
2951     ncm1.cbSize = sizeof(ncm1);
2952     ret = SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof(ncm1), &ncm1, FALSE );
2953     ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() );
2954     ncm2.cbSize = sizeof(ncm2);
2955     ret = pSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, sizeof(ncm2), &ncm2, FALSE, custom_dpi );
2956     ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() );
2957 
2958     for (i = 0; i < 92; i++)
2959     {
2960         int ret1 = GetSystemMetrics( i );
2961         int ret2 = pGetSystemMetricsForDpi( i, custom_dpi );
2962         switch (i)
2963         {
2964         case SM_CXVSCROLL:
2965         case SM_CYHSCROLL:
2966         case SM_CYVTHUMB:
2967         case SM_CXHTHUMB:
2968         case SM_CXICON:
2969         case SM_CYICON:
2970         case SM_CYVSCROLL:
2971         case SM_CXHSCROLL:
2972         case SM_CYSIZE:
2973         case SM_CXICONSPACING:
2974         case SM_CYICONSPACING:
2975         case SM_CXSMSIZE:
2976         case SM_CYSMSIZE:
2977         case SM_CYMENUSIZE:
2978             ok( ret1 == MulDiv( ret2, dpi, custom_dpi ), "%u: wrong value %u vs %u\n", i, ret1, ret2 );
2979             break;
2980         case SM_CXSIZE:
2981             ok( ret1 == ncm1.iCaptionWidth && ret2 == ncm2.iCaptionWidth,
2982                 "%u: wrong value %u vs %u caption %u vs %u\n",
2983                 i, ret1, ret2, ncm1.iCaptionWidth, ncm2.iCaptionWidth );
2984             break;
2985         case SM_CXCURSOR:
2986         case SM_CYCURSOR:
2987             val = MulDiv( 32, custom_dpi, USER_DEFAULT_SCREEN_DPI );
2988             if (val < 48) val = 32;
2989             else if (val < 64) val = 48;
2990             else val = 64;
2991             ok( val == ret2, "%u: wrong value %u vs %u\n", i, ret1, ret2 );
2992             break;
2993         case SM_CYCAPTION:
2994         case SM_CYSMCAPTION:
2995         case SM_CYMENU:
2996             ok( ret1 - 1 == MulDiv( ret2 - 1, dpi, custom_dpi ), "%u: wrong value %u vs %u\n", i, ret1, ret2 );
2997             break;
2998         case SM_CXMENUSIZE:
2999             ok( ret1 / 8 == MulDiv( ret2, dpi, custom_dpi ) / 8, "%u: wrong value %u vs %u\n", i, ret1, ret2 );
3000             break;
3001         case SM_CXFRAME:
3002         case SM_CYFRAME:
3003             ok( ret1 == ncm1.iBorderWidth + 3 && ret2 == ncm2.iBorderWidth + 3,
3004                 "%u: wrong value %u vs %u borders %u+%u vs %u+%u\n", i, ret1, ret2,
3005                 ncm1.iBorderWidth, ncm1.iPaddedBorderWidth, ncm2.iBorderWidth, ncm2.iPaddedBorderWidth );
3006             break;
3007         case SM_CXSMICON:
3008         case SM_CYSMICON:
3009             ok( ret1 == (MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI ) & ~1) &&
3010                 ret2 == (MulDiv( 16, custom_dpi, USER_DEFAULT_SCREEN_DPI ) & ~1),
3011                 "%u: wrong value %u vs %u\n", i, ret1, ret2 );
3012             break;
3013         case SM_CXMENUCHECK:
3014         case SM_CYMENUCHECK:
3015             ok( ret1 == ((get_tmheightW( &ncm1.lfMenuFont, 1 ) - 1) | 1) &&
3016                 ret2 == ((get_tmheightW( &ncm2.lfMenuFont, 1 ) - 1) | 1),
3017                 "%u: wrong value %u vs %u font %u vs %u\n", i, ret1, ret2,
3018                 get_tmheightW( &ncm1.lfMenuFont, 1 ), get_tmheightW( &ncm2.lfMenuFont, 1 ));
3019             break;
3020         default:
3021             ok( ret1 == ret2, "%u: wrong value %u vs %u\n", i, ret1, ret2 );
3022             break;
3023         }
3024     }
3025     im1.cbSize = sizeof(im1);
3026     ret = SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im1), &im1, FALSE );
3027     ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() );
3028     im2.cbSize = sizeof(im2);
3029     ret = pSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im2), &im2, FALSE, custom_dpi );
3030     ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() );
3031     ok( im1.iHorzSpacing == MulDiv( im2.iHorzSpacing, dpi, custom_dpi ), "wrong iHorzSpacing %u vs %u\n",
3032         im1.iHorzSpacing, im2.iHorzSpacing );
3033     ok( im1.iVertSpacing == MulDiv( im2.iVertSpacing, dpi, custom_dpi ), "wrong iVertSpacing %u vs %u\n",
3034         im1.iVertSpacing, im2.iVertSpacing );
3035     ok( im1.iTitleWrap == im2.iTitleWrap, "wrong iTitleWrap %u vs %u\n",
3036         im1.iTitleWrap, im2.iTitleWrap );
3037     compare_font( &im1.lfFont, &im2.lfFont, dpi, custom_dpi, __LINE__ );
3038 
3039     ret = SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf1), &lf1, FALSE );
3040     ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() );
3041     ret = pSystemParametersInfoForDpi( SPI_GETICONTITLELOGFONT, sizeof(lf2), &lf2, FALSE, custom_dpi );
3042     ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() );
3043     compare_font( &lf1, &lf2, dpi, custom_dpi, __LINE__ );
3044 
3045     /* on high-dpi iPaddedBorderWidth is used in addition to iBorderWidth */
3046     ok( ncm1.iBorderWidth + ncm1.iPaddedBorderWidth == MulDiv( ncm2.iBorderWidth + ncm2.iPaddedBorderWidth, dpi, custom_dpi ),
3047         "wrong iBorderWidth %u+%u vs %u+%u\n",
3048         ncm1.iBorderWidth, ncm1.iPaddedBorderWidth, ncm2.iBorderWidth, ncm2.iPaddedBorderWidth );
3049     ok( ncm1.iScrollWidth == MulDiv( ncm2.iScrollWidth, dpi, custom_dpi ),
3050         "wrong iScrollWidth %u vs %u\n", ncm1.iScrollWidth, ncm2.iScrollWidth );
3051     ok( ncm1.iScrollHeight == MulDiv( ncm2.iScrollHeight, dpi, custom_dpi ),
3052         "wrong iScrollHeight %u vs %u\n", ncm1.iScrollHeight, ncm2.iScrollHeight );
3053     ok( ((ncm1.iCaptionWidth + 1) & ~1) == ((MulDiv( ncm2.iCaptionWidth, dpi, custom_dpi ) + 1) & ~1),
3054         "wrong iCaptionWidth %u vs %u\n", ncm1.iCaptionWidth, ncm2.iCaptionWidth );
3055     ok( ncm1.iCaptionHeight == MulDiv( ncm2.iCaptionHeight, dpi, custom_dpi ),
3056         "wrong iCaptionHeight %u vs %u\n", ncm1.iCaptionHeight, ncm2.iCaptionHeight );
3057     compare_font( &ncm1.lfCaptionFont, &ncm2.lfCaptionFont, dpi, custom_dpi, __LINE__ );
3058     ok( ncm1.iSmCaptionHeight == MulDiv( ncm2.iSmCaptionHeight, dpi, custom_dpi ),
3059         "wrong iSmCaptionHeight %u vs %u\n", ncm1.iSmCaptionHeight, ncm2.iSmCaptionHeight );
3060     compare_font( &ncm1.lfSmCaptionFont, &ncm2.lfSmCaptionFont, dpi, custom_dpi, __LINE__ );
3061     ok( ncm1.iMenuHeight == MulDiv( ncm2.iMenuHeight, dpi, custom_dpi ),
3062         "wrong iMenuHeight %u vs %u\n", ncm1.iMenuHeight, ncm2.iMenuHeight );
3063     /* iSmCaptionWidth and iMenuWidth apparently need to be multiples of 8 */
3064     ok( ncm1.iSmCaptionWidth / 8 == MulDiv( ncm2.iSmCaptionWidth, dpi, custom_dpi ) / 8,
3065         "wrong iSmCaptionWidth %u vs %u\n", ncm1.iSmCaptionWidth, ncm2.iSmCaptionWidth );
3066     ok( ncm1.iMenuWidth / 8 == MulDiv( ncm2.iMenuWidth, dpi, custom_dpi ) / 8,
3067         "wrong iMenuWidth %u vs %u\n", ncm1.iMenuWidth, ncm2.iMenuWidth );
3068     compare_font( &ncm1.lfMenuFont, &ncm2.lfMenuFont, dpi, custom_dpi, __LINE__ );
3069     compare_font( &ncm1.lfStatusFont, &ncm2.lfStatusFont, dpi, custom_dpi, __LINE__ );
3070     compare_font( &ncm1.lfMessageFont, &ncm2.lfMessageFont, dpi, custom_dpi, __LINE__ );
3071 
3072     for (i = 1; i < 120; i++)
3073     {
3074         if (i == SPI_GETICONTITLELOGFONT || i == SPI_GETNONCLIENTMETRICS || i == SPI_GETICONMETRICS)
3075             continue;
3076         SetLastError( 0xdeadbeef );
3077         ret = pSystemParametersInfoForDpi( i, 0, &val, 0, custom_dpi );
3078         ok( !ret, "%u: SystemParametersInfoForDpi succeeded\n", i );
3079             ok( GetLastError() == ERROR_INVALID_PARAMETER, "%u: wrong error %u\n", i, GetLastError() );
3080     }
3081 }
3082 
3083 static void test_EnumDisplaySettings(void)
3084 {
3085     DEVMODEA devmode;
3086     DWORD val;
3087     HDC hdc;
3088     DWORD num;
3089 
3090     memset(&devmode, 0, sizeof(devmode));
3091     EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devmode);
3092 
3093     hdc = GetDC(0);
3094     val = GetDeviceCaps(hdc, BITSPIXEL);
3095     ok(devmode.dmBitsPerPel == val,
3096         "GetDeviceCaps(BITSPIXEL) returned %d, EnumDisplaySettings returned %d\n",
3097         val, devmode.dmBitsPerPel);
3098 
3099     val = GetDeviceCaps(hdc, NUMCOLORS);
3100     if(devmode.dmBitsPerPel <= 8) {
3101         ok(val == 256, "Screen bpp is %d, NUMCOLORS returned %d\n", devmode.dmBitsPerPel, val);
3102     } else {
3103         ok(val == -1, "Screen bpp is %d, NUMCOLORS returned %d\n", devmode.dmBitsPerPel, val);
3104     }
3105 
3106     ReleaseDC(0, hdc);
3107 
3108     num = 1;
3109     while (1) {
3110         SetLastError (0xdeadbeef);
3111         if (!EnumDisplaySettingsA(NULL, num, &devmode)) {
3112             DWORD le = GetLastError();
3113             ok(le == ERROR_NO_MORE_FILES ||
3114                le == ERROR_MOD_NOT_FOUND /* Win8 */ ||
3115                le == 0xdeadbeef, /* XP, 2003 */
3116                "Expected ERROR_NO_MORE_FILES, ERROR_MOD_NOT_FOUND or 0xdeadbeef, got %d for %d\n", le, num);
3117             break;
3118 	}
3119 	num++;
3120     }
3121 }
3122 
3123 static void test_GetSysColorBrush(void)
3124 {
3125     HBRUSH hbr;
3126 
3127     SetLastError(0xdeadbeef);
3128     hbr = GetSysColorBrush(-1);
3129     ok(hbr == NULL, "Expected NULL brush\n");
3130     ok(GetLastError() == 0xdeadbeef, "Expected last error not set, got %x\n", GetLastError());
3131     /* greater than max index */
3132     hbr = GetSysColorBrush(COLOR_MENUBAR);
3133     if (hbr)
3134     {
3135         SetLastError(0xdeadbeef);
3136         hbr = GetSysColorBrush(COLOR_MENUBAR + 1);
3137         ok(hbr == NULL, "Expected NULL brush\n");
3138         ok(GetLastError() == 0xdeadbeef, "Expected last error not set, got %x\n", GetLastError());
3139     }
3140     else
3141         win_skip("COLOR_MENUBAR unsupported\n");
3142 }
3143 
3144 static void test_dpi_stock_objects( HDC hdc )
3145 {
3146     DPI_AWARENESS_CONTEXT context;
3147     HGDIOBJ obj[STOCK_LAST + 1], obj2[STOCK_LAST + 1];
3148     LOGFONTW lf, lf2;
3149     UINT i, dpi;
3150 
3151     context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE );
3152     dpi = GetDeviceCaps( hdc, LOGPIXELSX );
3153     ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi );
3154     ok( !pIsProcessDPIAware(), "not aware\n" );
3155     for (i = 0; i <= STOCK_LAST; i++) obj[i] = GetStockObject( i );
3156 
3157     pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE );
3158     dpi = GetDeviceCaps( hdc, LOGPIXELSX );
3159     ok( dpi == real_dpi, "wrong dpi %u\n", dpi );
3160     ok( pIsProcessDPIAware(), "not aware\n" );
3161     for (i = 0; i <= STOCK_LAST; i++) obj2[i] = GetStockObject( i );
3162 
3163     for (i = 0; i <= STOCK_LAST; i++)
3164     {
3165         switch (i)
3166         {
3167         case OEM_FIXED_FONT:
3168         case SYSTEM_FIXED_FONT:
3169             ok( obj[i] != obj2[i], "%u: same object\n", i );
3170             break;
3171         case SYSTEM_FONT:
3172         case DEFAULT_GUI_FONT:
3173             ok( obj[i] != obj2[i], "%u: same object\n", i );
3174             GetObjectW( obj[i], sizeof(lf), &lf );
3175             GetObjectW( obj2[i], sizeof(lf2), &lf2 );
3176             ok( lf.lfHeight == MulDiv( lf2.lfHeight, USER_DEFAULT_SCREEN_DPI, real_dpi ),
3177                 "%u: wrong height %d / %d\n", i, lf.lfHeight, lf2.lfHeight );
3178             break;
3179         default:
3180             ok( obj[i] == obj2[i], "%u: different object\n", i );
3181             break;
3182         }
3183     }
3184 
3185     pSetThreadDpiAwarenessContext( context );
3186 }
3187 
3188 static void scale_point_dpi( POINT *pt, UINT src_dpi, UINT target_dpi )
3189 {
3190     pt->x = MulDiv( pt->x, target_dpi, src_dpi );
3191     pt->y = MulDiv( pt->y, target_dpi, src_dpi );
3192 }
3193 
3194 static void scale_rect_dpi( RECT *rect, UINT src_dpi, UINT target_dpi )
3195 {
3196     rect->left = MulDiv( rect->left, target_dpi, src_dpi );
3197     rect->top = MulDiv( rect->top, target_dpi, src_dpi );
3198     rect->right = MulDiv( rect->right, target_dpi, src_dpi );
3199     rect->bottom = MulDiv( rect->bottom, target_dpi, src_dpi );
3200 }
3201 
3202 static void scale_point_dpi_aware( POINT *pt, DPI_AWARENESS from, DPI_AWARENESS to )
3203 {
3204     if (from == DPI_AWARENESS_UNAWARE && to != DPI_AWARENESS_UNAWARE)
3205         scale_point_dpi( pt, USER_DEFAULT_SCREEN_DPI, real_dpi );
3206     else if (from != DPI_AWARENESS_UNAWARE && to == DPI_AWARENESS_UNAWARE)
3207         scale_point_dpi( pt, real_dpi, USER_DEFAULT_SCREEN_DPI );
3208 }
3209 
3210 static void scale_rect_dpi_aware( RECT *rect, DPI_AWARENESS from, DPI_AWARENESS to )
3211 {
3212     if (from == DPI_AWARENESS_UNAWARE && to != DPI_AWARENESS_UNAWARE)
3213         scale_rect_dpi( rect, USER_DEFAULT_SCREEN_DPI, real_dpi );
3214     else if (from != DPI_AWARENESS_UNAWARE && to == DPI_AWARENESS_UNAWARE)
3215         scale_rect_dpi( rect, real_dpi, USER_DEFAULT_SCREEN_DPI );
3216 }
3217 
3218 static void test_dpi_mapping(void)
3219 {
3220     HWND hwnd, child;
3221     HDC hdc;
3222     UINT win_dpi, units;
3223     POINT point;
3224     BOOL ret;
3225     HRGN rgn, update;
3226     RECT rect, orig, client, desktop, expect;
3227     ULONG_PTR i, j, k;
3228     WINDOWPLACEMENT wpl_orig, wpl;
3229     HMONITOR monitor;
3230     MONITORINFO mon_info;
3231     DPI_AWARENESS_CONTEXT context;
3232 
3233     if (!pLogicalToPhysicalPointForPerMonitorDPI)
3234     {
3235         win_skip( "LogicalToPhysicalPointForPerMonitorDPI not supported\n" );
3236         return;
3237     }
3238     context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3239     GetWindowRect( GetDesktopWindow(), &desktop );
3240     for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++)
3241     {
3242         pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i );
3243         /* test desktop rect */
3244         GetWindowRect( GetDesktopWindow(), &rect );
3245         expect = desktop;
3246         if (i == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI );
3247         ok( EqualRect( &expect, &rect ), "%lu: wrong desktop rect %s expected %s\n",
3248             i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3249         SetRect( &rect, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ));
3250         ok( EqualRect( &expect, &rect ), "%lu: wrong desktop rect %s expected %s\n",
3251             i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3252         SetRect( &rect, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ), GetSystemMetrics( SM_CYVIRTUALSCREEN ));
3253         ok( EqualRect( &expect, &rect ), "%lu: wrong virt desktop rect %s expected %s\n",
3254             i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3255         SetRect( &rect, 0, 0, 1, 1 );
3256         monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
3257         ok( monitor != 0, "failed to get monitor\n" );
3258         mon_info.cbSize = sizeof(mon_info);
3259         ok( GetMonitorInfoW( monitor, &mon_info ), "GetMonitorInfoExW failed\n" );
3260         ok( EqualRect( &expect, &mon_info.rcMonitor ), "%lu: wrong monitor rect %s expected %s\n",
3261             i, wine_dbgstr_rect(&mon_info.rcMonitor), wine_dbgstr_rect(&expect) );
3262         hdc = CreateDCA( "display", NULL, NULL, NULL );
3263         SetRect( &rect, 0, 0, GetDeviceCaps( hdc, HORZRES ), GetDeviceCaps( hdc, VERTRES ));
3264         ok( EqualRect( &expect, &rect ), "%lu: wrong caps desktop rect %s expected %s\n",
3265             i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3266         SetRect( &rect, 0, 0, GetDeviceCaps( hdc, DESKTOPHORZRES ), GetDeviceCaps( hdc, DESKTOPVERTRES ));
3267         ok( EqualRect( &desktop, &rect ), "%lu: wrong caps virt desktop rect %s expected %s\n",
3268             i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&desktop) );
3269         DeleteDC( hdc );
3270         /* test message window rect */
3271         hwnd = CreateWindowA( "SysParamsTestClass", "test", WS_CHILD,
3272                               10, 10, 20, 20, HWND_MESSAGE, 0, GetModuleHandleA(0), NULL );
3273         GetWindowRect( GetAncestor( hwnd, GA_PARENT ), &rect );
3274         SetRect( &expect, 0, 0, 100, 100 );
3275         if (i == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI );
3276         ok( EqualRect( &expect, &rect ), "%lu: wrong message rect %s expected %s\n",
3277             i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3278         DestroyWindow( hwnd );
3279     }
3280     for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++)
3281     {
3282         pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i );
3283         hwnd = CreateWindowA( "SysParamsTestClass", "test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3284                               193, 177, 295, 303, 0, 0, GetModuleHandleA(0), NULL );
3285         ok( hwnd != 0, "creating window failed err %u\n", GetLastError());
3286         child = CreateWindowA( "SysParamsTestClass", "child", WS_CHILD | WS_VISIBLE,
3287                                50, 60, 70, 80, hwnd, 0, GetModuleHandleA(0), NULL );
3288         ok( child != 0, "creating child failed err %u\n", GetLastError());
3289         GetWindowRect( hwnd, &orig );
3290         SetRect( &rect, 0, 0, 0, 0 );
3291         pAdjustWindowRectExForDpi( &rect, WS_OVERLAPPEDWINDOW, FALSE, 0, pGetDpiForWindow( hwnd ));
3292         SetRect( &client, orig.left - rect.left, orig.top - rect.top,
3293                  orig.right - rect.right, orig.bottom - rect.bottom );
3294         ShowWindow( hwnd, SW_MINIMIZE );
3295         ShowWindow( hwnd, SW_RESTORE );
3296         GetWindowPlacement( hwnd, &wpl_orig );
3297         units = GetDialogBaseUnits();
3298 
3299         for (j = DPI_AWARENESS_UNAWARE; j <= DPI_AWARENESS_PER_MONITOR_AWARE; j++)
3300         {
3301             pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j );
3302             /* test window rect */
3303             GetWindowRect( hwnd, &rect );
3304             expect = orig;
3305             scale_rect_dpi_aware( &expect, i, j );
3306             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong window rect %s expected %s\n",
3307                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3308             /* test client rect */
3309             GetClientRect( hwnd, &rect );
3310             expect = client;
3311             OffsetRect( &expect, -expect.left, -expect.top );
3312             scale_rect_dpi_aware( &expect, i, j );
3313             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong client rect %s expected %s\n",
3314                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3315             /* test window placement */
3316             GetWindowPlacement( hwnd, &wpl );
3317             point = wpl_orig.ptMinPosition;
3318             if (point.x != -1 || point.y != -1) scale_point_dpi_aware( &point, i, j );
3319             ok( wpl.ptMinPosition.x == point.x && wpl.ptMinPosition.y == point.y,
3320                 "%lu/%lu: wrong placement min pos %d,%d expected %d,%d\n", i, j,
3321                 wpl.ptMinPosition.x, wpl.ptMinPosition.y, point.x, point.y );
3322             point = wpl_orig.ptMaxPosition;
3323             if (point.x != -1 || point.y != -1) scale_point_dpi_aware( &point, i, j );
3324             ok( wpl.ptMaxPosition.x == point.x && wpl.ptMaxPosition.y == point.y,
3325                 "%lu/%lu: wrong placement max pos %d,%d expected %d,%d\n", i, j,
3326                 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, point.x, point.y );
3327             expect = wpl_orig.rcNormalPosition;
3328             scale_rect_dpi_aware( &expect, i, j );
3329             ok( EqualRect( &wpl.rcNormalPosition, &expect ),
3330                 "%lu/%lu: wrong placement rect %s expect %s\n", i, j,
3331                 wine_dbgstr_rect(&wpl.rcNormalPosition), wine_dbgstr_rect(&expect));
3332             /* test DC rect */
3333             hdc = GetDC( hwnd );
3334             GetClipBox( hdc, &rect );
3335             SetRect( &expect, 0, 0, client.right - client.left, client.bottom - client.top );
3336             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong clip box %s expected %s\n",
3337                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3338             /* test DC resolution */
3339             SetRect( &rect, 0, 0, GetDeviceCaps( hdc, HORZRES ), GetDeviceCaps( hdc, VERTRES ));
3340             expect = desktop;
3341             if (j == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI );
3342             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong DC resolution %s expected %s\n",
3343                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3344             SetRect( &rect, 0, 0, GetDeviceCaps( hdc, DESKTOPHORZRES ), GetDeviceCaps( hdc, DESKTOPVERTRES ));
3345             ok( EqualRect( &desktop, &rect ), "%lu/%lu: wrong desktop resolution %s expected %s\n",
3346                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&desktop) );
3347             ReleaseDC( hwnd, hdc );
3348             /* test DC win rect */
3349             hdc = GetWindowDC( hwnd );
3350             GetClipBox( hdc, &rect );
3351             SetRect( &expect, 0, 0, 295, 303 );
3352             todo_wine
3353             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong clip box win DC %s expected %s\n",
3354                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3355             ReleaseDC( hwnd, hdc );
3356             /* test window invalidation */
3357             UpdateWindow( hwnd );
3358             update = CreateRectRgn( 0, 0, 0, 0 );
3359             ret = GetUpdateRgn( hwnd, update, FALSE );
3360             ok( ret == NULLREGION, "update region not empty\n" );
3361             rgn = CreateRectRgn( 20, 20, 25, 25 );
3362             for (k = DPI_AWARENESS_UNAWARE; k <= DPI_AWARENESS_PER_MONITOR_AWARE; k++)
3363             {
3364                 pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~k );
3365                 RedrawWindow( hwnd, 0, rgn, RDW_INVALIDATE );
3366                 pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j );
3367                 GetUpdateRgn( hwnd, update, FALSE );
3368                 GetRgnBox( update, &rect );
3369                 SetRect( &expect, 20, 20, 25, 25 );
3370                 ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update region %s expected %s\n",
3371                     i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3372                 GetUpdateRect( hwnd, &rect, FALSE );
3373                 scale_rect_dpi_aware( &expect, i, j );
3374                 ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update rect %s expected %s\n",
3375                     i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3376                 UpdateWindow( hwnd );
3377             }
3378             for (k = DPI_AWARENESS_UNAWARE; k <= DPI_AWARENESS_PER_MONITOR_AWARE; k++)
3379             {
3380                 RedrawWindow( hwnd, 0, rgn, RDW_INVALIDATE );
3381                 pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~k );
3382                 GetUpdateRgn( hwnd, update, FALSE );
3383                 pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j );
3384                 GetRgnBox( update, &rect );
3385                 SetRect( &expect, 20, 20, 25, 25 );
3386                 ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update region %s expected %s\n",
3387                     i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3388                 GetUpdateRect( hwnd, &rect, FALSE );
3389                 scale_rect_dpi_aware( &expect, i, j );
3390                 ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update rect %s expected %s\n",
3391                     i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3392                 UpdateWindow( hwnd );
3393             }
3394             /* test desktop window invalidation */
3395             pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3396             GetClientRect( hwnd, &rect );
3397             InflateRect( &rect, -50, -50 );
3398             expect = rect;
3399             MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 );
3400             pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j );
3401             RedrawWindow( 0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN );
3402             GetUpdateRgn( hwnd, update, TRUE );
3403             GetRgnBox( update, &rect );
3404             if (i == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI );
3405             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong update region %s expected %s\n",
3406                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3407             GetUpdateRect( hwnd, &rect, FALSE );
3408             scale_rect_dpi_aware( &expect, i, j );
3409             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong update rect %s expected %s\n",
3410                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3411             UpdateWindow( hwnd );
3412             DeleteObject( update );
3413             /* test dialog units */
3414             ret = GetDialogBaseUnits();
3415             point.x = LOWORD( units );
3416             point.y = HIWORD( units );
3417             scale_point_dpi_aware( &point, i, j );
3418             ok( LOWORD(ret) == point.x && HIWORD(ret) == point.y, "%lu/%lu: wrong units %d,%d / %d,%d\n",
3419                 i, j, LOWORD(ret), HIWORD(ret), point.x, point.y );
3420             /* test window points mapping */
3421             SetRect( &rect, 0, 0, 100, 100 );
3422             rect.right = rect.left + 100;
3423             rect.bottom = rect.top + 100;
3424             MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 );
3425             expect = client;
3426             scale_rect_dpi_aware( &expect, i, j );
3427             expect.right = expect.left + 100;
3428             expect.bottom = expect.top + 100;
3429             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong MapWindowPoints rect %s expected %s\n",
3430                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3431             SetRect( &rect, 50, 60, 70, 80 );
3432             scale_rect_dpi_aware( &rect, i, j );
3433             SetRect( &expect, 40, 30, 60, 80 );
3434             OffsetRect( &expect, -rect.left, -rect.top );
3435             SetRect( &rect, 40, 30, 60, 80 );
3436             MapWindowPoints( hwnd, child, (POINT *)&rect, 2 );
3437             ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong MapWindowPoints child rect %s expected %s\n",
3438                 i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) );
3439             /* test logical<->physical coords mapping */
3440             win_dpi = pGetDpiForWindow( hwnd );
3441             if (i == DPI_AWARENESS_UNAWARE)
3442                 ok( win_dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", win_dpi );
3443             else if (i == DPI_AWARENESS_SYSTEM_AWARE)
3444                 ok( win_dpi == real_dpi, "wrong dpi %u / %u\n", win_dpi, real_dpi );
3445             point.x = 373;
3446             point.y = 377;
3447             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3448             ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j );
3449             ok( point.x == MulDiv( 373, real_dpi, win_dpi ) &&
3450                 point.y == MulDiv( 377, real_dpi, win_dpi ),
3451                 "%lu/%lu: wrong pos %d,%d dpi %u\n", i, j, point.x, point.y, win_dpi );
3452             point.x = 405;
3453             point.y = 423;
3454             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3455             ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j );
3456             ok( point.x == MulDiv( 405, win_dpi, real_dpi ) &&
3457                 point.y == MulDiv( 423, win_dpi, real_dpi ),
3458                 "%lu/%lu: wrong pos %d,%d dpi %u\n", i, j, point.x, point.y, win_dpi );
3459             /* point outside the window fails, but note that Windows (wrongly) checks against the
3460              * window rect transformed relative to the thread's awareness */
3461             GetWindowRect( hwnd, &rect );
3462             point.x = rect.left - 1;
3463             point.y = rect.top;
3464             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3465             ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j );
3466             point.x++;
3467             point.y--;
3468             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3469             ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j );
3470             point.y++;
3471             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3472             ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j );
3473             point.x = rect.right;
3474             point.y = rect.bottom + 1;
3475             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3476             ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j );
3477             point.x++;
3478             point.y--;
3479             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3480             ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j );
3481             point.x--;
3482             ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point );
3483             ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j );
3484             /* get physical window rect */
3485             pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3486             GetWindowRect( hwnd, &rect );
3487             pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j );
3488             point.x = rect.left - 1;
3489             point.y = rect.top;
3490             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3491             ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j );
3492             point.x++;
3493             point.y--;
3494             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3495             ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j );
3496             point.y++;
3497             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3498             ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j );
3499             point.x = rect.right;
3500             point.y = rect.bottom + 1;
3501             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3502             ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j );
3503             point.x++;
3504             point.y--;
3505             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3506             ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j );
3507             point.x--;
3508             ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point );
3509             ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j );
3510         }
3511         DestroyWindow( hwnd );
3512     }
3513     pSetThreadDpiAwarenessContext( context );
3514 }
3515 
3516 static void test_dpi_aware(void)
3517 {
3518     BOOL ret;
3519 
3520     if (!pIsProcessDPIAware)
3521     {
3522         win_skip("IsProcessDPIAware not available\n");
3523         return;
3524     }
3525 
3526     ret = pSetProcessDPIAware();
3527     ok(ret, "got %d\n", ret);
3528 
3529     ret = pIsProcessDPIAware();
3530     ok(ret, "got %d\n", ret);
3531 
3532     dpi = real_dpi;
3533     test_GetSystemMetrics();
3534     test_metrics_for_dpi( 96 );
3535     test_metrics_for_dpi( 192 );
3536 }
3537 
3538 static void test_dpi_context(void)
3539 {
3540     DPI_AWARENESS awareness;
3541     DPI_AWARENESS_CONTEXT context;
3542     ULONG_PTR i, flags;
3543     BOOL ret;
3544     UINT dpi;
3545     HDC hdc = GetDC( 0 );
3546 
3547     context = pGetThreadDpiAwarenessContext();
3548     /* Windows 10 >= 1709 adds extra 0x6000 flags */
3549     flags = (ULONG_PTR)context & 0x6000;
3550     todo_wine
3551         ok( context == (DPI_AWARENESS_CONTEXT)(0x10 | flags), "wrong context %p\n", context );
3552     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3553     todo_wine
3554         ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness );
3555     todo_wine
3556         ok( !pIsProcessDPIAware(), "already aware\n" );
3557     dpi = pGetDpiForSystem();
3558     todo_wine_if (real_dpi != USER_DEFAULT_SCREEN_DPI)
3559         ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi );
3560     dpi = GetDeviceCaps( hdc, LOGPIXELSX );
3561     todo_wine_if (real_dpi != USER_DEFAULT_SCREEN_DPI)
3562         ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi );
3563     SetLastError( 0xdeadbeef );
3564     ret = pSetProcessDpiAwarenessContext( NULL );
3565     ok( !ret, "got %d\n", ret );
3566     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3567     SetLastError( 0xdeadbeef );
3568     ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)-6 );
3569     ok( !ret, "got %d\n", ret );
3570     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3571     ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE );
3572     todo_wine
3573     ok( ret, "got %d\n", ret );
3574     ok( pIsProcessDPIAware(), "not aware\n" );
3575     real_dpi = pGetDpiForSystem();
3576     SetLastError( 0xdeadbeef );
3577     ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE );
3578     ok( !ret, "got %d\n", ret );
3579     ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() );
3580     SetLastError( 0xdeadbeef );
3581     ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE );
3582     ok( !ret, "got %d\n", ret );
3583     ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() );
3584 
3585     ret = pSetProcessDpiAwarenessInternal( DPI_AWARENESS_INVALID );
3586     ok( !ret, "got %d\n", ret );
3587     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3588     ret = pSetProcessDpiAwarenessInternal( DPI_AWARENESS_UNAWARE );
3589     ok( !ret, "got %d\n", ret );
3590     ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() );
3591     ret = pGetProcessDpiAwarenessInternal( 0, &awareness );
3592     ok( ret, "got %d\n", ret );
3593     todo_wine
3594     ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong value %d\n", awareness );
3595     ret = pGetProcessDpiAwarenessInternal( GetCurrentProcess(), &awareness );
3596     ok( ret, "got %d\n", ret );
3597     todo_wine
3598     ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong value %d\n", awareness );
3599     ret = pGetProcessDpiAwarenessInternal( (HANDLE)0xdeadbeef, &awareness );
3600     ok( ret, "got %d\n", ret );
3601     ok( awareness == DPI_AWARENESS_UNAWARE, "wrong value %d\n", awareness );
3602 
3603     ret = pIsProcessDPIAware();
3604     ok(ret, "got %d\n", ret);
3605     context = pGetThreadDpiAwarenessContext();
3606     todo_wine
3607     ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context );
3608     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3609     todo_wine
3610     ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong awareness %u\n", awareness );
3611     SetLastError( 0xdeadbeef );
3612     context = pSetThreadDpiAwarenessContext( 0 );
3613     ok( !context, "got %p\n", context );
3614     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3615     SetLastError( 0xdeadbeef );
3616     context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)-6 );
3617     ok( !context, "got %p\n", context );
3618     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3619     context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE );
3620     todo_wine
3621     ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "wrong context %p\n", context );
3622     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3623     todo_wine
3624     ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong awareness %u\n", awareness );
3625     dpi = pGetDpiForSystem();
3626     ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi );
3627     dpi = GetDeviceCaps( hdc, LOGPIXELSX );
3628     ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi );
3629     ok( !pIsProcessDPIAware(), "still aware\n" );
3630     context = pGetThreadDpiAwarenessContext();
3631     ok( context == (DPI_AWARENESS_CONTEXT)(0x10 | flags), "wrong context %p\n", context );
3632     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3633     ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness );
3634     context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3635     ok( context == (DPI_AWARENESS_CONTEXT)(0x10 | flags), "wrong context %p\n", context );
3636     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3637     ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness );
3638     dpi = pGetDpiForSystem();
3639     ok( dpi == real_dpi, "wrong dpi %u/%u\n", dpi, real_dpi );
3640     dpi = GetDeviceCaps( hdc, LOGPIXELSX );
3641     ok( dpi == real_dpi, "wrong dpi %u\n", dpi );
3642     context = pGetThreadDpiAwarenessContext();
3643     ok( context == (DPI_AWARENESS_CONTEXT)0x12, "wrong context %p\n", context );
3644     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3645     ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness );
3646     context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE );
3647     ok( context == (DPI_AWARENESS_CONTEXT)0x12, "wrong context %p\n", context );
3648     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3649     ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness );
3650     dpi = pGetDpiForSystem();
3651     ok( dpi == real_dpi, "wrong dpi %u/%u\n", dpi, real_dpi );
3652     dpi = GetDeviceCaps( hdc, LOGPIXELSX );
3653     ok( dpi == real_dpi, "wrong dpi %u\n", dpi );
3654     ok( pIsProcessDPIAware(), "not aware\n" );
3655     context = pGetThreadDpiAwarenessContext();
3656     ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context );
3657     context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(0x80000010 | flags) );
3658     ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context );
3659     context = pGetThreadDpiAwarenessContext();
3660     todo_wine
3661     ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context );
3662     context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(0x80000011 | flags) );
3663     todo_wine
3664     ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "wrong context %p\n", context );
3665     context = pGetThreadDpiAwarenessContext();
3666     todo_wine
3667     ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context );
3668     context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 );
3669     todo_wine
3670     ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "wrong context %p\n", context );
3671     context = pSetThreadDpiAwarenessContext( context );
3672     ok( context == (DPI_AWARENESS_CONTEXT)(0x12), "wrong context %p\n", context );
3673     context = pGetThreadDpiAwarenessContext();
3674     todo_wine
3675     ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context );
3676     for (i = 0; i < 0x100; i++)
3677     {
3678         awareness = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i );
3679         switch (i)
3680         {
3681         case 0x10:
3682         case 0x11:
3683         case 0x12:
3684             ok( awareness == (i & ~0x10), "%lx: wrong value %u\n", i, awareness );
3685             ok( pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i ), "%lx: not valid\n", i );
3686             break;
3687         default:
3688             ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", i, awareness );
3689             ok( !pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i ), "%lx: valid\n", i );
3690             break;
3691         }
3692         awareness = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x80000000) );
3693         switch (i)
3694         {
3695         case 0x10:
3696         case 0x11:
3697         case 0x12:
3698             ok( awareness == (i & ~0x10), "%lx: wrong value %u\n", i | 0x80000000, awareness );
3699             ok( pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x80000000) ),
3700                 "%lx: not valid\n", i | 0x80000000 );
3701             break;
3702         default:
3703             ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", i | 0x80000000, awareness );
3704             ok( !pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x80000000) ),
3705                 "%lx: valid\n", i | 0x80000000 );
3706             break;
3707         }
3708         awareness = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i );
3709         switch (~i)
3710         {
3711         case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
3712         case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
3713         case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
3714             ok( awareness == i, "%lx: wrong value %u\n", ~i, awareness );
3715             ok( pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ), "%lx: not valid\n", ~i );
3716             break;
3717         case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2:
3718             if (pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ))
3719                 ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "%lx: wrong value %u\n", ~i, awareness );
3720             else
3721                 ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", ~i, awareness );
3722             break;
3723         case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED:
3724             if (pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ))
3725                 ok( awareness == DPI_AWARENESS_UNAWARE, "%lx: wrong value %u\n", ~i, awareness );
3726             else
3727                 ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", ~i, awareness );
3728             break;
3729         default:
3730             ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", ~i, awareness );
3731             ok( !pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ), "%lx: valid\n", ~i );
3732             break;
3733         }
3734     }
3735     if (real_dpi != USER_DEFAULT_SCREEN_DPI) test_dpi_stock_objects( hdc );
3736     ReleaseDC( 0, hdc );
3737 }
3738 
3739 static LRESULT CALLBACK dpi_winproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
3740 {
3741     DPI_AWARENESS_CONTEXT ctx = pGetWindowDpiAwarenessContext( hwnd );
3742     DPI_AWARENESS_CONTEXT ctx2 = pGetThreadDpiAwarenessContext();
3743     DWORD pos, pos2;
3744 
3745     ok( pGetAwarenessFromDpiAwarenessContext( ctx ) == pGetAwarenessFromDpiAwarenessContext( ctx2 ),
3746         "msg %04x wrong awareness %p / %p\n", msg, ctx, ctx2 );
3747     pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE );
3748     pos = GetMessagePos();
3749     pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
3750     pos2 = GetMessagePos();
3751     ok( pos == pos2, "wrong pos %08x / %08x\n", pos, pos2 );
3752     pSetThreadDpiAwarenessContext( ctx2 );
3753     return DefWindowProcA( hwnd, msg, wp, lp );
3754 }
3755 
3756 static void test_dpi_window(void)
3757 {
3758     DPI_AWARENESS_CONTEXT context, orig;
3759     DPI_AWARENESS awareness;
3760     ULONG_PTR i, j;
3761     UINT dpi;
3762     HWND hwnd, child, ret;
3763     MSG msg = { 0, WM_USER + 1, 0, 0 };
3764 
3765     if (!pGetWindowDpiAwarenessContext)
3766     {
3767         win_skip( "GetWindowDpiAwarenessContext not supported\n" );
3768         return;
3769     }
3770     orig = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE );
3771     for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++)
3772     {
3773         pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i );
3774         hwnd = CreateWindowA( "DpiTestClass", "Test",
3775                               WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
3776         ok( hwnd != 0, "failed to create window\n" );
3777         context = pGetWindowDpiAwarenessContext( hwnd );
3778         awareness = pGetAwarenessFromDpiAwarenessContext( context );
3779         ok( awareness == i, "%lu: wrong awareness %u\n", i, awareness );
3780         dpi = pGetDpiForWindow( hwnd );
3781         ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi),
3782             "%lu: got %u / %u\n", i, dpi, real_dpi );
3783         if (pGetDpiForMonitorInternal)
3784         {
3785             BOOL res;
3786             SetLastError( 0xdeadbeef );
3787             res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 0, &dpi, NULL );
3788             ok( !res, "succeeded\n" );
3789             ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() );
3790             SetLastError( 0xdeadbeef );
3791             res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 3, &dpi, &dpi );
3792             ok( !res, "succeeded\n" );
3793             ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %u\n", GetLastError() );
3794             SetLastError( 0xdeadbeef );
3795             res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 3, &dpi, NULL );
3796             ok( !res, "succeeded\n" );
3797             ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %u\n", GetLastError() );
3798             res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 0, &dpi, &dpi );
3799             ok( res, "failed err %u\n", GetLastError() );
3800             ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi),
3801                 "%lu: got %u / %u\n", i, dpi, real_dpi );
3802         }
3803         msg.hwnd = hwnd;
3804         for (j = DPI_AWARENESS_UNAWARE; j <= DPI_AWARENESS_PER_MONITOR_AWARE; j++)
3805         {
3806             pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j );
3807             SendMessageA( hwnd, WM_USER, 0, 0 );
3808             DispatchMessageA( &msg );
3809             CallWindowProcA( dpi_winproc, hwnd, WM_USER + 2, 0, 0 );
3810             child = CreateWindowA( "DpiTestClass", "Test",
3811                                    WS_CHILD, 0, 0, 100, 100, hwnd, 0, GetModuleHandleA(0), NULL );
3812             context = pGetWindowDpiAwarenessContext( child );
3813             awareness = pGetAwarenessFromDpiAwarenessContext( context );
3814             ok( awareness == i, "%lu/%lu: wrong awareness %u\n", i, j, awareness );
3815             dpi = pGetDpiForWindow( child );
3816             ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi),
3817                 "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi );
3818             ret = SetParent( child, NULL );
3819             ok( ret != 0, "SetParent failed err %u\n", GetLastError() );
3820             context = pGetWindowDpiAwarenessContext( child );
3821             awareness = pGetAwarenessFromDpiAwarenessContext( context );
3822             ok( awareness == i, "%lu/%lu: wrong awareness %u\n", i, j, awareness );
3823             dpi = pGetDpiForWindow( child );
3824             ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi),
3825                 "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi );
3826             DestroyWindow( child );
3827             child = CreateWindowA( "DpiTestClass", "Test",
3828                                    WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
3829             context = pGetWindowDpiAwarenessContext( child );
3830             awareness = pGetAwarenessFromDpiAwarenessContext( context );
3831             ok( awareness == j, "%lu/%lu: wrong awareness %u\n", i, j, awareness );
3832             dpi = pGetDpiForWindow( child );
3833             ok( dpi == (j == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi),
3834                 "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi );
3835             ret = SetParent( child, hwnd );
3836             ok( ret != 0 || GetLastError() == ERROR_INVALID_STATE,
3837                 "SetParent failed err %u\n", GetLastError() );
3838             context = pGetWindowDpiAwarenessContext( child );
3839             awareness = pGetAwarenessFromDpiAwarenessContext( context );
3840             ok( awareness == (ret ? i : j), "%lu/%lu: wrong awareness %u\n", i, j, awareness );
3841             dpi = pGetDpiForWindow( child );
3842             ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi),
3843                 "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi );
3844             DestroyWindow( child );
3845         }
3846         DestroyWindow( hwnd );
3847     }
3848 
3849     SetLastError( 0xdeadbeef );
3850     context = pGetWindowDpiAwarenessContext( (HWND)0xdeadbeef );
3851     ok( !context, "got %p\n", context );
3852     ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
3853     SetLastError( 0xdeadbeef );
3854     dpi = pGetDpiForWindow( (HWND)0xdeadbeef );
3855     ok( !dpi, "got %u\n", dpi );
3856     ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_WINDOW_HANDLE,
3857         "wrong error %u\n", GetLastError() );
3858 
3859     SetLastError( 0xdeadbeef );
3860     context = pGetWindowDpiAwarenessContext( GetDesktopWindow() );
3861     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3862     ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness );
3863     dpi = pGetDpiForWindow( GetDesktopWindow() );
3864     ok( dpi == real_dpi, "got %u / %u\n", dpi, real_dpi );
3865 
3866     pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE );
3867     SetLastError( 0xdeadbeef );
3868     context = pGetWindowDpiAwarenessContext( GetDesktopWindow() );
3869     awareness = pGetAwarenessFromDpiAwarenessContext( context );
3870     ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness );
3871     dpi = pGetDpiForWindow( GetDesktopWindow() );
3872     ok( dpi == real_dpi, "got %u / %u\n", dpi, real_dpi );
3873 
3874     pSetThreadDpiAwarenessContext( orig );
3875 }
3876 
3877 static void test_GetAutoRotationState(void)
3878 {
3879     AR_STATE state;
3880     BOOL ret;
3881 
3882     if (!pGetAutoRotationState)
3883     {
3884         win_skip("GetAutoRotationState not supported\n");
3885         return;
3886     }
3887 
3888     SetLastError(0xdeadbeef);
3889     ret = pGetAutoRotationState(NULL);
3890     ok(!ret, "Expected GetAutoRotationState to fail\n");
3891     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3892 
3893     state = 0;
3894     ret = pGetAutoRotationState(&state);
3895     ok(ret, "Expected GetAutoRotationState to succeed, error %d\n", GetLastError());
3896 }
3897 
3898 START_TEST(sysparams)
3899 {
3900     int argc;
3901     char** argv;
3902     WNDCLASSA wc;
3903     MSG msg;
3904     HDC hdc;
3905     HANDLE hThread;
3906     DWORD dwThreadId;
3907     HANDLE hInstance, hdll;
3908 
3909     hdll = GetModuleHandleA("user32.dll");
3910     pChangeDisplaySettingsExA = (void*)GetProcAddress(hdll, "ChangeDisplaySettingsExA");
3911     pIsProcessDPIAware = (void*)GetProcAddress(hdll, "IsProcessDPIAware");
3912     pSetProcessDPIAware = (void*)GetProcAddress(hdll, "SetProcessDPIAware");
3913     pGetDpiForSystem = (void*)GetProcAddress(hdll, "GetDpiForSystem");
3914     pGetDpiForWindow = (void*)GetProcAddress(hdll, "GetDpiForWindow");
3915     pGetDpiForMonitorInternal = (void*)GetProcAddress(hdll, "GetDpiForMonitorInternal");
3916     pSetProcessDpiAwarenessContext = (void*)GetProcAddress(hdll, "SetProcessDpiAwarenessContext");
3917     pGetProcessDpiAwarenessInternal = (void*)GetProcAddress(hdll, "GetProcessDpiAwarenessInternal");
3918     pSetProcessDpiAwarenessInternal = (void*)GetProcAddress(hdll, "SetProcessDpiAwarenessInternal");
3919     pGetThreadDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetThreadDpiAwarenessContext");
3920     pSetThreadDpiAwarenessContext = (void*)GetProcAddress(hdll, "SetThreadDpiAwarenessContext");
3921     pGetWindowDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetWindowDpiAwarenessContext");
3922     pGetAwarenessFromDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetAwarenessFromDpiAwarenessContext");
3923     pIsValidDpiAwarenessContext = (void*)GetProcAddress(hdll, "IsValidDpiAwarenessContext");
3924     pGetSystemMetricsForDpi = (void*)GetProcAddress(hdll, "GetSystemMetricsForDpi");
3925     pSystemParametersInfoForDpi = (void*)GetProcAddress(hdll, "SystemParametersInfoForDpi");
3926     pAdjustWindowRectExForDpi = (void*)GetProcAddress(hdll, "AdjustWindowRectExForDpi");
3927     pLogicalToPhysicalPointForPerMonitorDPI = (void*)GetProcAddress(hdll, "LogicalToPhysicalPointForPerMonitorDPI");
3928     pPhysicalToLogicalPointForPerMonitorDPI = (void*)GetProcAddress(hdll, "PhysicalToLogicalPointForPerMonitorDPI");
3929     pGetAutoRotationState = (void*)GetProcAddress(hdll, "GetAutoRotationState");
3930 
3931     hInstance = GetModuleHandleA( NULL );
3932     hdc = GetDC(0);
3933     dpi = GetDeviceCaps( hdc, LOGPIXELSY);
3934     real_dpi = get_real_dpi();
3935     trace("dpi %d real_dpi %d\n", dpi, real_dpi);
3936     ReleaseDC( 0, hdc);
3937 
3938     /* This test requires interactivity, if we don't have it, give up */
3939     if (!SystemParametersInfoA( SPI_SETBEEP, TRUE, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ) &&
3940         GetLastError()==ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION) return;
3941 
3942     argc = winetest_get_mainargs(&argv);
3943     strict=(argc >= 3 && strcmp(argv[2],"strict")==0);
3944     trace("strict=%d\n",strict);
3945 
3946     trace("testing GetSystemMetrics with your current desktop settings\n");
3947     test_GetSystemMetrics( );
3948     test_metrics_for_dpi( 192 );
3949     test_EnumDisplaySettings( );
3950     test_GetSysColorBrush( );
3951     test_GetAutoRotationState( );
3952 
3953     change_counter = 0;
3954     change_last_param = 0;
3955 
3956     wc.lpszClassName = "SysParamsTestClass";
3957     wc.lpfnWndProc = SysParamsTestWndProc;
3958     wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
3959     wc.hInstance = hInstance;
3960     wc.hIcon = LoadIconA( 0, (LPCSTR)IDI_APPLICATION );
3961     wc.hCursor = LoadCursorA( 0, (LPCSTR)IDC_ARROW );
3962     wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
3963     wc.lpszMenuName = 0;
3964     wc.cbClsExtra = 0;
3965     wc.cbWndExtra = 0;
3966     RegisterClassA( &wc );
3967     wc.lpszClassName = "DpiTestClass";
3968     wc.lpfnWndProc = dpi_winproc;
3969     RegisterClassA( &wc );
3970 
3971     ghTestWnd = CreateWindowA( "SysParamsTestClass", "Test System Parameters Application",
3972                                WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, hInstance, NULL );
3973 
3974     hThread = CreateThread( NULL, 0, SysParamsThreadFunc, 0, 0, &dwThreadId );
3975     assert( hThread );
3976     CloseHandle( hThread );
3977 
3978     while( GetMessageA( &msg, 0, 0, 0 )) {
3979         TranslateMessage( &msg );
3980         DispatchMessageA( &msg );
3981     }
3982 
3983     if (pSetThreadDpiAwarenessContext)
3984     {
3985         test_dpi_context();
3986         test_dpi_mapping();
3987         test_dpi_window();
3988     }
3989     else win_skip( "SetThreadDpiAwarenessContext not supported\n" );
3990 
3991     test_dpi_aware();
3992 }
3993