1 
2 #include <apitest.h>
3 
4 #include <wingdi.h>
5 #include <winuser.h>
6 
7 #include "resource.h"
8 
9 // FIXME user32
10 
11 void
12 Test_GetIconInfo(BOOL fIcon, DWORD screen_bpp)
13 {
14     HICON hicon;
15     ICONINFO iconinfo, iconinfo2;
16     BITMAP bitmap;
17 
18     iconinfo.fIcon = fIcon;
19     iconinfo.xHotspot = 0;
20     iconinfo.yHotspot = 0;
21     iconinfo.hbmMask = NULL;
22     iconinfo.hbmColor = NULL;
23 
24     hicon = CreateIconIndirect(&iconinfo);
25     ok(hicon == 0, "should fail\n");
26 
27     iconinfo.hbmMask = CreateBitmap(8, 16, 1, 1, NULL);
28     hicon = CreateIconIndirect(&iconinfo);
29     ok(hicon != 0, "should not fail\n");
30 
31     ok(GetIconInfo(hicon, &iconinfo2), "\n");
32     ok(iconinfo2.fIcon == iconinfo.fIcon, "\n");
33     if (fIcon)
34     {
35         ok(iconinfo2.xHotspot == 4, "%ld\n", iconinfo2.xHotspot);
36         ok(iconinfo2.yHotspot == 4, "%ld\n", iconinfo2.yHotspot);
37     }
38     else
39     {
40         ok(iconinfo2.xHotspot == 0, "%ld\n", iconinfo2.xHotspot);
41         ok(iconinfo2.yHotspot == 0, "%ld\n", iconinfo2.yHotspot);
42     }
43     ok(iconinfo2.hbmMask != NULL, "\n");
44     ok(iconinfo2.hbmMask != iconinfo.hbmMask, "\n");
45     ok(iconinfo2.hbmColor == NULL, "\n");
46     DeleteObject(iconinfo2.hbmMask);
47 
48     ok(GetIconInfo(hicon, &iconinfo2), "\n");
49     ok(iconinfo2.fIcon == iconinfo.fIcon, "\n");
50     if (fIcon)
51     {
52         ok(iconinfo2.xHotspot == 4, "%ld\n", iconinfo2.xHotspot);
53         ok(iconinfo2.yHotspot == 4, "%ld\n", iconinfo2.yHotspot);
54     }
55     else
56     {
57         ok(iconinfo2.xHotspot == 0, "%ld\n", iconinfo2.xHotspot);
58         ok(iconinfo2.yHotspot == 0, "%ld\n", iconinfo2.yHotspot);
59     }
60     ok(iconinfo2.hbmMask != NULL, "\n");
61     ok(iconinfo2.hbmMask != iconinfo.hbmMask, "\n");
62     ok(iconinfo2.hbmColor == NULL, "\n");
63     DeleteObject(iconinfo2.hbmMask);
64     ok(DestroyIcon(hicon), "\n");
65 
66     iconinfo.hbmColor = CreateBitmap(2, 2, 1, 1, NULL);
67     hicon = CreateIconIndirect(&iconinfo);
68     ok(hicon != 0, "should not fail\n");
69 
70     ok(GetIconInfo(hicon, &iconinfo2), "\n");
71     ok(iconinfo2.fIcon == iconinfo.fIcon, "\n");
72     if (fIcon)
73     {
74         ok(iconinfo2.xHotspot == 4, "%ld\n", iconinfo2.xHotspot);
75         ok(iconinfo2.yHotspot == 8, "%ld\n", iconinfo2.yHotspot);
76     }
77     else
78     {
79         ok(iconinfo2.xHotspot == 0, "%ld\n", iconinfo2.xHotspot);
80         ok(iconinfo2.yHotspot == 0, "%ld\n", iconinfo2.yHotspot);
81     }
82     ok(iconinfo2.hbmMask != NULL, "\n");
83     ok(iconinfo2.hbmMask != iconinfo.hbmMask, "\n");
84     ok(iconinfo2.hbmColor != NULL, "\n");
85     ok(iconinfo2.hbmColor != iconinfo.hbmColor, "\n");
86 
87     ok(GetObject(iconinfo2.hbmMask, sizeof(bitmap), &bitmap), "GetObject failed\n");
88     ok(bitmap.bmType == 0, "\n");
89     ok(bitmap.bmWidth == 8, "\n");
90     ok(bitmap.bmHeight == 16, "\n");
91     ok(bitmap.bmWidthBytes == 2, "\n");
92     ok(bitmap.bmPlanes == 1, "\n");
93     ok(bitmap.bmBitsPixel == 1, "\n");
94     ok(bitmap.bmBits == NULL, "\n");
95 
96     ok(GetObject(iconinfo2.hbmColor, sizeof(bitmap), &bitmap), "GetObject failed\n");
97     ok(bitmap.bmType == 0, "\n");
98     ok(bitmap.bmWidth == 8, "\n");
99     ok(bitmap.bmHeight == 16, "\n");
100     ok(bitmap.bmWidthBytes == 8 * bitmap.bmBitsPixel / 8, "\n");
101     ok(bitmap.bmPlanes == 1, "\n");
102     ok(bitmap.bmBitsPixel == screen_bpp, "%d\n", bitmap.bmBitsPixel);
103     ok(bitmap.bmBits == NULL, "\n");
104     DeleteObject(iconinfo2.hbmMask);
105     DeleteObject(iconinfo2.hbmColor);
106     ok(DestroyIcon(hicon), "\n");
107 
108     DeleteObject(iconinfo.hbmMask);
109     iconinfo.hbmMask = NULL;
110     hicon = CreateIconIndirect(&iconinfo);
111     ok(hicon == 0, "should fail\n");
112 
113     DeleteObject(iconinfo.hbmColor);
114     iconinfo.hbmColor = CreateCompatibleBitmap(GetDC(0), 16, 16);
115     hicon = CreateIconIndirect(&iconinfo);
116     ok(hicon == 0, "should fail\n");
117 
118     iconinfo.hbmMask = CreateCompatibleBitmap(GetDC(0), 8, 16);
119     hicon = CreateIconIndirect(&iconinfo);
120     ok(hicon != 0, "should not fail\n");
121 
122     ok(GetIconInfo(hicon, &iconinfo2), "\n");
123 
124     ok(GetObject(iconinfo2.hbmMask, sizeof(bitmap), &bitmap), "GetObject failed\n");
125     ok(bitmap.bmType == 0, "\n");
126     ok(bitmap.bmWidth == 8, "%ld\n", bitmap.bmWidth);
127     ok(bitmap.bmHeight == 16, "%ld\n", bitmap.bmHeight);
128     ok(bitmap.bmWidthBytes == 2, "%ld\n", bitmap.bmWidthBytes);
129     ok(bitmap.bmPlanes == 1, "%d\n", bitmap.bmPlanes);
130     ok(bitmap.bmBitsPixel == 1, "%d\n", bitmap.bmBitsPixel);
131     ok(bitmap.bmBits == NULL, "\n");
132 
133     ok(GetObject(iconinfo2.hbmColor, sizeof(bitmap), &bitmap), "GetObject failed\n");
134     ok(bitmap.bmType == 0, "\n");
135     ok(bitmap.bmWidth == 8, "%ld\n", bitmap.bmWidth);
136     ok(bitmap.bmHeight == 16, "%ld\n", bitmap.bmHeight);
137     ok(bitmap.bmWidthBytes == screen_bpp, "%ld\n", bitmap.bmWidthBytes);
138     ok(bitmap.bmPlanes == 1, "%d\n", bitmap.bmPlanes);
139     ok(bitmap.bmBitsPixel == screen_bpp, "%d\n", bitmap.bmBitsPixel);
140     ok(bitmap.bmBits == NULL, "\n");
141     DeleteObject(iconinfo2.hbmMask);
142     DeleteObject(iconinfo2.hbmColor);
143     ok(DestroyIcon(hicon), "\n");
144 }
145 
146 
147 START_TEST(GetIconInfo)
148 {
149     HCURSOR hcursor;
150     ICONINFO iconinfo2;
151     BITMAP bitmap;
152     DWORD data[] = {0, 0, 0, 0, 0, 0};
153     DWORD bpp, screenbpp, creationbpp;
154     DEVMODEW dm;
155 
156     dm.dmSize = sizeof(dm);
157     dm.dmDriverExtra = 0;
158 
159     /* Test icons behaviour regarding display settings */
160     ok(EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dm), "\n");
161     screenbpp = dm.dmBitsPerPel;
162 
163     trace("Icon default size: %dx%d.\n", GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
164     trace("Cursor default size: %dx%d.\n", GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR));
165 
166     trace("Screen bpp: %lu.\n", screenbpp);
167     Test_GetIconInfo(FALSE, screenbpp);
168     Test_GetIconInfo(TRUE, screenbpp);
169 
170     hcursor = LoadCursor(GetModuleHandle(NULL), "TESTCURSOR");
171     ok(hcursor != 0, "should not fail, error %ld\n", GetLastError());
172     ok(GetIconInfo(hcursor, &iconinfo2), "\n");
173     ok(iconinfo2.fIcon == 0, "\n");
174     ok(iconinfo2.xHotspot == 8, "%ld\n", iconinfo2.xHotspot);
175     ok(iconinfo2.yHotspot == 29, "%ld\n", iconinfo2.yHotspot);
176     ok(iconinfo2.hbmMask != NULL, "\n");
177     ok(iconinfo2.hbmColor != NULL, "\n");
178     /* Delete objects */
179     DeleteObject(iconinfo2.hbmColor);
180     DeleteObject(iconinfo2.hbmMask);
181     /* Delete cursor */
182     DestroyCursor(hcursor);
183 
184     /* To sum it up:
185      * There are two criteria when using icons: performance and aesthetics (=alpha channel).
186      * Performance asks for bit parity with the screen display.
187      * Aesthetics needs a 32bpp bitmap.
188      * The behaviour is basically : aesthetics first if already loaded.
189      * ie: if the 32bpp bitmap were already loaded because of previous display settings, always use it.
190      * Otherwise, use the bitmap matching the screen bit depth.
191      */
192 
193     /* if we use LR_SHARED here, and reverse the loop (32->16), then hbmColor.bmBitsPixel is always 32. */
194     for(creationbpp = 16; creationbpp <=32; creationbpp += 8)
195     {
196         dm.dmBitsPerPel = creationbpp;
197         if(ChangeDisplaySettingsExW(NULL, &dm, NULL, 0, NULL) != DISP_CHANGE_SUCCESSFUL)
198         {
199             skip("Unable to change bpp to %lu.\n", creationbpp);
200             continue;
201         }
202         trace("starting with creationbpp = %lu\n", creationbpp);
203         hcursor = LoadImage(GetModuleHandle(NULL),
204             MAKEINTRESOURCE(IDI_TEST),
205             IMAGE_ICON,
206             0,
207             0,
208             LR_DEFAULTCOLOR);
209         ok(hcursor != 0, "should not fail\n");
210 
211         /* If we reverse the loop here (32->16 bpp), then hbmColor.bmBitsPixel is always 32 */
212         for(bpp = 16; bpp <=32; bpp += 8)
213         {
214             trace("testing resetting to %lu\n", bpp);
215             dm.dmBitsPerPel = bpp;
216             if(ChangeDisplaySettingsExW(NULL, &dm, NULL, 0, NULL) != DISP_CHANGE_SUCCESSFUL)
217             {
218                 skip("Unable to change bpp to %lu.\n", bpp);
219                 continue;
220             }
221             ok(GetIconInfo(hcursor, &iconinfo2), "\n");
222             ok(iconinfo2.fIcon == 1, "\n");
223             ok(iconinfo2.xHotspot == 24, "%ld\n", iconinfo2.xHotspot);
224             ok(iconinfo2.yHotspot == 24, "%ld\n", iconinfo2.yHotspot);
225             ok(iconinfo2.hbmMask != NULL, "\n");
226             ok(iconinfo2.hbmColor != NULL, "\n");
227 
228             ok(GetObject(iconinfo2.hbmMask, sizeof(bitmap), &bitmap), "GetObject failed\n");
229             ok(bitmap.bmType == 0, "\n");
230             ok(bitmap.bmWidth == 48, "%ld\n", bitmap.bmWidth);
231             ok(bitmap.bmHeight == 48, "\n");
232             ok(bitmap.bmWidthBytes == 6, "\n");
233             ok(bitmap.bmPlanes == 1, "\n");
234             ok(bitmap.bmBitsPixel == 1, "\n");
235             ok(bitmap.bmBits == NULL, "\n");
236 
237             ok(GetObject(iconinfo2.hbmColor, sizeof(bitmap), &bitmap), "GetObject failed\n");
238             ok(bitmap.bmType == 0, "\n");
239             ok(bitmap.bmWidth == 48, "\n");
240             ok(bitmap.bmHeight == 48, "\n");
241             ok(bitmap.bmWidthBytes == 48 * bitmap.bmBitsPixel / 8, "\n");
242             ok(bitmap.bmPlanes == 1, "\n");
243             ok(bitmap.bmBitsPixel == (creationbpp == 32 ? 32 : bpp), "creationbpp: %lu, bpp: %lu:\n", creationbpp, bpp);
244             ok(bitmap.bmBits == NULL, "\n");
245 
246             /* Delete objects */
247             DeleteObject(iconinfo2.hbmColor);
248             DeleteObject(iconinfo2.hbmMask);
249         }
250         ok(DestroyIcon(hcursor), "\n");
251     }
252     /* Restore display settings */
253     dm.dmBitsPerPel = screenbpp;
254     if(ChangeDisplaySettingsExW(NULL, &dm, NULL, 0, NULL) != DISP_CHANGE_SUCCESSFUL)
255         trace("Unable to go back to previous display settings. Sorry.\n");
256 
257     hcursor = CreateCursor(NULL, 1, 2, 4, 4, data, data);
258     ok(hcursor != 0, "should not fail\n");
259     ok(GetIconInfo(hcursor, &iconinfo2), "\n");
260     ok(iconinfo2.fIcon == 0, "\n");
261     ok(iconinfo2.xHotspot == 1, "%ld\n", iconinfo2.xHotspot);
262     ok(iconinfo2.yHotspot == 2, "%ld\n", iconinfo2.yHotspot);
263     ok(iconinfo2.hbmMask != NULL, "\n");
264     ok(iconinfo2.hbmColor == NULL, "\n");
265 
266     ok(GetObject(iconinfo2.hbmMask, sizeof(bitmap), &bitmap), "GetObject failed\n");
267     ok(bitmap.bmType == 0, "\n");
268     ok(bitmap.bmWidth == 4, "%ld\n", bitmap.bmWidth);
269     ok(bitmap.bmHeight == 8, "%ld\n", bitmap.bmHeight);
270     ok(bitmap.bmWidthBytes == 2, "%ld\n", bitmap.bmWidthBytes);
271     ok(bitmap.bmPlanes == 1, "\n");
272     ok(bitmap.bmBitsPixel == 1, "\n");
273     ok(bitmap.bmBits == NULL, "\n");
274 
275     /* Delete objects */
276     DeleteObject(iconinfo2.hbmColor);
277     DeleteObject(iconinfo2.hbmMask);
278     /* Delete cursor */
279     DestroyCursor(hcursor);
280 }
281 
282 
283