mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:23:03 +00:00
[WIN32SS]
- Commit everything I got on new cursor/icon implementation - Implement loading animated cursors (no display yet) - Get rid of this m:n relation between cursors and processes. (ie. proper implementation of LR_SHARED) - Get rid of the global linked list of cursors (ditto) - Use atoms instead of copying the module name into the object. (aka stop using non paged pool for nothing) - Misc fixes svn path=/trunk/; revision=60978
This commit is contained in:
parent
6e769a014e
commit
26b89c0907
12 changed files with 967 additions and 479 deletions
|
@ -2000,8 +2000,8 @@ NTAPI
|
||||||
NtUserGetCursorFrameInfo(
|
NtUserGetCursorFrameInfo(
|
||||||
HCURSOR hCursor,
|
HCURSOR hCursor,
|
||||||
DWORD istep,
|
DWORD istep,
|
||||||
PDWORD rate_jiffies,
|
INT* rate_jiffies,
|
||||||
INT *num_steps);
|
DWORD* num_steps);
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -2791,7 +2791,7 @@ NtUserSetCursorIconData(
|
||||||
_In_ HCURSOR hCursor,
|
_In_ HCURSOR hCursor,
|
||||||
_In_ PUNICODE_STRING pustrModule,
|
_In_ PUNICODE_STRING pustrModule,
|
||||||
_In_ PUNICODE_STRING puSrcName,
|
_In_ PUNICODE_STRING puSrcName,
|
||||||
_In_ PCURSORDATA pCursorData);
|
_In_ const CURSORDATA* pCursorData);
|
||||||
|
|
||||||
typedef struct _tagFINDEXISTINGCURICONPARAM
|
typedef struct _tagFINDEXISTINGCURICONPARAM
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,7 +90,7 @@ typedef struct
|
||||||
{ union
|
{ union
|
||||||
{
|
{
|
||||||
ICONRESDIR icon;
|
ICONRESDIR icon;
|
||||||
CURSORDIR cursor;
|
CURSORRESDIR cursor;
|
||||||
} ResInfo;
|
} ResInfo;
|
||||||
WORD wPlanes;
|
WORD wPlanes;
|
||||||
WORD wBitCount;
|
WORD wBitCount;
|
||||||
|
|
|
@ -1728,7 +1728,11 @@ IntSetClassMenuName(IN PCLS Class,
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Do this for now in anticipation of new cursor icon code.
|
//// Do this for now in anticipation of new cursor icon code.
|
||||||
|
#ifndef NEW_CURSORICON
|
||||||
BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT, PPROCESSINFO);
|
BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT, PPROCESSINFO);
|
||||||
|
#else
|
||||||
|
BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT, BOOLEAN);
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOL FASTCALL
|
BOOL FASTCALL
|
||||||
IntClassDestroyIcon(HANDLE hCurIcon)
|
IntClassDestroyIcon(HANDLE hCurIcon)
|
||||||
|
@ -1742,8 +1746,13 @@ IntClassDestroyIcon(HANDLE hCurIcon)
|
||||||
ERR("hCurIcon was not found!\n");
|
ERR("hCurIcon was not found!\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
#ifndef NEW_CURSORICON
|
||||||
Ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
|
Ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
|
||||||
/* Note: IntDestroyCurIconObject will remove our reference for us! */
|
/* Note: IntDestroyCurIconObject will remove our reference for us! */
|
||||||
|
#else
|
||||||
|
/* Note: IntDestroyCurIconObject will remove our reference for us! */
|
||||||
|
Ret = IntDestroyCurIconObject(CurIcon, TRUE);
|
||||||
|
#endif
|
||||||
if (!Ret)
|
if (!Ret)
|
||||||
{
|
{
|
||||||
ERR("hCurIcon was not Destroyed!\n");
|
ERR("hCurIcon was not Destroyed!\n");
|
||||||
|
|
|
@ -203,7 +203,7 @@ IntFindExistingCurIconObject(HMODULE hModule,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PCURICON_OBJECT
|
HANDLE
|
||||||
IntCreateCurIconHandle(DWORD dwNumber)
|
IntCreateCurIconHandle(DWORD dwNumber)
|
||||||
{
|
{
|
||||||
PCURICON_OBJECT CurIcon;
|
PCURICON_OBJECT CurIcon;
|
||||||
|
@ -230,7 +230,9 @@ IntCreateCurIconHandle(DWORD dwNumber)
|
||||||
|
|
||||||
InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
|
InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
|
||||||
|
|
||||||
return CurIcon;
|
UserDereferenceObject(CurIcon);
|
||||||
|
|
||||||
|
return hCurIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FASTCALL
|
BOOLEAN FASTCALL
|
||||||
|
@ -1519,4 +1521,20 @@ NtUserDrawIconEx(
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
HCURSOR
|
||||||
|
NTAPI
|
||||||
|
NtUserGetCursorFrameInfo(
|
||||||
|
HCURSOR hCursor,
|
||||||
|
DWORD istep,
|
||||||
|
INT* rate_jiffies,
|
||||||
|
DWORD* num_steps)
|
||||||
|
{
|
||||||
|
STUB
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -2,17 +2,11 @@
|
||||||
|
|
||||||
#define MAXCURICONHANDLES 4096
|
#define MAXCURICONHANDLES 4096
|
||||||
|
|
||||||
typedef struct tagCURICON_PROCESS
|
|
||||||
{
|
|
||||||
LIST_ENTRY ListEntry;
|
|
||||||
PPROCESSINFO Process;
|
|
||||||
} CURICON_PROCESS, *PCURICON_PROCESS;
|
|
||||||
|
|
||||||
#ifdef NEW_CURSORICON
|
#ifdef NEW_CURSORICON
|
||||||
typedef struct _CURICON_OBJECT
|
typedef struct _CURICON_OBJECT
|
||||||
{
|
{
|
||||||
PROCMARKHEAD head;
|
PROCMARKHEAD head;
|
||||||
struct _tagCURSOR* pcurNext;
|
struct _CURICON_OBJECT* pcurNext;
|
||||||
UNICODE_STRING strName;
|
UNICODE_STRING strName;
|
||||||
USHORT atomModName;
|
USHORT atomModName;
|
||||||
USHORT rt;
|
USHORT rt;
|
||||||
|
@ -27,15 +21,34 @@ typedef struct _CURICON_OBJECT
|
||||||
ULONG bpp;
|
ULONG bpp;
|
||||||
ULONG cx;
|
ULONG cx;
|
||||||
ULONG cy;
|
ULONG cy;
|
||||||
/* ReactOS specific, to be deleted */
|
|
||||||
LIST_ENTRY ListEntry;
|
|
||||||
HANDLE Self;
|
|
||||||
LIST_ENTRY ProcessList;
|
|
||||||
UNICODE_STRING ustrModule;
|
|
||||||
} CURICON_OBJECT, *PCURICON_OBJECT;
|
} CURICON_OBJECT, *PCURICON_OBJECT;
|
||||||
|
|
||||||
|
typedef struct tagACON
|
||||||
|
{
|
||||||
|
PROCMARKHEAD head;
|
||||||
|
struct _CURICON_OBJECT* pcurNext;
|
||||||
|
UNICODE_STRING strName;
|
||||||
|
USHORT atomModName;
|
||||||
|
USHORT rt;
|
||||||
|
ULONG CURSORF_flags;
|
||||||
|
INT cpcur;
|
||||||
|
INT cicur;
|
||||||
|
PCURICON_OBJECT * aspcur;
|
||||||
|
DWORD * aicur;
|
||||||
|
INT * ajifRate;
|
||||||
|
INT iicur;
|
||||||
|
} ACON, *PACON;
|
||||||
|
|
||||||
|
C_ASSERT(FIELD_OFFSET(ACON, cpcur) == FIELD_OFFSET(CURICON_OBJECT, xHotspot));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
typedef struct tagCURICON_PROCESS
|
||||||
|
{
|
||||||
|
LIST_ENTRY ListEntry;
|
||||||
|
PPROCESSINFO Process;
|
||||||
|
} CURICON_PROCESS, *PCURICON_PROCESS;
|
||||||
|
|
||||||
typedef struct _CURICON_OBJECT
|
typedef struct _CURICON_OBJECT
|
||||||
{
|
{
|
||||||
PROCMARKHEAD head;
|
PROCMARKHEAD head;
|
||||||
|
@ -91,7 +104,7 @@ typedef struct _SYSTEM_CURSORINFO
|
||||||
} SYSTEM_CURSORINFO, *PSYSTEM_CURSORINFO;
|
} SYSTEM_CURSORINFO, *PSYSTEM_CURSORINFO;
|
||||||
|
|
||||||
BOOL InitCursorImpl(VOID);
|
BOOL InitCursorImpl(VOID);
|
||||||
PCURICON_OBJECT IntCreateCurIconHandle(DWORD dwNumber);
|
HANDLE IntCreateCurIconHandle(BOOLEAN Anim);
|
||||||
VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process);
|
VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process);
|
||||||
|
|
||||||
BOOL UserDrawIconEx(HDC hDc, INT xLeft, INT yTop, PCURICON_OBJECT pIcon, INT cxWidth,
|
BOOL UserDrawIconEx(HDC hDc, INT xLeft, INT yTop, PCURICON_OBJECT pIcon, INT cxWidth,
|
||||||
|
|
|
@ -17,37 +17,16 @@
|
||||||
* Possibly shared by multiple processes
|
* Possibly shared by multiple processes
|
||||||
* Immune to NtDestroyCursorIcon()
|
* Immune to NtDestroyCursorIcon()
|
||||||
* CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
|
* 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 <win32k.h>
|
#include <win32k.h>
|
||||||
DBG_DEFAULT_CHANNEL(UserIcon);
|
DBG_DEFAULT_CHANNEL(UserIcon);
|
||||||
|
|
||||||
static LIST_ENTRY gCurIconList;
|
|
||||||
static PAGED_LOOKASIDE_LIST *pgProcessLookasideList;
|
|
||||||
|
|
||||||
SYSTEM_CURSORINFO gSysCursorInfo;
|
SYSTEM_CURSORINFO gSysCursorInfo;
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
InitCursorImpl()
|
InitCursorImpl()
|
||||||
{
|
{
|
||||||
pgProcessLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
|
|
||||||
if(!pgProcessLookasideList)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
ExInitializePagedLookasideList(pgProcessLookasideList,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
sizeof(CURICON_PROCESS),
|
|
||||||
TAG_DIB,
|
|
||||||
128);
|
|
||||||
InitializeListHead(&gCurIconList);
|
|
||||||
|
|
||||||
gSysCursorInfo.Enabled = FALSE;
|
gSysCursorInfo.Enabled = FALSE;
|
||||||
gSysCursorInfo.ButtonsDown = 0;
|
gSysCursorInfo.ButtonsDown = 0;
|
||||||
gSysCursorInfo.bClipped = FALSE;
|
gSysCursorInfo.bClipped = FALSE;
|
||||||
|
@ -84,6 +63,13 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(UserObjectInDestroy(hCurIcon))
|
||||||
|
{
|
||||||
|
ERR("Requesting destroyed cursor.\n");
|
||||||
|
EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
|
CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR);
|
||||||
if (!CurIcon)
|
if (!CurIcon)
|
||||||
{
|
{
|
||||||
|
@ -138,98 +124,19 @@ BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Ho
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
HANDLE
|
||||||
* We have to register that this object is in use by the current
|
IntCreateCurIconHandle(BOOLEAN Animated)
|
||||||
* 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 CurIcon)
|
|
||||||
{
|
|
||||||
PPROCESSINFO Win32Process;
|
|
||||||
PCURICON_PROCESS Current;
|
|
||||||
|
|
||||||
Win32Process = PsGetCurrentProcessWin32Process();
|
|
||||||
|
|
||||||
LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
|
|
||||||
{
|
|
||||||
if (Current->Process == Win32Process)
|
|
||||||
{
|
|
||||||
/* Already registered for this process */
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Not registered yet */
|
|
||||||
Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
|
|
||||||
if (NULL == Current)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
|
|
||||||
Current->Process = Win32Process;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
PCURICON_OBJECT
|
|
||||||
FASTCALL
|
|
||||||
IntFindExistingCurIconObject(
|
|
||||||
PUNICODE_STRING pustrModule,
|
|
||||||
PUNICODE_STRING pustrRsrc,
|
|
||||||
FINDEXISTINGCURICONPARAM* param)
|
|
||||||
{
|
|
||||||
PCURICON_OBJECT CurIcon;
|
|
||||||
|
|
||||||
LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
|
|
||||||
{
|
|
||||||
/* See if we are looking for an icon or a cursor */
|
|
||||||
if(MAKEINTRESOURCE(CurIcon->rt) != (param->bIcon ? RT_ICON : RT_CURSOR))
|
|
||||||
continue;
|
|
||||||
/* See if module names match */
|
|
||||||
if(RtlCompareUnicodeString(pustrModule, &CurIcon->ustrModule, TRUE) == 0)
|
|
||||||
{
|
|
||||||
/* They do. Now see if this is the same resource */
|
|
||||||
if(IS_INTRESOURCE(CurIcon->strName.Buffer) && IS_INTRESOURCE(pustrRsrc->Buffer))
|
|
||||||
{
|
|
||||||
if(CurIcon->strName.Buffer != pustrRsrc->Buffer)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if(IS_INTRESOURCE(CurIcon->strName.Buffer) || IS_INTRESOURCE(pustrRsrc->Buffer))
|
|
||||||
continue;
|
|
||||||
else if(RtlCompareUnicodeString(pustrRsrc, &CurIcon->strName, TRUE) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((param->cx == CurIcon->cx) && (param->cy == CurIcon->cy))
|
|
||||||
{
|
|
||||||
if (! ReferenceCurIconByProcess(CurIcon))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CurIcon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PCURICON_OBJECT
|
|
||||||
IntCreateCurIconHandle(DWORD dwNumber)
|
|
||||||
{
|
{
|
||||||
PCURICON_OBJECT CurIcon;
|
PCURICON_OBJECT CurIcon;
|
||||||
HANDLE hCurIcon;
|
HANDLE hCurIcon;
|
||||||
|
|
||||||
if(dwNumber == 0)
|
CurIcon = UserCreateObject(
|
||||||
dwNumber = 1;
|
gHandleTable,
|
||||||
|
NULL,
|
||||||
CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, TYPE_CURSOR, sizeof(CURICON_OBJECT));
|
NULL,
|
||||||
|
&hCurIcon,
|
||||||
|
TYPE_CURSOR,
|
||||||
|
Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT));
|
||||||
|
|
||||||
if (!CurIcon)
|
if (!CurIcon)
|
||||||
{
|
{
|
||||||
|
@ -237,91 +144,44 @@ IntCreateCurIconHandle(DWORD dwNumber)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurIcon->Self = hCurIcon;
|
|
||||||
InitializeListHead(&CurIcon->ProcessList);
|
|
||||||
|
|
||||||
if (! ReferenceCurIconByProcess(CurIcon))
|
|
||||||
{
|
|
||||||
ERR("Failed to add process\n");
|
|
||||||
UserDereferenceObject(CurIcon);
|
UserDereferenceObject(CurIcon);
|
||||||
UserDeleteObject(hCurIcon, TYPE_CURSOR);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
|
return hCurIcon;
|
||||||
|
|
||||||
return CurIcon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FASTCALL
|
BOOLEAN FASTCALL
|
||||||
IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi, BOOLEAN bForce)
|
IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOLEAN bForce)
|
||||||
{
|
{
|
||||||
HBITMAP bmpMask, bmpColor, bmpAlpha;
|
|
||||||
BOOLEAN Ret, bListEmpty, bFound = FALSE;
|
|
||||||
PCURICON_PROCESS Current = NULL;
|
|
||||||
|
|
||||||
/* Check if this is the current cursor */
|
|
||||||
if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
|
if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
|
||||||
{
|
{
|
||||||
UserDereferenceObject(CurIcon);
|
/* Mark the object as destroyed, and fail, as per wine tests */
|
||||||
|
UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For handles created without any data (error handling) */
|
if(CurIcon->head.ppi != PsGetCurrentProcessWin32Process())
|
||||||
if(IsListEmpty(&CurIcon->ProcessList))
|
|
||||||
goto emptyList;
|
|
||||||
|
|
||||||
/* Now find this process in the list of processes referencing this object and
|
|
||||||
remove it from that list */
|
|
||||||
LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
|
|
||||||
{
|
{
|
||||||
if (Current->Process == ppi)
|
/* This object doesn't belong to the current process */
|
||||||
{
|
WARN("Trying to delete foreign cursor!\n");
|
||||||
bFound = TRUE;
|
|
||||||
bListEmpty = RemoveEntryList(&Current->ListEntry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!bFound)
|
|
||||||
{
|
|
||||||
/* This object doesn't belong to this process */
|
|
||||||
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
||||||
/* Caller expects us to dereference! */
|
|
||||||
UserDereferenceObject(CurIcon);
|
UserDereferenceObject(CurIcon);
|
||||||
|
EngSetLastError(ERROR_DESTROY_OBJECT_OF_OTHER_THREAD);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We found our process, but we're told to not destroy it in case it is shared */
|
/* Do not destroy it if it is shared. (And we're not forced to) */
|
||||||
if((CurIcon->ustrModule.Buffer != NULL) && !bForce)
|
if((CurIcon->CURSORF_flags & CURSORF_LRSHARED) && !bForce)
|
||||||
{
|
{
|
||||||
/* Tests show this is a valid call */
|
/* Tests show this is a valid call */
|
||||||
|
WARN("Trying to destroy shared cursor!\n");
|
||||||
UserDereferenceObject(CurIcon);
|
UserDereferenceObject(CurIcon);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
|
if(!(CurIcon->CURSORF_flags & CURSORF_ACON))
|
||||||
|
|
||||||
/* If there are still processes referencing this object we can't destroy it yet */
|
|
||||||
if (!bListEmpty)
|
|
||||||
{
|
{
|
||||||
if(CurIcon->head.ppi == ppi)
|
HBITMAP bmpMask = CurIcon->hbmMask;
|
||||||
{
|
HBITMAP bmpColor = CurIcon->hbmColor;
|
||||||
/* Set the first process of the list as owner */
|
HBITMAP bmpAlpha = CurIcon->hbmAlpha;
|
||||||
Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
|
|
||||||
UserSetObjectOwner(CurIcon, TYPE_CURSOR, Current->Process);
|
|
||||||
}
|
|
||||||
UserDereferenceObject(CurIcon);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
emptyList:
|
|
||||||
/* Remove it from the list */
|
|
||||||
RemoveEntryList(&CurIcon->ListEntry);
|
|
||||||
|
|
||||||
bmpMask = CurIcon->hbmMask;
|
|
||||||
bmpColor = CurIcon->hbmColor;
|
|
||||||
bmpAlpha = CurIcon->hbmAlpha;
|
|
||||||
|
|
||||||
/* Delete bitmaps */
|
/* Delete bitmaps */
|
||||||
if (bmpMask)
|
if (bmpMask)
|
||||||
|
@ -342,29 +202,44 @@ emptyList:
|
||||||
GreDeleteObject(bmpAlpha);
|
GreDeleteObject(bmpAlpha);
|
||||||
CurIcon->hbmAlpha = NULL;
|
CurIcon->hbmAlpha = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PACON AniCurIcon = (PACON)CurIcon;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
for(i = 0; i < AniCurIcon->cpcur; i++)
|
||||||
|
IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
|
||||||
|
ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurIcon->CURSORF_flags & CURSORF_LRSHARED)
|
||||||
|
{
|
||||||
if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
|
if (!IS_INTRESOURCE(CurIcon->strName.Buffer))
|
||||||
ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
|
ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
|
||||||
if(CurIcon->ustrModule.Buffer)
|
if (CurIcon->atomModName)
|
||||||
ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
|
RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName);
|
||||||
|
CurIcon->strName.Buffer = NULL;
|
||||||
|
CurIcon->atomModName = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* We were given a pointer, no need to keep the reference any longer! */
|
/* We were given a pointer, no need to keep the reference any longer! */
|
||||||
UserDereferenceObject(CurIcon);
|
UserDereferenceObject(CurIcon);
|
||||||
Ret = UserDeleteObject(CurIcon->Self, TYPE_CURSOR);
|
return UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FASTCALL
|
VOID FASTCALL
|
||||||
IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
|
IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
|
||||||
{
|
{
|
||||||
PCURICON_OBJECT CurIcon, tmp;
|
PCURICON_OBJECT CurIcon;
|
||||||
|
|
||||||
/* Run through the list of icon objects */
|
/* Run through the list of icon objects */
|
||||||
LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
|
while(Win32Process->pCursorCache)
|
||||||
{
|
{
|
||||||
UserReferenceObject(CurIcon);
|
CurIcon = Win32Process->pCursorCache;
|
||||||
IntDestroyCurIconObject(CurIcon, Win32Process, TRUE);
|
Win32Process->pCursorCache = CurIcon->pcurNext;
|
||||||
|
ASSERT(CurIcon->head.cLockObj == 2);
|
||||||
|
IntDestroyCurIconObject(CurIcon, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,17 +285,24 @@ NtUserGetIconInfo(
|
||||||
/* Give back the icon information */
|
/* Give back the icon information */
|
||||||
if(IconInfo)
|
if(IconInfo)
|
||||||
{
|
{
|
||||||
|
PCURICON_OBJECT FrameCurIcon = CurIcon;
|
||||||
|
if(CurIcon->CURSORF_flags & CURSORF_ACON)
|
||||||
|
{
|
||||||
|
/* Get information from first frame. */
|
||||||
|
FrameCurIcon = ((PACON)CurIcon)->aspcur[0];
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill data */
|
/* Fill data */
|
||||||
ii.fIcon = is_icon(CurIcon);
|
ii.fIcon = is_icon(FrameCurIcon);
|
||||||
ii.xHotspot = CurIcon->xHotspot;
|
ii.xHotspot = FrameCurIcon->xHotspot;
|
||||||
ii.yHotspot = CurIcon->yHotspot;
|
ii.yHotspot = FrameCurIcon->yHotspot;
|
||||||
|
|
||||||
/* Copy bitmaps */
|
/* Copy bitmaps */
|
||||||
ii.hbmMask = BITMAP_CopyBitmap(CurIcon->hbmMask);
|
ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask);
|
||||||
GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
|
GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED);
|
||||||
ii.hbmColor = BITMAP_CopyBitmap(CurIcon->hbmColor);
|
ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor);
|
||||||
GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
|
GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED);
|
||||||
colorBpp = CurIcon->bpp;
|
colorBpp = FrameCurIcon->bpp;
|
||||||
|
|
||||||
/* Copy fields */
|
/* Copy fields */
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
|
@ -439,7 +321,6 @@ NtUserGetIconInfo(
|
||||||
Status = _SEH2_GetExceptionCode();
|
Status = _SEH2_GetExceptionCode();
|
||||||
}
|
}
|
||||||
_SEH2_END
|
_SEH2_END
|
||||||
}
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
@ -447,43 +328,49 @@ NtUserGetIconInfo(
|
||||||
SetLastNtError(Status);
|
SetLastNtError(Status);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Give back the module name */
|
/* Give back the module name */
|
||||||
if(lpModule)
|
if(lpModule)
|
||||||
{
|
{
|
||||||
if(!CurIcon->ustrModule.Buffer)
|
ULONG BufLen = 0;
|
||||||
{
|
if (!CurIcon->atomModName)
|
||||||
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
|
||||||
/* Copy what we can */
|
RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen);
|
||||||
|
/* Get the module name from the atom table */
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
ProbeForWrite(lpModule, sizeof(UNICODE_STRING), 1);
|
if (BufLen > (lpModule->MaximumLength * sizeof(WCHAR)))
|
||||||
|
{
|
||||||
|
lpModule->Length = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
|
ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1);
|
||||||
lpModule->Length = min(lpModule->MaximumLength, CurIcon->ustrModule.Length);
|
BufLen = lpModule->MaximumLength * sizeof(WCHAR);
|
||||||
RtlCopyMemory(lpModule->Buffer, CurIcon->ustrModule.Buffer, lpModule->Length);
|
RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen);
|
||||||
|
lpModule->Length = BufLen/sizeof(WCHAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
Status = _SEH2_GetExceptionCode();
|
Status = _SEH2_GetExceptionCode();
|
||||||
}
|
}
|
||||||
_SEH2_END
|
_SEH2_END
|
||||||
}
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
SetLastNtError(Status);
|
SetLastNtError(Status);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lpResName)
|
if (lpResName)
|
||||||
{
|
{
|
||||||
if (!CurIcon->strName.Buffer)
|
if (!CurIcon->strName.Buffer)
|
||||||
{
|
|
||||||
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
|
||||||
/* Copy it */
|
/* Copy it */
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
|
@ -493,9 +380,13 @@ NtUserGetIconInfo(
|
||||||
lpResName->Buffer = CurIcon->strName.Buffer;
|
lpResName->Buffer = CurIcon->strName.Buffer;
|
||||||
lpResName->Length = 0;
|
lpResName->Length = 0;
|
||||||
}
|
}
|
||||||
|
else if (lpResName->MaximumLength < CurIcon->strName.Length)
|
||||||
|
{
|
||||||
|
lpResName->Length = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lpResName->Length = min(lpResName->MaximumLength, CurIcon->strName.Length);
|
ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength * sizeof(WCHAR), 1);
|
||||||
RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
|
RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, lpResName->Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -547,6 +438,15 @@ NtUserGetIconSize(
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(CurIcon->CURSORF_flags & CURSORF_ACON)
|
||||||
|
{
|
||||||
|
/* Use first frame for animated cursors */
|
||||||
|
PACON AniCurIcon = (PACON)CurIcon;
|
||||||
|
CurIcon = AniCurIcon->aspcur[0];
|
||||||
|
UserDereferenceObject(AniCurIcon);
|
||||||
|
UserReferenceObject(CurIcon);
|
||||||
|
}
|
||||||
|
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
ProbeForWrite(plcx, sizeof(LONG), 1);
|
ProbeForWrite(plcx, sizeof(LONG), 1);
|
||||||
|
@ -597,7 +497,7 @@ NtUserGetCursorInfo(
|
||||||
|
|
||||||
SafeCi.cbSize = sizeof(CURSORINFO);
|
SafeCi.cbSize = sizeof(CURSORINFO);
|
||||||
SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
|
SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
|
||||||
SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
|
SafeCi.hCursor = (CurIcon ? CurIcon->head.h : NULL);
|
||||||
|
|
||||||
SafeCi.ptScreenPos = gpsi->ptCursor;
|
SafeCi.ptScreenPos = gpsi->ptCursor;
|
||||||
|
|
||||||
|
@ -739,7 +639,7 @@ NtUserDestroyCursor(
|
||||||
RETURN(FALSE);
|
RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce);
|
ret = IntDestroyCurIconObject(CurIcon, bForce);
|
||||||
/* Note: IntDestroyCurIconObject will remove our reference for us! */
|
/* Note: IntDestroyCurIconObject will remove our reference for us! */
|
||||||
|
|
||||||
RETURN(ret);
|
RETURN(ret);
|
||||||
|
@ -766,16 +666,11 @@ NtUserFindExistingCursorIcon(
|
||||||
UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
|
UNICODE_STRING ustrModuleSafe, ustrRsrcSafe;
|
||||||
FINDEXISTINGCURICONPARAM paramSafe;
|
FINDEXISTINGCURICONPARAM paramSafe;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process();
|
||||||
|
RTL_ATOM atomModName;
|
||||||
|
|
||||||
TRACE("Enter NtUserFindExistingCursorIcon\n");
|
TRACE("Enter NtUserFindExistingCursorIcon\n");
|
||||||
|
|
||||||
/* Capture resource name (it can be an INTRESOURCE == ATOM) */
|
|
||||||
Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
|
|
||||||
if(!NT_SUCCESS(Status))
|
|
||||||
return NULL;
|
|
||||||
Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
|
|
||||||
if(!NT_SUCCESS(Status))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
|
@ -788,16 +683,65 @@ NtUserFindExistingCursorIcon(
|
||||||
}
|
}
|
||||||
_SEH2_END
|
_SEH2_END
|
||||||
|
|
||||||
|
/* Capture resource name (it can be an INTRESOURCE == ATOM) */
|
||||||
|
Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc);
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
|
return NULL;
|
||||||
|
Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
|
goto done;
|
||||||
|
Status = RtlLookupAtomInAtomTable(gAtomTable, ustrModuleSafe.Buffer, &atomModName);
|
||||||
|
ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* The module is not in the atom table. No chance to find the cursor */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
UserEnterExclusive();
|
UserEnterExclusive();
|
||||||
CurIcon = IntFindExistingCurIconObject(&ustrModuleSafe, &ustrRsrcSafe, ¶mSafe);
|
CurIcon = pProcInfo->pCursorCache;
|
||||||
|
while(CurIcon)
|
||||||
|
{
|
||||||
|
/* Icon/cursor */
|
||||||
|
if (paramSafe.bIcon != is_icon(CurIcon))
|
||||||
|
{
|
||||||
|
CurIcon = CurIcon->pcurNext;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* See if module names match */
|
||||||
|
if (atomModName == CurIcon->atomModName)
|
||||||
|
{
|
||||||
|
/* They do. Now see if this is the same resource */
|
||||||
|
if (IS_INTRESOURCE(CurIcon->strName.Buffer) != IS_INTRESOURCE(ustrRsrcSafe.Buffer))
|
||||||
|
{
|
||||||
|
/* One is an INT resource and the other is not -> no match */
|
||||||
|
CurIcon = CurIcon->pcurNext;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_INTRESOURCE(CurIcon->strName.Buffer))
|
||||||
|
{
|
||||||
|
if (CurIcon->strName.Buffer == ustrRsrcSafe.Buffer)
|
||||||
|
{
|
||||||
|
/* INT resources match */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (RtlCompareUnicodeString(&ustrRsrcSafe, &CurIcon->strName, TRUE) == 0)
|
||||||
|
{
|
||||||
|
/* Resource name strings match */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CurIcon = CurIcon->pcurNext;
|
||||||
|
}
|
||||||
if(CurIcon)
|
if(CurIcon)
|
||||||
Ret = CurIcon->Self;
|
Ret = CurIcon->head.h;
|
||||||
UserLeave();
|
UserLeave();
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
|
if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer))
|
||||||
ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
|
ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING);
|
||||||
ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
|
|
||||||
|
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
@ -884,10 +828,19 @@ NtUserSetCursor(
|
||||||
pcurOld = UserSetCursor(pcurNew, FALSE);
|
pcurOld = UserSetCursor(pcurNew, FALSE);
|
||||||
if (pcurOld)
|
if (pcurOld)
|
||||||
{
|
{
|
||||||
hOldCursor = (HCURSOR)pcurOld->Self;
|
hOldCursor = pcurOld->head.h;
|
||||||
pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
|
pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
|
||||||
|
if(UserObjectInDestroy(hOldCursor))
|
||||||
|
{
|
||||||
|
/* Destroy it once and for all */
|
||||||
|
IntDestroyCurIconObject(pcurOld, TRUE);
|
||||||
|
hOldCursor = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
UserDereferenceObject(pcurOld);
|
UserDereferenceObject(pcurOld);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
UserLeave();
|
UserLeave();
|
||||||
|
@ -918,18 +871,17 @@ NtUserSetCursorIconData(
|
||||||
_In_ HCURSOR Handle,
|
_In_ HCURSOR Handle,
|
||||||
_In_opt_ PUNICODE_STRING pustrModule,
|
_In_opt_ PUNICODE_STRING pustrModule,
|
||||||
_In_opt_ PUNICODE_STRING pustrRsrc,
|
_In_opt_ PUNICODE_STRING pustrRsrc,
|
||||||
_In_ PCURSORDATA pCursorData)
|
_In_ const CURSORDATA* pCursorData)
|
||||||
{
|
{
|
||||||
PCURICON_OBJECT CurIcon;
|
PCURICON_OBJECT CurIcon;
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
BOOL Ret = FALSE;
|
BOOLEAN Ret = FALSE;
|
||||||
|
BOOLEAN IsShared = FALSE, IsAnim = FALSE;
|
||||||
|
DWORD numFrames;
|
||||||
|
UINT i = 0;
|
||||||
|
|
||||||
TRACE("Enter NtUserSetCursorIconData\n");
|
TRACE("Enter NtUserSetCursorIconData\n");
|
||||||
|
|
||||||
/* If a module name is provided, we need a resource name, and vice versa */
|
|
||||||
if((pustrModule && !pustrRsrc) || (!pustrModule && pustrRsrc))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
UserEnterExclusive();
|
UserEnterExclusive();
|
||||||
|
|
||||||
if (!(CurIcon = UserGetCurIconObject(Handle)))
|
if (!(CurIcon = UserGetCurIconObject(Handle)))
|
||||||
|
@ -942,6 +894,38 @@ NtUserSetCursorIconData(
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
|
ProbeForRead(pCursorData, sizeof(*pCursorData), 1);
|
||||||
|
if(pCursorData->CURSORF_flags & CURSORF_ACON)
|
||||||
|
{
|
||||||
|
/* This is an animated cursor */
|
||||||
|
PACON AniCurIcon = (PACON)CurIcon;
|
||||||
|
DWORD numSteps;
|
||||||
|
|
||||||
|
numFrames = AniCurIcon->cpcur = pCursorData->cpcur;
|
||||||
|
numSteps = AniCurIcon->cicur = pCursorData->cicur;
|
||||||
|
AniCurIcon->iicur = pCursorData->iicur;
|
||||||
|
AniCurIcon->rt = pCursorData->rt;
|
||||||
|
|
||||||
|
/* Calculate size: one cursor object for each frame, and a frame index and jiffies for each "step" */
|
||||||
|
AniCurIcon->aspcur = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, /* Let SEH catch allocation failures */
|
||||||
|
numFrames * sizeof(CURICON_OBJECT*) + numSteps * (sizeof(DWORD) + sizeof(INT)),
|
||||||
|
USERTAG_CURSOR);
|
||||||
|
AniCurIcon->aicur = (DWORD*)(AniCurIcon->aspcur + numFrames);
|
||||||
|
AniCurIcon->ajifRate = (INT*)(AniCurIcon->aicur + numSteps);
|
||||||
|
|
||||||
|
RtlZeroMemory(AniCurIcon->aspcur, numFrames * sizeof(CURICON_OBJECT*));
|
||||||
|
|
||||||
|
ProbeForRead(pCursorData->aicur, numSteps * sizeof(DWORD), 1);
|
||||||
|
RtlCopyMemory(AniCurIcon->aicur, pCursorData->aicur, numSteps * sizeof(DWORD));
|
||||||
|
ProbeForRead(pCursorData->ajifRate, numSteps * sizeof(INT), 1);
|
||||||
|
RtlCopyMemory(AniCurIcon->ajifRate, pCursorData->ajifRate, numSteps * sizeof(INT));
|
||||||
|
|
||||||
|
AniCurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
|
||||||
|
pCursorData = pCursorData->aspcur;
|
||||||
|
|
||||||
|
IsAnim = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
CurIcon->xHotspot = pCursorData->xHotspot;
|
CurIcon->xHotspot = pCursorData->xHotspot;
|
||||||
CurIcon->yHotspot = pCursorData->yHotspot;
|
CurIcon->yHotspot = pCursorData->yHotspot;
|
||||||
CurIcon->cx = pCursorData->cx;
|
CurIcon->cx = pCursorData->cx;
|
||||||
|
@ -951,6 +935,8 @@ NtUserSetCursorIconData(
|
||||||
CurIcon->hbmMask = pCursorData->hbmMask;
|
CurIcon->hbmMask = pCursorData->hbmMask;
|
||||||
CurIcon->hbmColor = pCursorData->hbmColor;
|
CurIcon->hbmColor = pCursorData->hbmColor;
|
||||||
CurIcon->hbmAlpha = pCursorData->hbmAlpha;
|
CurIcon->hbmAlpha = pCursorData->hbmAlpha;
|
||||||
|
CurIcon->CURSORF_flags = pCursorData->CURSORF_flags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
{
|
{
|
||||||
|
@ -964,17 +950,41 @@ NtUserSetCursorIconData(
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pustrModule)
|
if(IsAnim)
|
||||||
{
|
{
|
||||||
|
PACON AniCurIcon = (PACON)CurIcon;
|
||||||
|
/* This is an animated cursor. Create a cursor object for each frame and set up the data */
|
||||||
|
for(i = 0; i < numFrames; i++)
|
||||||
|
{
|
||||||
|
HANDLE hCurFrame = IntCreateCurIconHandle(FALSE);
|
||||||
|
if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData))
|
||||||
|
goto done;
|
||||||
|
AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame);
|
||||||
|
if(!AniCurIcon->aspcur[i])
|
||||||
|
goto done;
|
||||||
|
pCursorData++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CurIcon->CURSORF_flags & CURSORF_LRSHARED)
|
||||||
|
{
|
||||||
|
IsShared = TRUE;
|
||||||
|
if(pustrRsrc && pustrModule)
|
||||||
|
{
|
||||||
|
UNICODE_STRING ustrModuleSafe;
|
||||||
/* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
|
/* We use this convenient function, because INTRESOURCEs and ATOMs are the same */
|
||||||
Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
|
Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc);
|
||||||
if(!NT_SUCCESS(Status))
|
if(!NT_SUCCESS(Status))
|
||||||
goto done;
|
goto done;
|
||||||
Status = ProbeAndCaptureUnicodeString(&CurIcon->ustrModule, UserMode, pustrModule);
|
Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule);
|
||||||
|
if(!NT_SUCCESS(Status))
|
||||||
|
goto done;
|
||||||
|
Status = RtlAddAtomToAtomTable(gAtomTable, ustrModuleSafe.Buffer, &CurIcon->atomModName);
|
||||||
|
ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode);
|
||||||
if(!NT_SUCCESS(Status))
|
if(!NT_SUCCESS(Status))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!CurIcon->hbmMask)
|
if(!CurIcon->hbmMask)
|
||||||
{
|
{
|
||||||
|
@ -991,16 +1001,40 @@ NtUserSetCursorIconData(
|
||||||
if(CurIcon->hbmAlpha)
|
if(CurIcon->hbmAlpha)
|
||||||
GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
|
GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC);
|
||||||
|
|
||||||
|
if(IsShared)
|
||||||
|
{
|
||||||
|
/* Update process cache in case of shared cursor */
|
||||||
|
UserReferenceObject(CurIcon);
|
||||||
|
PPROCESSINFO ppi = CurIcon->head.ppi;
|
||||||
|
CurIcon->pcurNext = ppi->pCursorCache;
|
||||||
|
ppi->pCursorCache = CurIcon;
|
||||||
|
}
|
||||||
|
|
||||||
Ret = TRUE;
|
Ret = TRUE;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if(!Ret)
|
if(!Ret && IsShared)
|
||||||
{
|
{
|
||||||
if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
|
if(!IS_INTRESOURCE(CurIcon->strName.Buffer))
|
||||||
ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
|
ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING);
|
||||||
if(CurIcon->ustrModule.Buffer)
|
|
||||||
ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!Ret && IsAnim)
|
||||||
|
{
|
||||||
|
PACON AniCurIcon = (PACON)CurIcon;
|
||||||
|
for(i = 0; i < numFrames; i++)
|
||||||
|
{
|
||||||
|
if(AniCurIcon->aspcur[i])
|
||||||
|
IntDestroyCurIconObject(AniCurIcon->aspcur[i], TRUE);
|
||||||
|
}
|
||||||
|
AniCurIcon->cicur = 0;
|
||||||
|
AniCurIcon->cpcur = 0;
|
||||||
|
ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR);
|
||||||
|
AniCurIcon->aspcur = NULL;
|
||||||
|
AniCurIcon->aicur = NULL;
|
||||||
|
AniCurIcon->ajifRate = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
UserDereferenceObject(CurIcon);
|
UserDereferenceObject(CurIcon);
|
||||||
TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
|
TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
|
||||||
UserLeave();
|
UserLeave();
|
||||||
|
@ -1044,13 +1078,21 @@ UserDrawIconEx(
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pIcon->CURSORF_flags & CURSORF_ACON)
|
||||||
|
{
|
||||||
|
ACON* pAcon = (ACON*)pIcon;
|
||||||
|
if(istepIfAniCur >= pAcon->cicur)
|
||||||
|
{
|
||||||
|
ERR("NtUserDrawIconEx: istepIfAniCur too big!\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
pIcon = pAcon->aspcur[pAcon->aicur[istepIfAniCur]];
|
||||||
|
}
|
||||||
|
|
||||||
hbmMask = pIcon->hbmMask;
|
hbmMask = pIcon->hbmMask;
|
||||||
hbmColor = pIcon->hbmColor;
|
hbmColor = pIcon->hbmColor;
|
||||||
hbmAlpha = pIcon->hbmAlpha;
|
hbmAlpha = pIcon->hbmAlpha;
|
||||||
|
|
||||||
if (istepIfAniCur)
|
|
||||||
ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get our objects.
|
* Get our objects.
|
||||||
* Shared locks are enough, we are only reading those bitmaps
|
* Shared locks are enough, we are only reading those bitmaps
|
||||||
|
@ -1445,4 +1487,74 @@ NtUserDrawIconEx(
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
HCURSOR
|
||||||
|
NTAPI
|
||||||
|
NtUserGetCursorFrameInfo(
|
||||||
|
HCURSOR hCursor,
|
||||||
|
DWORD istep,
|
||||||
|
INT* rate_jiffies,
|
||||||
|
DWORD* num_steps)
|
||||||
|
{
|
||||||
|
PCURICON_OBJECT CurIcon;
|
||||||
|
HCURSOR ret;
|
||||||
|
INT jiffies = 0;
|
||||||
|
DWORD steps = 1;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
TRACE("Enter NtUserGetCursorFrameInfo\n");
|
||||||
|
UserEnterExclusive();
|
||||||
|
|
||||||
|
if (!(CurIcon = UserGetCurIconObject(hCursor)))
|
||||||
|
{
|
||||||
|
UserLeave();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = CurIcon->head.h;
|
||||||
|
|
||||||
|
if(CurIcon->CURSORF_flags & CURSORF_ACON)
|
||||||
|
{
|
||||||
|
PACON AniCurIcon = (PACON)CurIcon;
|
||||||
|
if(istep >= AniCurIcon->cicur)
|
||||||
|
{
|
||||||
|
UserDereferenceObject(CurIcon);
|
||||||
|
UserLeave();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jiffies = AniCurIcon->ajifRate[istep];
|
||||||
|
steps = AniCurIcon->cicur;
|
||||||
|
ret = AniCurIcon->aspcur[AniCurIcon->aicur[istep]]->head.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
ProbeForWrite(rate_jiffies, sizeof(INT), 1);
|
||||||
|
ProbeForWrite(num_steps, sizeof(DWORD), 1);
|
||||||
|
*rate_jiffies = jiffies;
|
||||||
|
*num_steps = steps;
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
Status = _SEH2_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH2_END
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
WARN("Status: 0x%08x.\n", Status);
|
||||||
|
SetLastNtError(Status);
|
||||||
|
ret = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserDereferenceObject(CurIcon);
|
||||||
|
UserLeave();
|
||||||
|
|
||||||
|
TRACE("Leaving NtUserGetCursorFrameInfo, ret = 0x%08x\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -1247,22 +1247,6 @@ BOOL APIENTRY NtUserGetUpdatedClipboardFormats(
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @unimplemented
|
|
||||||
*/
|
|
||||||
HCURSOR
|
|
||||||
NTAPI
|
|
||||||
NtUserGetCursorFrameInfo(
|
|
||||||
HCURSOR hCursor,
|
|
||||||
DWORD istep,
|
|
||||||
PDWORD rate_jiffies,
|
|
||||||
INT *num_steps)
|
|
||||||
{
|
|
||||||
STUB
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -237,17 +237,13 @@ NtUserCallOneParam(
|
||||||
|
|
||||||
case ONEPARAM_ROUTINE_CREATEEMPTYCUROBJECT:
|
case ONEPARAM_ROUTINE_CREATEEMPTYCUROBJECT:
|
||||||
{
|
{
|
||||||
PCURICON_OBJECT CurIcon;
|
|
||||||
DWORD_PTR Result ;
|
DWORD_PTR Result ;
|
||||||
|
|
||||||
if (!(CurIcon = IntCreateCurIconHandle((DWORD)Param)))
|
if (!(Result = (DWORD_PTR)IntCreateCurIconHandle((DWORD)Param)))
|
||||||
{
|
{
|
||||||
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = (DWORD_PTR)CurIcon->Self;
|
|
||||||
UserDereferenceObject(CurIcon);
|
|
||||||
RETURN(Result);
|
RETURN(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,7 @@ typedef struct _PROCESSINFO
|
||||||
ACCESS_MASK amwinsta;
|
ACCESS_MASK amwinsta;
|
||||||
DWORD dwHotkey;
|
DWORD dwHotkey;
|
||||||
HMONITOR hMonitor;
|
HMONITOR hMonitor;
|
||||||
|
struct _CURICON_OBJECT* pCursorCache;
|
||||||
LUID luidSession;
|
LUID luidSession;
|
||||||
USERSTARTUPINFO usi;
|
USERSTARTUPINFO usi;
|
||||||
DWORD dwLayout;
|
DWORD dwLayout;
|
||||||
|
|
|
@ -540,15 +540,6 @@ DeviceEventWorker(DWORD dw1, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HCURSOR
|
|
||||||
WINAPI
|
|
||||||
GetCursorFrameInfo(HCURSOR hCursor, LPCWSTR name, DWORD istep, PDWORD rate_jiffies, INT *num_steps)
|
|
||||||
{
|
|
||||||
if (hCursor) return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps);
|
|
||||||
|
|
||||||
return LoadImageW( NULL, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE );
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
WINAPI
|
WINAPI
|
||||||
GetReasonTitleFromReasonCode(DWORD dw1, DWORD dw2, DWORD dw3)
|
GetReasonTitleFromReasonCode(DWORD dw1, DWORD dw2, DWORD dw3)
|
||||||
|
|
|
@ -2207,3 +2207,10 @@ User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength)
|
||||||
return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS);
|
return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HCURSOR
|
||||||
|
WINAPI
|
||||||
|
GetCursorFrameInfo(HCURSOR hCursor, DWORD reserved, DWORD istep, PINT rate_jiffies, DWORD *num_steps)
|
||||||
|
{
|
||||||
|
return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(cursor);
|
||||||
WINE_DECLARE_DEBUG_CHANNEL(icon);
|
WINE_DECLARE_DEBUG_CHANNEL(icon);
|
||||||
//WINE_DECLARE_DEBUG_CHANNEL(resource);
|
//WINE_DECLARE_DEBUG_CHANNEL(resource);
|
||||||
|
|
||||||
|
/* We only use Wide string functions */
|
||||||
|
#undef MAKEINTRESOURCE
|
||||||
|
#define MAKEINTRESOURCE MAKEINTRESOURCEW
|
||||||
|
|
||||||
/************* USER32 INTERNAL FUNCTIONS **********/
|
/************* USER32 INTERNAL FUNCTIONS **********/
|
||||||
|
|
||||||
/* This callback routine is called directly after switching to gui mode */
|
/* This callback routine is called directly after switching to gui mode */
|
||||||
|
@ -28,14 +32,14 @@ User32SetupDefaultCursors(PVOID Arguments,
|
||||||
if(*DefaultCursor)
|
if(*DefaultCursor)
|
||||||
{
|
{
|
||||||
/* set default cursor */
|
/* set default cursor */
|
||||||
hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
|
hCursor = LoadCursorW(0, IDC_ARROW);
|
||||||
SetCursor(hCursor);
|
SetCursor(hCursor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* FIXME load system cursor scheme */
|
/* FIXME load system cursor scheme */
|
||||||
SetCursor(0);
|
SetCursor(0);
|
||||||
hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
|
hCursor = LoadCursorW(0, IDC_ARROW);
|
||||||
SetCursor(hCursor);
|
SetCursor(hCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +308,113 @@ done:
|
||||||
return alpha;
|
return alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "pshpack1.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE bWidth;
|
||||||
|
BYTE bHeight;
|
||||||
|
BYTE bColorCount;
|
||||||
|
BYTE bReserved;
|
||||||
|
WORD xHotspot;
|
||||||
|
WORD yHotspot;
|
||||||
|
DWORD dwDIBSize;
|
||||||
|
DWORD dwDIBOffset;
|
||||||
|
} CURSORICONFILEDIRENTRY;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
WORD idReserved;
|
||||||
|
WORD idType;
|
||||||
|
WORD idCount;
|
||||||
|
CURSORICONFILEDIRENTRY idEntries[1];
|
||||||
|
} CURSORICONFILEDIR;
|
||||||
|
|
||||||
|
#include "poppack.h"
|
||||||
|
|
||||||
|
static
|
||||||
|
const CURSORICONFILEDIRENTRY*
|
||||||
|
get_best_icon_file_entry(
|
||||||
|
_In_ const CURSORICONFILEDIR* dir,
|
||||||
|
_In_ DWORD dwFileSize,
|
||||||
|
_In_ int cxDesired,
|
||||||
|
_In_ int cyDesired,
|
||||||
|
_In_ BOOL bIcon,
|
||||||
|
_In_ DWORD fuLoad
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CURSORICONDIR* fakeDir;
|
||||||
|
CURSORICONDIRENTRY* fakeEntry;
|
||||||
|
WORD i;
|
||||||
|
const CURSORICONFILEDIRENTRY* entry;
|
||||||
|
|
||||||
|
if ( dwFileSize < sizeof(*dir) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ( dwFileSize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cute little hack:
|
||||||
|
* We allocate a buffer, fake it as if it was a pointer to a resource in a module,
|
||||||
|
* pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
|
||||||
|
*/
|
||||||
|
fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR, idEntries[dir->idCount]));
|
||||||
|
if(!fakeDir)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fakeDir->idReserved = 0;
|
||||||
|
fakeDir->idType = dir->idType;
|
||||||
|
fakeDir->idCount = dir->idCount;
|
||||||
|
for(i = 0; i<dir->idCount; i++)
|
||||||
|
{
|
||||||
|
fakeEntry = &fakeDir->idEntries[i];
|
||||||
|
entry = &dir->idEntries[i];
|
||||||
|
/* Take this as an occasion to perform a size check */
|
||||||
|
if((entry->dwDIBOffset + entry->dwDIBSize) > dwFileSize)
|
||||||
|
{
|
||||||
|
ERR("Corrupted icon file?.\n");
|
||||||
|
HeapFree(GetProcessHeap(), 0, fakeDir);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* File icon/cursors are not like resource ones */
|
||||||
|
if(bIcon)
|
||||||
|
{
|
||||||
|
fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
|
||||||
|
fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
|
||||||
|
fakeEntry->ResInfo.icon.bColorCount = 0;
|
||||||
|
fakeEntry->ResInfo.icon.bReserved = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
|
||||||
|
fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
|
||||||
|
}
|
||||||
|
/* Let's assume there's always one plane */
|
||||||
|
fakeEntry->wPlanes = 1;
|
||||||
|
/* We must get the bitcount from the BITMAPINFOHEADER itself */
|
||||||
|
fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biBitCount;
|
||||||
|
fakeEntry->dwBytesInRes = entry->dwDIBSize;
|
||||||
|
fakeEntry->wResId = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now call LookupIconIdFromResourceEx */
|
||||||
|
i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
|
||||||
|
/* We don't need this anymore */
|
||||||
|
HeapFree(GetProcessHeap(), 0, fakeDir);
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
WARN("Unable to get a fit entry index.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We found it */
|
||||||
|
return &dir->idEntries[i-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/************* IMPLEMENTATION CORE ****************/
|
/************* IMPLEMENTATION CORE ****************/
|
||||||
|
|
||||||
static BOOL CURSORICON_GetCursorDataFromBMI(
|
static BOOL CURSORICON_GetCursorDataFromBMI(
|
||||||
|
@ -509,6 +620,257 @@ static BOOL CURSORICON_GetCursorDataFromIconInfo(
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define RIFF_FOURCC( c0, c1, c2, c3 ) \
|
||||||
|
( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
|
||||||
|
( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
|
||||||
|
|
||||||
|
#define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
|
||||||
|
#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
|
||||||
|
#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
|
||||||
|
#define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
|
||||||
|
#define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
|
||||||
|
#define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
|
||||||
|
#define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
|
||||||
|
|
||||||
|
#define ANI_FLAG_ICON 0x1
|
||||||
|
#define ANI_FLAG_SEQUENCE 0x2
|
||||||
|
|
||||||
|
#include <pshpack1.h>
|
||||||
|
typedef struct {
|
||||||
|
DWORD header_size;
|
||||||
|
DWORD num_frames;
|
||||||
|
DWORD num_steps;
|
||||||
|
DWORD width;
|
||||||
|
DWORD height;
|
||||||
|
DWORD bpp;
|
||||||
|
DWORD num_planes;
|
||||||
|
DWORD display_rate;
|
||||||
|
DWORD flags;
|
||||||
|
} ani_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DWORD data_size;
|
||||||
|
const unsigned char *data;
|
||||||
|
} riff_chunk_t;
|
||||||
|
#include <poppack.h>
|
||||||
|
|
||||||
|
static void dump_ani_header( const ani_header *header )
|
||||||
|
{
|
||||||
|
TRACE(" header size: %d\n", header->header_size);
|
||||||
|
TRACE(" frames: %d\n", header->num_frames);
|
||||||
|
TRACE(" steps: %d\n", header->num_steps);
|
||||||
|
TRACE(" width: %d\n", header->width);
|
||||||
|
TRACE(" height: %d\n", header->height);
|
||||||
|
TRACE(" bpp: %d\n", header->bpp);
|
||||||
|
TRACE(" planes: %d\n", header->num_planes);
|
||||||
|
TRACE(" display rate: %d\n", header->display_rate);
|
||||||
|
TRACE(" flags: 0x%08x\n", header->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find an animated cursor chunk, given its type and ID */
|
||||||
|
static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
|
||||||
|
{
|
||||||
|
const unsigned char *ptr = parent_chunk->data;
|
||||||
|
const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
|
||||||
|
|
||||||
|
if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
if ((!chunk_type && *(const DWORD *)ptr == chunk_id )
|
||||||
|
|| (chunk_type && *(const DWORD *)ptr == chunk_type && *((const DWORD *)ptr + 2) == chunk_id ))
|
||||||
|
{
|
||||||
|
ptr += sizeof(DWORD);
|
||||||
|
chunk->data_size = (*(const DWORD *)ptr + 1) & ~1;
|
||||||
|
ptr += sizeof(DWORD);
|
||||||
|
if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
|
||||||
|
chunk->data = ptr;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += sizeof(DWORD);
|
||||||
|
ptr += (*(const DWORD *)ptr + 1) & ~1;
|
||||||
|
ptr += sizeof(DWORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL CURSORICON_GetCursorDataFromANI(
|
||||||
|
_Inout_ CURSORDATA* pCurData,
|
||||||
|
_In_ const BYTE *pData,
|
||||||
|
_In_ DWORD dwDataSize,
|
||||||
|
_In_ DWORD fuLoad
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT i;
|
||||||
|
const ani_header *pHeader;
|
||||||
|
riff_chunk_t root_chunk = { dwDataSize, pData };
|
||||||
|
riff_chunk_t ACON_chunk = {0};
|
||||||
|
riff_chunk_t anih_chunk = {0};
|
||||||
|
riff_chunk_t fram_chunk = {0};
|
||||||
|
riff_chunk_t rate_chunk = {0};
|
||||||
|
riff_chunk_t seq_chunk = {0};
|
||||||
|
const unsigned char *icon_chunk;
|
||||||
|
const unsigned char *icon_data;
|
||||||
|
|
||||||
|
/* Find the root chunk */
|
||||||
|
riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
|
||||||
|
if (!ACON_chunk.data)
|
||||||
|
{
|
||||||
|
ERR("Failed to get root chunk.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the header chunk */
|
||||||
|
riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
|
||||||
|
if (!ACON_chunk.data)
|
||||||
|
{
|
||||||
|
ERR("Failed to get header chunk.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
pHeader = (ani_header*)anih_chunk.data;
|
||||||
|
dump_ani_header(pHeader);
|
||||||
|
|
||||||
|
/* Set up the master data */
|
||||||
|
pCurData->CURSORF_flags |= CURSORF_ACON;
|
||||||
|
pCurData->cpcur = pHeader->num_frames;
|
||||||
|
pCurData->cicur = pHeader->num_steps;
|
||||||
|
pCurData->iicur = pHeader->display_rate;
|
||||||
|
|
||||||
|
/* Get the sequences */
|
||||||
|
if (pHeader->flags & ANI_FLAG_SEQUENCE)
|
||||||
|
{
|
||||||
|
riff_find_chunk( ANI_seq__ID, 0, &ACON_chunk, &seq_chunk );
|
||||||
|
if (!seq_chunk.data)
|
||||||
|
{
|
||||||
|
ERR("No sequence data although the flag is set!\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the frame rates */
|
||||||
|
riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk );
|
||||||
|
if (rate_chunk.data)
|
||||||
|
pCurData->ajifRate = (INT*)rate_chunk.data;
|
||||||
|
|
||||||
|
/* Get the frames chunk */
|
||||||
|
riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
|
||||||
|
if (!fram_chunk.data)
|
||||||
|
{
|
||||||
|
ERR("Failed to get icon list.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
icon_chunk = fram_chunk.data;
|
||||||
|
icon_data = fram_chunk.data + (2 * sizeof(DWORD));
|
||||||
|
|
||||||
|
if(pHeader->num_frames > 1)
|
||||||
|
{
|
||||||
|
/* Allocate frame descriptors, step indices and rates */
|
||||||
|
pCurData->aspcur = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||||
|
pHeader->num_frames * sizeof(CURSORDATA) + pHeader->num_steps * (sizeof(DWORD) + sizeof(INT)));
|
||||||
|
if(!pCurData->aspcur)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
pCurData->aicur = (DWORD*)(pCurData->aspcur + pHeader->num_frames);
|
||||||
|
pCurData->ajifRate = (INT*)(pCurData->aicur + pHeader->num_steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i < pHeader->num_frames; i++)
|
||||||
|
{
|
||||||
|
CURSORDATA* pFrameData;
|
||||||
|
const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD));
|
||||||
|
const BITMAPINFO* pbmi;
|
||||||
|
|
||||||
|
if(pHeader->num_frames > 1)
|
||||||
|
pFrameData = &pCurData->aspcur[i];
|
||||||
|
else
|
||||||
|
pFrameData = pCurData;
|
||||||
|
|
||||||
|
pFrameData->rt = pCurData->rt;
|
||||||
|
|
||||||
|
if (pHeader->flags & ANI_FLAG_ICON)
|
||||||
|
{
|
||||||
|
/* The chunks describe an icon file */
|
||||||
|
const CURSORICONFILEDIRENTRY* pDirEntry = get_best_icon_file_entry(
|
||||||
|
(const CURSORICONFILEDIR *) icon_data,
|
||||||
|
chunk_size,
|
||||||
|
pCurData->cx,
|
||||||
|
pCurData->cy,
|
||||||
|
TRUE,
|
||||||
|
fuLoad);
|
||||||
|
if(!pDirEntry)
|
||||||
|
{
|
||||||
|
ERR("Unable to find the right file entry for frame %d.\n", i);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
pFrameData->xHotspot = pDirEntry->xHotspot;
|
||||||
|
pFrameData->yHotspot = pDirEntry->yHotspot;
|
||||||
|
if(!pHeader->width || !pHeader->height)
|
||||||
|
{
|
||||||
|
pFrameData->cx = pDirEntry->bWidth;
|
||||||
|
pFrameData->cy = pDirEntry->bHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pFrameData->cx = pHeader->width;
|
||||||
|
pFrameData->cy = pHeader->height;
|
||||||
|
}
|
||||||
|
pbmi = (const BITMAPINFO *) (icon_data + pDirEntry->dwDIBOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The chunks just describe bitmaps */
|
||||||
|
pbmi = (const BITMAPINFO *)icon_data;
|
||||||
|
pFrameData->xHotspot = pFrameData->yHotspot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the real work */
|
||||||
|
CURSORICON_GetCursorDataFromBMI(pFrameData, pbmi);
|
||||||
|
|
||||||
|
if(pHeader->num_frames > 1)
|
||||||
|
pFrameData->CURSORF_flags |= CURSORF_ACONFRAME;
|
||||||
|
else
|
||||||
|
pFrameData->CURSORF_flags &= ~CURSORF_ACON;
|
||||||
|
|
||||||
|
|
||||||
|
/* Next frame */
|
||||||
|
icon_chunk += chunk_size + (2 * sizeof(DWORD));
|
||||||
|
icon_data = icon_chunk + (2 * sizeof(DWORD));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pHeader->num_frames <= 1)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if(rate_chunk.data)
|
||||||
|
CopyMemory(pCurData->ajifRate, rate_chunk.data, pHeader->num_steps * sizeof(INT));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(i=0; i < pHeader->num_steps; i++)
|
||||||
|
pCurData->ajifRate[i] = pHeader->display_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pHeader->flags & ANI_FLAG_SEQUENCE)
|
||||||
|
{
|
||||||
|
CopyMemory(pCurData->aicur, seq_chunk.data, pHeader->num_steps * sizeof(DWORD));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(i=0; i < pHeader->num_steps; i++)
|
||||||
|
pCurData->aicur[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
error:
|
||||||
|
HeapFree(GetProcessHeap(), 0, pCurData->aspcur);
|
||||||
|
ZeroMemory(pCurData, sizeof(CURSORDATA));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
HBITMAP
|
HBITMAP
|
||||||
BITMAP_LoadImageW(
|
BITMAP_LoadImageW(
|
||||||
|
@ -561,7 +923,7 @@ BITMAP_LoadImageW(
|
||||||
/* Caller wants an OEM bitmap */
|
/* Caller wants an OEM bitmap */
|
||||||
if(!hinst)
|
if(!hinst)
|
||||||
hinst = User32Instance;
|
hinst = User32Instance;
|
||||||
hrsrc = FindResourceW(hinst, lpszName, (LPWSTR)RT_BITMAP);
|
hrsrc = FindResourceW(hinst, lpszName, RT_BITMAP);
|
||||||
if(!hrsrc)
|
if(!hrsrc)
|
||||||
return NULL;
|
return NULL;
|
||||||
hgRsrc = LoadResource(hinst, hrsrc);
|
hgRsrc = LoadResource(hinst, hrsrc);
|
||||||
|
@ -774,28 +1136,6 @@ end:
|
||||||
return hbmpRet;
|
return hbmpRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "pshpack1.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BYTE bWidth;
|
|
||||||
BYTE bHeight;
|
|
||||||
BYTE bColorCount;
|
|
||||||
BYTE bReserved;
|
|
||||||
WORD xHotspot;
|
|
||||||
WORD yHotspot;
|
|
||||||
DWORD dwDIBSize;
|
|
||||||
DWORD dwDIBOffset;
|
|
||||||
} CURSORICONFILEDIRENTRY;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
WORD idReserved;
|
|
||||||
WORD idType;
|
|
||||||
WORD idCount;
|
|
||||||
CURSORICONFILEDIRENTRY idEntries[1];
|
|
||||||
} CURSORICONFILEDIR;
|
|
||||||
|
|
||||||
#include "poppack.h"
|
|
||||||
|
|
||||||
static
|
static
|
||||||
HANDLE
|
HANDLE
|
||||||
|
@ -807,14 +1147,11 @@ CURSORICON_LoadFromFileW(
|
||||||
_In_ BOOL bIcon
|
_In_ BOOL bIcon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
CURSORICONDIR* fakeDir;
|
const CURSORICONFILEDIRENTRY *entry;
|
||||||
CURSORICONDIRENTRY* fakeEntry;
|
const CURSORICONFILEDIR *dir;
|
||||||
CURSORICONFILEDIRENTRY *entry;
|
|
||||||
CURSORICONFILEDIR *dir;
|
|
||||||
DWORD filesize = 0;
|
DWORD filesize = 0;
|
||||||
LPBYTE bits;
|
LPBYTE bits;
|
||||||
HANDLE hCurIcon = NULL;
|
HANDLE hCurIcon = NULL;
|
||||||
WORD i;
|
|
||||||
CURSORDATA cursorData;
|
CURSORDATA cursorData;
|
||||||
|
|
||||||
TRACE("loading %s\n", debugstr_w( lpszName ));
|
TRACE("loading %s\n", debugstr_w( lpszName ));
|
||||||
|
@ -831,63 +1168,10 @@ CURSORICON_LoadFromFileW(
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = (CURSORICONFILEDIR*) bits;
|
dir = (CURSORICONFILEDIR*) bits;
|
||||||
if ( filesize < sizeof(*dir) )
|
entry = get_best_icon_file_entry(dir, filesize, cxDesired, cyDesired, bIcon, fuLoad);
|
||||||
|
if(!entry)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cute little hack:
|
|
||||||
* We allocate a buffer, fake it as if it was a pointer to a resource in a module,
|
|
||||||
* pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
|
|
||||||
*/
|
|
||||||
fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR, idEntries[dir->idCount]));
|
|
||||||
if(!fakeDir)
|
|
||||||
goto end;
|
|
||||||
fakeDir->idReserved = 0;
|
|
||||||
fakeDir->idType = dir->idType;
|
|
||||||
fakeDir->idCount = dir->idCount;
|
|
||||||
for(i = 0; i<dir->idCount; i++)
|
|
||||||
{
|
|
||||||
fakeEntry = &fakeDir->idEntries[i];
|
|
||||||
entry = &dir->idEntries[i];
|
|
||||||
/* Take this as an occasion to perform a size check */
|
|
||||||
if((entry->dwDIBOffset + entry->dwDIBSize) > filesize)
|
|
||||||
goto end;
|
|
||||||
/* File icon/cursors are not like resource ones */
|
|
||||||
if(bIcon)
|
|
||||||
{
|
|
||||||
fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
|
|
||||||
fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
|
|
||||||
fakeEntry->ResInfo.icon.bColorCount = 0;
|
|
||||||
fakeEntry->ResInfo.icon.bReserved = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
|
|
||||||
fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
|
|
||||||
}
|
|
||||||
/* Let's assume there's always one plane */
|
|
||||||
fakeEntry->wPlanes = 1;
|
|
||||||
/* We must get the bitcount from the BITMAPINFOHEADER itself */
|
|
||||||
fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biBitCount;
|
|
||||||
fakeEntry->dwBytesInRes = entry->dwDIBSize;
|
|
||||||
fakeEntry->wResId = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now call LookupIconIdFromResourceEx */
|
|
||||||
i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
|
|
||||||
/* We don't need this anymore */
|
|
||||||
HeapFree(GetProcessHeap(), 0, fakeDir);
|
|
||||||
if(i == 0)
|
|
||||||
{
|
|
||||||
WARN("Unable to get a fit entry index.\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get our entry */
|
|
||||||
entry = &dir->idEntries[i-1];
|
|
||||||
/* Fix dimensions */
|
/* Fix dimensions */
|
||||||
if(!cxDesired) cxDesired = entry->bWidth;
|
if(!cxDesired) cxDesired = entry->bWidth;
|
||||||
if(!cyDesired) cyDesired = entry->bHeight;
|
if(!cyDesired) cyDesired = entry->bHeight;
|
||||||
|
@ -904,7 +1188,7 @@ CURSORICON_LoadFromFileW(
|
||||||
if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)&bits[entry->dwDIBOffset]))
|
if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)&bits[entry->dwDIBOffset]))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
|
hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
|
||||||
if(!hCurIcon)
|
if(!hCurIcon)
|
||||||
goto end_error;
|
goto end_error;
|
||||||
|
|
||||||
|
@ -1020,7 +1304,7 @@ CURSORICON_LoadImageW(
|
||||||
hrsrc = FindResourceW(
|
hrsrc = FindResourceW(
|
||||||
hinst,
|
hinst,
|
||||||
lpszName,
|
lpszName,
|
||||||
(LPWSTR)(bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR));
|
bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
|
||||||
|
|
||||||
/* We let FindResource, LoadResource, etc. call SetLastError */
|
/* We let FindResource, LoadResource, etc. call SetLastError */
|
||||||
if(!hrsrc)
|
if(!hrsrc)
|
||||||
|
@ -1041,7 +1325,7 @@ CURSORICON_LoadImageW(
|
||||||
hrsrc = FindResourceW(
|
hrsrc = FindResourceW(
|
||||||
hinst,
|
hinst,
|
||||||
MAKEINTRESOURCEW(wResId),
|
MAKEINTRESOURCEW(wResId),
|
||||||
(LPWSTR)(bIcon ? RT_ICON : RT_CURSOR));
|
bIcon ? RT_ICON : RT_CURSOR);
|
||||||
if(!hrsrc)
|
if(!hrsrc)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@ -1058,6 +1342,9 @@ CURSORICON_LoadImageW(
|
||||||
|
|
||||||
ZeroMemory(&cursorData, sizeof(cursorData));
|
ZeroMemory(&cursorData, sizeof(cursorData));
|
||||||
|
|
||||||
|
/* This is from resource */
|
||||||
|
cursorData.CURSORF_flags = CURSORF_FROMRESOURCE;
|
||||||
|
|
||||||
if(dir->idType == 2)
|
if(dir->idType == 2)
|
||||||
{
|
{
|
||||||
/* idType == 2 for cursor resources */
|
/* idType == 2 for cursor resources */
|
||||||
|
@ -1080,11 +1367,8 @@ CURSORICON_LoadImageW(
|
||||||
if(!bStatus)
|
if(!bStatus)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* This is from resource */
|
|
||||||
cursorData.CURSORF_flags = CURSORF_FROMRESOURCE;
|
|
||||||
|
|
||||||
/* Create the handle */
|
/* Create the handle */
|
||||||
hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1);
|
hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
|
||||||
if(!hCurIcon)
|
if(!hCurIcon)
|
||||||
{
|
{
|
||||||
goto end_error;
|
goto end_error;
|
||||||
|
@ -1359,14 +1643,14 @@ CURSORICON_CopyImage(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ustrModule.Length < ustrModule.MaximumLength) && (ustrRsrc.Length < ustrRsrc.MaximumLength))
|
if (ustrModule.Length && (ustrRsrc.Length || IS_INTRESOURCE(ustrRsrc.Buffer)))
|
||||||
{
|
{
|
||||||
/* Buffers were big enough */
|
/* Buffers were big enough */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find which buffer were too small */
|
/* Find which buffer were too small */
|
||||||
if(ustrModule.Length == ustrModule.MaximumLength)
|
if (!ustrModule.Length)
|
||||||
{
|
{
|
||||||
PWSTR newBuffer;
|
PWSTR newBuffer;
|
||||||
ustrModule.MaximumLength *= 2;
|
ustrModule.MaximumLength *= 2;
|
||||||
|
@ -1379,7 +1663,7 @@ CURSORICON_CopyImage(
|
||||||
ustrModule.Buffer = newBuffer;
|
ustrModule.Buffer = newBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ustrRsrc.Length == ustrRsrc.MaximumLength)
|
if (!ustrRsrc.Length)
|
||||||
{
|
{
|
||||||
ustrRsrc.MaximumLength *= 2;
|
ustrRsrc.MaximumLength *= 2;
|
||||||
pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer, ustrRsrc.MaximumLength);
|
pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer, ustrRsrc.MaximumLength);
|
||||||
|
@ -1400,7 +1684,7 @@ CURSORICON_CopyImage(
|
||||||
/* Get the module handle */
|
/* Get the module handle */
|
||||||
if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule))
|
if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule))
|
||||||
{
|
{
|
||||||
/* This hould never happen */
|
/* This should never happen */
|
||||||
ERR("Invalid handle?.\n");
|
ERR("Invalid handle?.\n");
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -1489,8 +1773,7 @@ HICON WINAPI CopyIcon(
|
||||||
_In_ HICON hIcon
|
_In_ HICON hIcon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI DrawIcon(
|
BOOL WINAPI DrawIcon(
|
||||||
|
@ -1687,6 +1970,8 @@ HANDLE WINAPI LoadImageW(
|
||||||
_In_ UINT fuLoad
|
_In_ UINT fuLoad
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
|
||||||
|
hinst, debugstr_w(lpszName), uType, cxDesired, cyDesired, fuLoad);
|
||||||
/* Redirect to each implementation */
|
/* Redirect to each implementation */
|
||||||
switch(uType)
|
switch(uType)
|
||||||
{
|
{
|
||||||
|
@ -1900,29 +2185,78 @@ HICON WINAPI CreateIconFromResourceEx(
|
||||||
{
|
{
|
||||||
CURSORDATA cursorData;
|
CURSORDATA cursorData;
|
||||||
HICON hIcon;
|
HICON hIcon;
|
||||||
|
BOOL isAnimated;
|
||||||
|
|
||||||
TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags);
|
TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags);
|
||||||
|
|
||||||
if(uFlags & ~LR_DEFAULTSIZE)
|
|
||||||
FIXME("uFlags 0x%08x ignored.\n", uFlags & ~LR_DEFAULTSIZE);
|
|
||||||
|
|
||||||
if(uFlags & LR_DEFAULTSIZE)
|
if(uFlags & LR_DEFAULTSIZE)
|
||||||
{
|
{
|
||||||
if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
|
if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
|
||||||
if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
|
if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if this is an animated cursor */
|
|
||||||
if(!memcmp(pbIconBits, "RIFF", 4))
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZeroMemory(&cursorData, sizeof(cursorData));
|
ZeroMemory(&cursorData, sizeof(cursorData));
|
||||||
cursorData.cx = cxDesired;
|
cursorData.cx = cxDesired;
|
||||||
cursorData.cy = cyDesired;
|
cursorData.cy = cyDesired;
|
||||||
cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
|
cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
|
||||||
|
|
||||||
|
/* Convert to win32k-ready data */
|
||||||
|
if(!memcmp(pbIconBits, "RIFF", 4))
|
||||||
|
{
|
||||||
|
if(!CURSORICON_GetCursorDataFromANI(&cursorData, pbIconBits, cbIconBits, uFlags))
|
||||||
|
{
|
||||||
|
ERR("Could not get cursor data from .ani.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
isAnimated = !!(cursorData.CURSORF_flags & CURSORF_ACON);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* It is possible to pass Icon Directories to this API */
|
||||||
|
int wResId = LookupIconIdFromDirectoryEx(pbIconBits, fIcon, cxDesired, cyDesired, uFlags);
|
||||||
|
HANDLE ResHandle = NULL;
|
||||||
|
if(wResId)
|
||||||
|
{
|
||||||
|
HINSTANCE hinst;
|
||||||
|
HRSRC hrsrc;
|
||||||
|
CURSORICONDIR* pCurIconDir = (CURSORICONDIR*)pbIconBits;
|
||||||
|
|
||||||
|
TRACE("Pointer points to a directory structure.\n");
|
||||||
|
|
||||||
|
/* So this is a pointer to an icon directory structure. Find the module */
|
||||||
|
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
(LPCWSTR)pbIconBits,
|
||||||
|
&hinst))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check we were given the right type of resource */
|
||||||
|
if((fIcon && pCurIconDir->idType == 2) || (!fIcon && pCurIconDir->idType == 1))
|
||||||
|
{
|
||||||
|
WARN("Got a %s directory pointer, but called for a %s", fIcon ? "cursor" : "icon", fIcon ? "icon" : "cursor");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the relevant resource pointer */
|
||||||
|
hrsrc = FindResourceW(
|
||||||
|
hinst,
|
||||||
|
MAKEINTRESOURCEW(wResId),
|
||||||
|
fIcon ? RT_ICON : RT_CURSOR);
|
||||||
|
if (!hrsrc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ResHandle = LoadResource(hinst, hrsrc);
|
||||||
|
if (!ResHandle)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pbIconBits = LockResource(ResHandle);
|
||||||
|
if (!pbIconBits)
|
||||||
|
{
|
||||||
|
FreeResource(ResHandle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!fIcon)
|
if(!fIcon)
|
||||||
{
|
{
|
||||||
WORD* pt = (WORD*)pbIconBits;
|
WORD* pt = (WORD*)pbIconBits;
|
||||||
|
@ -1934,10 +2268,19 @@ HICON WINAPI CreateIconFromResourceEx(
|
||||||
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
|
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
|
||||||
{
|
{
|
||||||
ERR("Couldn't fill the CURSORDATA structure.\n");
|
ERR("Couldn't fill the CURSORDATA structure.\n");
|
||||||
|
if (ResHandle)
|
||||||
|
FreeResource(ResHandle);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (ResHandle)
|
||||||
|
FreeResource(ResHandle);
|
||||||
|
isAnimated = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
hIcon = NtUserxCreateEmptyCurObject(fIcon ? 0 : 1);
|
if (uFlags & LR_SHARED)
|
||||||
|
cursorData.CURSORF_flags |= CURSORF_LRSHARED;
|
||||||
|
|
||||||
|
hIcon = NtUserxCreateEmptyCurObject(isAnimated);
|
||||||
if (!hIcon)
|
if (!hIcon)
|
||||||
goto end_error;
|
goto end_error;
|
||||||
|
|
||||||
|
@ -1948,10 +2291,15 @@ HICON WINAPI CreateIconFromResourceEx(
|
||||||
goto end_error;
|
goto end_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isAnimated)
|
||||||
|
HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
|
||||||
|
|
||||||
return hIcon;
|
return hIcon;
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
end_error:
|
end_error:
|
||||||
|
if(isAnimated)
|
||||||
|
HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
|
||||||
DeleteObject(cursorData.hbmMask);
|
DeleteObject(cursorData.hbmMask);
|
||||||
if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
|
if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
|
||||||
if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
|
if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
|
||||||
|
@ -1969,10 +2317,12 @@ HICON WINAPI CreateIconIndirect(
|
||||||
|
|
||||||
TRACE("%p.\n", piconinfo);
|
TRACE("%p.\n", piconinfo);
|
||||||
|
|
||||||
|
ZeroMemory(&cursorData, sizeof(cursorData));
|
||||||
|
|
||||||
if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo))
|
if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
hiconRet = NtUserxCreateEmptyCurObject(piconinfo->fIcon ? 0 : 1);
|
hiconRet = NtUserxCreateEmptyCurObject(FALSE);
|
||||||
if(!hiconRet)
|
if(!hiconRet)
|
||||||
goto end_error;
|
goto end_error;
|
||||||
|
|
||||||
|
@ -2064,3 +2414,10 @@ BOOL WINAPI DestroyCursor(
|
||||||
{
|
{
|
||||||
return NtUserDestroyCursor(hCursor, FALSE);
|
return NtUserDestroyCursor(hCursor, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HCURSOR
|
||||||
|
WINAPI
|
||||||
|
GetCursorFrameInfo(HCURSOR hCursor, DWORD reserved, DWORD istep, PINT rate_jiffies, DWORD *num_steps)
|
||||||
|
{
|
||||||
|
return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue