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