|
|
/****************************** Module Header ******************************\
* Module Name: loadbits.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Loads and creates icons / cursors / bitmaps. All 3 functions can either * load from a client resource file, load from user's resource file, or * load from the display's resource file. Beware that hmodules are not * unique across processes! * * 05-Apr-1991 ScottLu Rewrote to work with client/server \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <wchar.h>
/***************************************************************************\
* _CreateEmptyCursorObject * * Creates a cursor object and links it into a cursor list. * * 08-Feb-92 ScottLu Created. \***************************************************************************/
HCURSOR _CreateEmptyCursorObject( BOOL fPublic) { PCURSOR pcurT;
/*
* Create the cursor object. */ pcurT = (PCURSOR)HMAllocObject(PtiCurrent(), NULL, TYPE_CURSOR, max(sizeof(CURSOR), sizeof(ACON)));
if ((fPublic) && (pcurT != NULL) && (ISCSRSS())) { pcurT->head.ppi = NULL; }
return (HCURSOR)PtoH(pcurT); }
/***************************************************************************\
* DestroyEmptyCursorObject * UnlinkCursor * * Destroys an empty cursor object (structure holds nothing that needs * destroying). * * 08-Feb-1992 ScottLu Created. \***************************************************************************/ VOID UnlinkCursor( PCURSOR pcur) { PCURSOR *ppcurT; BOOL fTriedPublicCache; BOOL fTriedThisProcessCache = FALSE;
/*
* First unlink this cursor object from the cursor list (it will be the * first one in the list, so this'll be fast... but just in case, make * it a loop). */ if (fTriedPublicCache = (pcur->head.ppi == NULL)) { ppcurT = &gpcurFirst; } else { ppcurT = &pcur->head.ppi->pCursorCache; }
LookAgain:
for (; *ppcurT != NULL; ppcurT = &((*ppcurT)->pcurNext)) { if (*ppcurT == pcur) { *ppcurT = pcur->pcurNext; FreeIt: pcur->pcurNext = NULL; pcur->CURSORF_flags &= ~CURSORF_LINKED; return; } }
/*
* If we get here, it means that the cursor used to be public but * got assigned to the current thread due to being unlocked. We * have to look for it in the public cache. */ if (!fTriedPublicCache) { ppcurT = &gpcurFirst; fTriedPublicCache = TRUE; goto LookAgain; }
/*
* If we got here, it means that it was locked during process * cleanup and got assigned to no owner. Try the current process * cache. */ if (!fTriedThisProcessCache) { ppcurT = &PpiCurrent()->pCursorCache; fTriedThisProcessCache = TRUE; goto LookAgain; }
/*
* Getting Desperate here... Look through every cursor and process * cache for it. */ { PHE pheMax, pheT;
pheMax = &gSharedInfo.aheList[giheLast]; for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { if (pheT->bType == TYPE_CURSOR) { if (((PCURSOR)pheT->phead)->pcurNext == pcur) { ((PCURSOR)pheT->phead)->pcurNext = pcur->pcurNext; goto FreeIt; } else if (pheT->pOwner && ((PPROCESSINFO)pheT->pOwner)->pCursorCache == pcur) { ((PPROCESSINFO)pheT->pOwner)->pCursorCache = pcur->pcurNext; goto FreeIt; } } } }
UserAssert(FALSE); }
/***************************************************************************\
* DestroyEmptyCursorObject * \***************************************************************************/
VOID DestroyEmptyCursorObject( PCURSOR pcur) { if (pcur->CURSORF_flags & CURSORF_LINKED) { UnlinkCursor(pcur); }
HMFreeObject(pcur); }
/***************************************************************************\
* ZombieCursor * * Unlink the cursor and set its owner to the system process. * * 3-Sep-1997 vadimg created \***************************************************************************/
VOID ZombieCursor(PCURSOR pcur) { if (pcur->CURSORF_flags & CURSORF_LINKED) { UnlinkCursor(pcur); }
#if DBG
if (ISTS()) { PHE phe; phe = HMPheFromObject(pcur);
if (phe->pOwner == NULL) { RIPMSG2(RIP_ERROR, "NULL owner for cursor %#p phe %#p\n", pcur, phe); } } #endif // DBG
HMChangeOwnerProcess(pcur, gptiRit);
RIPMSG1(RIP_WARNING, "ZombieCursor: %#p became a zombie", pcur); }
/***************************************************************************\
* ResStrCmp * * This function compares two strings taking into account that one or both * of them may be resource IDs. The function returns a TRUE if the strings * are equal, instead of the zero lstrcmp() returns. * * History: * 20-Apr-91 DavidPe Created \***************************************************************************/
BOOL ResStrCmp( PUNICODE_STRING cczpstr1, PUNICODE_STRING pstr2) { BOOL retval = FALSE; /*
* pstr1 is a STRING that is in kernel space, but the buffer may * be in client space. */
if (cczpstr1->Length == 0) {
/*
* pstr1 is a resource ID, so just compare the values. */ if (cczpstr1->Buffer == pstr2->Buffer) return TRUE;
} else {
try { /*
* pstr1 is a string. if pstr2 is an actual string compare the * string values; if pstr2 is not a string then pstr1 may be an * "integer string" of the form "#123456". so convert it to an * integer and compare the integers. * Before calling lstrcmp(), make sure pstr2 is an actual * string, not a resource ID. */ if (pstr2->Length != 0) {
if (RtlEqualUnicodeString(cczpstr1, pstr2, TRUE)) retval = TRUE;
} else if (cczpstr1->Buffer[0] == '#') {
UNICODE_STRING strId; int id;
strId.Length = cczpstr1->Length - sizeof(WCHAR); strId.MaximumLength = strId.Length; strId.Buffer = cczpstr1->Buffer + 1; RtlUnicodeStringToInteger(&strId, 10, (PULONG)&id);
if (id == (LONG_PTR)pstr2->Buffer) retval = TRUE; } } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { } }
return retval; }
/***********************************************************************\
* SearchIconCache * * Worker routine for FindExistingCursorIcon(). * * Returns: pCurFound * * 28-Sep-1995 SanfordS Created. \***********************************************************************/
PCURSOR SearchIconCache( PCURSOR pCursorCache, ATOM atomModName, PUNICODE_STRING cczpstrResName, PCURSOR pcurSrc, PCURSORFIND pcfSearch) { /*
* Run through the list of 'resource' objects created, * and see if the cursor requested has already been loaded. * If so just return it. We do this to be consistent with * Win 3.0 where they simply return a pointer to the res-data * for a cursor/icon handle. Many apps count on this and * call LoadCursor/Icon() often. * * LR_SHARED implies: * 1) icons never get deleted till process (LATER or WOW module) * goes away. * 2) This cache is consulted before trying to load a res. */ for (; pCursorCache != NULL; pCursorCache = pCursorCache->pcurNext) {
/*
* If we are given a specific cursor to look for, then * search for that first. */ if (pcurSrc && (pCursorCache == pcurSrc)) return pcurSrc;
/*
* No need to look further if the module name doesn't match. */ if (atomModName != pCursorCache->atomModName) continue;
/*
* We only return images that cannot be destroyed by the app. * so we don't have to deal with ref counts. This is owned * by us, but not LR_SHARED. */ if (!(pCursorCache->CURSORF_flags & CURSORF_LRSHARED)) continue;
/*
* Check the other distinguishing search criteria for * a match. */ if ((pCursorCache->rt == LOWORD(pcfSearch->rt)) && ResStrCmp(cczpstrResName, &pCursorCache->strName)) {
/*
* Acons don't have a size per se because each frame * can be a different size. We always make it a hit * on acons so replacement of system icons is possible. */ if (pCursorCache->CURSORF_flags & CURSORF_ACON) return pCursorCache;
/*
* First hit wins. Nothing fancy here. Apps that use * LR_SHARED have to watch out for this. */ if ((!pcfSearch->cx || (pCursorCache->cx == pcfSearch->cx)) && (!pcfSearch->cy || ((pCursorCache->cy / 2) == pcfSearch->cy)) && (!pcfSearch->bpp || (pCursorCache->bpp == pcfSearch->bpp))) {
return pCursorCache; } } }
return NULL; }
/***********************************************************************\
* _FindExistingCursorIcon * * This routine searches all existing icons for one matching the properties * given. This routine will only return cursors/icons that are of * the type that cannot be destroyed by the app. (CURSORF_LRSHARED or * unowned) and will take the first hit it finds. * * 32bit apps that call LoadImage() will normally not have this cacheing * feature unless they specify LR_SHARED. If they do so, it is the apps * responsability to be careful with how they use the cache since wild * lookups (ie 0s in cx, cy or bpp) will result in different results * depending on the history of icon/cursor creation. It is thus recommended * that apps only use the LR_SHARED option when they are only working * with one size/colordepth of icon or when they call LoadImage() with * specific size and/or color content requested. * * For the future it would be nice to have a cacheing scheeme that would * simply be used to speed up reloading of images. To do this right, * you would need ref counts to allow deletes to work properly and would * have to remember whether the images in the cache had been stretched * or color munged so you don't allow restretching. * * Returns: pcurFound * * * 17-Sep-1995 SanfordS Created. \***********************************************************************/
PCURSOR _FindExistingCursorIcon( ATOM atomModName, PUNICODE_STRING cczpstrResName, PCURSOR pcurSrc, PCURSORFIND pcfSearch) { PCURSOR pcurT = NULL;
/*
* If rt is zero we're doing an indirect create, so matching with * a previously loaded cursor/icon would be inappropriate. */ if (pcfSearch->rt && atomModName) {
pcurT = SearchIconCache(PpiCurrent()->pCursorCache, atomModName, cczpstrResName, pcurSrc, pcfSearch); if (pcurT == NULL) { pcurT = SearchIconCache(gpcurFirst, atomModName, cczpstrResName, pcurSrc, pcfSearch); } }
return pcurT; }
/***************************************************************************\
* _InternalGetIconInfo * * History: * 09-Mar-1993 MikeKe Created. \***************************************************************************/
BOOL _InternalGetIconInfo( IN PCURSOR pcur, OUT PICONINFO ccxpiconinfo, OUT OPTIONAL PUNICODE_STRING pstrInstanceName, OUT OPTIONAL PUNICODE_STRING pstrResName, OUT OPTIONAL LPDWORD ccxpbpp, IN BOOL fInternalCursor) { HBITMAP hbmBitsT; HBITMAP hbmDstT; HBITMAP hbmMask; HBITMAP hbmColor;
/*
* Note -- while the STRING structures are in kernel mode memory, the * buffers are in user-mode memory. So all use of the buffers should * be protected bytry blocks. */
/*
* If this is an animated cursor, just grab the first frame and return * the info for it. */ if (pcur->CURSORF_flags & CURSORF_ACON) pcur = ((PACON)pcur)->aspcur[0];
/*
* Make copies of the bitmaps * * If the color bitmap is around, then there is no XOR mask in the * hbmMask bitmap. */ hbmMask = GreCreateBitmap( pcur->cx, (pcur->hbmColor && !fInternalCursor) ? pcur->cy / 2 : pcur->cy, 1, 1, NULL);
if (hbmMask == NULL) return FALSE;
hbmColor = NULL;
if (pcur->hbmColor != NULL) { if (pcur->bpp == 32) { BITMAPINFO bi;
RtlZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = pcur->cx; bi.bmiHeader.biHeight = pcur->cy/2; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = 0; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0;
hbmColor = GreCreateDIBitmapReal(HDCBITS(), 0, NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS, sizeof(bi), 0, NULL, 0, NULL, 0, 0, NULL); } else { hbmColor = GreCreateCompatibleBitmap(HDCBITS(), pcur->cx, pcur->cy / 2); }
if (hbmColor == NULL) { GreDeleteObject(hbmMask); return FALSE; } }
hbmBitsT = GreSelectBitmap(ghdcMem2, pcur->hbmMask); hbmDstT = GreSelectBitmap(ghdcMem, hbmMask);
GreBitBlt(ghdcMem, 0, 0, pcur->cx, (pcur->hbmColor && !fInternalCursor) ? pcur->cy / 2 : pcur->cy, ghdcMem2, 0, 0, SRCCOPY, 0x00ffffff);
if (hbmColor != NULL) {
GreSelectBitmap(ghdcMem2, pcur->hbmColor); GreSelectBitmap(ghdcMem, hbmColor);
GreBitBlt(ghdcMem, 0, 0, pcur->cx, pcur->cy / 2, ghdcMem2, 0, 0, SRCCOPY, 0); }
GreSelectBitmap(ghdcMem2, hbmBitsT); GreSelectBitmap(ghdcMem, hbmDstT);
/*
* Fill in the iconinfo structure. make copies of the bitmaps. */ try {
ccxpiconinfo->fIcon = (pcur->rt == PTR_TO_ID(RT_ICON)); ccxpiconinfo->xHotspot = pcur->xHotspot; ccxpiconinfo->yHotspot = pcur->yHotspot; ccxpiconinfo->hbmMask = hbmMask; ccxpiconinfo->hbmColor = hbmColor;
if (pstrInstanceName != NULL) {
if (pcur->atomModName) { pstrInstanceName->Length = (USHORT) UserGetAtomName(pcur->atomModName, pstrInstanceName->Buffer, (int) (pstrInstanceName->MaximumLength / sizeof(WCHAR)) * sizeof(WCHAR)); } else { pstrInstanceName->Length = 0; } }
if (pstrResName != NULL) {
if (IS_PTR(pcur->strName.Buffer)) { RtlCopyUnicodeString(pstrResName, &pcur->strName); } else { *pstrResName = pcur->strName; } }
if (ccxpbpp) *ccxpbpp = pcur->bpp;
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) { GreDeleteObject(hbmMask); GreDeleteObject(hbmColor); return FALSE; }
return TRUE; }
/***************************************************************************\
* _DestroyCursor * * History: * 25-Apr-1991 DavidPe Created. * 04-Aug-1992 DarrinM Now destroys ACONs as well. \***************************************************************************/
BOOL _DestroyCursor( PCURSOR pcur, DWORD cmdDestroy) { PPROCESSINFO ppi; PPROCESSINFO ppiCursor; int i; extern BOOL DestroyAniIcon(PACON pacon);
if (pcur == NULL) { UserAssert(FALSE); return(TRUE); } ppi = PpiCurrent(); ppiCursor = GETPPI(pcur);
/*
* Remove this icon from the caption icon cache. */ for (i = 0; i < CCACHEDCAPTIONS; i++) { if (gcachedCaptions[i].spcursor == pcur) { Unlock( &(gcachedCaptions[i].spcursor) ); } }
/*
* First step in destroying an cursor */ switch (cmdDestroy) {
case CURSOR_ALWAYSDESTROY:
/*
* Always destroy? then don't do any checking... */ break;
case CURSOR_CALLFROMCLIENT:
/*
* Can't destroy public cursors/icons. */ if (ppiCursor == NULL) /*
* Fake success if its a resource loaded icon because * this is how win95 responded. */ return !!(pcur->CURSORF_flags & CURSORF_FROMRESOURCE);
/*
* If this cursor was loaded from a resource, don't free it till the * process exits. This is the way we stay compatible with win3.0's * cursors which were actually resources. Resources under win3 have * reference counting and other "features" like handle values that * never change. Read more in the comment in * ServerLoadCreateCursorIcon(). */ if (pcur->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_SECRET)) { return TRUE; }
/*
* One thread can't destroy the objects created by another. */ if (ppiCursor != ppi) { RIPERR0(ERROR_DESTROY_OBJECT_OF_OTHER_THREAD, RIP_ERROR, "DestroyCursor: cursor belongs to another process"); return FALSE; }
/*
* fall through. */
case CURSOR_THREADCLEANUP:
/*
* Don't destroy public objects either (pretend it worked though). */ if (ppiCursor == NULL) return TRUE; break; }
/*
* First mark the object for destruction. This tells the locking code that * we want to destroy this object when the lock count goes to 0. If this * returns FALSE, we can't destroy the object yet. */ if (!HMMarkObjectDestroy((PHEAD)pcur)) return FALSE;
if (pcur->strName.Length != 0) { UserFreePool((LPSTR)pcur->strName.Buffer); }
if (pcur->atomModName != 0) { UserDeleteAtom(pcur->atomModName); }
/*
* If this is an ACON call its special routine to destroy it. */ if (pcur->CURSORF_flags & CURSORF_ACON) { DestroyAniIcon((PACON)pcur); } else { if (pcur->hbmMask != NULL) { GreDeleteObject(pcur->hbmMask); GreDecQuotaCount((PW32PROCESS)(pcur->head.ppi)); } if (pcur->hbmColor != NULL) { GreDeleteObject(pcur->hbmColor); GreDecQuotaCount((PW32PROCESS)(pcur->head.ppi)); } if (pcur->hbmUserAlpha != NULL) { GreDeleteObject(pcur->hbmUserAlpha); GreDecQuotaCount((PW32PROCESS)(pcur->head.ppi)); } if (pcur->hbmAlpha != NULL) { /*
* This is an internal GDI object, and so not covered by quota. */ GreDeleteObject(pcur->hbmAlpha); } }
/*
* Ok to destroy... Free the handle (which will free the object and the * handle). */ DestroyEmptyCursorObject(pcur); return TRUE; }
/***************************************************************************\
* DestroyUnlockedCursor * * Called when a cursor is destoyed due to an unlock. * * History: * 24-Feb-1997 adams Created. \***************************************************************************/
void DestroyUnlockedCursor(void * pv) { _DestroyCursor((PCURSOR)pv, CURSOR_THREADCLEANUP); }
/***************************************************************************\
* _SetCursorContents * * * History: * 27-Apr-1992 ScottLu Created. \***************************************************************************/
BOOL _SetCursorContents( PCURSOR pcur, PCURSOR pcurNew) { HBITMAP hbmpT;
if (!(pcur->CURSORF_flags & CURSORF_ACON)) {
/*
* Swap bitmaps. */ hbmpT = pcur->hbmMask; pcur->hbmMask = pcurNew->hbmMask; pcurNew->hbmMask = hbmpT;
hbmpT = pcur->hbmColor; pcur->hbmColor = pcurNew->hbmColor; pcurNew->hbmColor = hbmpT;
hbmpT = pcur->hbmUserAlpha; pcur->hbmUserAlpha = pcurNew->hbmUserAlpha; pcurNew->hbmUserAlpha = hbmpT;
hbmpT = pcur->hbmAlpha; pcur->hbmAlpha = pcurNew->hbmAlpha; pcurNew->hbmAlpha = hbmpT;
/*
* Remember hotspot info and size info */ pcur->xHotspot = pcurNew->xHotspot; pcur->yHotspot = pcurNew->yHotspot; pcur->cx = pcurNew->cx; pcur->cy = pcurNew->cy;
pcur->bpp = pcurNew->bpp; pcur->rt = pcurNew->rt; pcur->rcBounds = pcurNew->rcBounds; }
/*
* Destroy the cursor we copied from. */ _DestroyCursor(pcurNew, CURSOR_THREADCLEANUP);
/*
* If the current logical cursor is changing then force the current physical * cursor to change. */ if (gpcurLogCurrent == pcur) { gpcurLogCurrent = NULL; gpcurPhysCurrent = NULL; zzzUpdateCursorImage(); } return TRUE; }
|