Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

782 lines
23 KiB

/****************************** 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;
}