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