Fixed loading icons with flag LR_LOADFROMFILE.
[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: bitmap.c,v 1.18 2003/10/15 19:39:08 navaraf Exp $
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 <string.h>
32 #include <windows.h>
33 #include <user32.h>
34 #include <debug.h>
35 #include <stdlib.h>
36
37 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
38 HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
39 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
40 CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
41
42
43 /* FUNCTIONS *****************************************************************/
44
45 /*
46 * @implemented
47 */
48 HANDLE STDCALL
49 LoadImageA(HINSTANCE hinst,
50 LPCSTR lpszName,
51 UINT uType,
52 int cxDesired,
53 int cyDesired,
54 UINT fuLoad)
55 {
56 LPWSTR lpszWName;
57 HANDLE Handle;
58 UNICODE_STRING NameString;
59
60 if (HIWORD(lpszName))
61 {
62 RtlCreateUnicodeStringFromAsciiz(&NameString, (LPSTR)lpszName);
63 lpszWName = NameString.Buffer;
64 Handle = LoadImageW(hinst, lpszWName, uType, cxDesired,
65 cyDesired, fuLoad);
66 RtlFreeUnicodeString(&NameString);
67 }
68 else
69 {
70 Handle = LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired,
71 cyDesired, fuLoad);
72 }
73 return(Handle);
74 }
75
76
77 HANDLE STATIC
78 LoadCursorImage(HINSTANCE hinst, LPCWSTR lpszName, UINT fuLoad)
79 {
80 HANDLE hResource;
81 HANDLE h2Resource;
82 HANDLE hFile;
83 HANDLE hSection;
84 CURSORICONDIR* IconDIR;
85 HDC hScreenDc;
86 HANDLE hIcon;
87 ULONG HeaderSize;
88 ULONG ColourCount;
89 PVOID Data;
90 CURSORICONDIRENTRY* dirEntry;
91 ICONIMAGE* SafeIconImage;
92 GRPCURSORICONDIR* IconResDir;
93 INT id;
94 ICONIMAGE *ResIcon;
95
96 if (fuLoad & LR_SHARED)
97 DbgPrint("FIXME: need LR_SHARED support Loading cursor images\n");
98
99 if (!(fuLoad & LR_LOADFROMFILE))
100 {
101 if (hinst == NULL)
102 {
103 hinst = GetModuleHandleW(L"USER32");
104 }
105 hResource = FindResourceW(hinst, lpszName, RT_GROUP_CURSOR);
106 if (hResource == NULL)
107 {
108 return(NULL);
109 }
110
111 hResource = LoadResource(hinst, hResource);
112 if (hResource == NULL)
113 {
114 return(NULL);
115 }
116 IconResDir = LockResource(hResource);
117 if (IconResDir == NULL)
118 {
119 return(NULL);
120 }
121
122 //find the best fitting in the IconResDir for this resolution
123 id = LookupIconIdFromDirectoryEx((PBYTE) IconResDir, TRUE,
124 32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
125
126 h2Resource = FindResourceW(hinst,
127 MAKEINTRESOURCEW(id),
128 MAKEINTRESOURCEW(RT_CURSOR));
129
130 hResource = LoadResource(hinst, h2Resource);
131 if (hResource == NULL)
132 {
133 return(NULL);
134 }
135
136 ResIcon = LockResource(hResource);
137 if (ResIcon == NULL)
138 {
139 return(NULL);
140 }
141 return CreateIconFromResourceEx((PBYTE) ResIcon,
142 SizeofResource(hinst, h2Resource), FALSE, 0x00030000,
143 32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
144 }
145 else
146 {
147 hFile = CreateFileW(lpszName,
148 GENERIC_READ,
149 FILE_SHARE_READ,
150 NULL,
151 OPEN_EXISTING,
152 0,
153 NULL);
154 if (hFile == NULL)
155 {
156 return(NULL);
157 }
158
159 hSection = CreateFileMappingW(hFile,
160 NULL,
161 PAGE_READONLY,
162 0,
163 0,
164 NULL);
165
166 CloseHandle(hFile);
167 if (hSection == NULL)
168 {
169 return(NULL);
170 }
171 IconDIR = MapViewOfFile(hSection,
172 FILE_MAP_READ,
173 0,
174 0,
175 0);
176
177 CloseHandle(hSection);
178 if (IconDIR == NULL)
179 {
180 return(NULL);
181 }
182
183 //pick the best size.
184 dirEntry = (CURSORICONDIRENTRY *) CURSORICON_FindBestIcon( IconDIR, 32, 32, 1);
185
186
187 if (!dirEntry)
188 {
189 if (fuLoad & LR_LOADFROMFILE)
190 {
191 UnmapViewOfFile(IconDIR);
192 }
193 return(NULL);
194 }
195
196 SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, dirEntry->dwBytesInRes);
197
198 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
199 }
200
201 //at this point we have a copy of the icon image to play with
202
203 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
204
205 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
206 {
207 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
208 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
209 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
210 }
211 else
212 {
213 ColourCount = SafeIconImage->icHeader.biClrUsed;
214 if (ColourCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
215 {
216 ColourCount = 1 << SafeIconImage->icHeader.biBitCount;
217 }
218 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
219 }
220
221 //make data point to the start of the XOR image data
222 Data = (PBYTE)SafeIconImage + HeaderSize;
223
224
225 //get a handle to the screen dc, the icon we create is going to be compatable with this
226 hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
227 if (hScreenDc == NULL)
228 {
229 if (fuLoad & LR_LOADFROMFILE)
230 {
231 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
232 UnmapViewOfFile(IconDIR);
233 }
234 return(NULL);
235 }
236
237 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
238 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
239 return hIcon;
240 }
241
242
243 HANDLE STATIC
244 LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuLoad)
245 {
246 HANDLE hResource;
247 HANDLE h2Resource;
248 HANDLE hFile;
249 HANDLE hSection;
250 CURSORICONDIR* IconDIR;
251 HDC hScreenDc;
252 HANDLE hIcon;
253 ULONG HeaderSize;
254 ULONG ColourCount;
255 PVOID Data;
256 CURSORICONDIRENTRY* dirEntry;
257 ICONIMAGE* SafeIconImage;
258 GRPCURSORICONDIR* IconResDir;
259 INT id;
260 ICONIMAGE *ResIcon;
261
262 if (fuLoad & LR_SHARED)
263 DbgPrint("FIXME: need LR_SHARED support Loading icon images\n");
264
265 if (!(fuLoad & LR_LOADFROMFILE))
266 {
267 if (hinst == NULL)
268 {
269 hinst = GetModuleHandleW(L"USER32");
270 }
271 hResource = FindResourceW(hinst, lpszName, RT_GROUP_ICON);
272 if (hResource == NULL)
273 {
274 return(NULL);
275 }
276
277 hResource = LoadResource(hinst, hResource);
278 if (hResource == NULL)
279 {
280 return(NULL);
281 }
282 IconResDir = LockResource(hResource);
283 if (IconResDir == NULL)
284 {
285 return(NULL);
286 }
287
288 //find the best fitting in the IconResDir for this resolution
289 id = LookupIconIdFromDirectoryEx((PBYTE) IconResDir, TRUE,
290 width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
291
292 h2Resource = FindResourceW(hinst,
293 MAKEINTRESOURCEW(id),
294 MAKEINTRESOURCEW(RT_ICON));
295
296 hResource = LoadResource(hinst, h2Resource);
297 if (hResource == NULL)
298 {
299 return(NULL);
300 }
301
302 ResIcon = LockResource(hResource);
303 if (ResIcon == NULL)
304 {
305 return(NULL);
306 }
307 return CreateIconFromResourceEx((PBYTE) ResIcon,
308 SizeofResource(hinst, h2Resource), TRUE, 0x00030000,
309 width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
310 }
311 else
312 {
313 hFile = CreateFileW(lpszName,
314 GENERIC_READ,
315 FILE_SHARE_READ,
316 NULL,
317 OPEN_EXISTING,
318 0,
319 NULL);
320 if (hFile == NULL)
321 {
322 return(NULL);
323 }
324
325 hSection = CreateFileMappingW(hFile,
326 NULL,
327 PAGE_READONLY,
328 0,
329 0,
330 NULL);
331
332 if (hSection == NULL)
333 {
334 CloseHandle(hFile);
335 return(NULL);
336 }
337 IconDIR = MapViewOfFile(hSection,
338 FILE_MAP_READ,
339 0,
340 0,
341 0);
342
343 if (IconDIR == NULL)
344 {
345 CloseHandle(hFile);
346 CloseHandle(hSection);
347 return(NULL);
348 }
349
350 //pick the best size.
351 dirEntry = (CURSORICONDIRENTRY *) CURSORICON_FindBestIcon( IconDIR, width, height, 1);
352
353
354 if (!dirEntry)
355 {
356 CloseHandle(hFile);
357 CloseHandle(hSection);
358 UnmapViewOfFile(IconDIR);
359 return(NULL);
360 }
361
362 SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, dirEntry->dwBytesInRes);
363
364 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
365
366 CloseHandle(hFile);
367 CloseHandle(hSection);
368 }
369
370 //at this point we have a copy of the icon image to play with
371
372 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
373
374 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
375 {
376 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
377 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
378 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
379 }
380 else
381 {
382 ColourCount = SafeIconImage->icHeader.biClrUsed;
383 if (ColourCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
384 {
385 ColourCount = 1 << SafeIconImage->icHeader.biBitCount;
386 }
387 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
388 }
389
390 //make data point to the start of the XOR image data
391 Data = (PBYTE)SafeIconImage + HeaderSize;
392
393
394 //get a handle to the screen dc, the icon we create is going to be compatable with this
395 hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
396 if (hScreenDc == NULL)
397 {
398 if (fuLoad & LR_LOADFROMFILE)
399 {
400 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
401 UnmapViewOfFile(IconDIR);
402 }
403 return(NULL);
404 }
405
406 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
407 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
408 return hIcon;
409 }
410
411
412 HANDLE STATIC
413 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
414 {
415 HANDLE hResource;
416 HANDLE hFile;
417 HANDLE hSection;
418 BITMAPINFO* BitmapInfo;
419 BITMAPINFO* PrivateInfo;
420 HDC hScreenDc;
421 HANDLE hBitmap;
422 ULONG HeaderSize;
423 ULONG ColourCount;
424 PVOID Data;
425
426 if (!(fuLoad & LR_LOADFROMFILE))
427 {
428 if (hInstance == NULL)
429 {
430 hInstance = GetModuleHandleW(L"USER32");
431 }
432 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
433 if (hResource == NULL)
434 {
435 return(NULL);
436 }
437 hResource = LoadResource(hInstance, hResource);
438 if (hResource == NULL)
439 {
440 return(NULL);
441 }
442 BitmapInfo = LockResource(hResource);
443 if (BitmapInfo == NULL)
444 {
445 return(NULL);
446 }
447 }
448 else
449 {
450 hFile = CreateFileW(lpszName,
451 GENERIC_READ,
452 FILE_SHARE_READ,
453 NULL,
454 OPEN_EXISTING,
455 0,
456 NULL);
457 if (hFile == NULL)
458 {
459 return(NULL);
460 }
461 hSection = CreateFileMappingW(hFile,
462 NULL,
463 PAGE_READONLY,
464 0,
465 0,
466 NULL);
467 CloseHandle(hFile);
468 if (hSection == NULL)
469 {
470 return(NULL);
471 }
472 BitmapInfo = MapViewOfFile(hSection,
473 FILE_MAP_READ,
474 0,
475 0,
476 0);
477 CloseHandle(hSection);
478 if (BitmapInfo == NULL)
479 {
480 return(NULL);
481 }
482 /* offset BitmapInfo by 14 bytes to acount for the size of BITMAPFILEHEADER
483 unfortunatly sizeof(BITMAPFILEHEADER) = 16, but the acutal size should be 14!
484 */
485 BitmapInfo = (BITMAPINFO*)(((PBYTE)BitmapInfo) + 14);
486 }
487
488 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
489 {
490 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
491 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
492 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
493 }
494 else
495 {
496 ColourCount = BitmapInfo->bmiHeader.biClrUsed;
497 if (ColourCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
498 {
499 ColourCount = 1 << BitmapInfo->bmiHeader.biBitCount;
500 }
501 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
502 }
503 Data = (PVOID)BitmapInfo + HeaderSize;
504
505 PrivateInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, HeaderSize);
506 if (PrivateInfo == NULL)
507 {
508 if (fuLoad & LR_LOADFROMFILE)
509 {
510 UnmapViewOfFile(BitmapInfo);
511 }
512 return(NULL);
513 }
514 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
515
516 /* FIXME: Handle colour conversion and transparency. */
517
518 hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
519 if (hScreenDc == NULL)
520 {
521 if (fuLoad & LR_LOADFROMFILE)
522 {
523 UnmapViewOfFile(BitmapInfo);
524 }
525 return(NULL);
526 }
527
528 if (fuLoad & LR_CREATEDIBSECTION)
529 {
530 DIBSECTION Dib;
531
532 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
533 0, 0);
534 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
535 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
536 DIB_RGB_COLORS);
537 }
538 else
539 {
540 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
541 Data, PrivateInfo, DIB_RGB_COLORS);
542 }
543
544 RtlFreeHeap(RtlGetProcessHeap(), 0, PrivateInfo);
545 /*DeleteDC(hScreenDc);*/
546 if (fuLoad & LR_LOADFROMFILE)
547 {
548 UnmapViewOfFile(BitmapInfo);
549 }
550 return(hBitmap);
551 }
552
553 HANDLE STDCALL
554 LoadImageW(HINSTANCE hinst,
555 LPCWSTR lpszName,
556 UINT uType,
557 int cxDesired,
558 int cyDesired,
559 UINT fuLoad)
560 {
561 if (fuLoad & LR_DEFAULTSIZE)
562 {
563 if (uType == IMAGE_ICON)
564 {
565 if (cxDesired == 0)
566 {
567 cxDesired = GetSystemMetrics(SM_CXICON);
568 }
569 if (cyDesired == 0)
570 {
571 cyDesired = GetSystemMetrics(SM_CYICON);
572 }
573 }
574 else if (uType == IMAGE_CURSOR)
575 {
576 if (cxDesired == 0)
577 {
578 cxDesired = GetSystemMetrics(SM_CXCURSOR);
579 }
580 if (cyDesired == 0)
581 {
582 cyDesired = GetSystemMetrics(SM_CYCURSOR);
583 }
584 }
585 }
586
587 switch (uType)
588 {
589 case IMAGE_BITMAP:
590 {
591 return(LoadBitmapImage(hinst, lpszName, fuLoad));
592 }
593 case IMAGE_CURSOR:
594 {
595 return(LoadCursorImage(hinst, lpszName, fuLoad));
596 }
597 case IMAGE_ICON:
598 {
599 return(LoadIconImage(hinst, lpszName, cxDesired, cyDesired, fuLoad));
600 }
601 default:
602 DbgBreakPoint();
603 break;
604 }
605 return(NULL);
606 }
607
608
609 /*
610 * @implemented
611 */
612 HBITMAP STDCALL
613 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
614 {
615 return(LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
616 }
617
618
619 /*
620 * @implemented
621 */
622 HBITMAP STDCALL
623 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
624 {
625 return(LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
626 }