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