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.
 
 
 
 
 
 

610 lines
19 KiB

/****************************** Module Header ******************************\
* Module Name: acons.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains code for dealing with animated icons/cursors.
*
* History:
* 10-02-91 DarrinM Created.
* 07-30-92 DarrinM Unicodized.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* zzzSetSystemCursor (API)
*
* Replace a system (aka 'public') cursor with a user provided one. The new
* cursor is pulled from a file (.CUR, .ICO, or .ANI) specified in WIN.INI.
*
* History:
* 12/26/1991 DarrinM Created.
* 08/04/1992 DarrinM Recreated.
* 10/14/1995 SanfordS Win95 support.
\***************************************************************************/
BOOL zzzSetSystemCursor(
PCURSOR pcur,
DWORD id)
{
int i;
if (!CheckWinstaWriteAttributesAccess()) {
return FALSE;
}
UserAssert(pcur);
/*
* Check if this cursor is one of the replaceable ones.
*/
for (i = 0; i < COCR_CONFIGURABLE; i++) {
if (gasyscur[i].Id == (WORD)id) {
break;
}
}
/*
* Not replaceable, bail out.
*/
if (i == COCR_CONFIGURABLE) {
RIPMSG1(RIP_WARNING, "_SetSystemCursor: called with bad id 0x%x", id);
return FALSE;
}
return zzzSetSystemImage(pcur, gasyscur[i].spcur);
}
/***********************************************************************\
* zzzSetSystemImage
*
* Places the contents of pcur into pcurSys and destroys pcur.
*
* 10/14/1995 Created SanfordS
\***********************************************************************/
BOOL zzzSetSystemImage(
PCURSOR pcur,
PCURSOR pcurSys)
{
#define CBCOPY (max(sizeof(CURSOR), sizeof(ACON)) - FIELD_OFFSET(CURSOR, CI_COPYSTART))
#define pacon ((PACON)pcur)
char cbT[CBCOPY];
UINT CURSORF_flags;
UserAssert(pcurSys);
if (pcurSys == pcur) {
return TRUE;
}
/*
* All ssytem images being replaced should have ordinal names
* and reference the USER module and be unowned.
*/
UserAssert(!IS_PTR(pcurSys->strName.Buffer));
UserAssert(pcurSys->atomModName == atomUSER32);
/*
* if pcur was an acon, transfer frame ownerships to pcurSys.
*/
UserAssert(pcurSys->head.ppi == NULL);
if (pcur->CURSORF_flags & CURSORF_ACON && pcur->head.ppi != NULL) {
int i;
PHE phe = HMPheFromObject(pcurSys);
PTHREADINFO ptiOwner = ((PPROCESSINFO)phe->pOwner)->ptiList;
for (i = 0; i < pacon->cpcur; i++) {
HMChangeOwnerProcess(pacon->aspcur[i], ptiOwner);
pacon->aspcur[i]->head.ppi = NULL;
}
}
/*
* If this assert fails, the CURSOR and ACON structures were changed
* incorrectly - read the comments in user.h and wingdi.w around
* tagCURSOR, tagACON, and CURSINFO.
*/
UserAssert(FIELD_OFFSET(CURSOR, CI_FIRST) == FIELD_OFFSET(ACON, CI_FIRST));
/*
* swap everything starting from CI_COPYSTART.
*/
RtlCopyMemory(cbT, &pcur->CI_COPYSTART, CBCOPY);
RtlCopyMemory(&pcur->CI_COPYSTART, &pcurSys->CI_COPYSTART, CBCOPY);
RtlCopyMemory(&pcurSys->CI_COPYSTART, cbT, CBCOPY);
/*
* Swap the CURSORF_ACON flags since they go with the swapped data.
*/
CURSORF_flags = pcur->CURSORF_flags & CURSORF_ACON;
pcur->CURSORF_flags =
(pcur->CURSORF_flags & ~CURSORF_ACON) |
(pcurSys->CURSORF_flags & CURSORF_ACON);
pcurSys->CURSORF_flags =
(pcurSys->CURSORF_flags & ~CURSORF_ACON) | CURSORF_flags;
/*
* If we swapped acons into pcur, then we need to change the ownerhsip to
* make sure they can get destroyed.
*/
if (pcur->CURSORF_flags & CURSORF_ACON) {
int i;
PTHREADINFO ptiCurrent = PtiCurrent();
for (i = 0; i < pacon->cpcur; i++) {
HMChangeOwnerProcess(pacon->aspcur[i], ptiCurrent);
}
}
/*
* Use THREADCLEANUP so system cursors are not destroyed.
*/
_DestroyCursor(pcur, CURSOR_THREADCLEANUP);
/*
* If the current logical cursor is changing then force the current physical
* cursor to change.
*/
if (gpcurLogCurrent == pcurSys) {
gpcurLogCurrent = NULL;
gpcurPhysCurrent = NULL;
zzzUpdateCursorImage();
}
/*
* Mark the cursor as a system cursor that can be shadowed by GDI.
*/
pcurSys->CURSORF_flags |= CURSORF_SYSTEM;
return TRUE;
#undef pacon
#undef CBCOPY
}
/***************************************************************************\
* _GetCursorFrameInfo (API)
*
* Example usage:
*
* hcur = _GetCursorFrameInfo(hacon, NULL, 4, &ccur);
* hcur = _GetCursorFrameInfo(NULL, IDC_NORMAL, 0, &ccur); // get device's arrow
*
* History:
* 08-05-92 DarrinM Created.
\***************************************************************************/
PCURSOR _GetCursorFrameInfo(
PCURSOR pcur,
int iFrame,
PJIF pjifRate,
LPINT pccur)
{
/*
* If this is only a single cursor (not an ACON) just return it and
* a frame count of 1.
*/
if (!(pcur->CURSORF_flags & CURSORF_ACON)) {
*pccur = 1;
*pjifRate = 0;
return pcur;
}
/*
* Return the useful cursor information for the specified frame
* of the ACON.
*/
#define pacon ((PACON)pcur)
if (iFrame < 0 || iFrame >= pacon->cicur) {
return NULL;
}
*pccur = pacon->cicur;
*pjifRate = pacon->ajifRate[iFrame];
return pacon->aspcur[pacon->aicur[iFrame]];
#undef pacon
}
/***************************************************************************\
* DestroyAniIcon
*
* Free all the individual cursors that make up the frames of an animated
* icon.
*
* WARNING: DestroyAniIcon assumes that all fields that an ACON shares with
* a cursor will be freed by some cursor code (probably the cursor function
* that calls this one).
*
* History:
* 08-04-92 DarrinM Created.
\***************************************************************************/
BOOL DestroyAniIcon(
PACON pacon)
{
int i;
PCURSOR pcur;
for (i = 0; i < pacon->cpcur; i++) {
UserAssert(pacon->aspcur[i]->CURSORF_flags & CURSORF_ACONFRAME);
/*
* This should not be a public acon; if it is, unlock won't be able
* to destroy it. If destroy a public icon, ownership must be called
* before calling this function (see zzzSetSystemImage).
*/
UserAssert(GETPPI(pacon->aspcur[i]) != NULL);
pcur = Unlock(&pacon->aspcur[i]);
if (pcur != NULL) {
_DestroyCursor(pcur, CURSOR_ALWAYSDESTROY);
}
}
UserFreePool(pacon->aspcur);
return TRUE;
}
/***********************************************************************\
* LinkCursor
*
* Links unlinked cursor into the apropriate icon cache IFF its the
* type of cursor that needs to be in the cache.
*
* Note that changing ownership if cursor objects needs to keep this
* cache linking in mind. The unlink routine in
* DestroyEmptyCursorObject() will handle public cursor objects made
* local but that is all.
*
* 10/18/1995 Created SanfordS
\***********************************************************************/
VOID LinkCursor(
PCURSOR pcur)
{
/*
* Should never try to link twice!
*/
UserAssert(!(pcur->CURSORF_flags & CURSORF_LINKED));
/*
* We don't cache acon frames because they all belong to the
* root acon object.
*
* We don't cache process owned objects that are not LRSHARED
* either.
*/
if (!(pcur->CURSORF_flags & CURSORF_ACONFRAME)) {
PPROCESSINFO ppi = pcur->head.ppi;
if (ppi == NULL) {
/*
* Public cache object.
*/
pcur->pcurNext = gpcurFirst;
gpcurFirst = pcur;
pcur->CURSORF_flags |= CURSORF_LINKED;
} else if (pcur->CURSORF_flags & CURSORF_LRSHARED) {
/*
* Private cache LR_SHARED object.
*/
pcur->pcurNext = ppi->pCursorCache;
ppi->pCursorCache = pcur;
pcur->CURSORF_flags |= CURSORF_LINKED;
}
}
}
/***************************************************************************\
* ProcessAlphaBitmap
*
* Examines the source bitmap to see if it supports and uses an alpha
* channel. If it does, a new DIB section is created that contains a
* premultiplied copy of the data from the source bitmap.
*
* If the source bitmap is not capable of supporting, or simply doesn't use,
* an alpha channel, the return value is NULL.
*
* If an error occurs, the return value is NULL.
*
* 8/10/2000 Created DwayneN
\***************************************************************************/
HBITMAP ProcessAlphaBitmap(
HBITMAP hbmSource)
{
BITMAP bmp;
BITMAPINFO bi;
HBITMAP hbmAlpha;
RGBQUAD * pAlphaBitmapBits;
DWORD cPixels;
DWORD i;
RGBQUAD pixel;
BOOL fAlphaChannel;
/*
* There are several code paths that end up calling us with a NULL
* hbmSource. This is fine, in that it simply indicates that there
* is no alpha channel.
*/
if (hbmSource == NULL) {
return NULL;
}
if (GreExtGetObjectW(hbmSource, sizeof(BITMAP), &bmp) == 0) {
return NULL;
}
/*
* Only single plane, 32bpp bitmaps can even contain an alpha channel.
*/
if (bmp.bmPlanes != 1 ||
bmp.bmBitsPixel != 32) {
return NULL;
}
/*
* Allocate room to hold the source bitmap's bits for examination.
* We actually allocate a DIB - that will be passed out if the
* source bitmap does indeed contain an alpha channel.
*/
RtlZeroMemory(&bi, sizeof(bi));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = bmp.bmWidth;
bi.bmiHeader.biHeight = bmp.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
hbmAlpha = GreCreateDIBitmapReal(gpDispInfo->hdcScreen,
0,
NULL,
(LPBITMAPINFO)&bi,
DIB_RGB_COLORS,
sizeof(bi),
0,
NULL,
0,
NULL,
0,
0,
&pAlphaBitmapBits);
if (NULL != hbmAlpha) {
/*
* Set up the header again in case it was tweaked by GreCreateDIBitmapReal.
*/
RtlZeroMemory(&bi, sizeof(bi));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = bmp.bmWidth;
bi.bmiHeader.biHeight = bmp.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
/*
* Copy the bitmap data from the source bitmap into our alpha DIB.
*/
if (0 == GreGetDIBitsInternal(gpDispInfo->hdcScreen,
hbmSource,
0,
bi.bmiHeader.biHeight,
(LPBYTE) pAlphaBitmapBits,
(LPBITMAPINFO)&bi,
DIB_RGB_COLORS,
BITMAPWIDTHSIZE(bi.bmiHeader.biWidth, bi.bmiHeader.biHeight,1,32),
bi.bmiHeader.biSize)) {
GreDeleteObject(hbmAlpha);
return NULL;
}
/*
* We need to examine the source bitmap to see if it contains an alpha
* channel. This is simply a heuristic since there is no format difference
* between 32bpp 888 RGB image and 32bpp 8888 ARGB image. What we do is look
* for any non-0 alpha/reserved values. If all alpha/reserved values are 0,
* then the image would be 100% invisible if blitted with alpha - which is
* almost cerainly not the desired result. So we assume such bitmaps are
* 32bpp non-alpha.
*/
cPixels = bi.bmiHeader.biWidth * bi.bmiHeader.biHeight;
fAlphaChannel = FALSE;
for (i = 0; i < cPixels; i++) {
if (pAlphaBitmapBits[i].rgbReserved != 0)
{
fAlphaChannel = TRUE;
break;
}
}
if (fAlphaChannel == FALSE) {
GreDeleteObject(hbmAlpha);
return NULL;
}
/*
* The source bitmap appears to use an alpha channel. Spin through our
* copy of the bits and premultiply them. This is a necessary step to
* prepare an alpha bitmap for use by GDI.
*/
for (i=0; i < cPixels; i++) {
pixel = pAlphaBitmapBits[i];
pAlphaBitmapBits[i].rgbRed = (pixel.rgbRed * pixel.rgbReserved) / 0xFF;
pAlphaBitmapBits[i].rgbGreen = (pixel.rgbGreen * pixel.rgbReserved) / 0xFF;
pAlphaBitmapBits[i].rgbBlue = (pixel.rgbBlue * pixel.rgbReserved) / 0xFF;
}
}
return hbmAlpha;
}
/***************************************************************************\
* _SetCursorIconData
*
* Initializes empty cursor/icons. Note that the string buffers and
* pcurData are not captured. If a fault occurs in this routine,
* all allocated memory will be freed when the cursors are destroyed.
*
* Critical side effect: If this function fails, the bitmaps must NOT
* have been made public. (See CreateIconIndirect()).
*
* History:
* 12-01-94 JimA Created.
\***************************************************************************/
BOOL _SetCursorIconData(
PCURSOR pcur,
PUNICODE_STRING cczpstrModName,
PUNICODE_STRING cczpstrName,
PCURSORDATA pcurData,
DWORD cbData)
{
#define pacon ((PACON)pcur)
int i;
#if DBG
BOOL fSuccess;
#endif
pcur->CURSORF_flags |= pcurData->CURSORF_flags;
pcur->rt = pcurData->rt;
if (pcurData->CURSORF_flags & CURSORF_ACON) {
UserAssert(pacon->aspcur == NULL);
RtlCopyMemory(&pacon->cpcur,
&pcurData->cpcur,
sizeof(ACON) - FIELD_OFFSET(ACON, cpcur));
} else {
RtlCopyMemory(&pcur->CI_COPYSTART,
&pcurData->CI_COPYSTART,
sizeof(CURSOR) - FIELD_OFFSET(CURSOR, CI_COPYSTART));
}
/*
* Save name of the cursor resource
*/
if (cczpstrName->Length != 0){
/*
* AllocateUnicodeString guards access to src Buffer with
* a try block.
*/
if (!AllocateUnicodeString(&pcur->strName, cczpstrName))
return FALSE;
} else {
pcur->strName = *cczpstrName;
}
/*
* Save the module name
*/
if (cczpstrModName->Buffer) {
/*
* UserAddAtom guards access to the string with a try block.
*/
pcur->atomModName = UserAddAtom(cczpstrModName->Buffer, FALSE);
if (pcur->atomModName == 0) {
return FALSE;
}
}
if (pcur->CURSORF_flags & CURSORF_ACON) {
/*
* Stash away animated icon info.
*/
pacon = (PACON)pcur;
pacon->aspcur = UserAllocPool(cbData, TAG_CURSOR);
if (pacon->aspcur == NULL)
return FALSE;
/*
* Copy the handle array. Do this in a try/except so the
* buffer will be freed if pcurData goes away. Even though
* cursor destruction would free the array, a fault will
* leave the contents in an undetermined state and cause
* problems during cursor destruction.
*/
try {
RtlCopyMemory(pacon->aspcur, pcurData->aspcur, cbData);
pacon->aicur = (DWORD *)((PBYTE)pacon->aspcur + (ULONG_PTR)pcurData->aicur);
pacon->ajifRate = (PJIF)((PBYTE)pacon->aspcur + (ULONG_PTR)pcurData->ajifRate);
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
UserFreePool(pacon->aspcur);
pacon->aspcur = NULL;
return FALSE;
}
/*
* Convert handles into pointers and lock them in.
*/
for (i = 0; i < pacon->cpcur; i++) {
PCURSOR pcurT;
pcurT = (PCURSOR) HMValidateHandle(pacon->aspcur[i], TYPE_CURSOR);
if (pcurT) {
pacon->aspcur[i] = NULL;
Lock(&pacon->aspcur[i], pcurT);
} else {
while (--i >= 0) {
Unlock(&pacon->aspcur[i]);
}
UserFreePool(pacon->aspcur);
pacon->aspcur = NULL;
RIPMSG0(RIP_WARNING, "SetCursorIconData: invalid cursor handle for animated cursor");
return FALSE;
}
}
} else {
PW32PROCESS W32Process = W32GetCurrentProcess();
/*
* If the icon's color bitmap has an alpha channel, pre-process it
* and cache it in our hbmUserAlpha field.
*/
pcur->hbmUserAlpha = ProcessAlphaBitmap(pcur->hbmColor);
/*
* Make the cursor and its bitmaps public - LAST THING!
*/
UserAssert(pcur->hbmMask);
UserAssert(pcur->cx);
UserAssert(pcur->cy);
/*
* Make the cursor public so that it can be shared across processes.
* Charge the curson to this very process GDI quota even if it's public.
*/
#if DBG
fSuccess =
#endif
GreSetBitmapOwner(pcur->hbmMask, OBJECT_OWNER_PUBLIC);
UserAssert(fSuccess);
GreIncQuotaCount(W32Process);
if (pcur->hbmColor) {
#if DBG
fSuccess =
#endif
GreSetBitmapOwner(pcur->hbmColor, OBJECT_OWNER_PUBLIC);
UserAssert(fSuccess);
GreIncQuotaCount(W32Process);
}
if (pcur->hbmUserAlpha != NULL) {
#if DBG
fSuccess =
#endif
GreSetBitmapOwner(pcur->hbmUserAlpha, OBJECT_OWNER_PUBLIC);
UserAssert(fSuccess);
GreIncQuotaCount(W32Process);
}
}
LinkCursor(pcur);
return TRUE;
#undef pacon
}