CreateFile() fails with INVALID_HANDLE_VALUE, not NULL - this fixes GetLastError...
[reactos.git] / reactos / lib / user32 / windows / bitmap.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
23 * PURPOSE: Input
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * UPDATE HISTORY:
26 * 09-05-2001 CSH Created
27 */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <user32.h>
32
33 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
34 HICON ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
35 HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
36 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
37 CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
38
39 /* FUNCTIONS *****************************************************************/
40
41 /*
42 * @implemented
43 */
44 HANDLE STDCALL
45 LoadImageA(HINSTANCE hinst,
46 LPCSTR lpszName,
47 UINT uType,
48 int cxDesired,
49 int cyDesired,
50 UINT fuLoad)
51 {
52 LPWSTR lpszWName;
53 HANDLE Handle;
54 UNICODE_STRING NameString;
55
56 if (HIWORD(lpszName))
57 {
58 RtlCreateUnicodeStringFromAsciiz(&NameString, (LPSTR)lpszName);
59 lpszWName = NameString.Buffer;
60 Handle = LoadImageW(hinst, lpszWName, uType, cxDesired,
61 cyDesired, fuLoad);
62 RtlFreeUnicodeString(&NameString);
63 }
64 else
65 {
66 Handle = LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired,
67 cyDesired, fuLoad);
68 }
69
70 return Handle;
71 }
72
73
74 static HANDLE
75 LoadCursorIconImage(
76 HINSTANCE hinst,
77 LPCWSTR lpszName,
78 INT width,
79 INT height,
80 UINT fuLoad,
81 ULONG uType)
82 {
83 HANDLE hResource;
84 HANDLE h2Resource;
85 HANDLE hfRes;
86 HANDLE hFile;
87 HANDLE hSection;
88 CURSORICONDIR *IconDIR;
89 HDC hScreenDc;
90 HICON hIcon;
91 ULONG HeaderSize;
92 ULONG ColorCount;
93 ULONG ColorBits;
94 PVOID Data;
95 CURSORICONDIRENTRY* dirEntry;
96 ICONIMAGE* SafeIconImage;
97 GRPCURSORICONDIR* IconResDir;
98 INT id;
99 ICONIMAGE *ResIcon;
100 BOOL Icon = (uType == IMAGE_ICON);
101
102 if (!(fuLoad & LR_LOADFROMFILE))
103 {
104 if (hinst == NULL)
105 hinst = User32Instance;
106
107 hResource = hfRes = FindResourceW(hinst, lpszName,
108 Icon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
109 if (hResource == NULL)
110 return NULL;
111
112 if (fuLoad & LR_SHARED)
113 {
114 hIcon = NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, width, height);
115 if (hIcon)
116 return hIcon;
117 }
118
119 hResource = LoadResource(hinst, hResource);
120 if (hResource == NULL)
121 return NULL;
122
123 IconResDir = LockResource(hResource);
124 if (IconResDir == NULL)
125 return NULL;
126
127 /*
128 * Find the best fitting in the IconResDir for this resolution
129 */
130
131 id = LookupIconIdFromDirectoryEx((PBYTE)IconResDir, Icon, width, height,
132 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
133
134 h2Resource = FindResourceW(hinst, MAKEINTRESOURCEW(id),
135 Icon ? MAKEINTRESOURCEW(RT_ICON) :
136 MAKEINTRESOURCEW(RT_CURSOR));
137
138 hResource = LoadResource(hinst, h2Resource);
139 if (hResource == NULL)
140 return NULL;
141
142 ResIcon = LockResource(hResource);
143 if (ResIcon == NULL)
144 return NULL;
145
146 hIcon = CreateIconFromResourceEx((PBYTE)ResIcon,
147 SizeofResource(hinst, h2Resource),
148 Icon, 0x00030000, width, height,
149 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
150 if (hIcon && 0 != (fuLoad & LR_SHARED))
151 {
152 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
153 (HRSRC)NULL);
154 }
155
156 return hIcon;
157 }
158
159 /*
160 * FIXME: This code is incorrect and is likely to crash in many cases.
161 * In the file the cursor/icon directory records are stored like
162 * CURSORICONFILEDIR, but we treat them like CURSORICONDIR. In Wine
163 * this is solved by creating a fake cursor/icon directory in memory
164 * and passing that to CURSORICON_FindBestIcon.
165 */
166
167 if (fuLoad & LR_SHARED)
168 {
169 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
170 }
171
172 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
173 OPEN_EXISTING, 0, NULL);
174 if (hFile == INVALID_HANDLE_VALUE)
175 return NULL;
176
177 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
178 CloseHandle(hFile);
179 if (hSection == NULL)
180 return NULL;
181
182 IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
183 CloseHandle(hSection);
184 if (IconDIR == NULL)
185 return NULL;
186
187 if (0 != IconDIR->idReserved ||
188 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
189 {
190 UnmapViewOfFile(IconDIR);
191 return NULL;
192 }
193
194 /* Get a handle to the screen dc, the icon we create is going to be
195 * compatable with this. */
196 hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
197 if (hScreenDc == NULL)
198 {
199 UnmapViewOfFile(IconDIR);
200 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
201 return NULL;
202 }
203
204 if (fuLoad & LR_MONOCHROME)
205 {
206 ColorBits = 1;
207 }
208 else
209 {
210 ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
211 /*
212 * FIXME:
213 * Remove this after proper support for alpha icons will be finished.
214 */
215 if (ColorBits > 8)
216 ColorBits = 8;
217 }
218
219 /* Pick the best size. */
220 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, width, height, ColorBits);
221 if (!dirEntry)
222 {
223 DeleteDC(hScreenDc);
224 UnmapViewOfFile(IconDIR);
225 return NULL;
226 }
227
228 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
229 if (SafeIconImage == NULL)
230 {
231 DeleteDC(hScreenDc);
232 UnmapViewOfFile(IconDIR);
233 return NULL;
234 }
235
236 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
237 UnmapViewOfFile(IconDIR);
238
239 /* At this point we have a copy of the icon image to play with. */
240
241 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
242
243 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
244 {
245 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
246 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
247 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
248 }
249 else
250 {
251 ColorCount = SafeIconImage->icHeader.biClrUsed;
252 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
253 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
254 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
255 }
256
257 /* Make data point to the start of the XOR image data. */
258 Data = (PBYTE)SafeIconImage + HeaderSize;
259
260 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
261 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
262 DeleteDC(hScreenDc);
263
264 return hIcon;
265 }
266
267
268 static HANDLE
269 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
270 {
271 HANDLE hResource;
272 HANDLE hFile;
273 HANDLE hSection;
274 LPBITMAPINFO BitmapInfo;
275 LPBITMAPINFO PrivateInfo;
276 HDC hScreenDc;
277 HANDLE hBitmap;
278 ULONG HeaderSize;
279 ULONG ColorCount;
280 PVOID Data;
281
282 if (!(fuLoad & LR_LOADFROMFILE))
283 {
284 if (hInstance == NULL)
285 hInstance = User32Instance;
286
287 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
288 if (hResource == NULL)
289 return NULL;
290 hResource = LoadResource(hInstance, hResource);
291 if (hResource == NULL)
292 return NULL;
293 BitmapInfo = LockResource(hResource);
294 if (BitmapInfo == NULL)
295 return NULL;
296 }
297 else
298 {
299 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
300 OPEN_EXISTING, 0, NULL);
301 if (hFile == INVALID_HANDLE_VALUE)
302 return NULL;
303
304 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
305 CloseHandle(hFile);
306 if (hSection == NULL)
307 return NULL;
308
309 BitmapInfo = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
310 CloseHandle(hSection);
311 if (BitmapInfo == NULL)
312 return NULL;
313
314 BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
315 }
316
317 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
318 {
319 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
320 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
321 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
322 }
323 else
324 {
325 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
326 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
327 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
328 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
329 }
330 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
331
332 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
333 if (PrivateInfo == NULL)
334 {
335 if (fuLoad & LR_LOADFROMFILE)
336 UnmapViewOfFile(BitmapInfo);
337 return NULL;
338 }
339 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
340
341 /* FIXME: Handle color conversion and transparency. */
342
343 hScreenDc = CreateCompatibleDC(NULL);
344 if (hScreenDc == NULL)
345 {
346 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
347 if (fuLoad & LR_LOADFROMFILE)
348 UnmapViewOfFile(BitmapInfo);
349 return NULL;
350 }
351
352 if (fuLoad & LR_CREATEDIBSECTION)
353 {
354 DIBSECTION Dib;
355
356 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
357 0, 0);
358 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
359 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
360 DIB_RGB_COLORS);
361 }
362 else
363 {
364 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
365 Data, PrivateInfo, DIB_RGB_COLORS);
366 }
367
368 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
369 DeleteDC(hScreenDc);
370 if (fuLoad & LR_LOADFROMFILE)
371 UnmapViewOfFile(BitmapInfo);
372
373 return hBitmap;
374 }
375
376 HANDLE STDCALL
377 LoadImageW(
378 IN HINSTANCE hinst,
379 IN LPCWSTR lpszName,
380 IN UINT uType,
381 IN INT cxDesired,
382 IN INT cyDesired,
383 IN UINT fuLoad)
384 {
385 if (fuLoad & LR_DEFAULTSIZE)
386 {
387 if (uType == IMAGE_ICON)
388 {
389 if (cxDesired == 0)
390 cxDesired = GetSystemMetrics(SM_CXICON);
391 if (cyDesired == 0)
392 cyDesired = GetSystemMetrics(SM_CYICON);
393 }
394 else if (uType == IMAGE_CURSOR)
395 {
396 if (cxDesired == 0)
397 cxDesired = GetSystemMetrics(SM_CXCURSOR);
398 if (cyDesired == 0)
399 cyDesired = GetSystemMetrics(SM_CYCURSOR);
400 }
401 }
402
403 switch (uType)
404 {
405 case IMAGE_BITMAP:
406 return LoadBitmapImage(hinst, lpszName, fuLoad);
407 case IMAGE_CURSOR:
408 case IMAGE_ICON:
409 return LoadCursorIconImage(hinst, lpszName, cxDesired, cyDesired,
410 fuLoad, uType);
411 default:
412 break;
413 }
414
415 return NULL;
416 }
417
418
419 /*
420 * @implemented
421 */
422 HBITMAP STDCALL
423 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
424 {
425 return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
426 }
427
428
429 /*
430 * @implemented
431 */
432 HBITMAP STDCALL
433 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
434 {
435 return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
436 }
437
438
439 /*
440 * @unimplemented
441 */
442 HANDLE WINAPI
443 CopyImage(
444 IN HANDLE hnd,
445 IN UINT type,
446 IN INT desiredx,
447 IN INT desiredy,
448 IN UINT flags)
449 {
450 HBITMAP res;
451 BITMAP bm;
452
453 switch (type)
454 {
455 case IMAGE_BITMAP:
456 {
457 DbgPrint("WARNING: Incomplete implementation of CopyImage!\n");
458 /*
459 * FIXME: Support flags LR_COPYDELETEORG, LR_COPYFROMRESOURCE,
460 * LR_COPYRETURNORG, LR_CREATEDIBSECTION and LR_MONOCHROME.
461 */
462 if (!GetObjectW(hnd, sizeof(bm), &bm))
463 return NULL;
464 bm.bmBits = NULL;
465 if ((res = CreateBitmapIndirect(&bm)))
466 {
467 char *buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight);
468 if (buf == NULL)
469 {
470 DeleteObject(res);
471 return NULL;
472 }
473 GetBitmapBits(hnd, bm.bmWidthBytes * bm.bmHeight, buf);
474 SetBitmapBits(res, bm.bmWidthBytes * bm.bmHeight, buf);
475 HeapFree(GetProcessHeap(), 0, buf);
476 }
477 return res;
478 }
479
480 case IMAGE_ICON:
481 {
482 static BOOL IconMsgDisplayed = FALSE;
483 /* FIXME: support loading the image as shared from an instance */
484 if (!IconMsgDisplayed)
485 {
486 DbgPrint("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
487 IconMsgDisplayed = TRUE;
488 }
489 return CopyIcon(hnd);
490 }
491
492 case IMAGE_CURSOR:
493 {
494 static BOOL IconMsgDisplayed = FALSE;
495 /* FIXME: support loading the image as shared from an instance */
496 if (!IconMsgDisplayed)
497 {
498 DbgPrint("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
499 IconMsgDisplayed = TRUE;
500 }
501 return CopyCursor(hnd);
502 }
503 }
504
505 return NULL;
506 }