d79281ec102235f6551c8a7841cfe54f9df5baa8
[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 if (h2Resource == NULL)
138 return NULL;
139
140 hResource = LoadResource(hinst, h2Resource);
141 if (hResource == NULL)
142 return NULL;
143
144 ResIcon = LockResource(hResource);
145 if (ResIcon == NULL)
146 return NULL;
147
148 hIcon = CreateIconFromResourceEx((PBYTE)ResIcon,
149 SizeofResource(hinst, h2Resource),
150 Icon, 0x00030000, width, height,
151 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
152 if (hIcon && 0 != (fuLoad & LR_SHARED))
153 {
154 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
155 (HRSRC)NULL);
156 }
157
158 return hIcon;
159 }
160
161 /*
162 * FIXME: This code is incorrect and is likely to crash in many cases.
163 * In the file the cursor/icon directory records are stored like
164 * CURSORICONFILEDIR, but we treat them like CURSORICONDIR. In Wine
165 * this is solved by creating a fake cursor/icon directory in memory
166 * and passing that to CURSORICON_FindBestIcon.
167 */
168
169 if (fuLoad & LR_SHARED)
170 {
171 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
172 }
173
174 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
175 OPEN_EXISTING, 0, NULL);
176 if (hFile == INVALID_HANDLE_VALUE)
177 return NULL;
178
179 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
180 CloseHandle(hFile);
181 if (hSection == NULL)
182 return NULL;
183
184 IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
185 CloseHandle(hSection);
186 if (IconDIR == NULL)
187 return NULL;
188
189 if (0 != IconDIR->idReserved ||
190 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
191 {
192 UnmapViewOfFile(IconDIR);
193 return NULL;
194 }
195
196 /* Get a handle to the screen dc, the icon we create is going to be
197 * compatable with this. */
198 hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
199 if (hScreenDc == NULL)
200 {
201 UnmapViewOfFile(IconDIR);
202 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
203 return NULL;
204 }
205
206 if (fuLoad & LR_MONOCHROME)
207 {
208 ColorBits = 1;
209 }
210 else
211 {
212 ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
213 /*
214 * FIXME:
215 * Remove this after proper support for alpha icons will be finished.
216 */
217 if (ColorBits > 8)
218 ColorBits = 8;
219 }
220
221 /* Pick the best size. */
222 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, width, height, ColorBits);
223 if (!dirEntry)
224 {
225 DeleteDC(hScreenDc);
226 UnmapViewOfFile(IconDIR);
227 return NULL;
228 }
229
230 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
231 if (SafeIconImage == NULL)
232 {
233 DeleteDC(hScreenDc);
234 UnmapViewOfFile(IconDIR);
235 return NULL;
236 }
237
238 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
239 UnmapViewOfFile(IconDIR);
240
241 /* At this point we have a copy of the icon image to play with. */
242
243 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
244
245 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
246 {
247 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
248 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
249 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
250 }
251 else
252 {
253 ColorCount = SafeIconImage->icHeader.biClrUsed;
254 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
255 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
256 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
257 }
258
259 /* Make data point to the start of the XOR image data. */
260 Data = (PBYTE)SafeIconImage + HeaderSize;
261
262 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
263 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
264 DeleteDC(hScreenDc);
265
266 return hIcon;
267 }
268
269
270 static HANDLE
271 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
272 {
273 HANDLE hResource;
274 HANDLE hFile;
275 HANDLE hSection;
276 LPBITMAPINFO BitmapInfo;
277 LPBITMAPINFO PrivateInfo;
278 HDC hScreenDc;
279 HANDLE hBitmap;
280 ULONG HeaderSize;
281 ULONG ColorCount;
282 PVOID Data;
283
284 if (!(fuLoad & LR_LOADFROMFILE))
285 {
286 if (hInstance == NULL)
287 hInstance = User32Instance;
288
289 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
290 if (hResource == NULL)
291 return NULL;
292 hResource = LoadResource(hInstance, hResource);
293 if (hResource == NULL)
294 return NULL;
295 BitmapInfo = LockResource(hResource);
296 if (BitmapInfo == NULL)
297 return NULL;
298 }
299 else
300 {
301 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
302 OPEN_EXISTING, 0, NULL);
303 if (hFile == INVALID_HANDLE_VALUE)
304 return NULL;
305
306 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
307 CloseHandle(hFile);
308 if (hSection == NULL)
309 return NULL;
310
311 BitmapInfo = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
312 CloseHandle(hSection);
313 if (BitmapInfo == NULL)
314 return NULL;
315
316 BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
317 }
318
319 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
320 {
321 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
322 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
323 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
324 }
325 else
326 {
327 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
328 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
329 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
330 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
331 }
332 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
333
334 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
335 if (PrivateInfo == NULL)
336 {
337 if (fuLoad & LR_LOADFROMFILE)
338 UnmapViewOfFile(BitmapInfo);
339 return NULL;
340 }
341 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
342
343 /* FIXME: Handle color conversion and transparency. */
344
345 hScreenDc = CreateCompatibleDC(NULL);
346 if (hScreenDc == NULL)
347 {
348 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
349 if (fuLoad & LR_LOADFROMFILE)
350 UnmapViewOfFile(BitmapInfo);
351 return NULL;
352 }
353
354 if (fuLoad & LR_CREATEDIBSECTION)
355 {
356 DIBSECTION Dib;
357
358 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
359 0, 0);
360 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
361 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
362 DIB_RGB_COLORS);
363 }
364 else
365 {
366 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
367 Data, PrivateInfo, DIB_RGB_COLORS);
368 }
369
370 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
371 DeleteDC(hScreenDc);
372 if (fuLoad & LR_LOADFROMFILE)
373 UnmapViewOfFile(BitmapInfo);
374
375 return hBitmap;
376 }
377
378 HANDLE STDCALL
379 LoadImageW(
380 IN HINSTANCE hinst,
381 IN LPCWSTR lpszName,
382 IN UINT uType,
383 IN INT cxDesired,
384 IN INT cyDesired,
385 IN UINT fuLoad)
386 {
387 if (fuLoad & LR_DEFAULTSIZE)
388 {
389 if (uType == IMAGE_ICON)
390 {
391 if (cxDesired == 0)
392 cxDesired = GetSystemMetrics(SM_CXICON);
393 if (cyDesired == 0)
394 cyDesired = GetSystemMetrics(SM_CYICON);
395 }
396 else if (uType == IMAGE_CURSOR)
397 {
398 if (cxDesired == 0)
399 cxDesired = GetSystemMetrics(SM_CXCURSOR);
400 if (cyDesired == 0)
401 cyDesired = GetSystemMetrics(SM_CYCURSOR);
402 }
403 }
404
405 switch (uType)
406 {
407 case IMAGE_BITMAP:
408 return LoadBitmapImage(hinst, lpszName, fuLoad);
409 case IMAGE_CURSOR:
410 case IMAGE_ICON:
411 return LoadCursorIconImage(hinst, lpszName, cxDesired, cyDesired,
412 fuLoad, uType);
413 default:
414 break;
415 }
416
417 return NULL;
418 }
419
420
421 /*
422 * @implemented
423 */
424 HBITMAP STDCALL
425 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
426 {
427 return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
428 }
429
430
431 /*
432 * @implemented
433 */
434 HBITMAP STDCALL
435 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
436 {
437 return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
438 }
439
440
441 /*
442 * @unimplemented
443 */
444 HANDLE WINAPI
445 CopyImage(
446 IN HANDLE hnd,
447 IN UINT type,
448 IN INT desiredx,
449 IN INT desiredy,
450 IN UINT flags)
451 {
452 HBITMAP res;
453 BITMAP bm;
454
455 switch (type)
456 {
457 case IMAGE_BITMAP:
458 {
459 DbgPrint("WARNING: Incomplete implementation of CopyImage!\n");
460 /*
461 * FIXME: Support flags LR_COPYDELETEORG, LR_COPYFROMRESOURCE,
462 * LR_COPYRETURNORG, LR_CREATEDIBSECTION and LR_MONOCHROME.
463 */
464 if (!GetObjectW(hnd, sizeof(bm), &bm))
465 return NULL;
466 bm.bmBits = NULL;
467 if ((res = CreateBitmapIndirect(&bm)))
468 {
469 char *buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight);
470 if (buf == NULL)
471 {
472 DeleteObject(res);
473 return NULL;
474 }
475 GetBitmapBits(hnd, bm.bmWidthBytes * bm.bmHeight, buf);
476 SetBitmapBits(res, bm.bmWidthBytes * bm.bmHeight, buf);
477 HeapFree(GetProcessHeap(), 0, buf);
478 }
479 return res;
480 }
481
482 case IMAGE_ICON:
483 {
484 static BOOL IconMsgDisplayed = FALSE;
485 /* FIXME: support loading the image as shared from an instance */
486 if (!IconMsgDisplayed)
487 {
488 DbgPrint("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
489 IconMsgDisplayed = TRUE;
490 }
491 return CopyIcon(hnd);
492 }
493
494 case IMAGE_CURSOR:
495 {
496 static BOOL IconMsgDisplayed = FALSE;
497 /* FIXME: support loading the image as shared from an instance */
498 if (!IconMsgDisplayed)
499 {
500 DbgPrint("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
501 IconMsgDisplayed = TRUE;
502 }
503 return CopyCursor(hnd);
504 }
505 }
506
507 return NULL;
508 }