source: trunk/src/user32/winicon.cpp@ 21951

Last change on this file since 21951 was 21951, checked in by dmik, 14 years ago

Align scanlines passed to GetDIBits on a LONG boundary.

This fixes crashes in CreateIconIndirect()/CreateIconFromResource()/LoadImage()
etc. See #58 for more info.

File size: 62.4 KB
Line 
1/* $Id: winicon.cpp,v 1.40 2003-01-07 10:26:01 sandervl Exp $ */
2/*
3 * Win32 Icon Code for OS/2
4 *
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl) (OS/2 Port)
7 *
8 * Based on Wine code (objects\bitmap.c, loader\resource.c, objects\cursoricon.c):
9 *
10 * Copyright 1993 Alexandre Julliard
11 * 1993 Robert J. Amstadt
12 * 1996 Martin Von Loewis
13 * 1997 Alex Korobka
14 * 1998 Turchanov Sergey
15 * 1998 Huw D M Davies
16 * Theory:
17 *
18 * http://www.microsoft.com/win32dev/ui/icons.htm
19 *
20 * Cursors and icons are stored in a global heap block, with the
21 * following layout:
22 *
23 * CURSORICONINFO info;
24 * BYTE[] ANDbits;
25 * BYTE[] XORbits;
26 *
27 * The bits structures are in the format of a device-dependent bitmap.
28 *
29 * This layout is very sub-optimal, as the bitmap bits are stored in
30 * the X client instead of in the server like other bitmaps; however,
31 * some programs (notably Paint Brush) expect to be able to manipulate
32 * the bits directly :-(
33 *
34 * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
35 *
36 **************************************************************************************************
37 *
38 * TODO: Scaling of system cursors (store them as resources in user32 instead of using PM pointers)
39 * TODO: We use the hColorBmp member of the CURSORICONINFO structure to store the PM cursor handle
40 * Might mess up PaintBrush (see above)
41 *
42 * Project Odin Software License can be found in LICENSE.TXT
43 *
44 */
45#include <os2win.h>
46#include <stdio.h>
47#include <string.h>
48#include <winicon.h>
49#include <win/cursoricon.h>
50#include <objhandle.h>
51#include "dib.h"
52#include <heapstring.h>
53#include <win/virtual.h>
54#include "initterm.h"
55#include "oslibres.h"
56#include "oslibwin.h"
57#include "dc.h"
58
59#define DBG_LOCALLOG DBG_winicon
60#include "dbglocal.h"
61
62
63/**********************************************************************
64 * ICONCACHE for cursors/icons loaded with LR_SHARED.
65 *
66 * FIXME: This should not be allocated on the system heap, but on a
67 * subsystem-global heap (i.e. one for all Win16 processes,
68 * and one for each Win32 process).
69 */
70typedef struct tagICONCACHE
71{
72 struct tagICONCACHE *next;
73
74 HMODULE hModule;
75 HRSRC hRsrc;
76 HRSRC hGroupRsrc;
77 HANDLE handle;
78 INT count;
79} ICONCACHE;
80
81static ICONCACHE *IconAnchor = NULL;
82static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT("User32WinIcon");
83static WORD ICON_HOTSPOT = 0x4242;
84static HCURSOR hActiveCursor = 0;
85static HCURSOR hActiveCursorPM = 0;
86
87
88static HGLOBAL CURSORICON_CreateFromResource( HINSTANCE hInstance, DWORD dwResGroupId, HGLOBAL hObj, LPBYTE bits,
89 UINT cbSize, BOOL bIcon, DWORD dwVersion, INT width, INT height, UINT loadflags );
90static HGLOBAL CURSORICON_Copy( HGLOBAL handle );
91static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
92 int height, int colors );
93static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
94 int width, int height, int color);
95BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
96 CURSORICONDIR **res, LPBYTE **ptr);
97
98static INT CURSORICON_DelSharedIcon( HANDLE handle );
99static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle );
100static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc );
101static ICONCACHE* CURSORICON_FindCache(HANDLE handle);
102
103static HGLOBAL CreateCursorIconIndirect( HINSTANCE hInstance,
104 CURSORICONINFO *info,
105 LPCVOID lpANDbits,
106 LPCVOID lpXORbits, BOOL fIcon);
107
108/***********************************************************************
109 * CreateIcon (USER32.75)
110 */
111HICON WIN32API CreateIcon(HINSTANCE hInstance, INT nWidth,
112 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
113 LPCVOID lpANDbits, LPCVOID lpXORbits )
114{
115 CURSORICONINFO info;
116
117 dprintf(("USER32: CreateIcon (%d,%d), %d, %x, %x", nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits));
118
119 info.ptHotSpot.x = ICON_HOTSPOT;
120 info.ptHotSpot.y = ICON_HOTSPOT;
121 info.nWidth = nWidth;
122 info.nHeight = nHeight;
123 info.nWidthBytes = 0;
124 info.bPlanes = bPlanes;
125 info.bBitsPerPixel = bBitsPixel;
126 info.hInstance = hInstance;
127 info.dwResGroupId = -1;
128 info.hColorBmp = 0;
129 return CreateCursorIconIndirect(0, &info, lpANDbits, lpXORbits, TRUE);
130}
131/**********************************************************************
132 * CreateIconFromResource (USER32.76)
133 */
134HICON WIN32API CreateIconFromResource(LPBYTE bits, UINT cbSize,
135 BOOL bIcon, DWORD dwVersion)
136{
137 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
138}
139//******************************************************************************
140//******************************************************************************
141HICON WIN32API CreateIconFromResourceEx(LPBYTE bits, UINT cbSize,
142 BOOL bIcon, DWORD dwVersion,
143 INT width, INT height,
144 UINT cFlag )
145{
146 dprintf(("USER32: CreateIconFromResourceEx %X %d %d %X %d %d %X,", bits, cbSize, bIcon, dwVersion, width, height, cFlag));
147 return CURSORICON_CreateFromResource(0, -1, 0, bits, cbSize, bIcon, dwVersion, width, height, cFlag );
148}
149/**********************************************************************
150 * CreateIconIndirect (USER32.78)
151 */
152HICON WINAPI CreateIconIndirect(ICONINFO *iconinfo)
153{
154 BITMAP bmpXor,bmpAnd;
155 HICON hObj;
156 int sizeXor,sizeAnd,colortablesize;
157
158 dprintf(("USER32: CreateIconIndirect %x %x %x %s", iconinfo, iconinfo->hbmMask, iconinfo->hbmColor, (iconinfo->fIcon) ? "icon" : "cursor"));
159
160 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
161 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
162
163 colortablesize = 0;
164
165 // CreateDIBits expectes DWORD-aligned scan lines
166 bmpXor.bmWidthBytes = (bmpXor.bmWidthBytes + 3) / 4 * 4;
167 bmpAnd.bmWidthBytes = (bmpAnd.bmWidthBytes + 3) / 4 * 4;
168
169 if(bmpXor.bmBitsPixel <= 8) {
170 colortablesize = sizeof(RGBQUAD)*(1<<bmpXor.bmBitsPixel);
171 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes + colortablesize;
172 }
173 else sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
174
175 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
176
177 hObj = GlobalAlloc( GMEM_MOVEABLE, sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
178 if (hObj)
179 {
180 CURSORICONINFO *info;
181
182 info = (CURSORICONINFO *)GlobalLock( hObj );
183
184 /* If we are creating an icon, the hotspot is unused */
185 if (iconinfo->fIcon)
186 {
187 info->ptHotSpot.x = ICON_HOTSPOT;
188 info->ptHotSpot.y = ICON_HOTSPOT;
189 }
190 else
191 {
192 info->ptHotSpot.x = iconinfo->xHotspot;
193 info->ptHotSpot.y = iconinfo->yHotspot;
194 }
195
196 info->nWidth = bmpXor.bmWidth;
197 info->nHeight = bmpXor.bmHeight;
198 info->nWidthBytes = bmpXor.bmWidthBytes;
199 info->bPlanes = bmpXor.bmPlanes;
200 info->bBitsPerPixel = bmpXor.bmBitsPixel;
201 info->hInstance = -1;
202 info->dwResGroupId = -1;
203 info->hColorBmp = 0;
204
205 /* Transfer the bitmap bits to the CURSORICONINFO structure */
206 if(bmpAnd.bmBitsPixel > 1)
207 {//Our code expects b&w masks, so convert it first
208 //We could also use GetDIBits to do the conversion for us, but it returns
209 //scanlines aligned differently from what we want.
210 HBITMAP oldbmpSrc, oldbmpDest, hbmMask;
211 HDC hdcSrc, hdcDest;
212
213 hdcSrc = CreateCompatibleDC(0);
214 oldbmpSrc = SelectObject(hdcSrc, iconinfo->hbmMask);
215
216 hdcDest = CreateCompatibleDC(0);
217 hbmMask = CreateBitmap(bmpAnd.bmWidth, bmpAnd.bmHeight, 1,
218 1, NULL);
219 oldbmpDest = SelectObject(hdcDest, hbmMask);
220
221 //blit to the destination HDC & convert to 1bpp
222 BitBlt(hdcDest, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight,
223 hdcSrc, 0, 0, SRCCOPY);
224
225 //recalculate the mask bitmap size
226 GetObjectA( hbmMask, sizeof(bmpAnd), &bmpAnd );
227 sizeAnd = bmpAnd.bmHeight * (bmpAnd.bmWidthBytes + 3) / 4 * 4;
228
229 //query the 1bpp bitmap data
230 GetBitmapBits( hbmMask ,sizeAnd,(char*)(info + 1) );
231
232 SelectObject(hdcSrc, oldbmpSrc);
233 SelectObject(hdcDest, oldbmpDest);
234 DeleteObject(hbmMask);
235 DeleteDC(hdcSrc);
236 DeleteDC(hdcDest);
237 }
238 else {
239 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
240 }
241 if(bmpXor.bmBitsPixel > 1)
242 {
243 BITMAPINFO* pInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO)+colortablesize+3*sizeof(DWORD)); //+ extra space for > 8bpp images
244 HBITMAP oldbmp;
245 HDC hdc;
246
247 hdc = CreateCompatibleDC(0);
248
249 memset(pInfo, 0, sizeof(BITMAPINFO)+colortablesize+3*sizeof(DWORD));
250 pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
251 pInfo->bmiHeader.biPlanes = info->bPlanes;
252 pInfo->bmiHeader.biBitCount = info->bBitsPerPixel;
253
254 GetDIBits(hdc, iconinfo->hbmColor, 0, bmpXor.bmHeight, (char *)(info + 1) + sizeAnd + colortablesize, pInfo, DIB_RGB_COLORS);
255 if(colortablesize) {
256 memcpy((char *)(info + 1) + sizeAnd, (char *)&pInfo->bmiHeader + pInfo->bmiHeader.biSize, colortablesize);
257 }
258
259 DeleteDC(hdc);
260 free(pInfo);
261 }
262 else {
263 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
264 }
265
266#ifdef __WIN32OS2__
267 info->hColorBmp = OSLibWinCreatePointer(info, (char*)(info + 1), (LPBITMAP_W)&bmpAnd, (char*)(info + 1) + sizeAnd, (LPBITMAP_W)&bmpXor, iconinfo->fIcon == FALSE);
268#endif
269 GlobalUnlock(hObj);
270
271#ifdef __WIN32OS2__
272 HICON hIcon;
273 if(ObjAllocateHandle(&hIcon, (DWORD)hObj, HNDL_CURSORICON) == FALSE) {
274 GlobalFree(hObj);
275 dprintf(("ERROR: CreateIconIndirect ObjAllocateHandle failed!!"));
276 return 0;
277 }
278#endif
279 dprintf(("USER32: CreateIconIndirect %x returned %x", iconinfo, hIcon));
280 return hIcon;
281 }
282 else {
283 dprintf(("ERROR: CreateIconIndirect GlobalAlloc failed!!"));
284 return 0;
285 }
286}
287//******************************************************************************
288//******************************************************************************
289BOOL WIN32API DestroyIcon( HICON hIcon)
290{
291 dprintf(("USER32: DestroyIcon %x", hIcon));
292 return CURSORICON_Destroy( hIcon, 0 );
293}
294//******************************************************************************
295//******************************************************************************
296HICON WIN32API CopyIcon( HICON hIcon)
297{
298 dprintf(("USER32: CopyIcon %x", hIcon));
299 return CURSORICON_Copy( hIcon );
300}
301//******************************************************************************
302//******************************************************************************
303HICON WIN32API GetOS2Icon(HICON hIcon)
304{
305 CURSORICONINFO *ciconinfo;
306
307 hIcon = ObjQueryHandleData(hIcon, HNDL_CURSORICON);
308 if(hIcon == -1) {
309 dprintf(("ERROR: Invalid cursor/icon!"));
310 return 0;
311 }
312 ciconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)hIcon);
313 if (!ciconinfo)
314 return 0;
315 HICON hOS2Icon = ciconinfo->hColorBmp;
316 GlobalUnlock(hIcon);
317 return hOS2Icon;
318}
319/**********************************************************************
320 * GetIconInfo (USER32.242)
321 */
322BOOL WINAPI GetIconInfo(HICON hIcon, ICONINFO *iconinfo)
323{
324 CURSORICONINFO *ciconinfo;
325
326 dprintf(("GetIconInfo %x %x", hIcon, iconinfo));
327
328#ifdef __WIN32OS2__
329 hIcon = ObjQueryHandleData(hIcon, HNDL_CURSORICON);
330 if(hIcon == -1) {
331 dprintf(("ERROR: Invalid cursor/icon!"));
332 return 0;
333 }
334#endif
335 ciconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)hIcon);
336 if (!ciconinfo)
337 return FALSE;
338
339 if((ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
340 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT))
341 {
342 iconinfo->fIcon = TRUE;
343 iconinfo->xHotspot = ciconinfo->nWidth / 2;
344 iconinfo->yHotspot = ciconinfo->nHeight / 2;
345 }
346 else
347 {
348 iconinfo->fIcon = FALSE;
349 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
350 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
351 }
352
353 //Create new bitmaps for the color and mask data; application is responsible
354 //for deleteing them (according to docs & verified in NT4)
355 if(ciconinfo->bBitsPerPixel > 1)
356 {
357 BITMAPINFO* pInfo;
358 int colorsize = 0;
359 int coloroff;
360
361 HDC hdc = CreateCompatibleDC(0);
362
363 if(ciconinfo->bBitsPerPixel <= 8) {
364 colorsize = (1<<ciconinfo->bBitsPerPixel)*sizeof(RGBQUAD);
365 }
366 else {
367 colorsize = 3*sizeof(DWORD); //color masks
368 }
369 pInfo = (BITMAPINFO *)malloc(ciconinfo->nHeight * ciconinfo->nWidthBytes + colorsize + sizeof(BITMAPINFO));
370 memset(pInfo, 0, sizeof(BITMAPINFO)+colorsize);
371
372 pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
373 pInfo->bmiHeader.biWidth = ciconinfo->nWidth;
374 pInfo->bmiHeader.biHeight = ciconinfo->nHeight,
375 pInfo->bmiHeader.biPlanes = ciconinfo->bPlanes;
376 pInfo->bmiHeader.biBitCount = ciconinfo->bBitsPerPixel;
377 pInfo->bmiHeader.biSizeImage= ciconinfo->nHeight * ciconinfo->nWidthBytes;
378
379 //offset in cursorinfo memory
380 coloroff = ciconinfo->nHeight * BITMAP_GetWidthBytes (ciconinfo->nWidth, 1);
381
382 char *src = (char *)(ciconinfo + 1) + coloroff;
383 if(ciconinfo->bBitsPerPixel <= 8) {
384 src += colorsize; //no color masks in cursorinfo data for bpp > 8
385 }
386 if(ciconinfo->bBitsPerPixel <= 8) {
387 memcpy(&pInfo->bmiColors[0], (char *)(ciconinfo + 1) + coloroff, colorsize);
388 }
389 //else TODO: color masks (currently unused in CreateDIBitmap)
390
391 iconinfo->hbmColor = CreateDIBitmap(hdc, &pInfo->bmiHeader, CBM_INIT, src, pInfo, DIB_RGB_COLORS);
392
393 free(pInfo);
394 DeleteDC(hdc);
395 }
396 else {
397 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
398 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
399 (char *)(ciconinfo + 1)
400 + ciconinfo->nHeight *
401 BITMAP_GetWidthBytes (ciconinfo->nWidth, 1) );
402 }
403
404 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
405 1, 1, (char *)(ciconinfo + 1));
406
407 GlobalUnlock(hIcon);
408
409 return TRUE;
410}
411//******************************************************************************
412//******************************************************************************
413HCURSOR WIN32API CreateCursor(HINSTANCE hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight,
414 const VOID *lpANDbits, const VOID *lpXORbits)
415{
416 CURSORICONINFO info;
417
418 dprintf(("CreateCursor %dx%d spot=%d,%d xor=%p and=%p\n",
419 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits));
420
421 info.ptHotSpot.x = xHotSpot;
422 info.ptHotSpot.y = yHotSpot;
423 info.nWidth = nWidth;
424 info.nHeight = nHeight;
425 info.nWidthBytes = 0;
426 info.bPlanes = 1;
427 info.bBitsPerPixel = 1;
428 info.hInstance = hInst;
429 info.dwResGroupId = -1;
430 info.hColorBmp = 0;
431
432 return CreateCursorIconIndirect( 0, &info, lpANDbits, lpXORbits, FALSE);
433}
434//******************************************************************************
435//******************************************************************************
436BOOL WIN32API DestroyCursor( HCURSOR hCursor)
437{
438 dprintf(("USER32: DestroyCursor %x", hCursor));
439 return CURSORICON_Destroy( hCursor, CID_WIN32 );
440}
441//******************************************************************************
442//******************************************************************************
443HCURSOR WIN32API GetCursor(void)
444{
445 dprintf2(("USER32: GetCursor"));
446 if(hActiveCursorPM && hActiveCursorPM != OSLibWinQueryPointer()) {
447 dprintf(("Another app changed mouse cursor"));
448 hActiveCursorPM = hActiveCursor = 0;
449 }
450 return hActiveCursor;
451}
452//******************************************************************************
453//******************************************************************************
454HCURSOR WIN32API SetCursor( HCURSOR hCursor)
455{
456 HCURSOR hOldCursor;
457
458 dprintf(("USER32: SetCursor %x (prev %x)", hCursor, hActiveCursor));
459 GetCursor();
460 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
461
462 hOldCursor = hActiveCursor;
463 hActiveCursor = hCursor;
464
465#ifdef __WIN32OS2__
466 hCursor = ObjQueryHandleData(hCursor, HNDL_CURSORICON);
467 if(hCursor == -1) {
468 dprintf(("ERROR: Invalid cursor/icon!"));
469 return 0;
470 }
471#endif
472
473 CURSORICONINFO *iconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)hCursor);
474 if (!iconinfo) {
475 dprintf(("ERROR: Invalid cursor!"));
476 return 0;
477 }
478 if(!iconinfo->hColorBmp) {
479 dprintf(("SetCursor: invalid os/2 pointer handle!!"));
480 }
481
482 dprintf2(("OSLibWinSetPointer %x", iconinfo->hColorBmp));
483 if(OSLibWinSetPointer(iconinfo->hColorBmp) == FALSE) {
484 dprintf(("OSLibWinSetPointer %x returned FALSE!!", iconinfo->hColorBmp));
485 }
486 hActiveCursorPM = iconinfo->hColorBmp;
487 GlobalUnlock(hCursor);
488
489 return hOldCursor;
490}
491/*****************************************************************************
492 * Name : BOOL WIN32API SetSystemCursor
493 * Purpose : The SetSystemCursor function replaces the contents of the system
494 * cursor specified by dwCursorId with the contents of the cursor
495 * specified by hCursor, and then destroys hCursor. This function
496 * lets an application customize the system cursors.
497 * Parameters: HCURSOR hCursor set specified system cursor to this cursor's
498 * contents, then destroy this
499 * DWORD dwCursorID system cursor specified by its identifier
500 * Variables :
501 * Result : If the function succeeds, the return value is TRUE.
502 * If the function fails, the return value is FALSE. To get extended
503 * error information, call GetLastError.
504 * Remark :
505 * Status : UNTESTED STUB
506 *
507 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
508 *****************************************************************************/
509BOOL WIN32API SetSystemCursor(HCURSOR hCursor, DWORD dwCursorId)
510{
511 dprintf(("USER32:SetSystemCursor (%08xh,%08x) not supported.\n",
512 hCursor,
513 dwCursorId));
514
515 return DestroyCursor(hCursor);
516}
517//******************************************************************************
518//******************************************************************************
519INT OPEN32API __ShowCursor(BOOL bShow);
520
521inline INT _ShowCursor (BOOL bShow)
522{
523 INT yyrc;
524 USHORT sel = RestoreOS2FS();
525
526 yyrc = __ShowCursor(bShow);
527 SetFS(sel);
528
529 return yyrc;
530}
531//******************************************************************************
532static int cursorshowcnt = 0;
533//******************************************************************************
534void RestoreCursor()
535{
536 dprintf2(("USER32: RestoreCursor %d", cursorshowcnt));
537 while(cursorshowcnt != 0)
538 {
539 if(cursorshowcnt > 0 )
540 {
541 ShowCursor(FALSE);
542 }
543 else
544 {
545 ShowCursor(TRUE);
546 }
547 }
548}
549//******************************************************************************
550//******************************************************************************
551int WIN32API ShowCursor(BOOL bShow)
552{
553 dprintf2(("USER32: ShowCursor %d", bShow));
554 cursorshowcnt = cursorshowcnt + ((bShow) ? 1 : -1);
555 return _ShowCursor(bShow);
556}
557/***********************************************************************
558 * CreateCursorIconIndirect
559 */
560static HGLOBAL CreateCursorIconIndirect( HINSTANCE hInstance,
561 CURSORICONINFO *info,
562 LPCVOID lpANDbits,
563 LPCVOID lpXORbits, BOOL fIcon)
564{
565 HGLOBAL handle;
566 char *ptr;
567 int sizeAnd, sizeXor;
568#ifdef __WIN32OS2__
569 BITMAP bmpXor, bmpAnd;
570#endif
571
572 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
573 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
574 sizeXor = info->nHeight * info->nWidthBytes;
575 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
576 if (!(handle = GlobalAlloc( GMEM_MOVEABLE,
577 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
578 return 0;
579 ptr = (char *)GlobalLock( handle );
580 memcpy( ptr, info, sizeof(*info) );
581 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
582 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
583#ifdef __WIN32OS2__
584 bmpAnd.bmType = 0;
585 bmpAnd.bmWidth = info->nWidth;
586 bmpAnd.bmHeight = info->nHeight;
587 bmpAnd.bmWidthBytes = BITMAP_GetWidthBytes(info->nWidth, 1);
588 bmpAnd.bmPlanes = info->bPlanes;
589 bmpAnd.bmBitsPixel = 1;
590 bmpAnd.bmBits = NULL;
591
592 bmpXor.bmType = 0;
593 bmpXor.bmWidth = info->nWidth;
594 bmpXor.bmHeight = info->nHeight;
595 bmpXor.bmWidthBytes = info->nWidthBytes;
596 bmpXor.bmPlanes = info->bPlanes;
597 bmpXor.bmBitsPixel = info->bBitsPerPixel;
598 bmpXor.bmBits = NULL;
599 ((CURSORICONINFO *)ptr)->hColorBmp =
600 OSLibWinCreatePointer(info, (char *)lpANDbits, (LPBITMAP_W)&bmpAnd, (char *)lpXORbits, (LPBITMAP_W)&bmpXor, fIcon == FALSE);
601#endif
602 GlobalUnlock( handle );
603
604#ifdef __WIN32OS2__
605 HICON hIcon;
606 if(ObjAllocateHandle(&hIcon, (DWORD)handle, HNDL_CURSORICON) == FALSE) {
607 GlobalFree(handle);
608 dprintf(("ERROR: CreateCursorIconIndirect ObjAllocateHandle failed!!"));
609 return 0;
610 }
611 dprintf(("USER32: CreateCursorIconIndirect returned %x", hIcon));
612 return hIcon;
613#else
614 return handle;
615#endif
616}
617/**********************************************************************
618 * CURSORICON_Load
619 *
620 * Load a cursor or icon from resource or file.
621 */
622HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
623 INT width, INT height, INT colors,
624 BOOL fCursor, UINT loadflags )
625{
626 HANDLE handle = 0, h = 0;
627 HANDLE hRsrc;
628 CURSORICONDIR *dir;
629 CURSORICONDIRENTRY *dirEntry;
630 LPBYTE bits;
631
632#ifdef __WIN32OS2__
633 //TODO: Can system cursors be loaded by name??? (#xxx)
634 if (fCursor && hInstance == NULL && !HIWORD(name))
635 {
636 HCURSOR hCursor = OSLibWinQuerySysPointer((ULONG)name, width, height);
637 if(hCursor)
638 {
639 /* If shared icon, check whether it was already loaded */
640 if ((loadflags & LR_SHARED)
641 && (h = CURSORICON_FindSharedIcon( -1, hCursor ) ) != 0 )
642 {
643 dprintf(("Found icon/cursor in cache; returned old handle %x", h));
644 return h;
645 }
646
647 HANDLE hObj = GlobalAlloc( GMEM_MOVEABLE, sizeof(CURSORICONINFO));
648 if (!hObj)
649 {
650 DebugInt3();
651 return 0;
652 }
653 CURSORICONINFO *info;
654
655 info = (CURSORICONINFO *)GlobalLock( hObj );
656 info->ptHotSpot.x = 0;
657 info->ptHotSpot.y = 0;
658 info->nWidth = width;
659 info->nHeight = height;
660 info->nWidthBytes = width*height/8;
661 info->bPlanes = 1;
662 info->bBitsPerPixel = 1;
663 info->hColorBmp = hCursor;
664 info->hInstance = -1;
665 info->dwResGroupId = -1;
666
667 HICON hIcon;
668 if(ObjAllocateHandle(&hIcon, (DWORD)hObj, HNDL_CURSORICON) == FALSE) {
669 GlobalUnlock( hObj );
670 GlobalFree(hObj);
671 dprintf(("ERROR: CURSORICON_Load ObjAllocateHandle failed!!"));
672 return 0;
673 }
674
675 if (loadflags & LR_SHARED )
676 CURSORICON_AddSharedIcon( -1, hCursor, -1, hIcon );
677
678 GlobalUnlock( hObj );
679
680 return hIcon;
681 }
682 }
683#endif
684 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
685 {
686 LPBYTE *ptr;
687
688 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
689 return 0;
690 if (fCursor)
691 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
692 else
693 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
694 bits = ptr[dirEntry->wResId-1];
695 h = CURSORICON_CreateFromResource( 0, -1, 0, bits, dirEntry->dwBytesInRes,
696 !fCursor, 0x00030000, width, height, loadflags);
697
698 HeapFree( GetProcessHeap(), 0, dir );
699 HeapFree( GetProcessHeap(), 0, ptr );
700 }
701 else /* Load from resource */
702 {
703 HANDLE hGroupRsrc;
704 WORD wResId;
705 DWORD dwBytesInRes;
706 BOOL bIsGroup = TRUE;
707
708 /* Get directory resource ID */
709 if (!hInstance)
710 {
711 hRsrc = FindResourceW(hInstanceUser32, name, fCursor ? RT_CURSORW : RT_ICONW);
712 if(!hRsrc) {
713 hRsrc = FindResourceW(hInstanceUser32, name, fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW);
714 }
715 else bIsGroup = FALSE;
716
717 if(!hRsrc) return 0;
718
719 hInstance = hInstanceUser32;
720 }
721 else {
722 hRsrc = FindResourceW(hInstance, name, fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW);
723 if(!hRsrc) return 0;
724 }
725 hGroupRsrc = hRsrc;
726
727 if(bIsGroup) {
728 /* Find the best entry in the directory */
729
730 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
731 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
732
733 if (fCursor)
734 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
735 width, height, 1);
736 else
737 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
738 width, height, colors );
739 if (!dirEntry) return 0;
740 wResId = dirEntry->wResId;
741 dwBytesInRes = dirEntry->dwBytesInRes;
742 FreeResource( handle );
743
744 /* Load the resource */
745 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
746 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
747 }
748
749 /* If shared icon, check whether it was already loaded */
750 if ((loadflags & LR_SHARED)
751 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
752 {
753 dprintf(("Found icon/cursor in cache; returned old handle %x", h));
754 return h;
755 }
756
757 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
758 bits = (LPBYTE)LockResource( handle );
759 h = CURSORICON_CreateFromResource( hInstance, (DWORD)name, 0, bits, dwBytesInRes,
760 !fCursor, 0x00030000, width, height, loadflags);
761 FreeResource( handle );
762
763 /* If shared icon, add to icon cache */
764
765 if ( h && (loadflags & LR_SHARED) )
766 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
767
768 }
769
770 return h;
771}
772
773/*********************************************************************
774 * The main purpose of this function is to create fake resource directory
775 * and fake resource entries. There are several reasons for this:
776 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
777 * fields
778 * There are some "bad" cursor files which do not have
779 * bColorCount initialized but instead one must read this info
780 * directly from corresponding DIB sections
781 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
782 */
783BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
784 CURSORICONDIR **res, LPBYTE **ptr)
785{
786 LPBYTE _free;
787 CURSORICONFILEDIR *bits;
788 int entries, size, i;
789 HANDLE hMapping = 0;
790
791 *res = NULL;
792 *ptr = NULL;
793
794 hMapping = VIRTUAL_MapFileW( filename, (LPVOID *)&bits, TRUE);
795 if(hMapping == INVALID_HANDLE_VALUE)
796 return FALSE;
797
798 /* FIXME: test for inimated icons
799 * hack to load the first icon from the *.ani file
800 */
801 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
802 {
803 LPBYTE pos = (LPBYTE) bits;
804 dprintf(("Animated icons not correctly implemented! %p \n", bits));
805
806 for (;;)
807 {
808 if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
809 {
810 dprintf(("icon entry found! %p\n", bits));
811 pos+=4;
812 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
813 {
814 goto fail;
815 }
816 bits=(CURSORICONFILEDIR*)(pos+4);
817 dprintf(("icon size ok. offset=%p \n", bits));
818 break;
819 }
820 pos+=2;
821 if (pos>=(LPBYTE)bits+766) goto fail;
822 }
823 }
824 if (!(entries = bits->idCount)) goto fail;
825 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
826 _free = (LPBYTE) size;
827
828 for (i=0; i < entries; i++)
829 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
830
831 if (!(*ptr = (LPBYTE *)HeapAlloc( GetProcessHeap(), 0,
832 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
833 if (!(*res = (CURSORICONDIR *)HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
834
835 _free = (LPBYTE)(*res) + (int)_free;
836 memcpy((*res), bits, 6);
837 for (i=0; i<entries; i++)
838 {
839 ((LPBYTE*)(*ptr))[i] = _free;
840 if (fCursor) {
841 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
842 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
843 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
844 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
845 _free+=sizeof(POINT16);
846 }
847 else {
848 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
849 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
850 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
851 }
852 (*res)->idEntries[i].wPlanes=1;
853 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
854 bits->idEntries[i].dwDIBOffset))->biBitCount;
855 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
856 (*res)->idEntries[i].wResId=i+1;
857
858 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
859 (*res)->idEntries[i].dwBytesInRes);
860 _free += (*res)->idEntries[i].dwBytesInRes;
861 }
862 UnmapViewOfFile( bits );
863 CloseHandle(hMapping);
864 return TRUE;
865
866fail:
867 if (*res) HeapFree( GetProcessHeap(), 0, *res );
868 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
869
870 UnmapViewOfFile( bits );
871 CloseHandle(hMapping);
872 return FALSE;
873}
874
875/**********************************************************************
876 * CURSORICON_CreateFromResource
877 *
878 * Create a cursor or icon from in-memory resource template.
879 *
880 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
881 * with cbSize parameter as well.
882 */
883static HGLOBAL CURSORICON_CreateFromResource( HINSTANCE hInstance, DWORD dwResGroupId, HGLOBAL hObj, LPBYTE bits,
884 UINT cbSize, BOOL bIcon, DWORD dwVersion,
885 INT width, INT height, UINT loadflags )
886{
887 int sizeAnd, sizeXor;
888 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
889 BITMAP bmpXor, bmpAnd;
890 POINT16 hotspot;
891 BITMAPINFO *bmi;
892 HDC hdc = 0;
893 BOOL DoStretch;
894 INT size, colortablesize, bwsize, colorsize;
895
896 hotspot.x = ICON_HOTSPOT;
897 hotspot.y = ICON_HOTSPOT;
898
899 dprintf2(("CURSORICON_CreateFromResource %x %x %x %x %d", hInstance, dwResGroupId, hObj, bits, cbSize));
900
901 if (dwVersion == 0x00020000)
902 {
903 dprintf(("CURSORICON_CreateFromResource 2.xx resources are not supported"));
904 return 0;
905 }
906
907 if (bIcon) {
908 bmi = (BITMAPINFO *)bits;
909 }
910 else /* get the hotspot */
911 {
912 POINT16 *pt = (POINT16 *)bits;
913 hotspot = *pt;
914 bmi = (BITMAPINFO *)(pt + 1);
915 }
916 size = DIB_BitmapInfoSize(bmi, DIB_RGB_COLORS);
917
918 if (!width) width = bmi->bmiHeader.biWidth;
919 if (!height) height = bmi->bmiHeader.biHeight/2;
920
921 DoStretch = (bmi->bmiHeader.biHeight/2 != height) || (bmi->bmiHeader.biWidth != width);
922
923 colorsize = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2, bmi->bmiHeader.biBitCount);
924 bwsize = BITMAP_GetWidthBytes(bmi->bmiHeader.biWidth, 1) * bmi->bmiHeader.biHeight/2;
925
926 /* Check bitmap header */
927 if((bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
928 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
929 bmi->bmiHeader.biCompression != BI_RGB) )
930 {
931 return 0;
932 }
933
934#ifdef __WIN32OS2__
935 if( (hdc = CreateCompatibleDC( 0 )) != 0 )
936#else
937 if( (hdc = GetDC( 0 )) )
938#endif
939 {
940 BITMAPINFO* pInfo;
941
942 /* Make sure we have room for the monochrome bitmap later on.
943 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
944 * up to and including the biBitCount. In-memory icon resource
945 * format is as follows:
946 *
947 * BITMAPINFOHEADER icHeader // DIB header
948 * RGBQUAD icColors[] // Color table
949 * BYTE icXOR[] // DIB bits for XOR mask
950 * BYTE icAND[] // DIB bits for AND mask
951 */
952
953 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
954 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))) != NULL)
955 {
956 memcpy( pInfo, bmi, size );
957 pInfo->bmiHeader.biHeight /= 2;
958
959 /* Create the XOR bitmap */
960 if (DoStretch)
961 {
962 if(bIcon)
963 {
964 hXorBits = CreateCompatibleBitmap(hdc, width, height);
965 }
966 else
967 {
968 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
969 }
970 if(hXorBits)
971 {
972 HBITMAP hOld;
973 HDC hMem = CreateCompatibleDC(hdc);
974 BOOL res;
975
976 if (hMem) {
977 hOld = SelectObject(hMem, hXorBits);
978 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
979 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
980 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
981 SelectObject(hMem, hOld);
982 DeleteDC(hMem);
983 }
984 else res = FALSE;
985 if (!res) {
986 DeleteObject(hXorBits);
987 hXorBits = 0;
988 }
989 }
990 }
991 else
992 {
993 hXorBits = CreateDIBitmap(hdc, &pInfo->bmiHeader,
994 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
995 }
996 if( hXorBits )
997 {
998 char* xbits = (char *)bmi + size + DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
999 bmi->bmiHeader.biHeight,
1000 bmi->bmiHeader.biBitCount) / 2;
1001
1002 pInfo->bmiHeader.biBitCount = 1;
1003 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
1004 {
1005 RGBQUAD *rgb = pInfo->bmiColors;
1006
1007 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
1008 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
1009 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
1010 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
1011 }
1012 else
1013 {
1014 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
1015
1016 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
1017 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
1018 }
1019
1020 /* Create the AND bitmap */
1021 if (DoStretch)
1022 {
1023 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL)) != 0)
1024 {
1025 HBITMAP hOld;
1026 HDC hMem = CreateCompatibleDC(hdc);
1027 BOOL res;
1028
1029 if (hMem) {
1030 hOld = SelectObject(hMem, hAndBits);
1031//SvL: This also doesn't work as StretchDIBits doesn't handle 1bpp bitmaps correctly
1032//--------->>> hack alert!
1033#if 1
1034 HBITMAP hBmp, hOld1;
1035 HDC hMem1;
1036
1037 hMem1 = CreateCompatibleDC(hdc);
1038
1039 int linewidth = BITMAP_GetWidthBytes(pInfo->bmiHeader.biWidth, 1);
1040
1041 char *newpix = (char *)malloc(linewidth*pInfo->bmiHeader.biHeight);
1042
1043 newpix += ((pInfo->bmiHeader.biHeight-1)*linewidth);
1044
1045 if(cbSize - size - colorsize - bwsize == bwsize)
1046 {//this means an AND and XOR mask is present (interleaved; and/xor)
1047 for(int i=0;i<pInfo->bmiHeader.biHeight;i++) {
1048 memcpy(newpix, xbits, linewidth);
1049 newpix -= linewidth;
1050 xbits += linewidth*2;
1051 }
1052 }
1053 else {
1054 for(int i=0;i<pInfo->bmiHeader.biHeight;i++) {
1055 memcpy(newpix, xbits, linewidth);
1056 newpix -= linewidth;
1057 xbits += linewidth;
1058 }
1059 }
1060 newpix += linewidth;
1061 hBmp = CreateBitmap(pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight, 1, 1, newpix);
1062 free(newpix);
1063
1064 hOld1 = SelectObject(hMem1, hBmp);
1065
1066 res = StretchBlt(hMem, 0, 0, width, height, hMem1, 0, 0, pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight, SRCCOPY);
1067
1068 SelectObject(hMem1, hOld1);
1069 DeleteObject(hBmp);
1070 DeleteDC(hMem1);
1071
1072
1073#else
1074 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
1075 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
1076 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
1077#endif
1078 SelectObject(hMem, hOld);
1079 DeleteDC(hMem);
1080 }
1081 else res = FALSE;
1082 if (!res) {
1083 DeleteObject(hAndBits);
1084 hAndBits = 0;
1085 }
1086 }
1087 }
1088 else {
1089//SvL: Must use CreateBitmap here as CreateDIBitmap converts data to 8bpp (GetObjectA info -> 8 bpp)
1090#if 1
1091 int linewidth;
1092 int orglinewidth;
1093
1094 linewidth = BITMAP_GetWidthBytes(width, 1);
1095
1096 //the lines in the image might be aligned differently
1097 //CreateBitmap expects them to be optimally aligned
1098 //(as calculated by BITMAP_GetWidthBytes)
1099 //(For now only applies when both masks (and/xor) aren't present)
1100 if(pInfo->bmiHeader.biSizeImage > colorsize + bwsize) {
1101 orglinewidth = (pInfo->bmiHeader.biSizeImage - colorsize)/height;
1102 }
1103 else orglinewidth = linewidth;
1104
1105 char *newpix = (char *)malloc(linewidth*height);
1106
1107 newpix += ((height-1)*linewidth);
1108
1109 if(cbSize - size - colorsize - bwsize == bwsize)
1110 {//this means an AND and XOR mask is present (interleaved; and/xor)
1111 for(int i=0;i<height;i++) {
1112 memcpy(newpix, xbits, linewidth);
1113 newpix -= linewidth;
1114 xbits += linewidth*2;
1115 }
1116 }
1117 else {
1118 for(int i=0;i<height;i++) {
1119 memcpy(newpix, xbits, linewidth);
1120 newpix -= linewidth;
1121 xbits += orglinewidth;
1122 }
1123 }
1124 newpix += linewidth;
1125 hAndBits = CreateBitmap(width, height, 1, 1, newpix);
1126
1127 free(newpix);
1128
1129#else
1130 hAndBits = CreateDIBitmap(hdc, &pInfo->bmiHeader,
1131 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
1132#endif
1133 }
1134 if( !hAndBits )
1135 DeleteObject( hXorBits );
1136 }
1137 HeapFree( GetProcessHeap(), 0, pInfo );
1138 }
1139#ifdef __WIN32OS2__
1140 DeleteDC(hdc );
1141#else
1142 ReleaseDC( 0, hdc );
1143#endif
1144 }
1145
1146 if( !hXorBits || !hAndBits )
1147 {
1148 dprintf(("\tunable to create an icon bitmap."));
1149 return 0;
1150 }
1151 /* Now create the CURSORICONINFO structure */
1152 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
1153 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
1154 colortablesize = 0;
1155
1156 //SvL: Workaround for problem with B&W cursor XOR bitmaps
1157 // End result = inverted PM cursor; not sure what's actually causing
1158 // this...
1159 // So we let GetDIBits convert the mono cursor to 8bpp
1160 if(bmpXor.bmBitsPixel == 1)
1161 {
1162 bmpXor.bmBitsPixel = 8;
1163 bmpXor.bmWidthBytes *= 8;
1164 }
1165
1166 // CreateDIBits expectes DWORD-aligned scan lines
1167 bmpXor.bmWidthBytes = (bmpXor.bmWidthBytes + 3) / 4 * 4;
1168 bmpAnd.bmWidthBytes = (bmpAnd.bmWidthBytes + 3) / 4 * 4;
1169
1170 if(bmpXor.bmBitsPixel <= 8) {
1171 colortablesize = sizeof(RGBQUAD)*(1<<bmpXor.bmBitsPixel);
1172 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes + colortablesize;
1173 }
1174 else sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1175
1176 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1177
1178 if (hObj) hObj = GlobalReAlloc( hObj,
1179 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
1180 if (!hObj) hObj = GlobalAlloc( GMEM_MOVEABLE,
1181 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1182 if (hObj)
1183 {
1184 CURSORICONINFO *info;
1185
1186 info = (CURSORICONINFO *)GlobalLock( hObj );
1187 info->ptHotSpot.x = hotspot.x;
1188 info->ptHotSpot.y = hotspot.y;
1189 info->nWidth = bmpXor.bmWidth;
1190 info->nHeight = bmpXor.bmHeight;
1191 info->nWidthBytes = bmpXor.bmWidthBytes;
1192 info->bPlanes = bmpXor.bmPlanes;
1193 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1194 info->hInstance = hInstance;
1195 info->dwResGroupId = dwResGroupId;
1196 info->hColorBmp = 0;
1197
1198 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1199 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1));
1200
1201 if(bmpXor.bmBitsPixel > 1)
1202 {
1203 BITMAPINFO* pInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO)+colortablesize+3*sizeof(DWORD)); //+ extra space for > 8bpp images
1204 HBITMAP oldbmp;
1205
1206 hdc = CreateCompatibleDC(0);
1207
1208 memset(pInfo, 0, sizeof(BITMAPINFO)+colortablesize+3*sizeof(DWORD));
1209 pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1210 pInfo->bmiHeader.biPlanes = info->bPlanes;
1211 pInfo->bmiHeader.biBitCount = info->bBitsPerPixel;
1212
1213 GetDIBits(hdc, hXorBits, 0, bmpXor.bmHeight, (char *)(info + 1) + sizeAnd + colortablesize, pInfo, DIB_RGB_COLORS);
1214 if(colortablesize) {
1215 memcpy((char *)(info + 1) + sizeAnd, (char *)&pInfo->bmiHeader + pInfo->bmiHeader.biSize, colortablesize);
1216 }
1217
1218 DeleteDC(hdc);
1219 free(pInfo);
1220 }
1221 else {
1222 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd);
1223 }
1224 info->hColorBmp = OSLibWinCreatePointer(info, (char*)(info + 1), (LPBITMAP_W)&bmpAnd, (char*)(info + 1) + sizeAnd, (LPBITMAP_W)&bmpXor, bIcon == FALSE);
1225
1226 dprintf(("Create cursor/icon %x with OS/2 pointer handle %x", hObj, info->hColorBmp));
1227 GlobalUnlock( hObj );
1228 }
1229
1230 DeleteObject( hAndBits );
1231 DeleteObject( hXorBits );
1232
1233#ifdef __WIN32OS2__
1234 if(hObj) {
1235 HICON hIcon;
1236 if(ObjAllocateHandle(&hIcon, (DWORD)hObj, HNDL_CURSORICON) == FALSE) {
1237 GlobalFree(hObj);
1238 dprintf(("ERROR: CURSORICON_Load ObjAllocateHandle failed!!"));
1239 return 0;
1240 }
1241 return hIcon;
1242 }
1243#endif
1244 return hObj;
1245}
1246
1247/**********************************************************************
1248 * CURSORICON_Destroy (USER.610)
1249 *
1250 * This routine is actually exported from Win95 USER under the name
1251 * DestroyIcon32 ... The behaviour implemented here should mimic
1252 * the Win95 one exactly, especially the return values, which
1253 * depend on the setting of various flags.
1254 */
1255WORD WIN32API CURSORICON_Destroy( HGLOBAL handle, UINT flags )
1256{
1257 WORD retv;
1258
1259 /* Check whether destroying active cursor */
1260
1261 if ( hActiveCursor == handle )
1262 {
1263 dprintf(("WARNING: Destroying active cursor!" ));
1264 SetCursor( 0 );
1265 }
1266
1267#ifdef __WIN32OS2__
1268 HICON hIcon = ObjQueryHandleData(handle, HNDL_CURSORICON);
1269 if(hIcon == -1) {
1270 dprintf(("ERROR: Invalid cursor/icon!"));
1271 return 0;
1272 }
1273#endif
1274
1275 /* Try shared cursor/icon first */
1276 if ( !(flags & CID_NONSHARED) )
1277 {
1278 INT count = CURSORICON_DelSharedIcon( handle );
1279
1280 if ( count != -1 )
1281 return (flags & CID_WIN32)? TRUE : (count == 0);
1282
1283 /* FIXME: OEM cursors/icons should be recognized */
1284 }
1285 /* Now assume non-shared cursor/icon */
1286
1287#ifdef __WIN32OS2__
1288 CURSORICONINFO *iconinfo = (CURSORICONINFO *)GlobalLock((HGLOBAL)hIcon);
1289 if (!iconinfo) {
1290 dprintf(("ERROR: Invalid cursor!"));
1291 return 0;
1292 }
1293
1294 if(iconinfo->hColorBmp) {
1295 OSLibWinDestroyPointer(iconinfo->hColorBmp);
1296 }
1297 GlobalUnlock(hIcon);
1298 retv = GlobalFree( hIcon );
1299 ObjDeleteHandle(handle, HNDL_CURSORICON);
1300
1301 return (flags & CID_RESOURCE)? retv : TRUE;
1302#else
1303 retv = GlobalFree( handle );
1304 return (flags & CID_RESOURCE)? retv : TRUE;
1305#endif
1306}
1307
1308/***********************************************************************
1309 * CURSORICON_Copy
1310 *
1311 * Make a copy of a cursor or icon.
1312 */
1313static HGLOBAL CURSORICON_Copy(HGLOBAL handle)
1314{
1315 char *ptrOld, *ptrNew;
1316 int size;
1317 HGLOBAL hNew;
1318
1319 handle = ObjQueryHandleData(handle, HNDL_CURSORICON);
1320 if(handle == -1) {
1321 dprintf(("ERROR: Invalid cursor/icon!"));
1322 return 0;
1323 }
1324
1325 if (!(ptrOld = (char *)GlobalLock( handle ))) return 0;
1326
1327 size = GlobalSize( handle );
1328 hNew = GlobalAlloc( GMEM_MOVEABLE, size );
1329#ifdef __WIN32OS2__
1330 if(hNew == NULL) {
1331 dprintf(("ERROR: CURSORICON_Copy GlobalAlloc failed!!"));
1332 return NULL;
1333 }
1334#endif
1335 ptrNew = (char *)GlobalLock( hNew );
1336 memcpy( ptrNew, ptrOld, size );
1337 GlobalUnlock( handle );
1338 GlobalUnlock( hNew );
1339
1340#ifdef __WIN32OS2__
1341 HICON hIcon;
1342 if(ObjAllocateHandle(&hIcon, (DWORD)hNew, HNDL_CURSORICON) == FALSE) {
1343 GlobalFree(hNew);
1344 dprintf(("ERROR: CURSORICON_Copy ObjAllocateHandle failed!!"));
1345 return 0;
1346 }
1347 return hIcon;
1348#else
1349 return hNew;
1350#endif
1351}
1352
1353/*************************************************************************
1354 * CURSORICON_ExtCopy
1355 *
1356 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1357 *
1358 * PARAMS
1359 * Handle [I] handle to an Image
1360 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1361 * iDesiredCX [I] The Desired width of the Image
1362 * iDesiredCY [I] The desired height of the Image
1363 * nFlags [I] The flags from CopyImage
1364 *
1365 * RETURNS
1366 * Success: The new handle of the Image
1367 *
1368 * NOTES
1369 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1370 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
1371 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1372 *
1373 *
1374 */
1375HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
1376 INT iDesiredCX, INT iDesiredCY,
1377 UINT nFlags)
1378{
1379 HGLOBAL hNew=0;
1380
1381#ifdef __WIN32OS2__
1382 HICON hIcon = ObjQueryHandleData(Handle, HNDL_CURSORICON);
1383 if(hIcon == -1) {
1384 dprintf(("ERROR: Invalid cursor/icon!"));
1385 return 0;
1386 }
1387
1388#else
1389 if(Handle == 0)
1390 {
1391 return 0;
1392 }
1393#endif
1394 /* Best Fit or Monochrome */
1395 if( (nFlags & LR_COPYFROMRESOURCE
1396 && (iDesiredCX > 0 || iDesiredCY > 0))
1397 || nFlags & LR_MONOCHROME)
1398 {
1399#ifdef __WIN32OS2__
1400 ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1401#else
1402 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
1403#endif
1404
1405 /* Not Found in Cache, then do a straight copy
1406 */
1407 if(pIconCache == NULL)
1408 {
1409#ifdef __WIN32OS2__
1410 hNew = CURSORICON_Copy(Handle);
1411#else
1412 hNew = CURSORICON_Copy(0, Handle);
1413#endif
1414 if(nFlags & LR_COPYFROMRESOURCE)
1415 {
1416 dprintf(("WARNING: LR_COPYFROMRESOURCE: Failed to load from cache\n"));
1417 }
1418 }
1419 else
1420 {
1421 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1422 LPBYTE pBits;
1423 HANDLE hMem;
1424 HRSRC hRsrc;
1425 DWORD dwBytesInRes;
1426 WORD wResId;
1427 DWORD dwResGroupId;
1428 HINSTANCE hInstance;
1429 CURSORICONINFO *iconinfo;
1430 CURSORICONDIR *pDir;
1431 CURSORICONDIRENTRY *pDirEntry;
1432 BOOL bIsIcon = (nType == IMAGE_ICON);
1433
1434#ifdef __WIN32OS2__
1435 iconinfo = (CURSORICONINFO *)GlobalLock( hIcon );
1436#else
1437 iconinfo = (CURSORICONINFO *)GlobalLock( Handle );
1438#endif
1439 if(iconinfo == NULL) {
1440 dprintf(("ERROR: CURSORICON_ExtCopy invalid icon!"));
1441 }
1442 hInstance = iconinfo->hInstance;
1443 dwResGroupId = iconinfo->dwResGroupId;
1444 GlobalUnlock( Handle );
1445 if(dwResGroupId == -1) {
1446 //todo: if scaling is necessary..
1447 dprintf(("WARNING: no resource associated with icon/cursor -> copy without scaling!"));
1448 hNew = CURSORICON_Copy(Handle);
1449 return hNew;
1450 }
1451
1452 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1453 */
1454 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1455 || (iDesiredCX == 0 && iDesiredCY == 0))
1456 {
1457 iDesiredCY = GetSystemMetrics(bIsIcon ? SM_CYICON : SM_CYCURSOR);
1458 iDesiredCX = GetSystemMetrics(bIsIcon ? SM_CXICON : SM_CXCURSOR);
1459 }
1460
1461 /* Retreive the CURSORICONDIRENTRY
1462 */
1463 hRsrc = FindResourceW(hInstance, (LPWSTR)dwResGroupId, bIsIcon ? RT_GROUP_ICONW : RT_GROUP_CURSORW);
1464 if(!hRsrc) {
1465 goto notfound;
1466 }
1467
1468 if (!(hMem = LoadResource( hInstance, hRsrc)))
1469 {
1470 goto notfound;
1471 }
1472 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
1473 {
1474 goto notfound;
1475 }
1476
1477 /* Find Best Fit
1478 */
1479 if(bIsIcon)
1480 {
1481 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
1482 pDir, iDesiredCX, iDesiredCY, 256);
1483 }
1484 else
1485 {
1486 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
1487 pDir, iDesiredCX, iDesiredCY, 1);
1488 }
1489
1490 wResId = pDirEntry->wResId;
1491 dwBytesInRes = pDirEntry->dwBytesInRes;
1492 FreeResource(hMem);
1493
1494 /* Get the Best Fit
1495 */
1496 if (!(hRsrc = FindResourceW(hInstance ,
1497 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
1498 {
1499 goto notfound;
1500 }
1501 if (!(hMem = LoadResource( hInstance, hRsrc )))
1502 {
1503 goto notfound;
1504 }
1505
1506 pBits = (LPBYTE)LockResource( hMem );
1507
1508 if(nFlags & LR_DEFAULTSIZE)
1509 {
1510 iTargetCY = GetSystemMetrics(SM_CYICON);
1511 iTargetCX = GetSystemMetrics(SM_CXICON);
1512 }
1513
1514 /* Create a New Icon with the proper dimension
1515 */
1516 hNew = CURSORICON_CreateFromResource( hInstance, dwResGroupId, 0, pBits, dwBytesInRes,
1517 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1518 FreeResource(hMem);
1519 }
1520 }
1521 else
1522 {
1523 hNew = CURSORICON_Copy(Handle);
1524 }
1525 return hNew;
1526
1527notfound:
1528 dprintf(("WARNING: unable to find resource associated with icon/cursor -> copy without scaling!"));
1529 hNew = CURSORICON_Copy(Handle);
1530 return hNew;
1531}
1532
1533/**********************************************************************
1534 * CURSORICON_FindBestIcon
1535 *
1536 * Find the icon closest to the requested size and number of colors.
1537 */
1538static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
1539 int height, int colors )
1540{
1541 int i;
1542 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
1543 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
1544 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
1545
1546 if (dir->idCount < 1)
1547 {
1548 dprintf(("Empty directory!\n" ));
1549 return NULL;
1550 }
1551 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
1552
1553 /* Find Best Fit */
1554 iTotalDiff = 0xFFFFFFFF;
1555 iColorDiff = 0xFFFFFFFF;
1556 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1557 {
1558 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
1559 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
1560
1561 if(iTotalDiff > (iTempXDiff + iTempYDiff))
1562 {
1563 iXDiff = iTempXDiff;
1564 iYDiff = iTempYDiff;
1565 iTotalDiff = iXDiff + iYDiff;
1566 }
1567 }
1568
1569 /* Find Best Colors for Best Fit */
1570 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1571 {
1572 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
1573 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
1574 {
1575#ifdef __WIN32OS2__
1576 iTempColorDiff = abs(colors - (1 << entry->wBitCount));
1577#else
1578 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
1579#endif
1580 if(iColorDiff > iTempColorDiff)
1581 {
1582 bestEntry = entry;
1583 iColorDiff = iTempColorDiff;
1584 }
1585 }
1586 }
1587////testestest
1588 dprintf(("CURSORICON_FindBestIcon (%d,%d) %d -> %d", width, height, colors, (bestEntry) ? bestEntry->wResId : 0));
1589 return bestEntry;
1590}
1591
1592
1593/**********************************************************************
1594 * CURSORICON_FindBestCursor
1595 *
1596 * Find the cursor closest to the requested size.
1597 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
1598 * ignored too
1599 */
1600static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
1601 int width, int height, int color)
1602{
1603 int i, maxwidth, maxheight;
1604 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
1605
1606 if (dir->idCount < 1)
1607 {
1608 dprintf(("Empty directory!\n" ));
1609 return NULL;
1610 }
1611 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
1612
1613 /* Double height to account for AND and XOR masks */
1614
1615 height *= 2;
1616
1617 /* First find the largest one smaller than or equal to the requested size*/
1618
1619 maxwidth = maxheight = 0;
1620 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1621 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
1622 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
1623 (entry->wBitCount == 1))
1624 {
1625 bestEntry = entry;
1626 maxwidth = entry->ResInfo.cursor.wWidth;
1627 maxheight = entry->ResInfo.cursor.wHeight;
1628 }
1629 if (bestEntry) return bestEntry;
1630
1631 /* Now find the smallest one larger than the requested size */
1632
1633 maxwidth = maxheight = 255;
1634 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
1635 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
1636 (entry->wBitCount == 1))
1637 {
1638 bestEntry = entry;
1639 maxwidth = entry->ResInfo.cursor.wWidth;
1640 maxheight = entry->ResInfo.cursor.wHeight;
1641 }
1642
1643 return bestEntry;
1644}
1645/**********************************************************************
1646 * LookupIconIdFromDirectoryEx (USER.364)
1647 *
1648 * FIXME: exact parameter sizes
1649 */
1650INT WIN32API LookupIconIdFromDirectoryEx(LPBYTE xdir, BOOL bIcon,
1651 INT width, INT height, UINT cFlag )
1652{
1653 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1654 UINT retVal = 0;
1655
1656 dprintf(("LookupIconIdFromDirectoryEx %x %d (%d,%d)", xdir, bIcon, width, height));
1657 if( dir && !dir->idReserved && (dir->idType & 3) )
1658 {
1659 CURSORICONDIRENTRY* entry;
1660 HDC hdc;
1661 UINT palEnts;
1662 int colors;
1663 hdc = GetDC(0);
1664 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1665 if (palEnts == 0)
1666 palEnts = 256;
1667 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1668
1669 ReleaseDC(0, hdc);
1670
1671 if( bIcon )
1672 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1673 else
1674 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1675
1676 if( entry ) retVal = entry->wResId;
1677 }
1678 else dprintf(("invalid resource directory\n"));
1679 return retVal;
1680}
1681/**********************************************************************
1682 * LookupIconIdFromDirectory (USER32.379)
1683 */
1684INT WIN32API LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1685{
1686 return LookupIconIdFromDirectoryEx( dir, bIcon,
1687 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1688 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1689}
1690//******************************************************************************
1691//******************************************************************************
1692
1693//ICON cache implementation (Wine code)
1694
1695/**********************************************************************
1696 * CURSORICON_FindSharedIcon
1697 */
1698static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
1699{
1700 HANDLE handle = 0;
1701 ICONCACHE *ptr;
1702
1703 EnterCriticalSection( &IconCrst );
1704
1705 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
1706 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
1707 {
1708 ptr->count++;
1709 handle = ptr->handle;
1710 break;
1711 }
1712
1713 LeaveCriticalSection( &IconCrst );
1714
1715 return handle;
1716}
1717
1718/*************************************************************************
1719 * CURSORICON_FindCache
1720 *
1721 * Given a handle, find the corresponding cache element
1722 *
1723 * PARAMS
1724 * Handle [I] handle to an Image
1725 *
1726 * RETURNS
1727 * Success: The cache entry
1728 * Failure: NULL
1729 *
1730 */
1731static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
1732{
1733 ICONCACHE *ptr;
1734 ICONCACHE *pRet=NULL;
1735 BOOL IsFound = FALSE;
1736 int count;
1737
1738 EnterCriticalSection( &IconCrst );
1739
1740 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
1741 {
1742 if ( handle == ptr->handle )
1743 {
1744 IsFound = TRUE;
1745 pRet = ptr;
1746 }
1747 }
1748
1749 LeaveCriticalSection( &IconCrst );
1750
1751 return pRet;
1752}
1753
1754/**********************************************************************
1755 * CURSORICON_AddSharedIcon
1756 */
1757static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
1758{
1759 ICONCACHE *ptr = (ICONCACHE *)HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
1760 if ( !ptr ) return;
1761
1762 ptr->hModule = hModule;
1763 ptr->hRsrc = hRsrc;
1764 ptr->handle = handle;
1765 ptr->hGroupRsrc = hGroupRsrc;
1766 ptr->count = 1;
1767
1768 EnterCriticalSection( &IconCrst );
1769 ptr->next = IconAnchor;
1770 IconAnchor = ptr;
1771 LeaveCriticalSection( &IconCrst );
1772}
1773
1774/**********************************************************************
1775 * CURSORICON_DelSharedIcon
1776 */
1777static INT CURSORICON_DelSharedIcon( HANDLE handle )
1778{
1779 INT count = -1;
1780 ICONCACHE *ptr;
1781
1782 EnterCriticalSection( &IconCrst );
1783
1784 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
1785 if ( ptr->handle == handle )
1786 {
1787 if ( ptr->count > 0 ) ptr->count--;
1788 count = ptr->count;
1789 break;
1790 }
1791
1792 LeaveCriticalSection( &IconCrst );
1793
1794 return count;
1795}
1796
1797/**********************************************************************
1798 * CURSORICON_FreeModuleIcons
1799 */
1800void CURSORICON_FreeModuleIcons( HMODULE hModule )
1801{
1802 ICONCACHE **ptr = &IconAnchor;
1803
1804 EnterCriticalSection( &IconCrst );
1805
1806 while ( *ptr )
1807 {
1808 if ( (*ptr)->hModule == hModule )
1809 {
1810 ICONCACHE *freePtr = *ptr;
1811 *ptr = freePtr->next;
1812
1813#ifdef __WIN32OS2__
1814 CURSORICON_Destroy(freePtr->handle, CID_NONSHARED);
1815#else
1816 GlobalFree( freePtr->handle );
1817#endif
1818 HeapFree( GetProcessHeap(), 0, freePtr );
1819 continue;
1820 }
1821 ptr = &(*ptr)->next;
1822 }
1823
1824 LeaveCriticalSection( &IconCrst );
1825}
1826
Note: See TracBrowser for help on using the repository browser.