update for HEAD-2003091401
[reactos.git] / 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 <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       CloseHandle(hFile);
333       if (hSection == NULL)
334           {
335             return(NULL);
336           }
337       IconDIR = MapViewOfFile(hSection,
338                                  FILE_MAP_READ,
339                                  0,
340                                  0,
341                                  0);
342
343       CloseHandle(hSection);
344       if (IconDIR == NULL)
345           {
346             return(NULL);
347           }
348
349       //pick the best size.
350       dirEntry = (CURSORICONDIRENTRY *)  CURSORICON_FindBestIcon( IconDIR, width, height, 1);
351
352
353       if (!dirEntry)
354           {
355          if (fuLoad & LR_LOADFROMFILE)
356                  {
357                UnmapViewOfFile(IconDIR);
358                  }
359          return(NULL);
360           }
361
362       SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, dirEntry->dwBytesInRes); 
363
364       memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
365   }
366
367   //at this point we have a copy of the icon image to play with
368
369   SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
370
371   if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
372     {
373       BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
374       ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
375       HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
376     }
377   else
378     {
379       ColourCount = SafeIconImage->icHeader.biClrUsed;
380       if (ColourCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
381         {
382           ColourCount = 1 << SafeIconImage->icHeader.biBitCount;
383         }
384       HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
385     }
386   
387   //make data point to the start of the XOR image data
388   Data = (PBYTE)SafeIconImage + HeaderSize;
389
390
391   //get a handle to the screen dc, the icon we create is going to be compatable with this
392   hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
393   if (hScreenDc == NULL)
394   {
395       if (fuLoad & LR_LOADFROMFILE)
396           {
397                 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
398         UnmapViewOfFile(IconDIR);
399           }
400       return(NULL);
401   }
402
403   hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
404   RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
405   return hIcon;
406 }
407
408
409 HANDLE STATIC
410 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
411 {
412   HANDLE hResource;
413   HANDLE hFile;
414   HANDLE hSection;
415   BITMAPINFO* BitmapInfo;
416   BITMAPINFO* PrivateInfo;
417   HDC hScreenDc;
418   HANDLE hBitmap;
419   ULONG HeaderSize;
420   ULONG ColourCount;
421   PVOID Data;
422
423   if (!(fuLoad & LR_LOADFROMFILE))
424     {
425       if (hInstance == NULL)
426         {
427           hInstance = GetModuleHandleW(L"USER32");
428         }
429       hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
430       if (hResource == NULL)
431         {
432           return(NULL);
433         }
434       hResource = LoadResource(hInstance, hResource);
435       if (hResource == NULL)
436         {
437           return(NULL);
438         }
439       BitmapInfo = LockResource(hResource);
440       if (BitmapInfo == NULL)
441         {
442           return(NULL);
443         }
444     }
445   else
446     {
447       hFile = CreateFileW(lpszName,
448                          GENERIC_READ,
449                          FILE_SHARE_READ,
450                          NULL,
451                          OPEN_EXISTING,
452                          0,
453                          NULL);
454       if (hFile == NULL)
455         {
456           return(NULL);
457         }
458       hSection = CreateFileMappingW(hFile,
459                                    NULL,
460                                    PAGE_READONLY,
461                                    0,
462                                    0,
463                                    NULL);
464       CloseHandle(hFile);
465       if (hSection == NULL)
466         {               
467           return(NULL);
468         }
469       BitmapInfo = MapViewOfFile(hSection,
470                                  FILE_MAP_READ,
471                                  0,
472                                  0,
473                                  0);
474       CloseHandle(hSection);
475       if (BitmapInfo == NULL)
476         {
477           return(NULL);
478         }
479         /* offset BitmapInfo by 14 bytes to acount for the size of BITMAPFILEHEADER
480            unfortunatly sizeof(BITMAPFILEHEADER) = 16, but the acutal size should be 14!
481         */
482         BitmapInfo = (BITMAPINFO*)(((PBYTE)BitmapInfo) + 14);
483     }
484
485   if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
486     {
487       BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
488       ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
489       HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
490     }
491   else
492     {
493       ColourCount = BitmapInfo->bmiHeader.biClrUsed;
494       if (ColourCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
495         {
496           ColourCount = 1 << BitmapInfo->bmiHeader.biBitCount;
497         }
498       HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
499     }
500   Data = (PVOID)BitmapInfo + HeaderSize;
501
502   PrivateInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, HeaderSize);
503   if (PrivateInfo == NULL)
504     {
505       if (fuLoad & LR_LOADFROMFILE)
506         {
507           UnmapViewOfFile(BitmapInfo);
508         }
509       return(NULL);
510     }
511   memcpy(PrivateInfo, BitmapInfo, HeaderSize);
512
513   /* FIXME: Handle colour conversion and transparency. */
514
515   hScreenDc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
516   if (hScreenDc == NULL)
517     {
518       if (fuLoad & LR_LOADFROMFILE)
519         {
520           UnmapViewOfFile(BitmapInfo);
521         }
522       return(NULL);
523     }
524
525   if (fuLoad & LR_CREATEDIBSECTION)
526     {
527       DIBSECTION Dib;
528
529       hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL, 
530                                  0, 0);
531       GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
532       SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
533                 DIB_RGB_COLORS);
534     }
535   else
536     {
537       hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
538                                Data, PrivateInfo, DIB_RGB_COLORS);
539     }
540
541   RtlFreeHeap(RtlGetProcessHeap(), 0, PrivateInfo);
542   /*DeleteDC(hScreenDc);*/
543   if (fuLoad & LR_LOADFROMFILE)
544     {
545       UnmapViewOfFile(BitmapInfo);
546     }
547   return(hBitmap);
548 }
549
550 HANDLE STDCALL
551 LoadImageW(HINSTANCE hinst,
552            LPCWSTR lpszName,
553            UINT uType,
554            int cxDesired,
555            int cyDesired,
556            UINT fuLoad)
557 {  
558   if (fuLoad & LR_DEFAULTSIZE)
559     {
560       if (uType == IMAGE_ICON)
561         {
562           if (cxDesired == 0)
563             {
564               cxDesired = GetSystemMetrics(SM_CXICON);
565             }
566           if (cyDesired == 0)
567             {
568               cyDesired = GetSystemMetrics(SM_CYICON);
569             }
570         }
571       else if (uType == IMAGE_CURSOR)
572         {
573           if (cxDesired == 0)
574             {
575               cxDesired = GetSystemMetrics(SM_CXCURSOR);
576             }
577           if (cyDesired == 0)
578             {
579               cyDesired = GetSystemMetrics(SM_CYCURSOR);
580             }
581         }
582     }
583
584   switch (uType)
585     {
586     case IMAGE_BITMAP:
587       {
588         return(LoadBitmapImage(hinst, lpszName, fuLoad));
589       }
590     case IMAGE_CURSOR:
591       {
592         return(LoadCursorImage(hinst, lpszName, fuLoad));
593       }
594     case IMAGE_ICON:
595       {
596         return(LoadIconImage(hinst, lpszName, cxDesired, cyDesired, fuLoad));
597       }
598     default:
599       DbgBreakPoint();
600       break;
601     }
602   return(NULL);
603 }
604
605
606 /*
607  * @implemented
608  */
609 HBITMAP STDCALL
610 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
611 {
612   return(LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
613 }
614
615
616 /*
617  * @implemented
618  */
619 HBITMAP STDCALL
620 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
621 {
622   return(LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0));
623 }