Don't destroy cursors/icons prematurely.

svn path=/trunk/; revision=12742
This commit is contained in:
Gé van Geldorp 2005-01-03 00:46:42 +00:00
parent c60f00807e
commit 8c1121a5be
5 changed files with 322 additions and 170 deletions

View file

@ -28,8 +28,6 @@ typedef struct _W32PROCESS
LIST_ENTRY MenuListHead;
FAST_MUTEX PrivateFontListLock;
LIST_ENTRY PrivateFontListHead;
FAST_MUTEX CursorIconListLock;
LIST_ENTRY CursorIconListHead;
struct _KBDTABLES* KeyboardLayout;
ULONG Flags;
LONG GDIObjects;

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: bitmap.c,v 1.34 2004/12/19 05:00:22 royce Exp $
/* $Id$
*
* PROJECT: ReactOS user32.dll
* FILE: lib/user32/windows/input.c
@ -149,7 +149,7 @@ LoadCursorImage(HINSTANCE hinst, LPCWSTR lpszName, UINT fuLoad)
hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE)ResIcon,
SizeofResource(hinst, h2Resource), FALSE, 0x00030000,
32, 32, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
if (hIcon)
if (hIcon && 0 != (fuLoad & LR_SHARED))
{
NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
(HRSRC)NULL);
@ -157,100 +157,98 @@ LoadCursorImage(HINSTANCE hinst, LPCWSTR lpszName, UINT fuLoad)
return hIcon;
}
else
if (fuLoad & LR_SHARED)
{
if (fuLoad & LR_SHARED)
{
DbgPrint("FIXME: need LR_SHARED support loading cursor images from files\n");
}
DbgPrint("FIXME: need LR_SHARED support loading cursor images from files\n");
}
hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (hFile == NULL)
{
return NULL;
}
hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
CloseHandle(hFile);
if (hSection == NULL)
{
return NULL;
}
IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hSection);
if (IconDIR == NULL || 0 != IconDIR->idReserved
|| (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
{
return NULL;
}
/*
* Get a handle to the screen dc, the icon we create is going to be
* compatable with it.
*/
hScreenDc = CreateCompatibleDC(0);
if (hScreenDc == NULL)
{
UnmapViewOfFile(IconDIR);
return NULL;
}
if (fuLoad & LR_MONOCHROME)
{
ColorBits = 1;
}
else
{
ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
/*
* FIXME:
* Remove this after proper support for alpha icons will be finished.
*/
if (ColorBits > 8)
ColorBits = 8;
}
/* Pick the best size. */
dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, 32, 32, ColorBits);
if (!dirEntry)
{
UnmapViewOfFile(IconDIR);
return(NULL);
}
SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (hFile == NULL)
{
return NULL;
}
//at this point we have a copy of the icon image to play with
hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
CloseHandle(hFile);
if (hSection == NULL)
{
return NULL;
}
SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hSection);
if (IconDIR == NULL || 0 != IconDIR->idReserved
|| (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
{
return NULL;
}
if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
{
/*
* Get a handle to the screen dc, the icon we create is going to be
* compatable with it.
*/
hScreenDc = CreateCompatibleDC(0);
if (hScreenDc == NULL)
{
UnmapViewOfFile(IconDIR);
return NULL;
}
if (fuLoad & LR_MONOCHROME)
{
ColorBits = 1;
}
else
{
ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
/*
* FIXME:
* Remove this after proper support for alpha icons will be finished.
*/
if (ColorBits > 8)
ColorBits = 8;
}
/* Pick the best size. */
dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR, 32, 32, ColorBits);
if (!dirEntry)
{
UnmapViewOfFile(IconDIR);
return(NULL);
}
SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwBytesInRes);
memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset, dirEntry->dwBytesInRes);
/* at this point we have a copy of the icon image to play with */
SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
}
else
{
}
else
{
ColorCount = SafeIconImage->icHeader.biClrUsed;
if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
{
ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
}
HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
}
}
//make data point to the start of the XOR image data
Data = (PBYTE)SafeIconImage + HeaderSize;
/* make data point to the start of the XOR image data */
Data = (PBYTE)SafeIconImage + HeaderSize;
hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
DeleteDC(hScreenDc);
RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
return hIcon;
hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, 32, 32, dirEntry->Info.cursor.wXHotspot, dirEntry->Info.cursor.wYHotspot);
DeleteDC(hScreenDc);
RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
return hIcon;
}
@ -326,7 +324,7 @@ LoadIconImage(HINSTANCE hinst, LPCWSTR lpszName, INT width, INT height, UINT fuL
hIcon = (HANDLE)CreateIconFromResourceEx((PBYTE) ResIcon,
SizeofResource(hinst, h2Resource), TRUE, 0x00030000,
width, height, fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
if(hIcon)
if (hIcon && 0 != (fuLoad & LR_SHARED))
{
NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
(HRSRC)NULL);

View file

@ -3,11 +3,18 @@
#define MAXCURICONHANDLES 4096
typedef struct _CURICON_OBJECT
typedef struct tagCURICON_PROCESS
{
HANDLE Self;
LIST_ENTRY ListEntry;
PW32PROCESS Process;
} CURICON_PROCESS, *PCURICON_PROCESS;
typedef struct _CURICON_OBJECT
{
LIST_ENTRY ListEntry;
HANDLE Self;
FAST_MUTEX Lock;
LIST_ENTRY ProcessList;
HMODULE hModule;
HRSRC hRsrc;
HRSRC hGroupRsrc;

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: dllmain.c,v 1.86 2004/12/29 19:55:01 gvg Exp $
/* $Id$
*
* Entry Point for win32k.sys
*/
@ -71,9 +71,6 @@ Win32kProcessCallback (struct _EPROCESS *Process,
InitializeListHead(&Win32Process->PrivateFontListHead);
ExInitializeFastMutex(&Win32Process->PrivateFontListLock);
InitializeListHead(&Win32Process->CursorIconListHead);
ExInitializeFastMutex(&Win32Process->CursorIconListLock);
Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
/* setup process flags */

View file

@ -16,9 +16,32 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: cursoricon.c,v 1.5 2004/12/30 02:32:18 navaraf Exp $ */
/*
* We handle two types of cursors/icons:
* - Private
* Loaded without LR_SHARED flag
* Private to a process
* Can be deleted by calling NtDestroyCursorIcon()
* CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
* - Shared
* Loaded with LR_SHARED flag
* Possibly shared by multiple processes
* Immune to NtDestroyCursorIcon()
* CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
* There's a M:N relationship between processes and (shared) cursor/icons.
* A process can have multiple cursor/icons and a cursor/icon can be used
* by multiple processes. To keep track of this we keep a list of all
* cursor/icons (CurIconList) and per cursor/icon we keep a list of
* CURICON_PROCESS structs starting at CurIcon->ProcessList.
*/
#include <w32k.h>
static PAGED_LOOKASIDE_LIST ProcessLookasideList;
static LIST_ENTRY CurIconList;
static FAST_MUTEX CurIconListLock;
PCURICON_OBJECT FASTCALL
IntGetCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle)
{
@ -248,6 +271,61 @@ IntSetCursor(PWINSTATION_OBJECT WinStaObject, PCURICON_OBJECT NewCursor,
BOOL FASTCALL
IntSetupCurIconHandles(PWINSTATION_OBJECT WinStaObject)
{
ExInitializePagedLookasideList(&ProcessLookasideList,
NULL,
NULL,
0,
sizeof(CURICON_PROCESS),
0,
128);
InitializeListHead(&CurIconList);
ExInitializeFastMutex(&CurIconListLock);
return TRUE;
}
/*
* We have to register that this object is in use by the current
* process. The only way to do that seems to be to walk the list
* of cursor/icon objects starting at W32Process->CursorIconListHead.
* If the object is already present in the list, we don't have to do
* anything, if it's not present we add it and inc the ProcessCount
* in the object. Having to walk the list kind of sucks, but that's
* life...
*/
static BOOLEAN FASTCALL
ReferenceCurIconByProcess(PCURICON_OBJECT Object)
{
PW32PROCESS Win32Process;
PLIST_ENTRY Search;
PCURICON_PROCESS Current;
Win32Process = PsGetWin32Process();
ExAcquireFastMutex(&Object->Lock);
Search = Object->ProcessList.Flink;
while (Search != &Object->ProcessList)
{
Current = CONTAINING_RECORD(Search, CURICON_PROCESS, ListEntry);
if (Current->Process == Win32Process)
{
/* Already registered for this process */
ExReleaseFastMutex(&Object->Lock);
return TRUE;
}
Search = Search->Flink;
}
/* Not registered yet */
Current = ExAllocateFromPagedLookasideList(&ProcessLookasideList);
if (NULL == Current)
{
return FALSE;
}
InsertHeadList(&Object->ProcessList, &Current->ListEntry);
Current->Process = Win32Process;
ExReleaseFastMutex(&Object->Lock);
return TRUE;
}
@ -255,41 +333,35 @@ PCURICON_OBJECT FASTCALL
IntFindExistingCurIconObject(PWINSTATION_OBJECT WinStaObject, HMODULE hModule,
HRSRC hRsrc, LONG cx, LONG cy)
{
PUSER_HANDLE_TABLE HandleTable;
PLIST_ENTRY CurrentEntry;
PUSER_HANDLE_BLOCK Current;
PCURICON_OBJECT Object;
ULONG i;
HandleTable = (PUSER_HANDLE_TABLE)WinStaObject->HandleTable;
ObmpLockHandleTable(HandleTable);
CurrentEntry = HandleTable->ListHead.Flink;
while(CurrentEntry != &HandleTable->ListHead)
ExAcquireFastMutex(&CurIconListLock);
CurrentEntry = CurIconList.Flink;
while (CurrentEntry != &CurIconList)
{
Current = CONTAINING_RECORD(CurrentEntry, USER_HANDLE_BLOCK, ListEntry);
for(i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
{
Object = (PCURICON_OBJECT)Current->Handles[i].ObjectBody;
if(Object && (ObmReferenceObjectByPointer(Object, otCursorIcon) == STATUS_SUCCESS))
{
if((Object->hModule == hModule) && (Object->hRsrc == hRsrc))
{
if(cx && ((cx != Object->Size.cx) || (cy != Object->Size.cy)))
{
ObmDereferenceObject(Object);
continue;
}
ObmpUnlockHandleTable(HandleTable);
return Object;
}
ObmDereferenceObject(Object);
}
}
Object = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
CurrentEntry = CurrentEntry->Flink;
if((Object->hModule == hModule) && (Object->hRsrc == hRsrc))
{
if(cx && ((cx != Object->Size.cx) || (cy != Object->Size.cy)))
{
ObmDereferenceObject(Object);
continue;
}
if (! ReferenceCurIconByProcess(Object))
{
ExReleaseFastMutex(&CurIconListLock);
return NULL;
}
ExReleaseFastMutex(&CurIconListLock);
return Object;
}
}
ObmpUnlockHandleTable(HandleTable);
ExReleaseFastMutex(&CurIconListLock);
return NULL;
}
@ -298,7 +370,6 @@ IntCreateCurIconHandle(PWINSTATION_OBJECT WinStaObject)
{
PCURICON_OBJECT Object;
HANDLE Handle;
PW32PROCESS Win32Process;
Object = ObmCreateObject(WinStaObject->HandleTable, &Handle, otCursorIcon, sizeof(CURICON_OBJECT));
@ -308,38 +379,89 @@ IntCreateCurIconHandle(PWINSTATION_OBJECT WinStaObject)
return FALSE;
}
Win32Process = PsGetWin32Process();
IntLockProcessCursorIcons(Win32Process);
InsertTailList(&Win32Process->CursorIconListHead, &Object->ListEntry);
IntUnLockProcessCursorIcons(Win32Process);
Object->Self = Handle;
Object->Process = PsGetWin32Process();
ExInitializeFastMutex(&Object->Lock);
InitializeListHead(&Object->ProcessList);
if (! ReferenceCurIconByProcess(Object))
{
DPRINT1("Failed to add process\n");
ObmCloseHandle(WinStaObject->HandleTable, Handle);
ObmDereferenceObject(Object);
return NULL;
}
ExAcquireFastMutex(&CurIconListLock);
InsertHeadList(&CurIconList, &Object->ListEntry);
ExReleaseFastMutex(&CurIconListLock);
ObmDereferenceObject(Object);
return Object;
}
BOOL FASTCALL
IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle, BOOL RemoveFromProcess)
BOOLEAN FASTCALL
IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, PCURICON_OBJECT Object, BOOL ProcessCleanup)
{
PSYSTEM_CURSORINFO CurInfo;
PCURICON_OBJECT Object;
HBITMAP bmpMask, bmpColor;
NTSTATUS Status;
BOOL Ret;
Status = ObmReferenceObjectByHandle(WinStaObject->HandleTable, Handle, otCursorIcon, (PVOID*)&Object);
if(!NT_SUCCESS(Status))
{
return FALSE;
}
if (Object->Process != PsGetWin32Process())
{
ObmDereferenceObject(Object);
return FALSE;
}
BOOLEAN Ret;
PLIST_ENTRY Search;
PCURICON_PROCESS Current;
PW32PROCESS W32Process = PsGetWin32Process();
ExAcquireFastMutex(&Object->Lock);
/* Private objects can only be destroyed by their own process */
if (NULL == Object->hModule)
{
ASSERT(Object->ProcessList.Flink->Flink == &Object->ProcessList);
Current = CONTAINING_RECORD(Object->ProcessList.Flink, CURICON_PROCESS, ListEntry);
if (Current->Process != W32Process)
{
ExReleaseFastMutex(&Object->Lock);
DPRINT1("Trying to destroy private icon/cursor of another process\n");
return FALSE;
}
}
else if (! ProcessCleanup)
{
ExReleaseFastMutex(&Object->Lock);
DPRINT("Trying to destroy shared icon/cursor\n");
return FALSE;
}
/* Now find this process in the list of processes referencing this object and
remove it from that list */
Search = Object->ProcessList.Flink;
while (Search != &Object->ProcessList)
{
Current = CONTAINING_RECORD(Object->ProcessList.Flink, CURICON_PROCESS, ListEntry);
if (Current->Process == W32Process)
{
break;
}
Search = Search->Flink;
}
ASSERT(Search != &Object->ProcessList);
RemoveEntryList(Search);
ExFreeToPagedLookasideList(&ProcessLookasideList, Current);
/* If there are still processes referencing this object we can't destroy it yet */
if (! IsListEmpty(&Object->ProcessList))
{
ExReleaseFastMutex(&Object->Lock);
return TRUE;
}
ExReleaseFastMutex(&Object->Lock);
if (! ProcessCleanup)
{
ExAcquireFastMutex(&CurIconListLock);
RemoveEntryList(&Object->ListEntry);
ExReleaseFastMutex(&CurIconListLock);
}
CurInfo = IntGetSysCursorInfo(WinStaObject);
@ -351,15 +473,8 @@ IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle, BOOL Rem
bmpMask = Object->IconInfo.hbmMask;
bmpColor = Object->IconInfo.hbmColor;
if (Object->Process && RemoveFromProcess)
{
IntLockProcessCursorIcons(Object->Process);
RemoveEntryList(&Object->ListEntry);
IntUnLockProcessCursorIcons(Object->Process);
}
Ret = NT_SUCCESS(ObmCloseHandle(WinStaObject->HandleTable, Handle));
Ret = NT_SUCCESS(ObmCloseHandle(WinStaObject->HandleTable, Object->Self));
/* delete bitmaps */
if(bmpMask)
@ -372,8 +487,6 @@ IntDestroyCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle, BOOL Rem
GDIOBJ_SetOwnership(bmpColor, PsGetCurrentProcess());
NtGdiDeleteObject(bmpColor);
}
ObmDereferenceObject(Object);
return Ret;
}
@ -382,23 +495,50 @@ VOID FASTCALL
IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
{
PWINSTATION_OBJECT WinStaObject;
PCURICON_OBJECT Current;
PLIST_ENTRY CurrentEntry, NextEntry;
PLIST_ENTRY CurrentEntry;
PCURICON_OBJECT Object;
PLIST_ENTRY ProcessEntry;
PCURICON_PROCESS ProcessData;
WinStaObject = IntGetWinStaObj();
if(WinStaObject != NULL)
if(WinStaObject == NULL)
{
CurrentEntry = Win32Process->CursorIconListHead.Flink;
while(CurrentEntry != &Win32Process->CursorIconListHead)
{
NextEntry = CurrentEntry->Flink;
Current = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
RemoveEntryList(&Current->ListEntry);
IntDestroyCurIconObject(WinStaObject, Current->Self, FALSE);
CurrentEntry = NextEntry;
}
ObDereferenceObject(WinStaObject);
return;
}
ExAcquireFastMutex(&CurIconListLock);
CurrentEntry = CurIconList.Flink;
while (CurrentEntry != &CurIconList)
{
Object = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
CurrentEntry = CurrentEntry->Flink;
if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon)))
{
ExAcquireFastMutex(&Object->Lock);
ProcessEntry = Object->ProcessList.Flink;
while (ProcessEntry != &Object->ProcessList)
{
ProcessData = CONTAINING_RECORD(ProcessEntry, CURICON_PROCESS, ListEntry);
if (Win32Process == ProcessData->Process)
{
ExReleaseFastMutex(&Object->Lock);
RemoveEntryList(&Object->ListEntry);
IntDestroyCurIconObject(WinStaObject, Object, TRUE);
break;
}
ProcessEntry = ProcessEntry->Flink;
}
if (ProcessEntry == &Object->ProcessList)
{
ExReleaseFastMutex(&Object->Lock);
}
ObmDereferenceObject(Object);
}
}
ExReleaseFastMutex(&CurIconListLock);
ObDereferenceObject(WinStaObject);
}
/*
@ -729,6 +869,8 @@ NtUserDestroyCursorIcon(
DWORD Unknown)
{
PWINSTATION_OBJECT WinStaObject;
PCURICON_OBJECT Object;
NTSTATUS Status;
WinStaObject = IntGetWinStaObj();
if(WinStaObject == NULL)
@ -736,14 +878,24 @@ NtUserDestroyCursorIcon(
return FALSE;
}
if(IntDestroyCurIconObject(WinStaObject, Handle, TRUE))
Status = ObmReferenceObjectByHandle(WinStaObject->HandleTable, Handle, otCursorIcon, (PVOID*)&Object);
if(!NT_SUCCESS(Status))
{
ObDereferenceObject(WinStaObject);
SetLastNtError(Status);
return FALSE;
}
if(IntDestroyCurIconObject(WinStaObject, Object, FALSE))
{
ObmDereferenceObject(Object);
ObDereferenceObject(WinStaObject);
return TRUE;
}
SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
ObmDereferenceObject(Object);
ObDereferenceObject(WinStaObject);
SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
return FALSE;
}