/*++ * * WOW v1.0 * * Copyright (c) 1991, Microsoft Corporation * * RMLOAD.C * WOW16 user resource services * * History: * * Created 12-Apr-1991 by Nigel Thompson (nigelt) * Much hacked about version of the Win 3.1 rmload.c source * It doesn't attempt any device driver resource loading * or do anything to support Win 2.x apps. * * Revised 19-May-1991 by Jeff Parsons (jeffpar) * IFDEF'ed everything except LoadString; because of the client/server * split in USER32, most resources are copied to the server's context and * freed in the client's, meaning the client no longer gets a handle to * a global memory object. We could give it one, but it would be a separate * object, which we would have to keep track of, and which would be difficult * to keep in sync with the server's copy if changes were made. --*/ /****************************************************************************/ /* */ /* RMLOAD.C - */ /* */ /* Resource Loading Routines. */ /* */ /****************************************************************************/ #define RESOURCESTRINGS #include "user.h" #include "multires.h" // // We define certain things here because including mvdm\inc\*.h files here // will lead to endless mess. // DWORD API NotifyWow(WORD, LPBYTE); typedef struct _LOADACCEL16 { /* ldaccel */ WORD hInst; WORD hAccel; LPBYTE pAccel; DWORD cbAccel; } LOADACCEL16, FAR *PLOADACCEL16; /* This must match its counterpart in mvdm\inc\wowusr.h */ #define NW_LOADACCELERATORS 3 // /*--------------------------------------------------------------------------*/ /* */ /* LoadAccelerators() - */ /* */ /*--------------------------------------------------------------------------*/ HACCEL API ILoadAccelerators(HINSTANCE hInstance, LPCSTR lpszAccName) { HRSRC hrl; HACCEL hAccel = NULL; LOADACCEL16 loadaccel; hrl = FindResource(hInstance, lpszAccName, RT_ACCELERATOR); #ifdef WOW if (hrl) { hAccel = (HACCEL)LoadResource(hInstance, hrl); if (hAccel) { // create 32bit accelerator and 16-32 alias. loadaccel.hInst = (WORD)hInstance; loadaccel.hAccel = (WORD)hAccel; loadaccel.pAccel = (LPBYTE)LockResource(hAccel); loadaccel.cbAccel = (DWORD)SizeofResource(hInstance, hrl); if (NotifyWow(NW_LOADACCELERATORS, (LPBYTE)&loadaccel)) { UnlockResource(hAccel); } else { UnlockResource(hAccel); hAccel = NULL; } } } return (hAccel); #else if (!hrl) return NULL; return (HACCEL)LoadResource(hInstance, hrl); #endif } int API ILoadString( HINSTANCE h16Task, UINT wID, LPSTR lpBuffer, register int nBufferMax) { HANDLE hResInfo; HANDLE hStringSeg; LPSTR lpsz; register int cch, i; /* Make sure the parms are valid. */ if (!lpBuffer || (nBufferMax-- == 0)) return(0); cch = 0; /* String Tables are broken up into 16 string segments. Find the segment * containing the string we are interested in. */ if (hResInfo = FindResource(h16Task, (LPSTR)((LONG)((wID >> 4) + 1)), RT_STRING)) { /* Load that segment. */ hStringSeg = LoadResource(h16Task, hResInfo); /* Lock the resource. */ if (lpsz = (LPSTR)LockResource(hStringSeg)) { /* Move past the other strings in this segment. */ wID &= 0x0F; while (TRUE) { cch = *((BYTE FAR *)lpsz++); if (wID-- == 0) break; lpsz += cch; } /* Don't copy more than the max allowed. */ if (cch > nBufferMax) cch = nBufferMax; /* Copy the string into the buffer. */ LCopyStruct(lpsz, lpBuffer, cch); GlobalUnlock(hStringSeg); /* BUG: If we free the resource here, we will have to reload it * immediately for many apps with sequential strings. * Force it to be discardable however because non-discardable * string resources make no sense. Chip */ GlobalReAlloc(hStringSeg, 0L, GMEM_MODIFY | GMEM_MOVEABLE | GMEM_DISCARDABLE); } } /* Append a NULL. */ lpBuffer[cch] = 0; return(cch); } #ifdef NEEDED #define DIB_RGB_COLORS 0 HBITMAP FAR PASCAL ConvertBitmap(HBITMAP hBitmap); HANDLE NEAR PASCAL LoadDIBCursorIconHandler(HANDLE, HANDLE, HANDLE, BOOL); WORD FAR PASCAL GetIconId(HANDLE, LPSTR); HBITMAP FAR PASCAL StretchBitmap(int, int, int, int, HBITMAP, BYTE, BYTE); WORD NEAR PASCAL StretchIcon(LPCURSORSHAPE, WORD, HBITMAP, BOOL); WORD NEAR PASCAL SizeReqd(BOOL, WORD, WORD, BOOL, int, int); WORD NEAR PASCAL CrunchAndResize(LPCURSORSHAPE, BOOL, BOOL, BOOL, BOOL); HANDLE FAR PASCAL LoadCursorIconHandler2(HANDLE, LPCURSORSHAPE, WORD); HANDLE FAR PASCAL LoadDIBCursorIconHandler2(HANDLE, LPCURSORSHAPE, WORD, BOOL); /*--------------------------------------------------------------------------*/ /* */ /* LoadIconHandler() - */ /* */ /*--------------------------------------------------------------------------*/ HICON FAR PASCAL LoadIconHandler(hIcon, fNewFormat) HICON hIcon; BOOL fNewFormat; { LPCURSORSHAPE lpIcon; WORD wSize; dprintf(7,"LoadIconHandler"); wSize = (WORD)GlobalSize(hIcon); lpIcon = (LPCURSORSHAPE)(GlobalLock(hIcon)); if (fNewFormat) return(LoadDIBCursorIconHandler2(hIcon, lpIcon, wSize, TRUE)); else return(LoadCursorIconHandler2(hIcon, lpIcon, wSize)); } /*--------------------------------------------------------------------------*/ /* */ /* FindIndividualResource() */ /* */ /*--------------------------------------------------------------------------*/ HANDLE NEAR PASCAL FindIndividualResource(register HANDLE hResFile, LPSTR lpszName, LPSTR lpszType) { WORD idIcon; register HANDLE h; dprintf(7,"FindIndividualResource"); /* Check if the resource is to be taken from the display driver. * If so, check the driver version; If the resource is to be taken from * the application, check the app version. */ if ((lpszType != RT_BITMAP) && ((LOWORD(GetExpWinVer(hResFile)) >= VER))) { /* Locate the directory resource */ h = SplFindResource(hResFile, lpszName, (LPSTR)(lpszType + DIFFERENCE)); if (h == NULL) return((HANDLE)0); /* Load the directory resource */ h = LoadResource(hResFile, h); /* Get the name of the matching resource */ idIcon = GetIconId(h, lpszType); /* NOTE: Don't free the (discardable) directory resource!!! - ChipA */ /* * We should not call SplFindResource here, because idIcon is * internal to us and GetDriverResourceId won't know how tomap it. */ return(FindResource(hResFile, MAKEINTRESOURCE(idIcon), lpszType)); } else /* It is an Old app; The resource is in old format */ return(SplFindResource(hResFile, lpszName, lpszType)); } /*--------------------------------------------------------------------------*/ /* */ /* GetBestFormIcon() */ /* */ /* Among the different forms of Icons present, choose the one that */ /* matches the PixelsPerInch values and the number of colors of the */ /* current display. */ /* */ /*--------------------------------------------------------------------------*/ WORD NEAR PASCAL GetBestFormIcon(LPRESDIR ResDirPtr, WORD ResCount) { register WORD wIndex; register WORD ColorCount; WORD MaxColorCount; WORD MaxColorIndex; WORD MoreColorCount; WORD MoreColorIndex; WORD LessColorCount; WORD LessColorIndex; WORD DevColorCount; dprintf(7,"GetBestFormIcon"); /* Initialse all the values to zero */ MaxColorCount = MaxColorIndex = MoreColorCount = MoreColorIndex = LessColorIndex = LessColorCount = 0; /* get number of colors on device. if device is very colorful, ** set to a high number without doing meaningless 1<= 16) DevColorCount = 32000; else DevColorCount = 1 << oemInfo.ScreenBitCount; for (wIndex=0; wIndex < ResCount; wIndex++, ResDirPtr++) { /* Check for the number of colors */ if ((ColorCount = (ResDirPtr->ResInfo.Icon.ColorCount)) <= DevColorCount) { if (ColorCount > MaxColorCount) { MaxColorCount = ColorCount; MaxColorIndex = wIndex; } } /* Check for the size */ /* Match the pixels per inch information */ if ((ResDirPtr->ResInfo.Icon.Width == (BYTE)oemInfo.cxIcon) && (ResDirPtr->ResInfo.Icon.Height == (BYTE)oemInfo.cyIcon)) { /* Matching size found */ /* Check if the color also matches */ if (ColorCount == DevColorCount) return(wIndex); /* Exact match found */ if (ColorCount < DevColorCount) { /* Choose the one with max colors, but less than reqd */ if (ColorCount > LessColorCount) { LessColorCount = ColorCount; LessColorIndex = wIndex; } } else { if ((LessColorCount == 0) && (ColorCount < MoreColorCount)) { MoreColorCount = ColorCount; MoreColorIndex = wIndex; } } } } /* Check if we have a correct sized but with less colors than reqd */ if (LessColorCount) return(LessColorIndex); /* Check if we have a correct sized but with more colors than reqd */ if (MoreColorCount) return(MoreColorIndex); /* Check if we have one that has maximum colors but less than reqd */ if (MaxColorCount) return(MaxColorIndex); return(0); } /*--------------------------------------------------------------------------*/ /* */ /* GetBestFormCursor() */ /* */ /* Among the different forms of cursors present, choose the one that */ /* matches the width and height defined by the current display driver. */ /* */ /*--------------------------------------------------------------------------*/ WORD NEAR PASCAL GetBestFormCursor(LPRESDIR ResDirPtr, WORD ResCount) { register WORD wIndex; dprintf(7,"GetBestFormCursor"); for (wIndex=0; wIndex < ResCount; wIndex++, ResDirPtr++) { /* Match the Width and Height of the cursor */ if ((ResDirPtr->ResInfo.Cursor.Width == oemInfo.cxCursor) && ((ResDirPtr->ResInfo.Cursor.Height >> 1) == oemInfo.cyCursor)) return(wIndex); } return(0); } /*--------------------------------------------------------------------------*/ /* */ /* GetIconId() */ /* */ /*--------------------------------------------------------------------------*/ WORD FAR PASCAL GetIconId(hRes, lpszType) HANDLE hRes; LPSTR lpszType; { WORD w; LPRESDIR ResDirPtr; LPNEWHEADER DataPtr; register WORD RetIndex; register WORD ResCount; dprintf(7,"GetIconId"); if ((DataPtr = (LPNEWHEADER)LockResource(hRes)) == NULL) return(0); ResCount = DataPtr->ResCount; ResDirPtr = (LPRESDIR)(DataPtr + 1); switch (LOWORD((DWORD)lpszType)) { case RT_ICON: RetIndex = GetBestFormIcon(ResDirPtr, ResCount); break; case RT_CURSOR: RetIndex = GetBestFormCursor(ResDirPtr, ResCount); break; } if (RetIndex == ResCount) RetIndex = 0; ResCount = ((LPRESDIR)(ResDirPtr+RetIndex))->idIcon; UnlockResource(hRes); return(ResCount); } /*--------------------------------------------------------------------------*/ /* */ /* UT_LoadCursorIconBitmap() - */ /* */ /*--------------------------------------------------------------------------*/ HANDLE NEAR PASCAL UT_LoadCursorIconBitmap(register HANDLE hrf, LPSTR lpszName, int type) { register HANDLE h; dprintf(7,"LoadCursorIconBitmap"); if (hrf == NULL) return (HANDLE)0; // no 2.x support - NigelT h = FindIndividualResource(hrf, lpszName, MAKEINTRESOURCE(type)); if (h != NULL) h = LoadResource(hrf, h); return(h); } /*--------------------------------------------------------------------------*/ /* */ /* fCheckMono() - */ /* Checks a DIB for being truely monochrome. Only called if */ /* BitCount == 1. This function checks the color table (address */ /* passed) for true black and white RGB's */ /* */ /*--------------------------------------------------------------------------*/ BOOL NEAR PASCAL fCheckMono(LPVOID lpColorTable, BOOL fNewDIB) { LPLONG lpRGB; LPWORD lpRGBw; dprintf(7,"fCheckMono"); lpRGB = lpColorTable; if (fNewDIB) { if ((*lpRGB == 0 && *(lpRGB + 1) == 0x00FFFFFF) || (*lpRGB == 0x00FFFFFF && *(lpRGB + 1) == 0)) return(TRUE); } else { lpRGBw = lpColorTable; if (*(LPSTR)lpRGBw == 0) { if (*lpRGBw == 0 && *(lpRGBw+1) == 0xFF00 && *(lpRGBw+2) == 0xFFFF) return(TRUE); } else if (*lpRGBw == 0xFFFF && *(lpRGBw+1) == 0x00FF && *(lpRGBw+2) == 0) return(TRUE); } return(FALSE); } /*--------------------------------------------------------------------------*/ /* */ /* LoadNewBitmap() - */ /* */ /*--------------------------------------------------------------------------*/ /* Loads a 3.x format bitmap into the DIB structure. */ HBITMAP NEAR PASCAL LoadNewBitmap(HANDLE hRes, LPSTR lpName) { register HBITMAP hbmS; register HBITMAP hBitmap; dprintf(7,"LoadNewBitmap"); if ((hbmS = hBitmap = UT_LoadCursorIconBitmap(hRes,lpName,(WORD)RT_BITMAP))) { /* Convert the DIB bitmap into a bitmap in the internal format */ hbmS = ConvertBitmap(hBitmap); /* Converted bitmap is in hbmS; So, release the DIB */ FreeResource(hBitmap); } return(hbmS); } /*--------------------------------------------------------------------------*/ /* */ /* ConvertBitmap() */ /* */ /* This takes in a handle to data in PM 1.1 or 1.2 DIB format or */ /* Windows 3.0 DIB format and creates a bitmap in the internal */ /* bitmap format and returns the handle to it. */ /* */ /* NOTE: */ /* This function is exported because it is called from CLIPBRD.EXE */ /* */ /*--------------------------------------------------------------------------*/ HBITMAP FAR PASCAL ConvertBitmap(HBITMAP hBitmap) { int Width; register int Height; HDC hDC; BOOL fMono = FALSE; LPSTR lpBits; register HBITMAP hbmS; LPBITMAPINFOHEADER lpBitmap1; LPBITMAPCOREHEADER lpBitmap2; dprintf(7,"ConvertBitmap"); lpBitmap1 = (LPBITMAPINFOHEADER)LockResource(hBitmap); if (!lpBitmap1) return(NULL); if ((WORD)lpBitmap1->biSize == sizeof(BITMAPCOREHEADER)) { /* This is an "old form" DIB. This matches the PM 1.1 format. */ lpBitmap2 = (LPBITMAPCOREHEADER)lpBitmap1; Width = lpBitmap2->bcWidth; Height = lpBitmap2->bcHeight; /* Calcluate the pointer to the Bits information */ /* First skip over the header structure */ lpBits = (LPSTR)(lpBitmap2 + 1); /* Skip the color table entries, if any */ if (lpBitmap2->bcBitCount != 24) { if (lpBitmap2->bcBitCount == 1) fMono = fCheckMono(lpBits, FALSE); lpBits += (1 << (lpBitmap2->bcBitCount)) * sizeof(RGBTRIPLE); } } else { Width = (WORD)lpBitmap1->biWidth; Height = (WORD)lpBitmap1->biHeight; /* Calcluate the pointer to the Bits information */ /* First skip over the header structure */ lpBits = (LPSTR)(lpBitmap1 + 1); /* Skip the color table entries, if any */ if (lpBitmap1->biClrUsed != 0) { if (lpBitmap1->biClrUsed == 2) fMono = fCheckMono(lpBits, TRUE); lpBits += lpBitmap1->biClrUsed * sizeof(RGBQUAD); } else { if (lpBitmap1->biBitCount != 24) { if (lpBitmap1->biBitCount == 1) fMono = fCheckMono(lpBits, TRUE); lpBits += (1 << (lpBitmap1->biBitCount)) * sizeof(RGBQUAD); } } } /* Create a bitmap */ if (fMono) hbmS = CreateBitmap(Width, Height, 1, 1, (LPSTR)NULL); else { /* Create a color bitmap compatible with the display device */ hDC = GetScreenDC(); hbmS = CreateCompatibleBitmap(hDC, Width, Height); InternalReleaseDC(hDC); } /* Initialize the new bitmap by converting from PM format */ if (hbmS != NULL) SetDIBits(hdcBits, hbmS, 0, Height, lpBits, (LPBITMAPINFO)lpBitmap1, DIB_RGB_COLORS); GlobalUnlock(hBitmap); return(hbmS); } HANDLE NEAR PASCAL Helper_LoadCursorOrIcon(HANDLE hRes, LPSTR lpName, WORD type) { HANDLE h; dprintf(7,"Helper_LoadCursorOrIcon"); /* If we can't find the cursor/icon in the app, and this is a 2.x app, we * need to search into the display driver to find it. */ h = UT_LoadCursorIconBitmap(hRes, lpName, type); return(h); } /*--------------------------------------------------------------------------*/ /* */ /* LoadCursor() - */ /* */ /*--------------------------------------------------------------------------*/ HCURSOR API LoadCursor(hRes, lpName) HANDLE hRes; LPSTR lpName; { HCURSOR hcur; dprintf(5,"LoadCursor"); if (hRes == NULL) { dprintf(9," Calling Win32 to load Cursor"); hcur = WOWLoadCursor32(hRes, lpName); } else { hcur = ((HCURSOR)Helper_LoadCursorOrIcon(hRes, lpName, (WORD)RT_CURSOR)); } #ifdef DEBUG if (hcur == NULL) { dprintf(9," Failed, BUT returning 1 so app won't die (yet)"); return (HCURSOR)1; } #endif dprintf(5,"LoadCursor returning %4.4XH", hcur); return hcur; } /*--------------------------------------------------------------------------*/ /* */ /* LoadIcon() - */ /* */ /*--------------------------------------------------------------------------*/ HICON API LoadIcon(hRes, lpName) HANDLE hRes; LPSTR lpName; { HICON hicon; dprintf(5,"LoadIcon"); if (hRes == NULL) { dprintf(9," Calling Win32 to load Icon"); hicon = WOWLoadIcon32(hRes, lpName); } else { hicon = ((HICON)Helper_LoadCursorOrIcon(hRes, lpName, (WORD)RT_ICON)); } #ifdef DEBUG if (hicon == NULL) { dprintf(9," Failed, BUT returning 1 so app won't die (yet)"); return (HICON)1; } #endif dprintf(5,"LoadIcon returning %4.4XH", hicon); return hicon; } /*--------------------------------------------------------------------------*/ /* */ /* StretchBitmap() - */ /* */ /* This routine stretches a bitmap into another bitmap, */ /* and returns the stretched bitmap. */ /*--------------------------------------------------------------------------*/ HBITMAP FAR PASCAL StretchBitmap(iOWidth, iOHeight, iNWidth, iNHeight, hbmS, byPlanes, byBitsPixel) int iOWidth; int iOHeight; int iNWidth; int iNHeight; HBITMAP hbmS; BYTE byPlanes; BYTE byBitsPixel; { register HBITMAP hbmD; HBITMAP hbmDSave; register HDC hdcSrc; dprintf(7,"StretchBitmap"); if ((hdcSrc = CreateCompatibleDC(hdcBits)) != NULL) { if ((hbmD = (HBITMAP)CreateBitmap(iNWidth, iNHeight, byPlanes, byBitsPixel, (LPINT)NULL)) == NULL) goto GiveUp; if ((hbmDSave = SelectObject(hdcBits, hbmD)) == NULL) goto GiveUp; if (SelectObject(hdcSrc, hbmS) != NULL) { /* NOTE: We don't have to save the bitmap returned from * SelectObject(hdcSrc) and select it back in to hdcSrc, * because we delete hdcSrc. */ SetStretchBltMode(hdcBits, COLORONCOLOR); StretchBlt(hdcBits, 0, 0, iNWidth, iNHeight, hdcSrc, 0, 0, iOWidth, iOHeight, SRCCOPY); SelectObject(hdcBits, hbmDSave); DeleteDC(hdcSrc); return(hbmD); } else { GiveUp: if (hbmD != NULL) DeleteObject(hbmD); DeleteDC(hdcSrc); goto Step1; } } else { Step1: return(NULL); } } /*--------------------------------------------------------------------------*/ /* */ /* LoadOldBitmap() - */ /* */ /* This loads bitmaps in old formats( Version 2.10 and below) */ /*--------------------------------------------------------------------------*/ HANDLE NEAR PASCAL LoadOldBitmap(HANDLE hRes, LPSTR lpName) { int oWidth; int oHeight; BYTE planes; BYTE bitsPixel; WORD wCount; DWORD dwCount; LPBITMAP lpBitmap; register HBITMAP hbmS; HBITMAP hbmD; register HBITMAP hBitmap; BOOL fCrunch; WORD wDevDep; dprintf(7,"LoadOldBitmap"); if (hbmS = hBitmap = UT_LoadCursorIconBitmap(hRes, lpName, BMR_BITMAP)) { lpBitmap = (LPBITMAP)LockResource(hBitmap); fCrunch = ((*(((BYTE FAR *)lpBitmap) + 1) & 0x0F) != BMR_DEVDEP); lpBitmap = (LPBITMAP)((BYTE FAR *)lpBitmap + 2); oWidth = lpBitmap->bmWidth; oHeight = lpBitmap->bmHeight; planes = lpBitmap->bmPlanes; bitsPixel = lpBitmap->bmBitsPixel; if (!(*(((BYTE FAR *)lpBitmap) + 1) & 0x80)) { hbmS = CreateBitmap(oWidth, oHeight, planes, bitsPixel, (LPSTR)(lpBitmap + 1)); } else { hbmS = (HBITMAP)CreateDiscardableBitmap(hdcBits, oWidth, oHeight); wCount = (((oWidth * bitsPixel + 0x0F) & ~0x0F) >> 3); dwCount = wCount * oHeight * planes; SetBitmapBits(hbmS, dwCount, (LPSTR)(lpBitmap + 1)); } GlobalUnlock(hBitmap); FreeResource(hBitmap); if (hbmS != NULL) { if (fCrunch && ((64/oemInfo.cxIcon + 64/oemInfo.cyIcon) > 2)) { /* Stretch the Bitmap to suit the device */ hbmD = StretchBitmap(oWidth, oHeight, (oWidth * oemInfo.cxIcon/64), (oHeight * oemInfo.cyIcon/64), hbmS, planes, bitsPixel); /* Delete the old bitmap */ DeleteObject(hbmS); if (hbmD == NULL) return(NULL); /* Some problem in stretching */ else return(hbmD); /* Return the stretched bitmap */ } } } else { return (HANDLE)0; } return(hbmS); } /*--------------------------------------------------------------------------*/ /* */ /* LoadBitmap() - */ /* */ /* This routine decides whether the bitmap to be loaded is in old or */ /* new (DIB) format and calls appropriate handlers. */ /* */ /*--------------------------------------------------------------------------*/ HANDLE API LoadBitmap(hRes, lpName) HANDLE hRes; LPSTR lpName; { HANDLE hbmp; dprintf(5,"LoadBitmap"); if (hRes == NULL) { dprintf(9," Calling Win32 to load Bitmap"); hbmp = WOWLoadBitmap32(hRes, lpName); } else { /* Check if the resource is to be taken from the display driver. If so, * check the driver version; If the resource is to be taken from the * application, check the app version */ if (((hRes == NULL) && (oemInfo.DispDrvExpWinVer >= VER)) || ((hRes != NULL) && (LOWORD(GetExpWinVer(hRes)) >= VER))) { hbmp = (LoadNewBitmap(hRes, lpName)); } else { hbmp = (LoadOldBitmap(hRes, lpName)); } } #ifdef DEBUG if (hbmp == NULL) { dprintf(9," Failed, BUT returning 1 so app won't die (yet)"); return (HANDLE)1; } #endif dprintf(5,"LoadBitmap returning %4.4XH", hbmp); return hbmp; } /*--------------------------------------------------------------------------*/ /* */ /* CrunchAndResize() - */ /* This Crunches the monochrome icons and cursors if required and */ /* returns the newsize of the resource after crunching. */ /* This routine is also called to resize the monochrome AND mask of a */ /* color icon. */ /* Parameters: */ /* lpIcon: Ptr to the resource */ /* fIcon : TRUE, if the resource is an icon. FALSE, if it is a cursor. */ /* fCrunch : TRUE if resource is to be resized. */ /* fSinglePlane: TRUE if only AND mask of a color icon is passed */ /* through lpIcon */ /* fUseSysMetrics: Whether to use the icon/cursor values found in */ /* oemInfo or not. */ /* Returns: */ /* The new size of the resource is returned. */ /* */ /*--------------------------------------------------------------------------*/ WORD NEAR PASCAL CrunchAndResize(lpIcon, fIcon, fCrunch, fSinglePlane, fUseSysMetrics) LPCURSORSHAPE lpIcon; BOOL fIcon; BOOL fCrunch; BOOL fSinglePlane; BOOL fUseSysMetrics; { WORD size; register int cx; register int cy; int oHeight; int nHeight; int iNewcbWidth; BOOL bStretch; HBITMAP hbmS; HBITMAP hbmD; dprintf(7,"CrunhAndResize"); if(fUseSysMetrics) { if(fIcon) { cx = oemInfo.cxIcon; cy = oemInfo.cyIcon; } else { cx = oemInfo.cxCursor; cy = oemInfo.cyCursor; } } else { cx = lpIcon->cx; cy = lpIcon->cy; } if (fIcon) { lpIcon->xHotSpot = cx >> 1; lpIcon->yHotSpot = cy >> 1; if (fSinglePlane) { /* Only the AND mask exists */ oHeight = lpIcon->cy; nHeight = cy; } else { /* Both AND ans XOR masks exist; So, height must be twice */ oHeight = lpIcon->cy << 1; nHeight = cy << 1; } } else { oHeight = lpIcon->cy << 1; nHeight = cy << 1; } iNewcbWidth = ((cx + 0x0F) & ~0x0F) >> 3; size = iNewcbWidth * nHeight; if (fCrunch && ((lpIcon->cx != cx) || (lpIcon->cy != cy))) { if (!fIcon) { lpIcon->xHotSpot = (lpIcon->xHotSpot * cx)/(lpIcon->cx); lpIcon->yHotSpot = (lpIcon->yHotSpot * cy)/(lpIcon->cy); } /* To begin with, assume that no stretching is required */ bStretch = FALSE; /* Check if the width is to be reduced */ if (lpIcon->cx != cx) { /* Stretching the Width is necessary */ bStretch = TRUE; } /* Check if the Height is to be reduced */ if (lpIcon->cy != cy) { /* Stretching in Y direction is necessary */ bStretch = TRUE; } /* Check if stretching is necessary */ if (bStretch) { /* Create a monochrome bitmap with the icon/cursor bits */ if ((hbmS = CreateBitmap(lpIcon->cx, oHeight, 1, 1, (LPSTR)(lpIcon + 1))) == NULL) return(NULL); if ((hbmD = StretchBitmap(lpIcon->cx, oHeight, cx, nHeight, hbmS, 1, 1)) == NULL) { DeleteObject(hbmS); return(NULL); } DeleteObject(hbmS); lpIcon->cx = cx; lpIcon->cy = cy; lpIcon->cbWidth = iNewcbWidth; GetBitmapBits(hbmD, (DWORD)size, (LPSTR)(lpIcon + 1)); DeleteObject(hbmD); } } return(size + sizeof(CURSORSHAPE)); } /*--------------------------------------------------------------------------*/ /* */ /* LoadCursorIconHandler() - */ /* */ /* This handles 2.x (and less) Cursors and Icons */ /* */ /*--------------------------------------------------------------------------*/ HANDLE FAR PASCAL LoadCursorIconHandler(hRes, hResFile, hResIndex) register HANDLE hRes; HANDLE hResFile; HANDLE hResIndex; { register int fh = 0; BOOL bNew = FALSE; WORD wMemSize; LPCURSORSHAPE lpIcon; HANDLE hTempRes; dprintf(7,"LoadCursorIconHandler"); wMemSize = SizeofResource(hResFile, hResIndex); #if 1 // was 0 - NigelT if (!hRes) { if (!(hRes = AllocResource(hResFile, hResIndex, 0L))) return(NULL); fh = -1; bNew = TRUE; } while (!(lpIcon = (LPCURSORSHAPE)GlobalLock(hRes))) { if (!GlobalReAlloc(hRes, (DWORD)wMemSize, 0)) goto LoadCIFail; else fh = -1; } if (fh) { fh = AccessResource(hResFile, hResIndex); if (fh != -1 && _lread(fh, (LPSTR)lpIcon, wMemSize) != 0xFFFF) _lclose(fh); else { if (fh != -1) _lclose(fh); GlobalUnlock(hRes); goto LoadCIFail; } } #else /* Call kernel's resource handler instead of doing the stuff ourselves * because we use cached file handles that way. davidds */ // For resources which are not preloaded, hRes will be NULL at this point. // For such cases, the default resource handler does the memory allocation // and returns a valid handle. // Fix for Bug #4257 -- 01/21/91 -- SANKAR if (!(hTempRes = lpDefaultResourceHandler(hRes, hResFile, hResIndex))) goto LoadCIFail; // We must use the handle returned by lpDefaultResourceHandler. hRes = hTempRes; lpIcon = (LPCURSORSHAPE)GlobalLock(hRes); #endif if (LoadCursorIconHandler2(hRes, lpIcon, wMemSize)) return(hRes); LoadCIFail: /* If the loading of the resource fails, we MUST discard the memory we * reallocated above, or kernel will simply globallock the thing on the * next call to LockResource(), leaving invalid data in the object. */ if (bNew) GlobalFree(hRes); else GlobalDiscard(hRes); return(NULL); } /*--------------------------------------------------------------------------*/ /* */ /* LoadCursorIconHandler2() - */ /* */ /* This handles all 2.x Cursors and Icons */ /* */ /*--------------------------------------------------------------------------*/ HANDLE FAR PASCAL LoadCursorIconHandler2(hRes, lpIcon, wMemSize) register HANDLE hRes; LPCURSORSHAPE lpIcon; register WORD wMemSize; { BOOL fCrunch; BOOL fIcon; WORD wNewSize; BOOL fStretchInXdirection; BOOL fStretchInYdirection; dprintf(7,"LoadCursorIconHandler2"); fIcon = (*(LPSTR)lpIcon == BMR_ICON); /* Is this a device dependant icon/cursor?. */ fCrunch = (*((LPSTR)lpIcon+1) != BMR_DEVDEP); LCopyStruct((LPSTR)lpIcon+2, (LPSTR)lpIcon, wMemSize-2); fCrunch = fCrunch || (lpIcon->cx != GetSystemMetrics(SM_CXICON)) || (lpIcon->cy != GetSystemMetrics(SM_CYICON)); /* Only support monochrome cursors. */ lpIcon->Planes = lpIcon->BitsPixel = 1; fStretchInXdirection = fStretchInYdirection = TRUE; // Assume we need stretching. if(fIcon) { if((oemInfo.cxIcon > STD_ICONWIDTH) && (lpIcon->cx <= oemInfo.cxIcon)) fStretchInXdirection = FALSE; // No Need to stretch in X direction; if((oemInfo.cyIcon > STD_ICONHEIGHT) && (lpIcon->cy <= oemInfo.cyIcon)) fStretchInYdirection = FALSE; // No need to stretch in Y direction; } else { if((oemInfo.cxCursor > STD_CURSORWIDTH) && (lpIcon->cx <= oemInfo.cxCursor)) fStretchInXdirection = FALSE; // No need to stretch in X direction. if((oemInfo.cyCursor > STD_CURSORHEIGHT) && (lpIcon->cy <= oemInfo.cyCursor)) fStretchInYdirection = FALSE; // No need to stretch in Y direction. } // Check if the Icon/Cursor needs to be stretched now or not if(!(fStretchInXdirection || fStretchInYdirection)) { GlobalUnlock(hRes); return(hRes); } wNewSize = SizeReqd(fIcon, 1, 1, TRUE, 0, 0); /* Before we crunch, let us make sure we have a big enough resource. */ if (fCrunch) { if (wNewSize > wMemSize) { GlobalUnlock(hRes); /* Make this non discardable so that kernel will try to move this * block when reallocing. DavidDS */ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_NODISCARD); if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0)) { /* So it gets discarded. Note that since the above realloc is * less than 64K, the handle won't change. */ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE); return(NULL); } /* So it gets discarded */ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE); if (!(lpIcon = (LPCURSORSHAPE)GlobalLock(hRes))) return(NULL); wMemSize = wNewSize; } } wNewSize = CrunchAndResize(lpIcon, fIcon, fCrunch, FALSE, TRUE); GlobalUnlock(hRes); /* Has it already been resized? */ if (wNewSize < wMemSize) { /* Make it an exact fit. */ if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0)) return(NULL); } return(hRes); } /*--------------------------------------------------------------------------*/ /* */ /* LoadDIBCursorHandler() - */ /* */ /* This is called when a Cursor in DIB format is loaded */ /* This converts the cursor into Old format and returns the handle */ /* */ /*--------------------------------------------------------------------------*/ HANDLE FAR PASCAL LoadDIBCursorHandler(hRes, hResFile, hResIndex) HANDLE hRes; HANDLE hResFile; HANDLE hResIndex; { dprintf(7,"LoadDIBCursorIconHandler"); return(LoadDIBCursorIconHandler(hRes, hResFile, hResIndex, FALSE)); } /*--------------------------------------------------------------------------*/ /* */ /* LoadDIBIconHandler() - */ /* */ /* This is called when an Icon in DIB format is loaded */ /* This converts the cursor into Old format and returns the handle */ /* */ /*--------------------------------------------------------------------------*/ HANDLE FAR PASCAL LoadDIBIconHandler(hRes, hResFile, hResIndex) HANDLE hRes; HANDLE hResFile; HANDLE hResIndex; { dprintf(7,"LoadDIBIconHandler"); return(LoadDIBCursorIconHandler(hRes, hResFile, hResIndex, TRUE)); } /*--------------------------------------------------------------------------*/ /* */ /* StretchIcon() - */ /* When this routine is called, lpIcon already has the monochrome */ /* AND bitmap properly sized. This routine adds the color XOR bitmap at */ /* end of lpIcon and updates the header with the values of the color */ /* info(bitcount and Planes); */ /* wOldSize : Contains the size of AND mask + CURSORSHAPE */ /* */ /* Returns: The new size ( Size of AND mask + XOR bitmap + CURSORSHAPE) */ /* */ /*--------------------------------------------------------------------------*/ WORD NEAR PASCAL StretchIcon(lpIcon, wOldSize, hXORbitmap, fStretchToSysMetrics) LPCURSORSHAPE lpIcon; WORD wOldSize; register HBITMAP hXORbitmap; BOOL fStretchToSysMetrics; { WORD wCount; BITMAP bitmap; register HBITMAP hNewBitmap; dprintf(7,"StretchIcon"); GetObject(hXORbitmap, sizeof(BITMAP), (LPSTR)&bitmap); if(fStretchToSysMetrics) { /* Do we need to resize things? */ if ((oemInfo.cxIcon != bitmap.bmWidth) || (oemInfo.cyIcon != bitmap.bmHeight)) { hNewBitmap = StretchBitmap(bitmap.bmWidth, bitmap.bmHeight, oemInfo.cxIcon, oemInfo.cyIcon, hXORbitmap, bitmap.bmPlanes, bitmap.bmBitsPixel); DeleteObject(hXORbitmap); if (hNewBitmap == NULL) return(0); GetObject(hNewBitmap, sizeof(BITMAP), (LPSTR)&bitmap); hXORbitmap = hNewBitmap; } } /* Update the Planes and BitsPixels field with the color values */ lpIcon->Planes = bitmap.bmPlanes; lpIcon->BitsPixel = bitmap.bmBitsPixel; wCount = bitmap.bmWidthBytes * bitmap.bmHeight * bitmap.bmPlanes; GetBitmapBits(hXORbitmap, (DWORD)wCount, (LPSTR)((LPSTR)lpIcon + wOldSize)); DeleteObject(hXORbitmap); return(wCount + wOldSize); } /*--------------------------------------------------------------------------*/ /* */ /* LoadDIBCursorIconHandler() - */ /* */ /* This is called when a Cursor/Icon in DIB format is loaded */ /* This converts the cursor/icon internal format and returns the */ /* handle */ /* */ /*--------------------------------------------------------------------------*/ HANDLE NEAR PASCAL LoadDIBCursorIconHandler(hRes, hResFile, hResIndex, fIcon) register HANDLE hRes; HANDLE hResFile; HANDLE hResIndex; BOOL fIcon; { register int fh = 0; BOOL bNew = FALSE; WORD wMemBlkSize; LPCURSORSHAPE lpCurSh; HANDLE hTempRes; dprintf(7,"LoadDIBCursorIconHandler"); wMemBlkSize = (WORD)SizeofResource(hResFile, hResIndex); #if 1 // was 0 - NigelT if (!hRes) { if (!(hRes = AllocResource(hResFile, hResIndex, 0L))) goto LoadDIBFail; fh = -1; bNew = TRUE; } while (!(lpCurSh = (LPCURSORSHAPE)GlobalLock(hRes))) { if (!GlobalReAlloc(hRes, (DWORD)wMemBlkSize, 0)) goto LoadDIBFail; else fh = -1; } if (fh) { fh = AccessResource(hResFile, hResIndex); if (fh != -1 && _lread(fh, (LPSTR)lpCurSh, wMemBlkSize) != 0xFFFF) _lclose(fh); else { if (fh != -1) _lclose(fh); GlobalUnlock(hRes); goto LoadDIBFail; } } #else /* Call kernel's resource handler instead of doing the stuff ourselves * because we use cached file handles that way. davidds */ // For resources which are not preloaded, hRes will be NULL at this point. // For such cases, the default resource handler does the memory allocation // and returns a valid handle. // Fix for Bug #4257 -- 01/21/91 -- SANKAR if (!(hTempRes = lpDefaultResourceHandler(hRes, hResFile, hResIndex))) goto LoadDIBFail; // We must use the handle returned by lpDefaultResourceHandler. hRes = hTempRes; lpCurSh = (LPCURSORSHAPE)GlobalLock(hRes); #endif if (LoadDIBCursorIconHandler2(hRes, lpCurSh, wMemBlkSize, fIcon)) return(hRes); LoadDIBFail: /* if the loading of the resource fails, we MUST discard the memory we * reallocated above, or kernel will simply globallock the thing on the * next call to LockResource(), leaving invalid data in the object. */ if (bNew) FreeResource(hRes); else GlobalDiscard(hRes); return(NULL); } /*--------------------------------------------------------------------------*/ /* */ /* LoadDIBCursorIconHandler2() - */ /* */ /* This is called when a Cursor/Icon in DIB format is loaded */ /* This converts the cursor/icon into Old format and returns the */ /* handle */ /* */ /* NOTE: All cursors(always monochrome) and Monochrome Icons are treated */ /* alike by this routine. Color Icons are treated as special case */ /* determined by the local flag "fMono". */ /* */ /*--------------------------------------------------------------------------*/ HANDLE FAR PASCAL LoadDIBCursorIconHandler2(hRes, lpCurSh, wMemBlkSize, fIcon) register HANDLE hRes; WORD wMemBlkSize; LPCURSORSHAPE lpCurSh; register BOOL fIcon; { HDC hDC; BOOL fMono = FALSE; WORD Width; WORD Height; WORD wCount; WORD BitCount; WORD Planes; LPSTR lpBits; BITMAP bitmap; HBITMAP hBitmap; WORD wNewSize; HBITMAP hANDbitmap; HBITMAP hXORbitmap; LPWORD lpColorTable; LPBITMAPINFOHEADER lpHeader; LPBITMAPCOREHEADER lpHeader1 = 0; BOOL fStretchToSysMetrics; BOOL fStretchInXdirection; BOOL fStretchInYdirection; dprintf(7,"LoadDIBCursorIconHandler2"); lpHeader = (LPBITMAPINFOHEADER)lpCurSh; if (!fIcon) { /* Skip over the cursor hotspot data in the first 2 words. */ lpHeader = (LPBITMAPINFOHEADER)((LPSTR)lpHeader + 4); } if ((WORD)lpHeader->biSize == sizeof(BITMAPCOREHEADER)) { /* This is an "old form" DIB. This matches the PM 1.1 format. */ lpHeader1 = (LPBITMAPCOREHEADER)lpHeader; Width = lpHeader1->bcWidth; Height = lpHeader1->bcHeight; BitCount = lpHeader1->bcBitCount; Planes = lpHeader1->bcPlanes; /* Calcluate the pointer to the Bits information */ /* First skip over the header structure */ lpColorTable = (LPWORD)(lpBits = (LPSTR)(lpHeader1 + 1)); /* Skip the color table entries, if any */ if (lpHeader1->bcBitCount != 24) { if (lpHeader1->bcBitCount == 1) fMono = fCheckMono(lpBits, FALSE); lpBits += (1 << (lpHeader1->bcBitCount)) * sizeof(RGBTRIPLE); } } else { Width = (WORD)lpHeader->biWidth; Height = (WORD)lpHeader->biHeight; BitCount = lpHeader->biBitCount; Planes = lpHeader->biPlanes; /* Calcluate the pointer to the Bits information */ /* First skip over the header structure */ lpColorTable = (LPWORD)(lpBits = (LPSTR)(lpHeader + 1)); /* Skip the color table entries, if any */ if (lpHeader->biClrUsed != 0) { if (lpHeader->biClrUsed == 2) fMono = fCheckMono(lpBits, TRUE); lpBits += lpHeader->biClrUsed * sizeof(RGBQUAD); } else { if (lpHeader->biBitCount != 24) { if (lpHeader->biBitCount == 1) fMono = fCheckMono(lpBits, TRUE); lpBits += (1 << (lpHeader->biBitCount)) * sizeof(RGBQUAD); } } } // By default Stretch the icon/cursor to the dimensions in oemInfo; // If this is FALSE, then the stretching will take place during DrawIcon(); fStretchInXdirection = TRUE; fStretchInYdirection = TRUE; // Check if the Icon/Cursor needs to be stretched to the dimensions in // oemInfo now or not. if(fIcon) { if((oemInfo.cxIcon > STD_ICONWIDTH) && (Width <= oemInfo.cxIcon)) fStretchInXdirection = FALSE; // No Need to stretch in X direction; if((oemInfo.cyIcon > STD_ICONHEIGHT) && (Height <= oemInfo.cyIcon)) fStretchInYdirection = FALSE; // No need to stretch in Y direction; } else { if((oemInfo.cxCursor > STD_CURSORWIDTH) && (Width <= oemInfo.cxCursor)) fStretchInXdirection = FALSE; // No need to stretch in X direction. if((oemInfo.cyCursor > STD_CURSORHEIGHT) && (Height <= oemInfo.cyCursor)) fStretchInYdirection = FALSE; // No need to stretch in Y direction. } fStretchToSysMetrics = fStretchInXdirection || fStretchInYdirection; if (fMono) { /* Create a bitmap */ if (!(hBitmap = CreateBitmap(Width, Height, 1, 1, (LPSTR)NULL))) { GlobalUnlock(hRes); return(NULL); } /* Convert the DIBitmap format into internal format */ SetDIBits(hdcBits, hBitmap, 0, Height, lpBits, (LPBITMAPINFO)lpHeader, DIB_RGB_COLORS); // Cursors/Icons in DIB format have a height twice the actual height. wNewSize = SizeReqd(fIcon, BitCount, Planes, fStretchToSysMetrics, Width, Height>>1); } else { /* The height is twice that of icons */ Height >>= 1; if (lpHeader1) lpHeader1->bcHeight = Height; else lpHeader->biHeight = Height; /* Create the XOR bitmap Compatible with the current device */ hDC = GetScreenDC(); if (!(hXORbitmap = CreateCompatibleBitmap(hDC, Width, Height))) { InternalReleaseDC(hDC); GlobalUnlock(hRes); return(NULL); } InternalReleaseDC(hDC); /* Convert the DIBitmap into internal format */ SetDIBits(hdcBits, hXORbitmap, 0, Height, lpBits, (LPBITMAPINFO)lpHeader, DIB_RGB_COLORS); GetObject(hXORbitmap, sizeof(BITMAP), (LPSTR)(&bitmap)); wNewSize = SizeReqd(fIcon, bitmap.bmBitsPixel, bitmap.bmPlanes, fStretchToSysMetrics, Width, Height); /* Create the monochrome AND bitmap */ if (!(hANDbitmap = CreateBitmap(Width, Height, 1, 1, (LPSTR)NULL))) { GlobalUnlock(hRes); return(NULL); } /* Get the offset to the AND bitmap */ lpBits += (((Width * BitCount + 0x1F) & ~0x1F) >> 3) * Height; /* Set the header with data for a monochrome bitmap */ Planes = BitCount = 1; /* Set the color table for a monochrome bitmap */ *lpColorTable++ = 0; *lpColorTable++ = 0xFF00; *lpColorTable = 0xFFFF; if (lpHeader1) { lpHeader1->bcWidth = Width; lpHeader1->bcHeight = Height; lpHeader1->bcPlanes = Planes; lpHeader1->bcBitCount = BitCount; } else { lpHeader->biWidth = Width; lpHeader->biHeight = Height; lpHeader->biPlanes = Planes; lpHeader->biBitCount = BitCount; } SetDIBits(hdcBits, hANDbitmap, 0, Height, lpBits, (LPBITMAPINFO)lpHeader, DIB_RGB_COLORS); hBitmap = hANDbitmap; } GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bitmap); if (fIcon) { lpCurSh->xHotSpot = 0; lpCurSh->yHotSpot = 0; } /* The following lines are replaced by a single functon call * * lpCurSh->cx = bitmap.bmwidth; * lpCurSh->cy = bitmap.bmHeight; * lpCurSh->cbWidth = bitmap.bmWidthBytes; * lpCurSh->Planes = bitmap.bmPlanes; * lpCurSh->BitsPixel = bitmap.bmBitsPixel; */ LCopyStruct((LPSTR)&(bitmap.bmWidth), (LPSTR)&(lpCurSh->cx), (sizeof(WORD)) << 2); /* Cursors in PM format have twice the actual height. */ if (fMono) lpCurSh->cy = lpCurSh->cy >> 1; wCount = bitmap.bmWidthBytes * bitmap.bmHeight * bitmap.bmPlanes; lpBits = (LPSTR)(lpCurSh + 1); /* Copy the bits in Bitmap into the resource */ GetBitmapBits(hBitmap, (DWORD)wCount, lpBits); /* Delete the bitmap */ DeleteObject(hBitmap); /* Before crunching, let us make sure we have a big enough resource */ if (wNewSize > wMemBlkSize) { GlobalUnlock(hRes); /* Make this non discardable so that kernel will try to move this block * when reallocing. DavidDS */ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_NODISCARD); if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0)) { /* So it gets discarded. Note that since the above realloc is less * than 64K, the handle won't change. */ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE); return(NULL); } GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE); if (!(lpCurSh = (LPCURSORSHAPE)GlobalLock(hRes))) return(NULL); wMemBlkSize = wNewSize; } wNewSize = CrunchAndResize(lpCurSh, fIcon, TRUE, !fMono, fStretchToSysMetrics); if (!fMono) { if (!(wNewSize = StretchIcon(lpCurSh, wNewSize, hXORbitmap, fStretchToSysMetrics))) { GlobalUnlock(hRes); return(NULL); } } GlobalUnlock(hRes); /* Does it need to be resized? */ if (wNewSize < wMemBlkSize) { if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0)) return(NULL); } return(hRes); } /*--------------------------------------------------------------------------*/ /* */ /* SizeReqd() - */ /* This returns the size of an Icon or Cursor after it is stretched */ /* or crunched */ /* */ /*--------------------------------------------------------------------------*/ WORD NEAR PASCAL SizeReqd(fIcon, BitCount, Planes, fUseSysMetrics, iWidth, iHeight) BOOL fIcon; WORD BitCount; WORD Planes; BOOL fUseSysMetrics; int iWidth; int iHeight; { WORD size; dprintf(7,"SizeReqd"); if(fUseSysMetrics) //Use the dimensions in oemInfo; Else, use given dimensions { if(fIcon) { iWidth = oemInfo.cxIcon; iHeight = oemInfo.cyIcon; } else { iWidth = oemInfo.cxCursor; iHeight = oemInfo.cyCursor; } } size = (((iWidth*BitCount+0x0F) & ~0x0F) >> 3) * iHeight * Planes; if ((BitCount == 1) && (Planes == 1)) size <<= 1; else size += (((iWidth+0x0F) & ~0x0F) >> 3)*iHeight; return(size + sizeof(CURSORSHAPE)); } #endif // NEEDED