diff --git a/reactos/win32ss/CMakeLists.txt b/reactos/win32ss/CMakeLists.txt index 5f9e390a9cb..67876ffaa6f 100644 --- a/reactos/win32ss/CMakeLists.txt +++ b/reactos/win32ss/CMakeLists.txt @@ -1,6 +1,5 @@ set(USE_DIBLIB FALSE) -set(USE_NEW_CURSORICON TRUE) # Give WIN32 subsystem its own project. PROJECT(WIN32SS) @@ -11,10 +10,6 @@ if(USE_DIBLIB) add_subdirectory(gdi/diblib) endif() -if(USE_NEW_CURSORICON) - add_definitions(-DNEW_CURSORICON) -endif() - add_subdirectory(gdi/gdi32) add_subdirectory(reactx) add_subdirectory(user/user32) @@ -106,6 +101,7 @@ list(APPEND SOURCE user/ntuser/class.c user/ntuser/clipboard.c user/ntuser/csr.c + user/ntuser/cursoricon.c user/ntuser/dde.c user/ntuser/defwnd.c user/ntuser/desktop.c @@ -198,12 +194,6 @@ else() ${GENDIB_FILES}) endif() -if(USE_NEW_CURSORICON) - list(APPEND SOURCE user/ntuser/cursoricon_new.c) -else() - list(APPEND SOURCE user/ntuser/cursoricon.c) -endif() - if(ARCH STREQUAL "i386") list(APPEND ASM_SOURCE gdi/dib/i386/dib24bpp_hline.s diff --git a/reactos/win32ss/include/ntuser.h b/reactos/win32ss/include/ntuser.h index 7794ac0930f..5815224bb89 100644 --- a/reactos/win32ss/include/ntuser.h +++ b/reactos/win32ss/include/ntuser.h @@ -435,7 +435,7 @@ typedef struct tagPOPUPMENU struct _WND *spwndPrevPopup; PMENU spmenu; PMENU spmenuAlternate; - struct _WND *spwndActivePopup; + struct _WND *spwndActivePopup; struct tagPOPUPMENU *ppopupmenuRoot; struct tagPOPUPMENU *ppmDelayedFree; UINT posSelectedItem; @@ -545,24 +545,12 @@ typedef struct _CLS INT cbclsExtra; INT cbwndExtra; HINSTANCE hModule; -#ifdef NEW_CURSORICON struct _CURICON_OBJECT *spicn; struct _CURICON_OBJECT *spcur; -#else - HANDLE hIcon; /* FIXME - Use pointer! */ - HANDLE hCursor; /* FIXME - Use pointer! */ -#endif HBRUSH hbrBackground; PWSTR lpszMenuName; /* kernel use */ PSTR lpszAnsiClassName; /* " */ -#ifdef NEW_CURSORICON struct _CURICON_OBJECT *spicnSm; -#else - HANDLE hIconSm; /* FIXME - Use pointer! */ - - //// ReactOS doesn't support cache icons. */ - HICON hIconSmIntern; /* Internal small icon, derived from hIcon */ -#endif //// UINT Unicode:1; // !CSF_ANSIPROC UINT Global:1; // CS_GLOBALCLASS or CSF_SERVERSIDEPROC @@ -2990,8 +2978,6 @@ NtUserSetCursorContents( HANDLE Handle, PICONINFO IconInfo); -#ifdef NEW_CURSORICON - BOOL NTAPI NtUserSetCursorIconData( @@ -3014,28 +3000,6 @@ NtUserFindExistingCursorIcon( _In_ PUNICODE_STRING pustrRsrc, _In_ FINDEXISTINGCURICONPARAM *param); -#else /* NEW_CURSORICON */ - -BOOL -NTAPI -NtUserSetCursorIconData( - HANDLE Handle, - PBOOL fIcon, - POINT *Hotspot, - HMODULE hModule, - HRSRC hRsrc, - HRSRC hGroupRsrc); - -HICON -NTAPI -NtUserFindExistingCursorIcon( - HMODULE hModule, - HRSRC hRsrc, - LONG cx, - LONG cy); - -#endif /* NEW_CURSORICON */ - DWORD NTAPI NtUserSetDbgTag( diff --git a/reactos/win32ss/user/ntuser/class.c b/reactos/win32ss/user/ntuser/class.c index a80bd9c3645..e1f788322d8 100644 --- a/reactos/win32ss/user/ntuser/class.c +++ b/reactos/win32ss/user/ntuser/class.c @@ -265,7 +265,6 @@ IntDestroyClass(IN OUT PCLS Class) IntFreeClassMenuName(Class); } -#ifdef NEW_CURSORICON if (Class->spicn) UserDereferenceObject(Class->spicn); if (Class->spcur) @@ -278,10 +277,6 @@ IntDestroyClass(IN OUT PCLS Class) && !(UserObjectInDestroy(UserHMGetHandle(Class->spicnSm)))) IntDestroyCurIconObject(Class->spicnSm); } -#else - if (Class->hIconSmIntern) - IntClassDestroyIcon(Class->hIconSmIntern); -#endif pDesk = Class->rpdeskParent; Class->rpdeskParent = NULL; @@ -377,14 +372,14 @@ RegisterControlAtoms(VOID) RTL_ATOM Atom; UNICODE_STRING ClassName; INT i = 0; - + while ( i < ICLS_DESKTOP) { RtlInitUnicodeString(&ClassName, ControlsList[i]); if (IntRegisterClassAtom(&ClassName, &Atom)) { gpsi->atomSysClass[i] = Atom; - ERR("Reg Control Atoms 0x%x\n",Atom); + ERR("Reg Control Atoms 0x%x\n",Atom); } i++; } @@ -648,7 +643,6 @@ IntGetClassForDesktop(IN OUT PCLS BaseClass, /* Simply clone the class */ RtlCopyMemory( Class, BaseClass, ClassSize); -#ifdef NEW_CURSORICON /* Reference our objects */ if (Class->spcur) UserReferenceObject(Class->spcur); @@ -656,7 +650,6 @@ IntGetClassForDesktop(IN OUT PCLS BaseClass, UserReferenceObject(Class->spicn); if (Class->spicnSm) UserReferenceObject(Class->spicnSm); -#endif TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName); @@ -884,15 +877,12 @@ IntMoveClassToSharedHeap(IN OUT PCLS Class, NewClass->rpdeskParent = NULL; NewClass->pclsBase = NewClass; -#ifdef NEW_CURSORICON if (NewClass->spcur) UserReferenceObject(NewClass->spcur); if (NewClass->spicn) UserReferenceObject(NewClass->spicn); if (NewClass->spicnSm) UserReferenceObject(NewClass->spicnSm); -#endif - /* Replace the class in the list */ (void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr, @@ -1086,15 +1076,9 @@ IntCreateClass(IN CONST WNDCLASSEXW* lpwcx, Class->cbclsExtra = lpwcx->cbClsExtra; Class->cbwndExtra = lpwcx->cbWndExtra; Class->hModule = lpwcx->hInstance; -#ifdef NEW_CURSORICON Class->spicn = lpwcx->hIcon ? UserGetCurIconObject(lpwcx->hIcon) : NULL; Class->spcur = lpwcx->hCursor ? UserGetCurIconObject(lpwcx->hCursor) : NULL; Class->spicnSm = lpwcx->hIconSm ? UserGetCurIconObject(lpwcx->hIconSm) : NULL; -#else - Class->hIcon = lpwcx->hIcon; - Class->hIconSm = lpwcx->hIconSm; - Class->hCursor = lpwcx->hCursor; -#endif //// Class->hbrBackground = lpwcx->hbrBackground; @@ -1808,29 +1792,6 @@ IntSetClassMenuName(IN PCLS Class, return Ret; } -#ifndef NEW_CURSORICON -BOOL FASTCALL -IntClassDestroyIcon(HANDLE hCurIcon) -{ - PCURICON_OBJECT CurIcon; - BOOL Ret; - - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { - - ERR("hCurIcon was not found!\n"); - return FALSE; - } - /* Note: IntDestroyCurIconObject will remove our reference for us! */ - Ret = IntDestroyCurIconObject(CurIcon, GetW32ProcessInfo()); - if (!Ret) - { - ERR("hCurIcon was not Destroyed!\n"); - } - return Ret; -} -#endif - ULONG_PTR UserSetClassLongPtr(IN PCLS Class, IN INT Index, @@ -1838,9 +1799,6 @@ UserSetClassLongPtr(IN PCLS Class, IN BOOL Ansi) { ULONG_PTR Ret = 0; -#ifndef NEW_CURSORICON - HANDLE hIconSmIntern = NULL; -#endif /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */ @@ -1912,7 +1870,6 @@ UserSetClassLongPtr(IN PCLS Class, } break; -#ifdef NEW_CURSORICON case GCLP_HCURSOR: { PCURICON_OBJECT NewCursor = NULL; @@ -1959,21 +1916,6 @@ UserSetClassLongPtr(IN PCLS Class, break; } -#else - case GCLP_HCURSOR: - /* FIXME: Get handle from pointer to CURSOR object */ - Ret = (ULONG_PTR)Class->hCursor; - Class->hCursor = (HANDLE)NewLong; - - /* Update the clones */ - Class = Class->pclsClone; - while (Class != NULL) - { - Class->hCursor = (HANDLE)NewLong; - Class = Class->pclsNext; - } - break; -#endif // MSDN: // hIconSm, A handle to a small icon that is associated with the window class. @@ -1981,7 +1923,6 @@ UserSetClassLongPtr(IN PCLS Class, // the hIcon member for an icon of the appropriate size to use as the small icon. // case GCLP_HICON: -#ifdef NEW_CURSORICON { PCURICON_OBJECT NewIcon = NULL; PCURICON_OBJECT NewSmallIcon = NULL; @@ -2076,38 +2017,8 @@ UserSetClassLongPtr(IN PCLS Class, } break; } -#else - /* FIXME: Get handle from pointer to ICON object */ - Ret = (ULONG_PTR)Class->hIcon; - if (Class->hIcon == (HANDLE)NewLong) break; - if (Ret && Class->hIconSmIntern) - { - IntClassDestroyIcon(Class->hIconSmIntern); - Class->CSF_flags &= ~CSF_CACHEDSMICON; - Class->hIconSmIntern = NULL; - } - if (NewLong && !Class->hIconSm) - { - hIconSmIntern = Class->hIconSmIntern = co_IntCopyImage( (HICON)NewLong, IMAGE_ICON, - UserGetSystemMetrics( SM_CXSMICON ), - UserGetSystemMetrics( SM_CYSMICON ), 0 ); - Class->CSF_flags |= CSF_CACHEDSMICON; - } - Class->hIcon = (HANDLE)NewLong; - - /* Update the clones */ - Class = Class->pclsClone; - while (Class != NULL) - { - Class->hIcon = (HANDLE)NewLong; - Class->hIconSmIntern = hIconSmIntern; - Class = Class->pclsNext; - } - break; -#endif case GCLP_HICONSM: -#ifdef NEW_CURSORICON { PCURICON_OBJECT NewSmallIcon = NULL; BOOLEAN NewIconFromCache = FALSE; @@ -2199,41 +2110,6 @@ UserSetClassLongPtr(IN PCLS Class, } } break; -#else - /* FIXME: Get handle from pointer to ICON object */ - Ret = (ULONG_PTR)Class->hIconSm; - if (Class->hIconSm == (HANDLE)NewLong) break; - if (Class->CSF_flags & CSF_CACHEDSMICON) - { - if (Class->hIconSmIntern) - { - IntClassDestroyIcon(Class->hIconSmIntern); - Class->hIconSmIntern = NULL; - } - Class->CSF_flags &= ~CSF_CACHEDSMICON; - } - if (Class->hIcon && !Class->hIconSmIntern) - { - hIconSmIntern = Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON, - UserGetSystemMetrics( SM_CXSMICON ), - UserGetSystemMetrics( SM_CYSMICON ), 0 ); - - if (hIconSmIntern) Class->CSF_flags |= CSF_CACHEDSMICON; - //// FIXME: Very hacky here but it passes the tests.... - Ret = 0; // Fixes 1009 - } - Class->hIconSm = (HANDLE)NewLong; - - /* Update the clones */ - Class = Class->pclsClone; - while (Class != NULL) - { - Class->hIconSm = (HANDLE)NewLong; - Class->hIconSmIntern = hIconSmIntern; - Class = Class->pclsNext; - } - break; -#endif case GCLP_HMODULE: Ret = (ULONG_PTR)Class->hModule; @@ -2325,16 +2201,9 @@ UserGetClassInfo(IN PCLS Class, lpwcx->cbClsExtra = Class->cbclsExtra; lpwcx->cbWndExtra = Class->cbwndExtra; -#ifdef NEW_CURSORICON lpwcx->hIcon = Class->spicn ? UserHMGetHandle(Class->spicn) : NULL; lpwcx->hCursor = Class->spcur ? UserHMGetHandle(Class->spcur) : NULL; lpwcx->hIconSm = Class->spicnSm ? UserHMGetHandle(Class->spicnSm) : NULL; -#else - lpwcx->hIcon = Class->hIcon; /* FIXME: Get handle from pointer */ - lpwcx->hCursor = Class->hCursor; /* FIXME: Get handle from pointer */ - /* FIXME: Get handle from pointer */ - lpwcx->hIconSm = Class->hIconSm ? Class->hIconSm : Class->hIconSmIntern; -#endif lpwcx->hbrBackground = Class->hbrBackground; /* Copy non-string to user first. */ diff --git a/reactos/win32ss/user/ntuser/cursoricon.c b/reactos/win32ss/user/ntuser/cursoricon.c index 0a4ff41b0e0..94ea1426009 100644 --- a/reactos/win32ss/user/ntuser/cursoricon.c +++ b/reactos/win32ss/user/ntuser/cursoricon.c @@ -17,55 +17,128 @@ * 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 DBG_DEFAULT_CHANNEL(UserIcon); -static PPAGED_LOOKASIDE_LIST pgProcessLookasideList; -static LIST_ENTRY gCurIconList; - SYSTEM_CURSORINFO gSysCursorInfo; +PCURICON_OBJECT gcurFirst = NULL; // After all is done, this should be WINLOGO! + +// +// System Cursors +// +SYSTEMCURICO gasyscur[] = { + {OCR_NORMAL, NULL}, + {OCR_IBEAM, NULL}, + {OCR_WAIT, NULL}, + {OCR_CROSS, NULL}, + {OCR_UP, NULL}, + {OCR_ICON, NULL}, + {OCR_SIZE, NULL}, + {OCR_SIZENWSE, NULL}, + {OCR_SIZENESW, NULL}, + {OCR_SIZEWE, NULL}, + {OCR_SIZENS, NULL}, + {OCR_SIZEALL, NULL}, + {OCR_NO, NULL}, + {OCR_HAND, NULL}, + {OCR_APPSTARTING,NULL}, + {OCR_HELP, NULL}, + }; + +// +// System Icons +// +SYSTEMCURICO gasysico[] = { + {OIC_SAMPLE, NULL}, + {OIC_HAND, NULL}, + {OIC_QUES, NULL}, + {OIC_BANG, NULL}, + {OIC_NOTE, NULL}, + {OIC_WINLOGO,NULL}, + }; + BOOL -InitCursorImpl() +InitCursorImpl(VOID) { - 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.ButtonsDown = 0; - gSysCursorInfo.bClipped = FALSE; - gSysCursorInfo.LastBtnDown = 0; - gSysCursorInfo.CurrentCursorObject = NULL; - gSysCursorInfo.ShowingCursor = -1; - gSysCursorInfo.ClickLockActive = FALSE; - gSysCursorInfo.ClickLockTime = 0; + gSysCursorInfo.Enabled = FALSE; + gSysCursorInfo.ButtonsDown = 0; + gSysCursorInfo.bClipped = FALSE; + gSysCursorInfo.LastBtnDown = 0; + gSysCursorInfo.CurrentCursorObject = NULL; + gSysCursorInfo.ShowingCursor = -1; + gSysCursorInfo.ClickLockActive = FALSE; + gSysCursorInfo.ClickLockTime = 0; return TRUE; } +VOID +IntLoadSystenIcons(HICON hcur, DWORD id) +{ + PCURICON_OBJECT pcur; + int i; + PPROCESSINFO ppi; + + if (hcur) + { + pcur = UserGetCurIconObject(hcur); + if (!pcur) + { + EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); + return; + } + + ppi = PsGetCurrentProcessWin32Process(); + + if (!(ppi->W32PF_flags & W32PF_CREATEDWINORDC)) + return; + + // Set Small Window Icon and do not link. + if ( id == OIC_WINLOGO+1 ) + { + pcur->CURSORF_flags |= CURSORF_GLOBAL; + UserReferenceObject(pcur); + pcur->head.ppi = NULL; + return; + } + + for(i = 0 ; i < 6; i++) + { + if (gasysico[i].type == id) + { + gasysico[i].handle = pcur; + pcur->CURSORF_flags |= CURSORF_GLOBAL|CURSORF_LINKED; + UserReferenceObject(pcur); + // + // The active switch between LR shared and Global public. + // This is hacked around to support this while at the initial system start up. + // + pcur->head.ppi = NULL; + // + pcur->pcurNext = gcurFirst; + gcurFirst = pcur; + return; + } + } + } +} + PSYSTEM_CURSORINFO IntGetSysCursorInfo() { return &gSysCursorInfo; } +FORCEINLINE +BOOL +is_icon(PCURICON_OBJECT object) +{ + return MAKEINTRESOURCE(object->rt) == RT_ICON; +} + /* This function creates a reference for the object! */ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon) { @@ -77,6 +150,13 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon) return NULL; } + if (UserObjectInDestroy(hCurIcon)) + { + WARN("Requesting invalid/destroyed cursor.\n"); + EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); + return NULL; + } + CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR); if (!CurIcon) { @@ -131,89 +211,8 @@ BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Ho 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 CurIcon) -{ - PPROCESSINFO Win32Process; - PLIST_ENTRY ListEntry; - PCURICON_PROCESS Current; - - Win32Process = PsGetCurrentProcessWin32Process(); - - ListEntry = CurIcon->ProcessList.Flink; - while (ListEntry != &CurIcon->ProcessList) - { - Current = CONTAINING_RECORD(ListEntry, CURICON_PROCESS, ListEntry); - ListEntry = ListEntry->Flink; - 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; - IntReferenceProcessInfo(Win32Process); - - return TRUE; -} - -PCURICON_OBJECT FASTCALL -IntFindExistingCurIconObject(HMODULE hModule, - HRSRC hRsrc, LONG cx, LONG cy) -{ - PLIST_ENTRY ListEntry; - PCURICON_OBJECT CurIcon; - - ListEntry = gCurIconList.Flink; - while (ListEntry != &gCurIconList) - { - CurIcon = CONTAINING_RECORD(ListEntry, CURICON_OBJECT, ListEntry); - ListEntry = ListEntry->Flink; - - // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, TYPE_CURSOR))) // <- huh???? -// UserReferenceObject( CurIcon); -// { - if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc)) - { - if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy))) - { -// UserDereferenceObject(CurIcon); - continue; - } - if (! ReferenceCurIconByProcess(CurIcon)) - { - return NULL; - } - - return CurIcon; - } -// } -// UserDereferenceObject(CurIcon); - - } - - return NULL; -} - HANDLE -IntCreateCurIconHandle(BOOLEAN Anim) +IntCreateCurIconHandle(BOOLEAN Animated) { PCURICON_OBJECT CurIcon; HANDLE hCurIcon; @@ -224,7 +223,7 @@ IntCreateCurIconHandle(BOOLEAN Anim) GetW32ThreadInfo(), &hCurIcon, TYPE_CURSOR, - sizeof(CURICON_OBJECT)); + Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT)); if (!CurIcon) { @@ -232,159 +231,125 @@ IntCreateCurIconHandle(BOOLEAN Anim) return FALSE; } - CurIcon->Self = hCurIcon; - InitializeListHead(&CurIcon->ProcessList); - - if (!ReferenceCurIconByProcess(CurIcon)) - { - ERR("Failed to add process\n"); - UserDeleteObject(hCurIcon, TYPE_CURSOR); - UserDereferenceObject(CurIcon); - return NULL; - } - - InsertHeadList(&gCurIconList, &CurIcon->ListEntry); - UserDereferenceObject(CurIcon); return hCurIcon; } -BOOLEAN FASTCALL -IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi) +BOOLEAN +IntDestroyCurIconObject( + _In_ PVOID Object) { - PSYSTEM_CURSORINFO CurInfo; - HBITMAP bmpMask, bmpColor; - BOOLEAN Ret, bListEmpty, bFound = FALSE; - PLIST_ENTRY ListEntry; - PCURICON_PROCESS Current; + PCURICON_OBJECT CurIcon = Object; - /* For handles created without any data (error handling) */ - if(IsListEmpty(&CurIcon->ProcessList)) - goto emptyList; - - /* Now find this process in the list of processes referencing this object and - remove it from that list */ - ListEntry = CurIcon->ProcessList.Flink; - while (ListEntry != &CurIcon->ProcessList) + /* Try finding it in its process cache */ + if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) { - Current = CONTAINING_RECORD(ListEntry, CURICON_PROCESS, ListEntry); - ListEntry = ListEntry->Flink; - if (Current->Process == ppi) + PPROCESSINFO ppi; + + ppi = CurIcon->head.ppi; + if (ppi->pCursorCache == CurIcon) { - bFound = TRUE; - bListEmpty = RemoveEntryList(&Current->ListEntry); - IntDereferenceProcessInfo(ppi); - break; + ppi->pCursorCache = CurIcon->pcurNext; + UserDereferenceObject(CurIcon); } - } - - if(!bFound) - { - /* This object doesn't belong to this process */ - EngSetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - ExFreeToPagedLookasideList(pgProcessLookasideList, Current); - - /* If there are still processes referencing this object we can't destroy it yet */ - if (!bListEmpty) - { - if(CurIcon->head.ppi == ppi) + else { - /* Set the first process of the list as owner */ - Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry); - UserSetObjectOwner(CurIcon, TYPE_CURSOR, Current->Process); + PCURICON_OBJECT CacheCurIcon = ppi->pCursorCache; + while (CacheCurIcon) + { + if (CacheCurIcon->pcurNext == CurIcon) + { + CacheCurIcon->pcurNext = CurIcon->pcurNext; + break; + } + CacheCurIcon = CacheCurIcon->pcurNext; + } + + /* We must have found it! */ + ASSERT(CacheCurIcon != NULL); + UserDereferenceObject(CurIcon); } - UserDereferenceObject(CurIcon); - return TRUE; + CurIcon->CURSORF_flags &= ~CURSORF_LINKED; } -emptyList: - /* Remove it from the list */ - RemoveEntryList(&CurIcon->ListEntry); - - CurInfo = IntGetSysCursorInfo(); - - if (CurInfo->CurrentCursorObject == CurIcon) - { - /* Hide the cursor if we're destroying the current cursor */ - UserSetCursor(NULL, TRUE); - } - - bmpMask = CurIcon->IconInfo.hbmMask; - bmpColor = CurIcon->IconInfo.hbmColor; - - /* Delete bitmaps */ - if (bmpMask) - { - GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(bmpMask); - CurIcon->IconInfo.hbmMask = NULL; - } - if (bmpColor) - { - GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(bmpColor); - CurIcon->IconInfo.hbmColor = NULL; - } - - /* We were given a pointer, no need to keep the reference anylonger! */ - UserDereferenceObject(CurIcon); - Ret = UserDeleteObject(CurIcon->Self, TYPE_CURSOR); - - return Ret; + /* We just mark the handle as being destroyed. + * Deleting all the stuff will be deferred to the actual struct free. */ + UserDeleteObject(CurIcon->head.h, TYPE_CURSOR); + return TRUE; } -HCURSOR FASTCALL -IntSetCursor( - HCURSOR hCursor) +void +FreeCurIconObject( + _In_ PVOID Object) { - PCURICON_OBJECT pcurOld, pcurNew; - HCURSOR hOldCursor = NULL; - - if (hCursor) + PCURICON_OBJECT CurIcon = Object; + + if(!(CurIcon->CURSORF_flags & CURSORF_ACON)) { - pcurNew = UserGetCurIconObject(hCursor); - if (!pcurNew) + HBITMAP bmpMask = CurIcon->hbmMask; + HBITMAP bmpColor = CurIcon->hbmColor; + HBITMAP bmpAlpha = CurIcon->hbmAlpha; + + /* Delete bitmaps */ + if (bmpMask) { - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - goto leave; + GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED); + GreDeleteObject(bmpMask); + CurIcon->hbmMask = NULL; + } + if (bmpColor) + { + GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED); + GreDeleteObject(bmpColor); + CurIcon->hbmColor = NULL; + } + if (bmpAlpha) + { + GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED); + GreDeleteObject(bmpAlpha); + CurIcon->hbmAlpha = NULL; } } else { - pcurNew = NULL; + PACON AniCurIcon = (PACON)CurIcon; + UINT i; + + for(i = 0; i < AniCurIcon->cpcur; i++) + { + UserDereferenceObject(AniCurIcon->aspcur[i]); + IntDestroyCurIconObject(AniCurIcon->aspcur[i]); + } + ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR); } - pcurOld = UserSetCursor(pcurNew, FALSE); - if (pcurOld) + if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) { - hOldCursor = (HCURSOR)pcurOld->Self; - UserDereferenceObject(pcurOld); + if (!IS_INTRESOURCE(CurIcon->strName.Buffer)) + ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING); + if (CurIcon->atomModName) + RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName); + CurIcon->strName.Buffer = NULL; + CurIcon->atomModName = 0; } -leave: - return hOldCursor; + + /* Finally free the thing */ + FreeProcMarkObject(CurIcon); } -BOOL FASTCALL -IntDestroyCursor( - HANDLE hCurIcon, - BOOL bForce) +VOID FASTCALL +IntCleanupCurIconCache(PPROCESSINFO Win32Process) { PCURICON_OBJECT CurIcon; - BOOL ret; - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) + /* Run through the list of icon objects */ + while (Win32Process->pCursorCache) { - return FALSE; + CurIcon = Win32Process->pCursorCache; + Win32Process->pCursorCache = CurIcon->pcurNext; + UserDereferenceObject(CurIcon); } - - ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process()); - /* Note: IntDestroyCurIconObject will remove our reference for us! */ - - return ret; } /* @@ -393,12 +358,12 @@ IntDestroyCursor( BOOL APIENTRY NtUserGetIconInfo( - HANDLE hCurIcon, - PICONINFO IconInfo, - PUNICODE_STRING lpInstName, // Optional - PUNICODE_STRING lpResName, // Optional - LPDWORD pbpp, // Optional - BOOL bInternal) + _In_ HANDLE hCurIcon, + _Out_opt_ PICONINFO IconInfo, + _Out_opt_ PUNICODE_STRING lpModule, // Optional + _Out_opt_ PUNICODE_STRING lpResName, // Optional + _Out_opt_ LPDWORD pbpp, // Optional + _In_ BOOL bInternal) { ICONINFO ii; PCURICON_OBJECT CurIcon; @@ -407,75 +372,155 @@ NtUserGetIconInfo( DWORD colorBpp = 0; TRACE("Enter NtUserGetIconInfo\n"); - UserEnterExclusive(); - if (!IconInfo) + /* Check if something was actually asked */ + if (!IconInfo && !lpModule && !lpResName) { + WARN("Nothing to fill.\n"); EngSetLastError(ERROR_INVALID_PARAMETER); - goto leave; + return FALSE; } + + UserEnterExclusive(); if (!(CurIcon = UserGetCurIconObject(hCurIcon))) { + WARN("UserGetIconObject(0x%08x) Failed.\n", hCurIcon); + UserLeave(); + return FALSE; + } + + /* Give back the icon information */ + if(IconInfo) + { + PCURICON_OBJECT FrameCurIcon = CurIcon; + if(CurIcon->CURSORF_flags & CURSORF_ACON) + { + /* Get information from first frame. */ + FrameCurIcon = ((PACON)CurIcon)->aspcur[0]; + } + + /* Fill data */ + ii.fIcon = is_icon(FrameCurIcon); + ii.xHotspot = FrameCurIcon->xHotspot; + ii.yHotspot = FrameCurIcon->yHotspot; + + /* Copy bitmaps */ + ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask); + GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED); + ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor); + GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED); + colorBpp = FrameCurIcon->bpp; + + /* Copy fields */ + _SEH2_TRY + { + ProbeForWrite(IconInfo, sizeof(ICONINFO), 1); + RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO)); + + if (pbpp) + { + ProbeForWrite(pbpp, sizeof(DWORD), 1); + *pbpp = colorBpp; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END + + if (!NT_SUCCESS(Status)) + { + WARN("Status: 0x%08x.\n", Status); + SetLastNtError(Status); + goto leave; + } + } + + /* Give back the module name */ + if(lpModule) + { + ULONG BufLen = 0; + if (!CurIcon->atomModName) + goto leave; + + RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen); + /* Get the module name from the atom table */ + _SEH2_TRY + { + BufLen += sizeof(WCHAR); + if (BufLen > (lpModule->MaximumLength)) + { + lpModule->Length = 0; + lpModule->MaximumLength = BufLen; + } + else + { + ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1); + BufLen = lpModule->MaximumLength; + RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen); + lpModule->Length = BufLen; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END + + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + goto leave; + } + } + + if (lpResName) + { + if (!CurIcon->strName.Buffer) + goto leave; + + /* Copy it */ + _SEH2_TRY + { + ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1); + if (IS_INTRESOURCE(CurIcon->strName.Buffer)) + { + lpResName->Buffer = CurIcon->strName.Buffer; + lpResName->Length = 0; + lpResName->MaximumLength = 0; + } + else if (lpResName->MaximumLength < CurIcon->strName.MaximumLength) + { + lpResName->Length = 0; + lpResName->MaximumLength = CurIcon->strName.MaximumLength; + } + else + { + ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength, 1); + RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, CurIcon->strName.Length); + lpResName->Length = CurIcon->strName.Length; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END + } + + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); goto leave; } - - RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO)); - - /* Copy bitmaps */ - ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask); - ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor); - - if (pbpp) - { - PSURFACE psurfBmp; - - psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor); - if (psurfBmp) - { - colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat); - SURFACE_ShareUnlockSurface(psurfBmp); - } - } - - /* Copy fields */ - _SEH2_TRY - { - ProbeForWrite(IconInfo, sizeof(ICONINFO), 1); - RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO)); - - /// @todo Implement support for lpInstName - if (lpInstName) - { - RtlInitEmptyUnicodeString(lpInstName, NULL, 0); - } - - /// @todo Implement support for lpResName - if (lpResName) - { - RtlInitEmptyUnicodeString(lpResName, NULL, 0); - } - - if (pbpp) - { - ProbeForWrite(pbpp, sizeof(DWORD), 1); - *pbpp = colorBpp; - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if (NT_SUCCESS(Status)) - Ret = TRUE; - else - SetLastNtError(Status); - - UserDereferenceObject(CurIcon); + + Ret = TRUE; leave: + UserDereferenceObject(CurIcon); + TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret); UserLeave(); @@ -499,19 +544,28 @@ NtUserGetIconSize( BOOL bRet = FALSE; TRACE("Enter NtUserGetIconSize\n"); - UserEnterExclusive(); + UserEnterShared(); if (!(CurIcon = UserGetCurIconObject(hCurIcon))) { 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 { ProbeForWrite(plcx, sizeof(LONG), 1); - RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG)); + *plcx = CurIcon->cx; ProbeForWrite(plcy, sizeof(LONG), 1); - RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG)); + *plcy = CurIcon->cy; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { @@ -549,14 +603,14 @@ NtUserGetCursorInfo( DECLARE_RETURN(BOOL); TRACE("Enter NtUserGetCursorInfo\n"); - UserEnterExclusive(); + UserEnterShared(); CurInfo = IntGetSysCursorInfo(); CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject; SafeCi.cbSize = sizeof(CURSORINFO); 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; @@ -596,10 +650,14 @@ APIENTRY UserClipCursor( RECTL *prcl) { - /* FIXME: Check if process has WINSTA_WRITEATTRIBUTES */ PSYSTEM_CURSORINFO CurInfo; PWND DesktopWindow = NULL; + if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES)) + { + return FALSE; + } + CurInfo = IntGetSysCursorInfo(); DesktopWindow = UserGetDesktopWindow(); @@ -666,7 +724,7 @@ NtUserClipCursor( prcl = &rclLocal; } - UserEnterExclusive(); + UserEnterExclusive(); /* Call the internal function */ bResult = UserClipCursor(prcl); @@ -683,30 +741,65 @@ NtUserClipCursor( BOOL APIENTRY NtUserDestroyCursor( - _In_ HANDLE hCurIcon, - _In_ BOOL bForce) + _In_ HANDLE hCurIcon, + _In_ BOOL bForce) { - PCURICON_OBJECT CurIcon; BOOL ret; - DECLARE_RETURN(BOOL); + PCURICON_OBJECT CurIcon = NULL; - TRACE("Enter NtUserDestroyCursorIcon\n"); + TRACE("Enter NtUserDestroyCursorIcon (%p, %u)\n", hCurIcon, bForce); UserEnterExclusive(); - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) + CurIcon = UserGetCurIconObject(hCurIcon); + if (!CurIcon) { - RETURN(FALSE); + ret = FALSE; + goto leave; } - ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process()); - /* Note: IntDestroyCurIconObject will remove our reference for us! */ + if (!bForce) + { + /* Can not destroy global objects */ + if (CurIcon->head.ppi == NULL) + { + ERR("Trying to delete global cursor!\n"); + ret = TRUE; + goto leave; + } - RETURN(ret); + /* Maybe we have good reasons not to destroy this object */ + if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process()) + { + /* No way, you're not touching my cursor */ + ret = FALSE; + goto leave; + } -CLEANUP: - TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_); + if (CurIcon->CURSORF_flags & CURSORF_CURRENT) + { + WARN("Trying to delete current cursor!\n"); + ret = FALSE; + goto leave; + } + + if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) + { + WARN("Trying to delete shared cursor.\n"); + /* This one is not an error */ + ret = TRUE; + goto leave; + } + } + + /* Destroy the handle */ + ret = IntDestroyCurIconObject(CurIcon); + +leave: + if (CurIcon) + UserDereferenceObject(CurIcon); + TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret); UserLeave(); - END_CLEANUP; + return ret; } @@ -714,36 +807,136 @@ CLEANUP: * @implemented */ HICON -APIENTRY +NTAPI NtUserFindExistingCursorIcon( - HMODULE hModule, - HRSRC hRsrc, - LONG cx, - LONG cy) + _In_ PUNICODE_STRING pustrModule, + _In_ PUNICODE_STRING pustrRsrc, + _In_ FINDEXISTINGCURICONPARAM* param) { PCURICON_OBJECT CurIcon; - HANDLE Ret = (HANDLE)0; - DECLARE_RETURN(HICON); + HICON Ret = NULL; + UNICODE_STRING ustrModuleSafe, ustrRsrcSafe; + FINDEXISTINGCURICONPARAM paramSafe; + NTSTATUS Status; + PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process(); + RTL_ATOM atomModName; TRACE("Enter NtUserFindExistingCursorIcon\n"); - UserEnterExclusive(); - - CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy); - if (CurIcon) + + + _SEH2_TRY { - Ret = CurIcon->Self; + ProbeForRead(param, sizeof(*param), 1); + RtlCopyMemory(¶mSafe, param, sizeof(paramSafe)); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END -// IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref? - RETURN(Ret); + /* 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; } - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - RETURN((HANDLE)0); + UserEnterShared(); + 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; + } -CLEANUP: - TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_); + 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; + } + // + // Now search Global Cursors or Icons. + // + if(CurIcon == NULL) + { + CurIcon = gcurFirst; + 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) + Ret = CurIcon->head.h; UserLeave(); - END_CLEANUP; + +done: + if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer)) + ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING); + + return Ret; } @@ -755,14 +948,18 @@ APIENTRY NtUserGetClipCursor( RECTL *lpRect) { - /* FIXME: Check if process has WINSTA_READATTRIBUTES */ PSYSTEM_CURSORINFO CurInfo; RECTL Rect; NTSTATUS Status; DECLARE_RETURN(BOOL); TRACE("Enter NtUserGetClipCursor\n"); - UserEnterExclusive(); + UserEnterShared(); + + if (!CheckWinstaAttributeAccess(WINSTA_READATTRIBUTES)) + { + RETURN(FALSE); + } if (!lpRect) RETURN(FALSE); @@ -807,7 +1004,7 @@ NtUserSetCursor( PCURICON_OBJECT pcurOld, pcurNew; HCURSOR hOldCursor = NULL; - TRACE("Enter NtUserSetCursor\n"); + TRACE("Enter NtUserSetCursor: %p\n", hCursor); UserEnterExclusive(); if (hCursor) @@ -818,6 +1015,7 @@ NtUserSetCursor( EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); goto leave; } + pcurNew->CURSORF_flags |= CURSORF_CURRENT; } else { @@ -827,7 +1025,26 @@ NtUserSetCursor( pcurOld = UserSetCursor(pcurNew, FALSE); if (pcurOld) { - hOldCursor = (HCURSOR)pcurOld->Self; + hOldCursor = pcurOld->head.h; + /* + Problem: + + System Global Cursors start out having at least 2 lock counts. If a system + cursor is the default cursor and is returned to the caller twice in its + life, the count will reach zero. Causing an assert to occur in objects. + + This fixes a SeaMonkey crash while the mouse crosses a boundary. + */ + if (pcurOld->CURSORF_flags & CURSORF_GLOBAL) + { + TRACE("Returning Global Cursor hcur %p\n",hOldCursor); + goto leave; + } + + /* See if it was destroyed in the meantime */ + if (UserObjectInDestroy(hOldCursor)) + hOldCursor = NULL; + pcurOld->CURSORF_flags &= ~CURSORF_CURRENT; UserDereferenceObject(pcurOld); } @@ -838,7 +1055,7 @@ leave: /* - * @implemented + * @unimplemented */ BOOL APIENTRY @@ -846,145 +1063,85 @@ NtUserSetCursorContents( HANDLE hCurIcon, PICONINFO UnsafeIconInfo) { - PCURICON_OBJECT CurIcon; - ICONINFO IconInfo; - PSURFACE psurfBmp; - NTSTATUS Status; - BOOL Ret = FALSE; - DECLARE_RETURN(BOOL); - - TRACE("Enter NtUserSetCursorContents\n"); - UserEnterExclusive(); - - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { - RETURN(FALSE); - } - - /* Copy fields */ - Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO)); - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - goto done; - } - - /* Delete old bitmaps */ - if ((CurIcon->IconInfo.hbmColor) - && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)) - { - GreDeleteObject(CurIcon->IconInfo.hbmColor); - } - if ((CurIcon->IconInfo.hbmMask) - && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask) - { - GreDeleteObject(CurIcon->IconInfo.hbmMask); - } - - /* Copy new IconInfo field */ - CurIcon->IconInfo = IconInfo; - - if (CurIcon->IconInfo.hbmColor) - { - psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor); - if (!psurfBmp) - goto done; - - CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; - CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy; - SURFACE_ShareUnlockSurface(psurfBmp); - GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC); - } - else - { - psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmMask); - if (!psurfBmp) - goto done; - - CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; - CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2; - - SURFACE_ShareUnlockSurface(psurfBmp); - } - GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC); - - Ret = TRUE; - -done: - - if (CurIcon) - { - UserDereferenceObject(CurIcon); - } - RETURN(Ret); - -CLEANUP: - TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_); - UserLeave(); - END_CLEANUP; + FIXME(" is UNIMPLEMENTED.\n"); + return FALSE; } /* * @implemented */ -#if 0 BOOL APIENTRY NtUserSetCursorIconData( - HANDLE Handle, - HMODULE hModule, - PUNICODE_STRING pstrResName, - PICONINFO pIconInfo) + _In_ HCURSOR Handle, + _In_opt_ PUNICODE_STRING pustrModule, + _In_opt_ PUNICODE_STRING pustrRsrc, + _In_ const CURSORDATA* pCursorData) { PCURICON_OBJECT CurIcon; - PSURFACE psurfBmp; NTSTATUS Status = STATUS_SUCCESS; - BOOL Ret = FALSE; - DECLARE_RETURN(BOOL); - + BOOLEAN Ret = FALSE; + BOOLEAN IsShared = FALSE, IsAnim = FALSE; + DWORD numFrames; + UINT i = 0; + TRACE("Enter NtUserSetCursorIconData\n"); + UserEnterExclusive(); if (!(CurIcon = UserGetCurIconObject(Handle))) { - RETURN(FALSE); + UserLeave(); + EngSetLastError(ERROR_INVALID_HANDLE); + return FALSE; } - CurIcon->hModule = hModule; - CurIcon->hRsrc = NULL; //hRsrc; - CurIcon->hGroupRsrc = NULL; //hGroupRsrc; - _SEH2_TRY { - ProbeForRead(pIconInfo, sizeof(ICONINFO), 1); - RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO)); - - CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask); - CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor); - - if (CurIcon->IconInfo.hbmColor) + ProbeForRead(pCursorData, sizeof(*pCursorData), 1); + if(pCursorData->CURSORF_flags & CURSORF_ACON) { - if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor))) - { - CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; - CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy; - SURFACE_UnlockSurface(psurfBmp); - GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC); - } + /* 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; } - if (CurIcon->IconInfo.hbmMask) + else { - if (CurIcon->IconInfo.hbmColor == NULL) - { - if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask))) - { - CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; - CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy; - SURFACE_UnlockSurface(psurfBmp); - } - } - GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC); + CurIcon->xHotspot = pCursorData->xHotspot; + CurIcon->yHotspot = pCursorData->yHotspot; + CurIcon->cx = pCursorData->cx; + CurIcon->cy = pCursorData->cy; + CurIcon->rt = pCursorData->rt; + CurIcon->bpp = pCursorData->bpp; + CurIcon->hbmMask = pCursorData->hbmMask; + CurIcon->hbmColor = pCursorData->hbmColor; + CurIcon->hbmAlpha = pCursorData->hbmAlpha; + CurIcon->CURSORF_flags = pCursorData->CURSORF_flags; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) @@ -992,104 +1149,113 @@ NtUserSetCursorIconData( Status = _SEH2_GetExceptionCode(); } _SEH2_END - + if (!NT_SUCCESS(Status)) + { SetLastNtError(Status); - else - Ret = TRUE; - - UserDereferenceObject(CurIcon); - RETURN(Ret); - -CLEANUP: - TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_); - UserLeave(); - END_CLEANUP; -} -#else -BOOL -APIENTRY -NtUserSetCursorIconData( - HANDLE hCurIcon, - PBOOL fIcon, - POINT *Hotspot, - HMODULE hModule, - HRSRC hRsrc, - HRSRC hGroupRsrc) -{ - PCURICON_OBJECT CurIcon; - NTSTATUS Status; - POINT SafeHotspot; - BOOL Ret = FALSE; - DECLARE_RETURN(BOOL); - - TRACE("Enter NtUserSetCursorIconData\n"); - UserEnterExclusive(); - - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { - RETURN(FALSE); + goto done; } - CurIcon->hModule = hModule; - CurIcon->hRsrc = hRsrc; - CurIcon->hGroupRsrc = hGroupRsrc; - - /* Copy fields */ - if (fIcon) + if(IsAnim) { - Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL)); - if (!NT_SUCCESS(Status)) + 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++) { - SetLastNtError(Status); - goto done; + HANDLE hCurFrame = IntCreateCurIconHandle(FALSE); + if(!NtUserSetCursorIconData(hCurFrame, NULL, NULL, pCursorData)) + goto done; + AniCurIcon->aspcur[i] = UserGetCurIconObject(hCurFrame); + if(!AniCurIcon->aspcur[i]) + goto done; + pCursorData++; } } - else + + if(CurIcon->CURSORF_flags & CURSORF_LRSHARED) { - if (!Hotspot) - Ret = TRUE; + IsShared = TRUE; } - if (Hotspot) + // Support global public cursors and icons too. + if(!IsAnim || IsShared) { - Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT)); - if (NT_SUCCESS(Status)) + if(pustrRsrc && pustrModule) { - CurIcon->IconInfo.xHotspot = SafeHotspot.x; - CurIcon->IconInfo.yHotspot = SafeHotspot.y; - - Ret = TRUE; + UNICODE_STRING ustrModuleSafe; + /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */ + Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc); + if(!NT_SUCCESS(Status)) + goto done; + 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)) + goto done; } - else - SetLastNtError(Status); } - if (!fIcon && !Hotspot) + if(!CurIcon->hbmMask) { - Ret = TRUE; + ERR("NtUserSetCursorIconData was got no hbmMask.\n"); + EngSetLastError(ERROR_INVALID_PARAMETER); + goto done; } + GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC); + + if(CurIcon->hbmColor) + GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC); + + if(CurIcon->hbmAlpha) + GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC); + + if(IsShared) + { + /* Update process cache in case of shared cursor */ + PPROCESSINFO ppi = CurIcon->head.ppi; + UserReferenceObject(CurIcon); + CurIcon->pcurNext = ppi->pCursorCache; + ppi->pCursorCache = CurIcon; + CurIcon->CURSORF_flags |= CURSORF_LINKED; + } + + Ret = TRUE; + done: - if(Ret) - { - /* This icon is shared now */ - GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC); - if(CurIcon->IconInfo.hbmColor) - { - GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC); - } - } + if(!Ret && (!IsAnim || IsShared)) + { + if(!IS_INTRESOURCE(CurIcon->strName.Buffer)) + ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING); + } + + if(!Ret && IsAnim) + { + PACON AniCurIcon = (PACON)CurIcon; + for(i = 0; i < numFrames; i++) + { + if(AniCurIcon->aspcur[i]) + { + UserDereferenceObject(AniCurIcon->aspcur[i]); + IntDestroyCurIconObject(AniCurIcon->aspcur[i]); + } + } + AniCurIcon->cicur = 0; + AniCurIcon->cpcur = 0; + ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR); + AniCurIcon->aspcur = NULL; + AniCurIcon->aicur = NULL; + AniCurIcon->ajifRate = NULL; + } + UserDereferenceObject(CurIcon); - RETURN(Ret); - - -CLEANUP: - TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_); + TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret); UserLeave(); - END_CLEANUP; + + return Ret; } -#endif /* Mostly inspired from wine code. * We use low level functions because: @@ -1111,15 +1277,15 @@ UserDrawIconEx( HBRUSH hbrFlickerFreeDraw, UINT diFlags) { - PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen; + PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL; PDC pdc = NULL; BOOL Ret = FALSE; - HBITMAP hbmMask, hbmColor; - BOOL bOffScreen, bAlpha = FALSE; + HBITMAP hbmMask, hbmColor, hbmAlpha; + BOOL bOffScreen; RECTL rcDest, rcSrc; CLIPOBJ* pdcClipObj = NULL; EXLATEOBJ exlo; - + /* Stupid case */ if((diFlags & DI_NORMAL) == 0) { @@ -1127,14 +1293,23 @@ UserDrawIconEx( return FALSE; } - hbmMask = pIcon->IconInfo.hbmMask; - hbmColor = pIcon->IconInfo.hbmColor; - - if (istepIfAniCur) - ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n"); + 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; + hbmColor = pIcon->hbmColor; + hbmAlpha = pIcon->hbmAlpha; + /* - * Get our objects. + * Get our objects. * Shared locks are enough, we are only reading those bitmaps */ psurfMask = SURFACE_ShareLockSurface(hbmMask); @@ -1143,12 +1318,12 @@ UserDrawIconEx( ERR("Unable to lock the mask surface.\n"); return FALSE; } - + /* Color bitmap is not mandatory */ if(hbmColor == NULL) { /* But then the mask bitmap must have the information in it's bottom half */ - ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy); + ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy); psurfColor = NULL; } else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL) @@ -1157,95 +1332,93 @@ UserDrawIconEx( SURFACE_ShareUnlockSurface(psurfMask); return FALSE; } - - /* Set source rect */ - RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy); - - /* Check for alpha */ - if (psurfColor && - (psurfColor->SurfObj.iBitmapFormat == BMF_32BPP) && - (diFlags & DI_IMAGE)) + + pdc = DC_LockDc(hDc); + if(!pdc) { - PFN_DIB_GetPixel fnSource_GetPixel = NULL; - INT i, j; - - /* In order to correctly display 32 bit icons Windows first scans the image, - because information about transparency is not stored in any image's headers */ - fnSource_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel; - for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++) - { - for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++) - { - bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j) >> 24) & 0xff); - if (bAlpha) - break; - } - if (bAlpha) - break; - } + ERR("Could not lock the destination DC.\n"); + SURFACE_ShareUnlockSurface(psurfMask); + if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); + return FALSE; } /* Fix width parameter, if needed */ if (!cxWidth) { if(diFlags & DI_DEFAULTSIZE) - cxWidth = pIcon->IconInfo.fIcon ? + cxWidth = is_icon(pIcon) ? UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR); else - cxWidth = pIcon->Size.cx; + cxWidth = pIcon->cx; } /* Fix height parameter, if needed */ if (!cyHeight) { if(diFlags & DI_DEFAULTSIZE) - cyHeight = pIcon->IconInfo.fIcon ? + cyHeight = is_icon(pIcon) ? UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR); else - cyHeight = pIcon->Size.cy; + cyHeight = pIcon->cy; } + /* Calculate destination rectangle */ + RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); + IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); + RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); + + /* Prepare the underlying surface */ + DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL); + + /* We now have our destination surface and rectangle */ + psurfDest = pdc->dclevel.pSurface; + + if(psurfDest == NULL) + { + /* Empty DC */ + DC_vFinishBlit(pdc, NULL); + DC_UnlockDc(pdc); + SURFACE_ShareUnlockSurface(psurfMask); + if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); + return FALSE; + } + + /* Set source rect */ + RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy); + /* Should we render off-screen? */ - bOffScreen = hbrFlickerFreeDraw && (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH); + bOffScreen = hbrFlickerFreeDraw && + (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH); if (bOffScreen) { /* Yes: Allocate and paint the offscreen surface */ EBRUSHOBJ eboFill; PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw); - + TRACE("Performing off-screen rendering.\n"); - + if(!pbrush) { ERR("Failed to get brush object.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - return FALSE; - } - - if (!psurfColor) - { - ERR("Attention HAX FIX API DrawIconEx TEST Line 37: psurfColor is NULL going with Mask!\n"); - psurfColor = SURFACE_ShareLockSurface(hbmMask); + goto Cleanup; } +#if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP, - cxWidth, cyHeight, psurfColor->SurfObj.iBitmapFormat, + cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat, 0, 0, NULL); if(!psurfOffScreen) { ERR("Failed to allocate the off-screen surface.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); BRUSH_ShareUnlockBrush(pbrush); - return FALSE; + goto Cleanup; } - + /* Paint the brush */ EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL); RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight); - + Ret = IntEngBitBlt(&psurfOffScreen->SurfObj, NULL, NULL, @@ -1261,100 +1434,67 @@ UserDrawIconEx( /* Clean up everything */ EBRUSHOBJ_vCleanup(&eboFill); BRUSH_ShareUnlockBrush(pbrush); - + if(!Ret) { ERR("Failed to paint the off-screen surface.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject); - return FALSE; + goto Cleanup; } - + /* We now have our destination surface */ psurfDest = psurfOffScreen; +#else + pdcClipObj = &pdc->co.ClipObj; + /* Paint the brush */ + EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL); + + Ret = IntEngBitBlt(&psurfDest->SurfObj, + NULL, + NULL, + pdcClipObj, + NULL, + &rcDest, + NULL, + NULL, + &eboFill.BrushObject, + &pbrush->ptOrigin, + ROP4_PATCOPY); + + /* Clean up everything */ + EBRUSHOBJ_vCleanup(&eboFill); + BRUSH_ShareUnlockBrush(pbrush); + + if(!Ret) + { + ERR("Failed to paint the off-screen surface.\n"); + goto Cleanup; + } +#endif } else { /* We directly draw to the DC */ TRACE("Performing on screen rendering.\n"); - - psurfOffScreen = NULL; - pdc = DC_LockDc(hDc); - if(!pdc) - { - ERR("Could not lock the destination DC.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - return FALSE; - } - /* Calculate destination rectangle */ - RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); - IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); - RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); - - /* Prepare the underlying surface */ - DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL); - - /* Get the clip object */ pdcClipObj = &pdc->co.ClipObj; - - /* We now have our destination surface and rectangle */ - psurfDest = pdc->dclevel.pSurface; - - if(psurfDest == NULL) - { - /* Empty DC */ - DC_vFinishBlit(pdc, NULL); - DC_UnlockDc(pdc); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - return FALSE; - } + // psurfOffScreen = NULL; } /* Now do the rendering */ - if(bAlpha && (diFlags & DI_IMAGE)) - { - BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } }; - BYTE Alpha; - INT i, j; + if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL)) + { + BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } }; PSURFACE psurf = NULL; - PBYTE ptr ; - HBITMAP hsurfCopy = NULL; - hsurfCopy = BITMAP_CopyBitmap(hbmColor); - if(!hsurfCopy) - { - ERR("BITMAP_CopyBitmap failed!"); - goto CleanupAlpha; - } - - psurf = SURFACE_ShareLockSurface(hsurfCopy); + psurf = SURFACE_ShareLockSurface(hbmAlpha); if(!psurf) { ERR("SURFACE_LockSurface failed!\n"); - goto CleanupAlpha; + goto NoAlpha; } - - /* Premultiply with the alpha channel value */ - for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++) - { - ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta; - for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++) - { - Alpha = ptr[3]; - ptr[0] = (ptr[0] * Alpha) / 0xff; - ptr[1] = (ptr[1] * Alpha) / 0xff; - ptr[2] = (ptr[2] * Alpha) / 0xff; - - ptr += 4; - } - } - + /* Initialize color translation object */ EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0); - + /* Now do it */ Ret = IntEngAlphaBlend(&psurfDest->SurfObj, &psurf->SurfObj, @@ -1363,22 +1503,19 @@ UserDrawIconEx( &rcDest, &rcSrc, &blendobj); - + EXLATEOBJ_vCleanup(&exlo); - - CleanupAlpha: - if(psurf) SURFACE_ShareUnlockSurface(psurf); - if(hsurfCopy) NtGdiDeleteObjectApp(hsurfCopy); - if(Ret) goto done; - ERR("NtGdiAlphaBlend failed!\n"); + SURFACE_ShareUnlockSurface(psurf); + if(Ret) goto done; + ERR("NtGdiAlphaBlend failed!\n"); } - +NoAlpha: if (diFlags & DI_MASK) { DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY; - + EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0); - + Ret = IntEngStretchBlt(&psurfDest->SurfObj, &psurfMask->SurfObj, NULL, @@ -1391,7 +1528,7 @@ UserDrawIconEx( NULL, NULL, rop4); - + EXLATEOBJ_vCleanup(&exlo); if(!Ret) @@ -1403,12 +1540,12 @@ UserDrawIconEx( if(diFlags & DI_IMAGE) { - if (psurfColor) + if (psurfColor) { DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ; - + EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0); - + Ret = IntEngStretchBlt(&psurfDest->SurfObj, &psurfColor->SurfObj, NULL, @@ -1421,7 +1558,7 @@ UserDrawIconEx( NULL, NULL, rop4); - + EXLATEOBJ_vCleanup(&exlo); if(!Ret) @@ -1434,10 +1571,10 @@ UserDrawIconEx( { /* Mask bitmap holds the information in its bottom half */ DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY; - RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy); - + RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy); + EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0); - + Ret = IntEngStretchBlt(&psurfDest->SurfObj, &psurfMask->SurfObj, NULL, @@ -1450,7 +1587,7 @@ UserDrawIconEx( NULL, NULL, rop4); - + EXLATEOBJ_vCleanup(&exlo); if(!Ret) @@ -1462,40 +1599,27 @@ UserDrawIconEx( } done: +#if 0 /* We're done. Was it a double buffered draw ? */ if(bOffScreen) { /* Yes. Draw it back to our DC */ POINTL ptSrc = {0, 0}; - pdc = DC_LockDc(hDc); - if(!pdc) - { - ERR("Could not lock the destination DC.\n"); - return FALSE; - } + /* Calculate destination rectangle */ RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); - - /* Prepare the underlying surface */ - DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL); - + /* Get the clip object */ - pdcClipObj = &pdc->co.ClipObj; - + pdcClipObj = pdc->rosdc.CombinedClip; + /* We now have our destination surface and rectangle */ psurfDest = pdc->dclevel.pSurface; - if(!psurfDest) - { - /* So, you did all of this for an empty DC. */ - DC_UnlockDc(pdc); - goto Cleanup2; - } - + /* Color translation */ EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0); - + /* Blt it! */ Ret = IntEngBitBlt(&psurfDest->SurfObj, &psurfOffScreen->SurfObj, @@ -1508,9 +1632,10 @@ done: NULL, NULL, ROP4_SRCCOPY); - + EXLATEOBJ_vCleanup(&exlo); } +#endif Cleanup: if(pdc) { @@ -1518,10 +1643,11 @@ Cleanup: DC_UnlockDc(pdc); } -Cleanup2: +#if 0 /* Delete off screen rendering surface */ if(psurfOffScreen) GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject); +#endif /* Unlock other surfaces */ SURFACE_ShareUnlockSurface(psurfMask); @@ -1556,7 +1682,7 @@ NtUserDrawIconEx( if (!(pIcon = UserGetCurIconObject(hIcon))) { - ERR("UserGetCurIconObject() failed!\n"); + ERR("UserGetCurIconObject(0x%08x) failed!\n", hIcon); UserLeave(); return FALSE; } @@ -1588,13 +1714,67 @@ NtUserGetCursorFrameInfo( INT* rate_jiffies, DWORD* num_steps) { - STUB + PCURICON_OBJECT CurIcon; + HCURSOR ret; + INT jiffies = 0; + DWORD steps = 1; + NTSTATUS Status = STATUS_SUCCESS; - return 0; + TRACE("Enter NtUserGetCursorFrameInfo\n"); + UserEnterShared(); + + 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; } /* - * @unimplemented + * @implemented */ BOOL APIENTRY @@ -1602,7 +1782,57 @@ NtUserSetSystemCursor( HCURSOR hcur, DWORD id) { - return FALSE; + PCURICON_OBJECT pcur, pcurOrig = NULL; + int i; + PPROCESSINFO ppi; + BOOL Ret = FALSE; + UserEnterExclusive(); + + if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES)) + { + goto Exit; + } + + if (hcur) + { + pcur = UserGetCurIconObject(hcur); + if (!pcur) + { + EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); + goto Exit; + } + + ppi = PsGetCurrentProcessWin32Process(); + + for(i = 0 ; i < 16; i++) + { + if (gasyscur[i].type == id) + { + pcurOrig = gasyscur[i].handle; + + if (pcurOrig) break; + + if (ppi->W32PF_flags & W32PF_CREATEDWINORDC) + { + gasyscur[i].handle = pcur; + pcur->CURSORF_flags |= CURSORF_GLOBAL|CURSORF_LINKED; + UserReferenceObject(pcur); + pcur->head.ppi = NULL; + pcur->pcurNext = gcurFirst; + gcurFirst = pcur; + Ret = TRUE; + } + break; + } + } + if (pcurOrig) + { + FIXME("Need to copy cursor data or do something! pcurOrig %p new pcur %p\n",pcurOrig,pcur); + } + } +Exit: + UserLeave(); + return Ret; } /* EOF */ diff --git a/reactos/win32ss/user/ntuser/cursoricon.h b/reactos/win32ss/user/ntuser/cursoricon.h index c5d7f5f5fcd..b3513d81ab6 100644 --- a/reactos/win32ss/user/ntuser/cursoricon.h +++ b/reactos/win32ss/user/ntuser/cursoricon.h @@ -2,7 +2,6 @@ #define MAXCURICONHANDLES 4096 -#ifdef NEW_CURSORICON typedef struct _CURICON_OBJECT { PROCMARKHEAD head; @@ -49,32 +48,6 @@ IntCleanupCurIconCache(PPROCESSINFO Win32Process); void FreeCurIconObject(PVOID Object); -#else - -typedef struct tagCURICON_PROCESS -{ - LIST_ENTRY ListEntry; - PPROCESSINFO Process; -} CURICON_PROCESS, *PCURICON_PROCESS; - -typedef struct _CURICON_OBJECT -{ - PROCMARKHEAD head; - LIST_ENTRY ListEntry; - HANDLE Self; - LIST_ENTRY ProcessList; - HMODULE hModule; - HRSRC hRsrc; - HRSRC hGroupRsrc; - SIZE Size; - BYTE Shadow; - ICONINFO IconInfo; -} CURICON_OBJECT, *PCURICON_OBJECT; -BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi); -BOOL FASTCALL IntDestroyCursor(HANDLE hCurIcon, BOOL bForce); -HCURSOR FASTCALL IntSetCursor(HCURSOR hCursor); -#endif - typedef struct _CURSORACCELERATION_INFO { UINT FirstThreshold; diff --git a/reactos/win32ss/user/ntuser/cursoricon_new.c b/reactos/win32ss/user/ntuser/cursoricon_new.c deleted file mode 100644 index 94ea1426009..00000000000 --- a/reactos/win32ss/user/ntuser/cursoricon_new.c +++ /dev/null @@ -1,1838 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Win32k subsystem - * PURPOSE: Cursor and icon functions - * FILE: win32ss/user/ntuser/cursoricon.c - * PROGRAMER: ReactOS Team - */ -/* - * 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 - */ - -#include -DBG_DEFAULT_CHANNEL(UserIcon); - -SYSTEM_CURSORINFO gSysCursorInfo; - -PCURICON_OBJECT gcurFirst = NULL; // After all is done, this should be WINLOGO! - -// -// System Cursors -// -SYSTEMCURICO gasyscur[] = { - {OCR_NORMAL, NULL}, - {OCR_IBEAM, NULL}, - {OCR_WAIT, NULL}, - {OCR_CROSS, NULL}, - {OCR_UP, NULL}, - {OCR_ICON, NULL}, - {OCR_SIZE, NULL}, - {OCR_SIZENWSE, NULL}, - {OCR_SIZENESW, NULL}, - {OCR_SIZEWE, NULL}, - {OCR_SIZENS, NULL}, - {OCR_SIZEALL, NULL}, - {OCR_NO, NULL}, - {OCR_HAND, NULL}, - {OCR_APPSTARTING,NULL}, - {OCR_HELP, NULL}, - }; - -// -// System Icons -// -SYSTEMCURICO gasysico[] = { - {OIC_SAMPLE, NULL}, - {OIC_HAND, NULL}, - {OIC_QUES, NULL}, - {OIC_BANG, NULL}, - {OIC_NOTE, NULL}, - {OIC_WINLOGO,NULL}, - }; - -BOOL -InitCursorImpl(VOID) -{ - gSysCursorInfo.Enabled = FALSE; - gSysCursorInfo.ButtonsDown = 0; - gSysCursorInfo.bClipped = FALSE; - gSysCursorInfo.LastBtnDown = 0; - gSysCursorInfo.CurrentCursorObject = NULL; - gSysCursorInfo.ShowingCursor = -1; - gSysCursorInfo.ClickLockActive = FALSE; - gSysCursorInfo.ClickLockTime = 0; - - return TRUE; -} - -VOID -IntLoadSystenIcons(HICON hcur, DWORD id) -{ - PCURICON_OBJECT pcur; - int i; - PPROCESSINFO ppi; - - if (hcur) - { - pcur = UserGetCurIconObject(hcur); - if (!pcur) - { - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - return; - } - - ppi = PsGetCurrentProcessWin32Process(); - - if (!(ppi->W32PF_flags & W32PF_CREATEDWINORDC)) - return; - - // Set Small Window Icon and do not link. - if ( id == OIC_WINLOGO+1 ) - { - pcur->CURSORF_flags |= CURSORF_GLOBAL; - UserReferenceObject(pcur); - pcur->head.ppi = NULL; - return; - } - - for(i = 0 ; i < 6; i++) - { - if (gasysico[i].type == id) - { - gasysico[i].handle = pcur; - pcur->CURSORF_flags |= CURSORF_GLOBAL|CURSORF_LINKED; - UserReferenceObject(pcur); - // - // The active switch between LR shared and Global public. - // This is hacked around to support this while at the initial system start up. - // - pcur->head.ppi = NULL; - // - pcur->pcurNext = gcurFirst; - gcurFirst = pcur; - return; - } - } - } -} - -PSYSTEM_CURSORINFO -IntGetSysCursorInfo() -{ - return &gSysCursorInfo; -} - -FORCEINLINE -BOOL -is_icon(PCURICON_OBJECT object) -{ - return MAKEINTRESOURCE(object->rt) == RT_ICON; -} - -/* This function creates a reference for the object! */ -PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon) -{ - PCURICON_OBJECT CurIcon; - - if (!hCurIcon) - { - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - return NULL; - } - - if (UserObjectInDestroy(hCurIcon)) - { - WARN("Requesting invalid/destroyed cursor.\n"); - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - return NULL; - } - - CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, TYPE_CURSOR); - if (!CurIcon) - { - /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */ - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - return NULL; - } - - ASSERT(CurIcon->head.cLockObj >= 1); - return CurIcon; -} - -BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook) -{ - PWND DesktopWindow; - PSYSTEM_CURSORINFO CurInfo; - MSG Msg; - RECTL rcClip; - POINT pt; - - if(!(DesktopWindow = UserGetDesktopWindow())) - { - return FALSE; - } - - CurInfo = IntGetSysCursorInfo(); - - /* Clip cursor position */ - if (!CurInfo->bClipped) - rcClip = DesktopWindow->rcClient; - else - rcClip = CurInfo->rcClip; - - if(x >= rcClip.right) x = rcClip.right - 1; - if(x < rcClip.left) x = rcClip.left; - if(y >= rcClip.bottom) y = rcClip.bottom - 1; - if(y < rcClip.top) y = rcClip.top; - - pt.x = x; - pt.y = y; - - /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */ - Msg.message = WM_MOUSEMOVE; - Msg.wParam = UserGetMouseButtonsState(); - Msg.lParam = MAKELPARAM(x, y); - Msg.pt = pt; - co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook); - - /* 2. Store the new cursor position */ - gpsi->ptCursor = pt; - - return TRUE; -} - -HANDLE -IntCreateCurIconHandle(BOOLEAN Animated) -{ - PCURICON_OBJECT CurIcon; - HANDLE hCurIcon; - - CurIcon = UserCreateObject( - gHandleTable, - NULL, - GetW32ThreadInfo(), - &hCurIcon, - TYPE_CURSOR, - Animated ? sizeof(ACON) : sizeof(CURICON_OBJECT)); - - if (!CurIcon) - { - EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - - UserDereferenceObject(CurIcon); - - return hCurIcon; -} - -BOOLEAN -IntDestroyCurIconObject( - _In_ PVOID Object) -{ - PCURICON_OBJECT CurIcon = Object; - - /* Try finding it in its process cache */ - if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) - { - PPROCESSINFO ppi; - - ppi = CurIcon->head.ppi; - if (ppi->pCursorCache == CurIcon) - { - ppi->pCursorCache = CurIcon->pcurNext; - UserDereferenceObject(CurIcon); - } - else - { - PCURICON_OBJECT CacheCurIcon = ppi->pCursorCache; - while (CacheCurIcon) - { - if (CacheCurIcon->pcurNext == CurIcon) - { - CacheCurIcon->pcurNext = CurIcon->pcurNext; - break; - } - CacheCurIcon = CacheCurIcon->pcurNext; - } - - /* We must have found it! */ - ASSERT(CacheCurIcon != NULL); - UserDereferenceObject(CurIcon); - } - CurIcon->CURSORF_flags &= ~CURSORF_LINKED; - } - - /* We just mark the handle as being destroyed. - * Deleting all the stuff will be deferred to the actual struct free. */ - UserDeleteObject(CurIcon->head.h, TYPE_CURSOR); - return TRUE; -} - -void -FreeCurIconObject( - _In_ PVOID Object) -{ - PCURICON_OBJECT CurIcon = Object; - - if(!(CurIcon->CURSORF_flags & CURSORF_ACON)) - { - HBITMAP bmpMask = CurIcon->hbmMask; - HBITMAP bmpColor = CurIcon->hbmColor; - HBITMAP bmpAlpha = CurIcon->hbmAlpha; - - /* Delete bitmaps */ - if (bmpMask) - { - GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(bmpMask); - CurIcon->hbmMask = NULL; - } - if (bmpColor) - { - GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(bmpColor); - CurIcon->hbmColor = NULL; - } - if (bmpAlpha) - { - GreSetObjectOwner(bmpAlpha, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(bmpAlpha); - CurIcon->hbmAlpha = NULL; - } - } - else - { - PACON AniCurIcon = (PACON)CurIcon; - UINT i; - - for(i = 0; i < AniCurIcon->cpcur; i++) - { - UserDereferenceObject(AniCurIcon->aspcur[i]); - IntDestroyCurIconObject(AniCurIcon->aspcur[i]); - } - ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR); - } - - if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) - { - if (!IS_INTRESOURCE(CurIcon->strName.Buffer)) - ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING); - if (CurIcon->atomModName) - RtlDeleteAtomFromAtomTable(gAtomTable, CurIcon->atomModName); - CurIcon->strName.Buffer = NULL; - CurIcon->atomModName = 0; - } - - /* Finally free the thing */ - FreeProcMarkObject(CurIcon); -} - -VOID FASTCALL -IntCleanupCurIconCache(PPROCESSINFO Win32Process) -{ - PCURICON_OBJECT CurIcon; - - /* Run through the list of icon objects */ - while (Win32Process->pCursorCache) - { - CurIcon = Win32Process->pCursorCache; - Win32Process->pCursorCache = CurIcon->pcurNext; - UserDereferenceObject(CurIcon); - } -} - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserGetIconInfo( - _In_ HANDLE hCurIcon, - _Out_opt_ PICONINFO IconInfo, - _Out_opt_ PUNICODE_STRING lpModule, // Optional - _Out_opt_ PUNICODE_STRING lpResName, // Optional - _Out_opt_ LPDWORD pbpp, // Optional - _In_ BOOL bInternal) -{ - ICONINFO ii; - PCURICON_OBJECT CurIcon; - NTSTATUS Status = STATUS_SUCCESS; - BOOL Ret = FALSE; - DWORD colorBpp = 0; - - TRACE("Enter NtUserGetIconInfo\n"); - - /* Check if something was actually asked */ - if (!IconInfo && !lpModule && !lpResName) - { - WARN("Nothing to fill.\n"); - EngSetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - UserEnterExclusive(); - - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { - WARN("UserGetIconObject(0x%08x) Failed.\n", hCurIcon); - UserLeave(); - return FALSE; - } - - /* Give back the icon information */ - if(IconInfo) - { - PCURICON_OBJECT FrameCurIcon = CurIcon; - if(CurIcon->CURSORF_flags & CURSORF_ACON) - { - /* Get information from first frame. */ - FrameCurIcon = ((PACON)CurIcon)->aspcur[0]; - } - - /* Fill data */ - ii.fIcon = is_icon(FrameCurIcon); - ii.xHotspot = FrameCurIcon->xHotspot; - ii.yHotspot = FrameCurIcon->yHotspot; - - /* Copy bitmaps */ - ii.hbmMask = BITMAP_CopyBitmap(FrameCurIcon->hbmMask); - GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED); - ii.hbmColor = BITMAP_CopyBitmap(FrameCurIcon->hbmColor); - GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED); - colorBpp = FrameCurIcon->bpp; - - /* Copy fields */ - _SEH2_TRY - { - ProbeForWrite(IconInfo, sizeof(ICONINFO), 1); - RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO)); - - if (pbpp) - { - ProbeForWrite(pbpp, sizeof(DWORD), 1); - *pbpp = colorBpp; - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if (!NT_SUCCESS(Status)) - { - WARN("Status: 0x%08x.\n", Status); - SetLastNtError(Status); - goto leave; - } - } - - /* Give back the module name */ - if(lpModule) - { - ULONG BufLen = 0; - if (!CurIcon->atomModName) - goto leave; - - RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, NULL, &BufLen); - /* Get the module name from the atom table */ - _SEH2_TRY - { - BufLen += sizeof(WCHAR); - if (BufLen > (lpModule->MaximumLength)) - { - lpModule->Length = 0; - lpModule->MaximumLength = BufLen; - } - else - { - ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1); - BufLen = lpModule->MaximumLength; - RtlQueryAtomInAtomTable(gAtomTable, CurIcon->atomModName, NULL, NULL, lpModule->Buffer, &BufLen); - lpModule->Length = BufLen; - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - goto leave; - } - } - - if (lpResName) - { - if (!CurIcon->strName.Buffer) - goto leave; - - /* Copy it */ - _SEH2_TRY - { - ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1); - if (IS_INTRESOURCE(CurIcon->strName.Buffer)) - { - lpResName->Buffer = CurIcon->strName.Buffer; - lpResName->Length = 0; - lpResName->MaximumLength = 0; - } - else if (lpResName->MaximumLength < CurIcon->strName.MaximumLength) - { - lpResName->Length = 0; - lpResName->MaximumLength = CurIcon->strName.MaximumLength; - } - else - { - ProbeForWrite(lpResName->Buffer, lpResName->MaximumLength, 1); - RtlCopyMemory(lpResName->Buffer, CurIcon->strName.Buffer, CurIcon->strName.Length); - lpResName->Length = CurIcon->strName.Length; - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - } - - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - goto leave; - } - - Ret = TRUE; - -leave: - UserDereferenceObject(CurIcon); - - TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret); - UserLeave(); - - return Ret; -} - - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserGetIconSize( - HANDLE hCurIcon, - UINT istepIfAniCur, - PLONG plcx, // &size.cx - PLONG plcy) // &size.cy -{ - PCURICON_OBJECT CurIcon; - NTSTATUS Status = STATUS_SUCCESS; - BOOL bRet = FALSE; - - TRACE("Enter NtUserGetIconSize\n"); - UserEnterShared(); - - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { - 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 - { - ProbeForWrite(plcx, sizeof(LONG), 1); - *plcx = CurIcon->cx; - ProbeForWrite(plcy, sizeof(LONG), 1); - *plcy = CurIcon->cy; - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if (NT_SUCCESS(Status)) - bRet = TRUE; - else - SetLastNtError(Status); // Maybe not, test this - - UserDereferenceObject(CurIcon); - -cleanup: - TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet); - UserLeave(); - return bRet; -} - - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserGetCursorInfo( - PCURSORINFO pci) -{ - CURSORINFO SafeCi; - PSYSTEM_CURSORINFO CurInfo; - NTSTATUS Status = STATUS_SUCCESS; - PCURICON_OBJECT CurIcon; - BOOL Ret = FALSE; - DECLARE_RETURN(BOOL); - - TRACE("Enter NtUserGetCursorInfo\n"); - UserEnterShared(); - - CurInfo = IntGetSysCursorInfo(); - CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject; - - SafeCi.cbSize = sizeof(CURSORINFO); - SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0); - SafeCi.hCursor = (CurIcon ? CurIcon->head.h : NULL); - - SafeCi.ptScreenPos = gpsi->ptCursor; - - _SEH2_TRY - { - if (pci->cbSize == sizeof(CURSORINFO)) - { - ProbeForWrite(pci, sizeof(CURSORINFO), 1); - RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO)); - Ret = TRUE; - } - else - { - EngSetLastError(ERROR_INVALID_PARAMETER); - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - } - - RETURN(Ret); - -CLEANUP: - TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_); - UserLeave(); - END_CLEANUP; -} - -BOOL -APIENTRY -UserClipCursor( - RECTL *prcl) -{ - PSYSTEM_CURSORINFO CurInfo; - PWND DesktopWindow = NULL; - - if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES)) - { - return FALSE; - } - - CurInfo = IntGetSysCursorInfo(); - - DesktopWindow = UserGetDesktopWindow(); - - if (prcl != NULL && DesktopWindow != NULL) - { - if (prcl->right < prcl->left || prcl->bottom < prcl->top) - { - EngSetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - CurInfo->bClipped = TRUE; - - /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because - it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */ - CurInfo->rcClip.left = max(prcl->left, DesktopWindow->rcWindow.left); - CurInfo->rcClip.right = min(prcl->right, DesktopWindow->rcWindow.right); - if (CurInfo->rcClip.right < CurInfo->rcClip.left) - CurInfo->rcClip.right = CurInfo->rcClip.left; - - CurInfo->rcClip.top = max(prcl->top, DesktopWindow->rcWindow.top); - CurInfo->rcClip.bottom = min(prcl->bottom, DesktopWindow->rcWindow.bottom); - if (CurInfo->rcClip.bottom < CurInfo->rcClip.top) - CurInfo->rcClip.bottom = CurInfo->rcClip.top; - - /* Make sure cursor is in clipping region */ - UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE); - } - else - { - CurInfo->bClipped = FALSE; - } - - return TRUE; -} - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserClipCursor( - RECTL *prcl) -{ - RECTL rclLocal; - BOOL bResult; - - if (prcl) - { - _SEH2_TRY - { - /* Probe and copy rect */ - ProbeForRead(prcl, sizeof(RECTL), 1); - rclLocal = *prcl; - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - EngSetLastError(ERROR_INVALID_PARAMETER); - _SEH2_YIELD(return FALSE;) - } - _SEH2_END - - prcl = &rclLocal; - } - - UserEnterExclusive(); - - /* Call the internal function */ - bResult = UserClipCursor(prcl); - - UserLeave(); - - return bResult; -} - - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserDestroyCursor( - _In_ HANDLE hCurIcon, - _In_ BOOL bForce) -{ - BOOL ret; - PCURICON_OBJECT CurIcon = NULL; - - TRACE("Enter NtUserDestroyCursorIcon (%p, %u)\n", hCurIcon, bForce); - UserEnterExclusive(); - - CurIcon = UserGetCurIconObject(hCurIcon); - if (!CurIcon) - { - ret = FALSE; - goto leave; - } - - if (!bForce) - { - /* Can not destroy global objects */ - if (CurIcon->head.ppi == NULL) - { - ERR("Trying to delete global cursor!\n"); - ret = TRUE; - goto leave; - } - - /* Maybe we have good reasons not to destroy this object */ - if (CurIcon->head.ppi != PsGetCurrentProcessWin32Process()) - { - /* No way, you're not touching my cursor */ - ret = FALSE; - goto leave; - } - - if (CurIcon->CURSORF_flags & CURSORF_CURRENT) - { - WARN("Trying to delete current cursor!\n"); - ret = FALSE; - goto leave; - } - - if (CurIcon->CURSORF_flags & CURSORF_LRSHARED) - { - WARN("Trying to delete shared cursor.\n"); - /* This one is not an error */ - ret = TRUE; - goto leave; - } - } - - /* Destroy the handle */ - ret = IntDestroyCurIconObject(CurIcon); - -leave: - if (CurIcon) - UserDereferenceObject(CurIcon); - TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n", ret); - UserLeave(); - return ret; -} - - -/* - * @implemented - */ -HICON -NTAPI -NtUserFindExistingCursorIcon( - _In_ PUNICODE_STRING pustrModule, - _In_ PUNICODE_STRING pustrRsrc, - _In_ FINDEXISTINGCURICONPARAM* param) -{ - PCURICON_OBJECT CurIcon; - HICON Ret = NULL; - UNICODE_STRING ustrModuleSafe, ustrRsrcSafe; - FINDEXISTINGCURICONPARAM paramSafe; - NTSTATUS Status; - PPROCESSINFO pProcInfo = PsGetCurrentProcessWin32Process(); - RTL_ATOM atomModName; - - TRACE("Enter NtUserFindExistingCursorIcon\n"); - - - _SEH2_TRY - { - ProbeForRead(param, sizeof(*param), 1); - RtlCopyMemory(¶mSafe, param, sizeof(paramSafe)); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _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; - } - - UserEnterShared(); - 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; - } - // - // Now search Global Cursors or Icons. - // - if(CurIcon == NULL) - { - CurIcon = gcurFirst; - 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) - Ret = CurIcon->head.h; - UserLeave(); - -done: - if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer)) - ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING); - - return Ret; -} - - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserGetClipCursor( - RECTL *lpRect) -{ - PSYSTEM_CURSORINFO CurInfo; - RECTL Rect; - NTSTATUS Status; - DECLARE_RETURN(BOOL); - - TRACE("Enter NtUserGetClipCursor\n"); - UserEnterShared(); - - if (!CheckWinstaAttributeAccess(WINSTA_READATTRIBUTES)) - { - RETURN(FALSE); - } - - if (!lpRect) - RETURN(FALSE); - - CurInfo = IntGetSysCursorInfo(); - if (CurInfo->bClipped) - { - Rect = CurInfo->rcClip; - } - else - { - Rect.left = 0; - Rect.top = 0; - Rect.right = UserGetSystemMetrics(SM_CXSCREEN); - Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN); - } - - Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT)); - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - RETURN(FALSE); - } - - RETURN(TRUE); - -CLEANUP: - TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_); - UserLeave(); - END_CLEANUP; -} - - -/* - * @implemented - */ -HCURSOR -APIENTRY -NtUserSetCursor( - HCURSOR hCursor) -{ - PCURICON_OBJECT pcurOld, pcurNew; - HCURSOR hOldCursor = NULL; - - TRACE("Enter NtUserSetCursor: %p\n", hCursor); - UserEnterExclusive(); - - if (hCursor) - { - pcurNew = UserGetCurIconObject(hCursor); - if (!pcurNew) - { - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - goto leave; - } - pcurNew->CURSORF_flags |= CURSORF_CURRENT; - } - else - { - pcurNew = NULL; - } - - pcurOld = UserSetCursor(pcurNew, FALSE); - if (pcurOld) - { - hOldCursor = pcurOld->head.h; - /* - Problem: - - System Global Cursors start out having at least 2 lock counts. If a system - cursor is the default cursor and is returned to the caller twice in its - life, the count will reach zero. Causing an assert to occur in objects. - - This fixes a SeaMonkey crash while the mouse crosses a boundary. - */ - if (pcurOld->CURSORF_flags & CURSORF_GLOBAL) - { - TRACE("Returning Global Cursor hcur %p\n",hOldCursor); - goto leave; - } - - /* See if it was destroyed in the meantime */ - if (UserObjectInDestroy(hOldCursor)) - hOldCursor = NULL; - pcurOld->CURSORF_flags &= ~CURSORF_CURRENT; - UserDereferenceObject(pcurOld); - } - -leave: - UserLeave(); - return hOldCursor; -} - - -/* - * @unimplemented - */ -BOOL -APIENTRY -NtUserSetCursorContents( - HANDLE hCurIcon, - PICONINFO UnsafeIconInfo) -{ - FIXME(" is UNIMPLEMENTED.\n"); - return FALSE; -} - - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserSetCursorIconData( - _In_ HCURSOR Handle, - _In_opt_ PUNICODE_STRING pustrModule, - _In_opt_ PUNICODE_STRING pustrRsrc, - _In_ const CURSORDATA* pCursorData) -{ - PCURICON_OBJECT CurIcon; - NTSTATUS Status = STATUS_SUCCESS; - BOOLEAN Ret = FALSE; - BOOLEAN IsShared = FALSE, IsAnim = FALSE; - DWORD numFrames; - UINT i = 0; - - TRACE("Enter NtUserSetCursorIconData\n"); - - UserEnterExclusive(); - - if (!(CurIcon = UserGetCurIconObject(Handle))) - { - UserLeave(); - EngSetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - _SEH2_TRY - { - 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->yHotspot = pCursorData->yHotspot; - CurIcon->cx = pCursorData->cx; - CurIcon->cy = pCursorData->cy; - CurIcon->rt = pCursorData->rt; - CurIcon->bpp = pCursorData->bpp; - CurIcon->hbmMask = pCursorData->hbmMask; - CurIcon->hbmColor = pCursorData->hbmColor; - CurIcon->hbmAlpha = pCursorData->hbmAlpha; - CurIcon->CURSORF_flags = pCursorData->CURSORF_flags; - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END - - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - goto done; - } - - 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; - } - - // Support global public cursors and icons too. - if(!IsAnim || IsShared) - { - if(pustrRsrc && pustrModule) - { - UNICODE_STRING ustrModuleSafe; - /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */ - Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->strName, pustrRsrc); - if(!NT_SUCCESS(Status)) - goto done; - 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)) - goto done; - } - } - - if(!CurIcon->hbmMask) - { - ERR("NtUserSetCursorIconData was got no hbmMask.\n"); - EngSetLastError(ERROR_INVALID_PARAMETER); - goto done; - } - - GreSetObjectOwner(CurIcon->hbmMask, GDI_OBJ_HMGR_PUBLIC); - - if(CurIcon->hbmColor) - GreSetObjectOwner(CurIcon->hbmColor, GDI_OBJ_HMGR_PUBLIC); - - if(CurIcon->hbmAlpha) - GreSetObjectOwner(CurIcon->hbmAlpha, GDI_OBJ_HMGR_PUBLIC); - - if(IsShared) - { - /* Update process cache in case of shared cursor */ - PPROCESSINFO ppi = CurIcon->head.ppi; - UserReferenceObject(CurIcon); - CurIcon->pcurNext = ppi->pCursorCache; - ppi->pCursorCache = CurIcon; - CurIcon->CURSORF_flags |= CURSORF_LINKED; - } - - Ret = TRUE; - -done: - if(!Ret && (!IsAnim || IsShared)) - { - if(!IS_INTRESOURCE(CurIcon->strName.Buffer)) - ExFreePoolWithTag(CurIcon->strName.Buffer, TAG_STRING); - } - - if(!Ret && IsAnim) - { - PACON AniCurIcon = (PACON)CurIcon; - for(i = 0; i < numFrames; i++) - { - if(AniCurIcon->aspcur[i]) - { - UserDereferenceObject(AniCurIcon->aspcur[i]); - IntDestroyCurIconObject(AniCurIcon->aspcur[i]); - } - } - AniCurIcon->cicur = 0; - AniCurIcon->cpcur = 0; - ExFreePoolWithTag(AniCurIcon->aspcur, USERTAG_CURSOR); - AniCurIcon->aspcur = NULL; - AniCurIcon->aicur = NULL; - AniCurIcon->ajifRate = NULL; - } - - UserDereferenceObject(CurIcon); - TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret); - UserLeave(); - - return Ret; -} - -/* Mostly inspired from wine code. - * We use low level functions because: - * - at this point, the icon bitmap could have a different bit depth than the DC, - * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap. - * This happens after a mode setting change. - * - it avoids massive GDI objects locking when only the destination surface needs it. - * - It makes (small) performance gains. - */ -BOOL -UserDrawIconEx( - HDC hDc, - INT xLeft, - INT yTop, - PCURICON_OBJECT pIcon, - INT cxWidth, - INT cyHeight, - UINT istepIfAniCur, - HBRUSH hbrFlickerFreeDraw, - UINT diFlags) -{ - PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL; - PDC pdc = NULL; - BOOL Ret = FALSE; - HBITMAP hbmMask, hbmColor, hbmAlpha; - BOOL bOffScreen; - RECTL rcDest, rcSrc; - CLIPOBJ* pdcClipObj = NULL; - EXLATEOBJ exlo; - - /* Stupid case */ - if((diFlags & DI_NORMAL) == 0) - { - ERR("DrawIconEx called without mask or color bitmap to draw.\n"); - 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; - hbmColor = pIcon->hbmColor; - hbmAlpha = pIcon->hbmAlpha; - - /* - * Get our objects. - * Shared locks are enough, we are only reading those bitmaps - */ - psurfMask = SURFACE_ShareLockSurface(hbmMask); - if(psurfMask == NULL) - { - ERR("Unable to lock the mask surface.\n"); - return FALSE; - } - - /* Color bitmap is not mandatory */ - if(hbmColor == NULL) - { - /* But then the mask bitmap must have the information in it's bottom half */ - ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->cy); - psurfColor = NULL; - } - else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL) - { - ERR("Unable to lock the color bitmap.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - return FALSE; - } - - pdc = DC_LockDc(hDc); - if(!pdc) - { - ERR("Could not lock the destination DC.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - return FALSE; - } - - /* Fix width parameter, if needed */ - if (!cxWidth) - { - if(diFlags & DI_DEFAULTSIZE) - cxWidth = is_icon(pIcon) ? - UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR); - else - cxWidth = pIcon->cx; - } - - /* Fix height parameter, if needed */ - if (!cyHeight) - { - if(diFlags & DI_DEFAULTSIZE) - cyHeight = is_icon(pIcon) ? - UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR); - else - cyHeight = pIcon->cy; - } - - /* Calculate destination rectangle */ - RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); - IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); - RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); - - /* Prepare the underlying surface */ - DC_vPrepareDCsForBlit(pdc, &rcDest, NULL, NULL); - - /* We now have our destination surface and rectangle */ - psurfDest = pdc->dclevel.pSurface; - - if(psurfDest == NULL) - { - /* Empty DC */ - DC_vFinishBlit(pdc, NULL); - DC_UnlockDc(pdc); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - return FALSE; - } - - /* Set source rect */ - RECTL_vSetRect(&rcSrc, 0, 0, pIcon->cx, pIcon->cy); - - /* Should we render off-screen? */ - bOffScreen = hbrFlickerFreeDraw && - (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH); - - if (bOffScreen) - { - /* Yes: Allocate and paint the offscreen surface */ - EBRUSHOBJ eboFill; - PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw); - - TRACE("Performing off-screen rendering.\n"); - - if(!pbrush) - { - ERR("Failed to get brush object.\n"); - goto Cleanup; - } - -#if 0 //We lock the hdc surface during the whole function it makes no sense to use an offscreen surface for "flicker free" drawing - psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP, - cxWidth, cyHeight, psurfDest->SurfObj.iBitmapFormat, - 0, 0, NULL); - if(!psurfOffScreen) - { - ERR("Failed to allocate the off-screen surface.\n"); - BRUSH_ShareUnlockBrush(pbrush); - goto Cleanup; - } - - /* Paint the brush */ - EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL); - RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight); - - Ret = IntEngBitBlt(&psurfOffScreen->SurfObj, - NULL, - NULL, - NULL, - NULL, - &rcDest, - NULL, - NULL, - &eboFill.BrushObject, - &pbrush->ptOrigin, - ROP4_PATCOPY); - - /* Clean up everything */ - EBRUSHOBJ_vCleanup(&eboFill); - BRUSH_ShareUnlockBrush(pbrush); - - if(!Ret) - { - ERR("Failed to paint the off-screen surface.\n"); - goto Cleanup; - } - - /* We now have our destination surface */ - psurfDest = psurfOffScreen; -#else - pdcClipObj = &pdc->co.ClipObj; - /* Paint the brush */ - EBRUSHOBJ_vInit(&eboFill, pbrush, psurfDest, 0x00FFFFFF, 0, NULL); - - Ret = IntEngBitBlt(&psurfDest->SurfObj, - NULL, - NULL, - pdcClipObj, - NULL, - &rcDest, - NULL, - NULL, - &eboFill.BrushObject, - &pbrush->ptOrigin, - ROP4_PATCOPY); - - /* Clean up everything */ - EBRUSHOBJ_vCleanup(&eboFill); - BRUSH_ShareUnlockBrush(pbrush); - - if(!Ret) - { - ERR("Failed to paint the off-screen surface.\n"); - goto Cleanup; - } -#endif - } - else - { - /* We directly draw to the DC */ - TRACE("Performing on screen rendering.\n"); - pdcClipObj = &pdc->co.ClipObj; - // psurfOffScreen = NULL; - } - - /* Now do the rendering */ - if(hbmAlpha && ((diFlags & DI_NORMAL) == DI_NORMAL)) - { - BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } }; - PSURFACE psurf = NULL; - - psurf = SURFACE_ShareLockSurface(hbmAlpha); - if(!psurf) - { - ERR("SURFACE_LockSurface failed!\n"); - goto NoAlpha; - } - - /* Initialize color translation object */ - EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0); - - /* Now do it */ - Ret = IntEngAlphaBlend(&psurfDest->SurfObj, - &psurf->SurfObj, - pdcClipObj, - &exlo.xlo, - &rcDest, - &rcSrc, - &blendobj); - - EXLATEOBJ_vCleanup(&exlo); - SURFACE_ShareUnlockSurface(psurf); - if(Ret) goto done; - ERR("NtGdiAlphaBlend failed!\n"); - } -NoAlpha: - if (diFlags & DI_MASK) - { - DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY; - - EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0); - - Ret = IntEngStretchBlt(&psurfDest->SurfObj, - &psurfMask->SurfObj, - NULL, - pdcClipObj, - &exlo.xlo, - NULL, - &rcDest, - &rcSrc, - NULL, - NULL, - NULL, - rop4); - - EXLATEOBJ_vCleanup(&exlo); - - if(!Ret) - { - ERR("Failed to mask the bitmap data.\n"); - goto Cleanup; - } - } - - if(diFlags & DI_IMAGE) - { - if (psurfColor) - { - DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ; - - EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0); - - Ret = IntEngStretchBlt(&psurfDest->SurfObj, - &psurfColor->SurfObj, - NULL, - pdcClipObj, - &exlo.xlo, - NULL, - &rcDest, - &rcSrc, - NULL, - NULL, - NULL, - rop4); - - EXLATEOBJ_vCleanup(&exlo); - - if(!Ret) - { - ERR("Failed to render the icon bitmap.\n"); - goto Cleanup; - } - } - else - { - /* Mask bitmap holds the information in its bottom half */ - DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY; - RECTL_vOffsetRect(&rcSrc, 0, pIcon->cy); - - EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0); - - Ret = IntEngStretchBlt(&psurfDest->SurfObj, - &psurfMask->SurfObj, - NULL, - pdcClipObj, - &exlo.xlo, - NULL, - &rcDest, - &rcSrc, - NULL, - NULL, - NULL, - rop4); - - EXLATEOBJ_vCleanup(&exlo); - - if(!Ret) - { - ERR("Failed to render the icon bitmap.\n"); - goto Cleanup; - } - } - } - -done: -#if 0 - /* We're done. Was it a double buffered draw ? */ - if(bOffScreen) - { - /* Yes. Draw it back to our DC */ - POINTL ptSrc = {0, 0}; - - /* Calculate destination rectangle */ - RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight); - IntLPtoDP(pdc, (LPPOINT)&rcDest, 2); - RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); - - /* Get the clip object */ - pdcClipObj = pdc->rosdc.CombinedClip; - - /* We now have our destination surface and rectangle */ - psurfDest = pdc->dclevel.pSurface; - - /* Color translation */ - EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0); - - /* Blt it! */ - Ret = IntEngBitBlt(&psurfDest->SurfObj, - &psurfOffScreen->SurfObj, - NULL, - pdcClipObj, - &exlo.xlo, - &rcDest, - &ptSrc, - NULL, - NULL, - NULL, - ROP4_SRCCOPY); - - EXLATEOBJ_vCleanup(&exlo); - } -#endif -Cleanup: - if(pdc) - { - DC_vFinishBlit(pdc, NULL); - DC_UnlockDc(pdc); - } - -#if 0 - /* Delete off screen rendering surface */ - if(psurfOffScreen) - GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject); -#endif - - /* Unlock other surfaces */ - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - - return Ret; -} - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserDrawIconEx( - HDC hdc, - int xLeft, - int yTop, - HICON hIcon, - int cxWidth, - int cyHeight, - UINT istepIfAniCur, - HBRUSH hbrFlickerFreeDraw, - UINT diFlags, - BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32! - PVOID pDIXData) -{ - PCURICON_OBJECT pIcon; - BOOL Ret; - - TRACE("Enter NtUserDrawIconEx\n"); - UserEnterExclusive(); - - if (!(pIcon = UserGetCurIconObject(hIcon))) - { - ERR("UserGetCurIconObject(0x%08x) failed!\n", hIcon); - UserLeave(); - return FALSE; - } - - Ret = UserDrawIconEx(hdc, - xLeft, - yTop, - pIcon, - cxWidth, - cyHeight, - istepIfAniCur, - hbrFlickerFreeDraw, - diFlags); - - UserDereferenceObject(pIcon); - - UserLeave(); - 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"); - UserEnterShared(); - - 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; -} - -/* - * @implemented - */ -BOOL -APIENTRY -NtUserSetSystemCursor( - HCURSOR hcur, - DWORD id) -{ - PCURICON_OBJECT pcur, pcurOrig = NULL; - int i; - PPROCESSINFO ppi; - BOOL Ret = FALSE; - UserEnterExclusive(); - - if (!CheckWinstaAttributeAccess(WINSTA_WRITEATTRIBUTES)) - { - goto Exit; - } - - if (hcur) - { - pcur = UserGetCurIconObject(hcur); - if (!pcur) - { - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - goto Exit; - } - - ppi = PsGetCurrentProcessWin32Process(); - - for(i = 0 ; i < 16; i++) - { - if (gasyscur[i].type == id) - { - pcurOrig = gasyscur[i].handle; - - if (pcurOrig) break; - - if (ppi->W32PF_flags & W32PF_CREATEDWINORDC) - { - gasyscur[i].handle = pcur; - pcur->CURSORF_flags |= CURSORF_GLOBAL|CURSORF_LINKED; - UserReferenceObject(pcur); - pcur->head.ppi = NULL; - pcur->pcurNext = gcurFirst; - gcurFirst = pcur; - Ret = TRUE; - } - break; - } - } - if (pcurOrig) - { - FIXME("Need to copy cursor data or do something! pcurOrig %p new pcur %p\n",pcurOrig,pcur); - } - } -Exit: - UserLeave(); - return Ret; -} - -/* EOF */ diff --git a/reactos/win32ss/user/ntuser/defwnd.c b/reactos/win32ss/user/ntuser/defwnd.c index e7e21be47f8..3fee813f1c4 100644 --- a/reactos/win32ss/user/ntuser/defwnd.c +++ b/reactos/win32ss/user/ntuser/defwnd.c @@ -301,11 +301,7 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) RECT sizingRect, mouseRect, origRect, unmodRect; HDC hdc; LONG hittest = (LONG)(wParam & 0x0f); -#ifdef NEW_CURSORICON PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL; -#else - HCURSOR hDragCursor = 0, hOldCursor = 0; -#endif POINT minTrack, maxTrack; POINT capturePoint, pt; ULONG Style, ExStyle; @@ -413,7 +409,6 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) } hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE ); -#ifdef NEW_CURSORICON if (iconic) { DragCursor = pwnd->pcls->spicn; @@ -434,14 +429,6 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) } } } -#else - if ( iconic ) /* create a cursor for dragging */ - { - hDragCursor = pwnd->pcls->hIcon; - if ( !hDragCursor ) hDragCursor = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 ); - if ( !hDragCursor ) iconic = FALSE; - } -#endif /* repaint the window before moving it around */ co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN); @@ -500,11 +487,7 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) moved = TRUE; if ( iconic ) /* ok, no system popup tracking */ { -#ifdef NEW_CURSORICON OldCursor = UserSetCursor(DragCursor, FALSE); -#else - hOldCursor = IntSetCursor(hDragCursor); -#endif UserShowCursor( TRUE ); } else if(!DragFullWindows) @@ -588,21 +571,14 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) if ( moved ) /* restore cursors, show icon title later on */ { UserShowCursor( FALSE ); -#ifdef NEW_CURSORICON OldCursor = UserSetCursor(OldCursor, FALSE); -#else - IntSetCursor( hOldCursor ); -#endif } -#ifdef NEW_CURSORICON + /* It could be that the cursor was already changed while we were proceeding, * so we must unreference whatever cursor was current at the time we restored the old one. * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed. */ if (OldCursor) UserDereferenceObject(OldCursor); -#else - IntDestroyCursor( hDragCursor, FALSE ); -#endif } else if ( moved && !DragFullWindows ) UserDrawMovingFrame( hdc, &sizingRect, thickframe ); @@ -831,7 +807,7 @@ DefWndHandleSetCursor(PWND pWnd, WPARAM wParam, LPARAM lParam) { if (pwndPopUP) { - FLASHWINFO fwi = + FLASHWINFO fwi = {sizeof(FLASHWINFO), UserHMGetHandle(pwndPopUP), FLASHW_ALL, @@ -1112,7 +1088,6 @@ IntDefWindowProc( hDC = IntBeginPaint(Wnd, &Ps); if (hDC) { -#ifdef NEW_CURSORICON if (((Wnd->style & WS_MINIMIZE) != 0) && (Wnd->pcls->spicn)) { RECT ClientRect; @@ -1124,22 +1099,7 @@ IntDefWindowProc( y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2; UserDrawIconEx(hDC, x, y, Wnd->pcls->spicn, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE); } -#else - HICON hIcon; - if (((Wnd->style & WS_MINIMIZE) != 0) && (hIcon = Wnd->pcls->hIcon)) - { - RECT ClientRect; - INT x, y; - PCURICON_OBJECT pIcon; - if (!(pIcon = UserGetCurIconObject(hIcon))) return 0; - ERR("Doing Paint and Client area is empty!\n"); - IntGetClientRect(Wnd, &ClientRect); - x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2; - y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2; - UserDrawIconEx( hDC, x, y, pIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE ); - UserDereferenceObject(pIcon); - } -#endif + IntEndPaint(Wnd, &Ps); } return (0); @@ -1245,15 +1205,11 @@ PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd ) hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp); if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp); -#ifdef NEW_CURSORICON + if (!hIcon && pWnd->pcls->spicnSm) return pWnd->pcls->spicnSm; if (!hIcon && pWnd->pcls->spicn) return pWnd->pcls->spicn; -#else - if (!hIcon) hIcon = pWnd->pcls->hIconSm; - if (!hIcon) hIcon = pWnd->pcls->hIcon; -#endif if (!hIcon && (pWnd->style & DS_MODALFRAME)) { diff --git a/reactos/win32ss/user/ntuser/desktop.c b/reactos/win32ss/user/ntuser/desktop.c index 5184ae36f8c..7d48454048c 100644 --- a/reactos/win32ss/user/ntuser/desktop.c +++ b/reactos/win32ss/user/ntuser/desktop.c @@ -666,15 +666,12 @@ DesktopWindowProc(PWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lRe { return TRUE; } -#ifdef NEW_CURSORICON + pcurNew->CURSORF_flags |= CURSORF_CURRENT; -#endif pcurOld = UserSetCursor(pcurNew, FALSE); if (pcurOld) { -#ifdef NEW_CURSORICON pcurOld->CURSORF_flags &= ~CURSORF_CURRENT; -#endif UserDereferenceObject(pcurOld); } return TRUE; diff --git a/reactos/win32ss/user/ntuser/main.c b/reactos/win32ss/user/ntuser/main.c index 8454ca2d242..7ec500d4b0b 100644 --- a/reactos/win32ss/user/ntuser/main.c +++ b/reactos/win32ss/user/ntuser/main.c @@ -220,10 +220,8 @@ UserProcessDestroy(PEPROCESS Process) ppiCurrent->hdeskStartup = NULL; } -#ifdef NEW_CURSORICON /* Clean up the process icon cache */ IntCleanupCurIconCache(ppiCurrent); -#endif return STATUS_SUCCESS; } diff --git a/reactos/win32ss/user/ntuser/msgqueue.c b/reactos/win32ss/user/ntuser/msgqueue.c index 05be9ca872c..af082e31f53 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.c +++ b/reactos/win32ss/user/ntuser/msgqueue.c @@ -118,7 +118,6 @@ UserSetCursor( if (NewCursor) { /* Call GDI to set the new screen cursor */ -#ifdef NEW_CURSORICON PCURICON_OBJECT CursorFrame = NewCursor; if(NewCursor->CURSORF_flags & CURSORF_ACON) { @@ -133,16 +132,6 @@ UserSetCursor( gpsi->ptCursor.x, gpsi->ptCursor.y, CursorFrame->hbmAlpha ? SPS_ALPHA : 0); -#else - GreSetPointerShape(hdcScreen, - NewCursor->IconInfo.hbmMask, - NewCursor->IconInfo.hbmColor, - NewCursor->IconInfo.xHotspot, - NewCursor->IconInfo.yHotspot, - gpsi->ptCursor.x, - gpsi->ptCursor.y, - 0); -#endif } else /* Note: OldCursor != NewCursor so we have to hide cursor */ { @@ -663,7 +652,6 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject) { /* Call GDI to set the new screen cursor */ -#ifdef NEW_CURSORICON GreSetPointerShape(hdcScreen, MessageQueue->CursorObject->hbmAlpha ? NULL : MessageQueue->CursorObject->hbmMask, @@ -674,16 +662,7 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook gpsi->ptCursor.x, gpsi->ptCursor.y, MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0); -#else - GreSetPointerShape(hdcScreen, - MessageQueue->CursorObject->IconInfo.hbmMask, - MessageQueue->CursorObject->IconInfo.hbmColor, - MessageQueue->CursorObject->IconInfo.xHotspot, - MessageQueue->CursorObject->IconInfo.yHotspot, - gpsi->ptCursor.x, - gpsi->ptCursor.y, - 0); -#endif + } else GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); } diff --git a/reactos/win32ss/user/ntuser/object.c b/reactos/win32ss/user/ntuser/object.c index b6c47e0c1d5..3501d670412 100644 --- a/reactos/win32ss/user/ntuser/object.c +++ b/reactos/win32ss/user/ntuser/object.c @@ -218,11 +218,7 @@ static const struct { NULL, NULL, NULL }, /* TYPE_FREE */ { AllocDeskThreadObject, co_UserDestroyWindow, FreeDeskThreadObject }, /* TYPE_WINDOW */ { AllocDeskProcObject, UserDestroyMenuObject, FreeDeskProcObject }, /* TYPE_MENU */ -#ifndef NEW_CURSORICON - { AllocProcMarkObject, /*UserCursorCleanup*/NULL, FreeProcMarkObject }, /* TYPE_CURSOR */ -#else { AllocProcMarkObject, IntDestroyCurIconObject, FreeCurIconObject }, /* TYPE_CURSOR */ -#endif { AllocSysObject, /*UserSetWindowPosCleanup*/NULL, FreeSysObject }, /* TYPE_SETWINDOWPOS */ { AllocDeskThreadObject, IntRemoveHook, FreeDeskThreadObject }, /* TYPE_HOOK */ { AllocSysObject, /*UserClipDataCleanup*/NULL,FreeSysObject }, /* TYPE_CLIPDATA */ @@ -694,43 +690,6 @@ UserReferenceObjectByHandle(HANDLE handle, HANDLE_TYPE type) return object; } -#ifndef NEW_CURSORICON -VOID -FASTCALL -UserSetObjectOwner(PVOID obj, HANDLE_TYPE type, PVOID owner) -{ - PUSER_HANDLE_ENTRY entry = handle_to_entry(gHandleTable, ((PHEAD)obj)->h ); - PPROCESSINFO ppi, oldppi; - - /* This must be called with a valid object */ - ASSERT(entry); - - /* For now, only supported for CursorIcon object */ - switch(type) - { - case TYPE_CURSOR: - ppi = (PPROCESSINFO)owner; - entry->pi = ppi; - oldppi = ((PPROCMARKHEAD)obj)->ppi; - ((PPROCMARKHEAD)obj)->ppi = ppi; - break; - default: - ASSERT(FALSE); - return; - } - -#if DBG - oldppi->DbgHandleCount[type]--; - ppi->DbgHandleCount[type]++; -#endif - - oldppi->UserHandleCount--; - IntDereferenceProcessInfo(oldppi); - ppi->UserHandleCount++; - IntReferenceProcessInfo(ppi); -} -#endif - BOOLEAN UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner) { @@ -750,19 +709,6 @@ UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner) if (Entry->flags & HANDLEENTRY_INDESTROY) continue; -#ifndef NEW_CURSORICON - /* Spcial case for cursors until cursoricon_new is there */ - if (Entry->type == TYPE_CURSOR) - { - UserReferenceObject(Entry->ptr); - if (!IntDestroyCurIconObject(Entry->ptr, Owner)) - { - Ret = FALSE; - } - continue; - } -#endif - /* Call destructor */ if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr)) { @@ -774,7 +720,7 @@ UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner) return Ret; } - + /* * NtUserValidateHandleSecure W2k3 has one argument. * diff --git a/reactos/win32ss/user/ntuser/object.h b/reactos/win32ss/user/ntuser/object.h index 1ed672b8700..7fbe46bf631 100644 --- a/reactos/win32ss/user/ntuser/object.h +++ b/reactos/win32ss/user/ntuser/object.h @@ -17,9 +17,6 @@ PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE, HANDLE, HANDLE_TYPE); BOOL FASTCALL UserCreateHandleTable(VOID); BOOL FASTCALL UserObjectInDestroy(HANDLE); void DbgUserDumpHandleTable(); -#ifndef NEW_CURSORICON -VOID FASTCALL UserSetObjectOwner(PVOID obj, HANDLE_TYPE type, PVOID owner); -#endif PVOID FASTCALL ValidateHandle(HANDLE handle, HANDLE_TYPE type); BOOLEAN UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner); diff --git a/reactos/win32ss/user/ntuser/windc.c b/reactos/win32ss/user/ntuser/windc.c index 578f3e2c56d..cc3d775d86b 100644 --- a/reactos/win32ss/user/ntuser/windc.c +++ b/reactos/win32ss/user/ntuser/windc.c @@ -403,11 +403,7 @@ UserGetDCEx(PWND Wnd OPTIONAL, HANDLE ClipRegion, ULONG Flags) Flags |= DCX_CLIPCHILDREN; } /* If minized with icon in the set, we are forced to be cheap! */ -#ifdef NEW_CURSORICON if (Wnd->style & WS_MINIMIZE && Wnd->pcls->spicn) -#else - if (Wnd->style & WS_MINIMIZE && Wnd->pcls->hIcon) -#endif { Flags |= DCX_CACHE; } diff --git a/reactos/win32ss/user/ntuser/window.c b/reactos/win32ss/user/ntuser/window.c index aa3122d881e..2012f69f6ec 100644 --- a/reactos/win32ss/user/ntuser/window.c +++ b/reactos/win32ss/user/ntuser/window.c @@ -125,7 +125,7 @@ IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits ) pwnd->style = styleNew; if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change. { - if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--; + if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--; if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++; DceResetActiveDCEs( pwnd ); } @@ -340,7 +340,7 @@ IntGetWindow(HWND hWnd, if (Wnd->spwndPrev != NULL) FoundWnd = Wnd->spwndPrev; break; - + case GW_CHILD: if (Wnd->spwndChild != NULL) FoundWnd = Wnd->spwndChild; @@ -563,7 +563,7 @@ LRESULT co_UserFreeWindow(PWND Window, /* Fixes dialog test_focus breakage due to r66237. */ if (ThreadData->MessageQueue->spwndFocus == Window) ThreadData->MessageQueue->spwndFocus = NULL; - + if (ThreadData->MessageQueue->spwndActive == Window) ThreadData->MessageQueue->spwndActive = NULL; @@ -1450,7 +1450,7 @@ NtUserBuildHwndList( dwCount++; } } - } + } ObDereferenceObject(Thread); } @@ -1671,7 +1671,7 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs, } pWnd->head.pti->cWindows++; -#ifdef NEW_CURSORICON + if (Class->spicn && !Class->spicnSm) { HICON IconSmHandle = NULL; @@ -1702,16 +1702,6 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs, Class->CSF_flags |= CSF_CACHEDSMICON; } } -#else - if (Class->hIcon && !Class->hIconSm) - { - Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON, - UserGetSystemMetrics( SM_CXSMICON ), - UserGetSystemMetrics( SM_CYSMICON ), 0 ); - TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern); - Class->CSF_flags |= CSF_CACHEDSMICON; - } -#endif if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC) pWnd->state |= WNDS_SERVERSIDEWINDOWPROC; @@ -2135,7 +2125,7 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs, if (ParentWindow != co_GetDesktopWindow(Window)) { Cs->x += ParentWindow->rcClient.left; - Cs->y += ParentWindow->rcClient.top; + Cs->y += ParentWindow->rcClient.top; } } @@ -2168,7 +2158,7 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs, /* correct child window coordinates if mirroring on parent is enabled */ if (ParentWindow != NULL) { - if ( ((Cs->style & WS_CHILD) == WS_CHILD) && + if ( ((Cs->style & WS_CHILD) == WS_CHILD) && ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL)) { Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left); @@ -2433,7 +2423,7 @@ NtUserCreateWindowEx( ASSERT(plstrWindowName); - if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD) + if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD) { /* check hMenu is valid handle */ if (hMenu && !UserGetMenuObject(hMenu)) @@ -2442,7 +2432,7 @@ NtUserCreateWindowEx( EngSetLastError(ERROR_INVALID_MENU_HANDLE); return NULL; } - } + } /* Copy the window name to kernel mode */ Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName); @@ -3244,7 +3234,7 @@ NtUserGetComboBoxInfo( SetLastNtError(_SEH2_GetExceptionCode()); } _SEH2_END; - + RETURN( Ret); CLEANUP: @@ -3332,7 +3322,7 @@ NtUserGetListBoxInfo( SetLastNtError(_SEH2_GetExceptionCode()); } _SEH2_END; - + RETURN( Ret); CLEANUP: @@ -3712,7 +3702,7 @@ NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) ret = co_IntSetWindowLong(hWnd, Index, NewValue, Ansi, FALSE); UserLeave(); - + return ret; } @@ -3733,7 +3723,7 @@ NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue) ret = co_IntSetWindowLong(hWnd, Index, NewValue, FALSE, TRUE); UserLeave(); - + return ret; } diff --git a/reactos/win32ss/user/user32/CMakeLists.txt b/reactos/win32ss/user/user32/CMakeLists.txt index b17170f04ca..409d325255a 100644 --- a/reactos/win32ss/user/user32/CMakeLists.txt +++ b/reactos/win32ss/user/user32/CMakeLists.txt @@ -40,7 +40,7 @@ list(APPEND SOURCE windows/caret.c windows/class.c windows/clipboard.c -# windows/cursoricon.c + windows/cursoricon.c windows/dc.c windows/defwnd.c windows/dialog.c @@ -63,12 +63,6 @@ list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/user32_stubs.c include/user32.h) -if(USE_NEW_CURSORICON) - list(APPEND SOURCE windows/cursoricon_new.c) -else() - list(APPEND SOURCE windows/cursoricon.c) -endif() - add_library(user32 SHARED ${SOURCE} user32.rc diff --git a/reactos/win32ss/user/user32/windows/class.c b/reactos/win32ss/user/user32/windows/class.c index b46f3f7e1d7..3c9ac499ac4 100644 --- a/reactos/win32ss/user/user32/windows/class.c +++ b/reactos/win32ss/user/user32/windows/class.c @@ -712,7 +712,7 @@ IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex) case GCW_ATOM: Ret = (ULONG_PTR)Class->atomClassName; break; -#ifdef NEW_CURSORICON + case GCLP_HCURSOR: Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0; break; @@ -724,22 +724,6 @@ IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex) case GCLP_HICONSM: Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0; break; -#else - case GCLP_HCURSOR: - /* FIXME - get handle from pointer to CURSOR object */ - Ret = (ULONG_PTR)Class->hCursor; - break; - - case GCLP_HICON: - /* FIXME - get handle from pointer to ICON object */ - Ret = (ULONG_PTR)Class->hIcon; - break; - - case GCLP_HICONSM: - /* FIXME - get handle from pointer to ICON object */ - Ret = (ULONG_PTR)(Class->hIconSm ? Class->hIconSm : Class->hIconSmIntern); - break; -#endif case GCLP_WNDPROC: Ret = IntGetClsWndProc(Wnd, Class, TRUE); @@ -803,7 +787,6 @@ IntGetClassLongW (PWND Wnd, PCLS Class, int nIndex) Ret = (ULONG_PTR)Class->atomClassName; break; -#ifdef NEW_CURSORICON case GCLP_HCURSOR: Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0; break; @@ -815,22 +798,6 @@ IntGetClassLongW (PWND Wnd, PCLS Class, int nIndex) case GCLP_HICONSM: Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0; break; -#else - case GCLP_HCURSOR: - /* FIXME - get handle from pointer to CURSOR object */ - Ret = (ULONG_PTR)Class->hCursor; - break; - - case GCLP_HICON: - /* FIXME - get handle from pointer to ICON object */ - Ret = (ULONG_PTR)Class->hIcon; - break; - - case GCLP_HICONSM: - /* FIXME - get handle from pointer to ICON object */ - Ret = (ULONG_PTR)(Class->hIconSm ? Class->hIconSm : Class->hIconSmIntern); - break; -#endif case GCLP_WNDPROC: Ret = IntGetClsWndProc(Wnd, Class, FALSE); diff --git a/reactos/win32ss/user/user32/windows/cursoricon.c b/reactos/win32ss/user/user32/windows/cursoricon.c index 150b56f714f..c0b29e331c8 100644 --- a/reactos/win32ss/user/user32/windows/cursoricon.c +++ b/reactos/win32ss/user/user32/windows/cursoricon.c @@ -1,25 +1,9 @@ /* - * Cursor and icon support - * - * Copyright 1995 Alexandre Julliard - * 1996 Martin Von Loewis - * 1997 Alex Korobka - * 1998 Turchanov Sergey - * 2007 Henri Verbeet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * PROJECT: ReactOS user32.dll + * COPYRIGHT: GPL - See COPYING in the top level directory + * FILE: win32ss/user//user32/windows/cursoricon.c + * PURPOSE: cursor and icons implementation + * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org) */ #include @@ -28,72 +12,82 @@ WINE_DEFAULT_DEBUG_CHANNEL(cursor); WINE_DECLARE_DEBUG_CHANNEL(icon); -WINE_DECLARE_DEBUG_CHANNEL(resource); +//WINE_DECLARE_DEBUG_CHANNEL(resource); -#include "pshpack1.h" +/* We only use Wide string functions */ +#undef MAKEINTRESOURCE +#define MAKEINTRESOURCE MAKEINTRESOURCEW -typedef struct { - BYTE bWidth; - BYTE bHeight; - BYTE bColorCount; - BYTE bReserved; - WORD xHotspot; - WORD yHotspot; - DWORD dwDIBSize; - DWORD dwDIBOffset; -} CURSORICONFILEDIRENTRY; +/************* USER32 INTERNAL FUNCTIONS **********/ -typedef struct +VOID LoadSystemCursors(VOID) { - WORD idReserved; - WORD idType; - WORD idCount; - CURSORICONFILEDIRENTRY idEntries[1]; -} CURSORICONFILEDIR; - -#include "poppack.h" - -static HDC screen_dc; - -static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0}; - - -static CRITICAL_SECTION IconCrst; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &IconCrst, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") } -}; -static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 }; - -/*********************************************************************** - * CreateCursorIconHandle - * - * Creates a handle with everything in there - */ -static -HICON -CreateCursorIconHandle( PICONINFO IconInfo ) -{ - HICON hIcon = NtUserxCreateEmptyCurObject(0); - if(!hIcon) - return NULL; - - NtUserSetCursorContents(hIcon, IconInfo); - return hIcon; + if (!gpsi->hIconSmWindows) + { + ERR("Loading System Cursors\n"); + NtUserSetSystemCursor(LoadImageW( 0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_NORMAL); + NtUserSetSystemCursor(LoadImageW( 0, IDC_IBEAM, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_IBEAM); + NtUserSetSystemCursor(LoadImageW( 0, IDC_WAIT, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_WAIT); + NtUserSetSystemCursor(LoadImageW( 0, IDC_CROSS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_CROSS); + NtUserSetSystemCursor(LoadImageW( 0, IDC_UPARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_UP); + NtUserSetSystemCursor(LoadImageW( 0, IDC_ICON, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_ICON); + NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZE); + NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENWSE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENWSE); + NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENESW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENESW); + NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEWE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZEWE); + NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENS); + NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEALL, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZEALL); + NtUserSetSystemCursor(LoadImageW( 0, IDC_NO, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_NO); + NtUserSetSystemCursor(LoadImageW( 0, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_HAND); + NtUserSetSystemCursor(LoadImageW( 0, IDC_APPSTARTING, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_APPSTARTING); + NtUserSetSystemCursor(LoadImageW( 0, IDC_HELP, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_HELP); + } } +/* This callback routine is called directly after switching to gui mode */ +NTSTATUS +WINAPI +User32SetupDefaultCursors(PVOID Arguments, + ULONG ArgumentLength) +{ + BOOL *DefaultCursor = (BOOL*)Arguments; + HCURSOR hCursor; + /* Load system cursors first */ + LoadSystemCursors(); + + if(*DefaultCursor) + { + /* set default cursor */ + hCursor = LoadCursorW(0, IDC_ARROW); + SetCursor(hCursor); + } + else + { + /* FIXME load system cursor scheme */ + SetCursor(0); + hCursor = LoadCursorW(0, IDC_ARROW); + SetCursor(hCursor); + } + + return(ZwCallbackReturn(&hCursor, sizeof(HCURSOR), STATUS_SUCCESS)); +} + +BOOL get_icon_size(HICON hIcon, SIZE *size) +{ + return NtUserGetIconSize(hIcon, 0, &size->cx, &size->cy); +} + +HCURSOR CursorIconToCursor(HICON hIcon, BOOL SemiTransparent) +{ + UNIMPLEMENTED; + return NULL; +} + +/************* IMPLEMENTATION HELPERS ******************/ + +static const WCHAR DISPLAYW[] = L"DISPLAY"; -/*********************************************************************** - * map_fileW - * - * Helper function to map a file to memory: - * name - file name - * [RETURN] ptr - pointer to mapped file - * [RETURN] filesize - pointer size of file to be stored if not NULL - */ static void *map_fileW( LPCWSTR name, LPDWORD filesize ) { HANDLE hFile, hMapping; @@ -116,76 +110,11 @@ static void *map_fileW( LPCWSTR name, LPDWORD filesize ) return ptr; } - -/*********************************************************************** - * get_dib_width_bytes - * - * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned. - */ -static int get_dib_width_bytes( int width, int depth ) +static int get_dib_image_size( int width, int height, int depth ) { - int words; - - switch(depth) - { - case 1: words = (width + 31) / 32; break; - case 4: words = (width + 7) / 8; break; - case 8: words = (width + 3) / 4; break; - case 15: - case 16: words = (width + 1) / 2; break; - case 24: words = (width * 3 + 3)/4; break; - default: - WARN("(%d): Unsupported depth\n", depth ); - /* fall through */ - case 32: - words = width; - } - return 4 * words; + return (((width * depth + 31) / 8) & ~3) * abs( height ); } - -/*********************************************************************** - * bitmap_info_size - * - * Return the size of the bitmap info structure including color table. - */ -static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) -{ - unsigned int colors, size, masks = 0; - - if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; - colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; - return sizeof(BITMAPCOREHEADER) + colors * - ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD)); - } - else /* assume BITMAPINFOHEADER */ - { - colors = info->bmiHeader.biClrUsed; - if (colors > 256) /* buffer overflow otherwise */ - colors = 256; - if (!colors && (info->bmiHeader.biBitCount <= 8)) - colors = 1 << info->bmiHeader.biBitCount; - if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; - size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); - return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD)); - } -} - - -/*********************************************************************** - * is_dib_monochrome - * - * Returns whether a DIB can be converted to a monochrome DDB. - * - * A DIB can be converted if its color table contains only black and - * white. Black must be the first color in the color table. - * - * Note : If the first color in the color table is white followed by - * black, we can't convert it to a monochrome DDB with - * SetDIBits, because black and white would be inverted. - */ static BOOL is_dib_monochrome( const BITMAPINFO* info ) { if (info->bmiHeader.biBitCount != 1) return FALSE; @@ -223,12 +152,30 @@ static BOOL is_dib_monochrome( const BITMAPINFO* info ) } } -/*********************************************************************** - * DIB_GetBitmapInfo - * - * Get the info from a bitmap header. - * Return 1 for INFOHEADER, 0 for COREHEADER, - */ +static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) +{ + unsigned int colors, size, masks = 0; + + if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; + colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; + return sizeof(BITMAPCOREHEADER) + colors * + ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD)); + } + else /* assume BITMAPINFOHEADER */ + { + colors = info->bmiHeader.biClrUsed; + if (colors > 256) /* buffer overflow otherwise */ + colors = 256; + if (!colors && (info->bmiHeader.biBitCount <= 8)) + colors = 1 << info->bmiHeader.biBitCount; + if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; + size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); + return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD)); + } +} + static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, LONG *height, WORD *bpp, DWORD *compr ) { @@ -255,347 +202,616 @@ static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, return -1; } - -/* - * The following macro functions account for the irregularities of - * accessing cursor and icon resources in files and resource entries. - */ -typedef BOOL (*fnGetCIEntry)( LPCVOID dir, DWORD size, int n, - int *width, int *height, int *bits ); - -/********************************************************************** - * CURSORICON_FindBestIcon - * - * Find the icon closest to the requested size and bit depth. - */ -static int CURSORICON_FindBestIcon( LPCVOID dir, DWORD size, fnGetCIEntry get_entry, - int width, int height, int depth ) +/* copy an icon bitmap, even when it can't be selected into a DC */ +/* helper for CreateIconIndirect */ +static void stretch_blt_icon(HDC hdc_dst, int dst_width, int dst_height, HBITMAP src) { - int i, cx, cy, bits, bestEntry = -1; - UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff; - UINT iTempXDiff, iTempYDiff, iTempColorDiff; + HDC hdc = CreateCompatibleDC( 0 ); + BITMAP bm; + HBITMAP hbmpPrev; - /* Find Best Fit */ - iTotalDiff = 0xFFFFFFFF; - iColorDiff = 0xFFFFFFFF; - for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ ) + GetObjectW(src, sizeof(bm), &bm); + + hbmpPrev = SelectObject(hdc, src); + + if (!hbmpPrev) /* do it the hard way */ { - iTempXDiff = abs(width - cx); - iTempYDiff = abs(height - cy); + BITMAPINFO *info; + void *bits; - if(iTotalDiff > (iTempXDiff + iTempYDiff)) - { - iXDiff = iTempXDiff; - iYDiff = iTempYDiff; - iTotalDiff = iXDiff + iYDiff; - } - } + if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return; + info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + info->bmiHeader.biWidth = bm.bmWidth; + info->bmiHeader.biHeight = bm.bmHeight; + info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES ); + info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL ); + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biSizeImage = get_dib_image_size( bm.bmWidth, bm.bmHeight, info->bmiHeader.biBitCount ); + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrUsed = 0; + info->bmiHeader.biClrImportant = 0; + bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ); + if (bits && GetDIBits( hdc, src, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) + StretchDIBits( hdc_dst, 0, 0, dst_width, dst_height, + 0, 0, bm.bmWidth, bm.bmHeight, bits, info, DIB_RGB_COLORS, SRCCOPY ); - /* Find Best Colors for Best Fit */ - for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ ) - { - if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff) - { - iTempColorDiff = abs(depth - bits); - if(iColorDiff > iTempColorDiff) - { - bestEntry = i; - iColorDiff = iTempColorDiff; - } - } - } - - return bestEntry; -} - -static BOOL CURSORICON_GetResIconEntry( LPCVOID dir, DWORD size, int n, - int *width, int *height, int *bits ) -{ - const CURSORICONDIR *resdir = dir; - const ICONRESDIR *icon; - - if ( resdir->idCount <= n ) - return FALSE; - if ((const char *)&resdir->idEntries[n + 1] - (const char *)dir > size) - return FALSE; - icon = &resdir->idEntries[n].ResInfo.icon; - *width = icon->bWidth; - *height = icon->bHeight; - *bits = resdir->idEntries[n].wBitCount; - return TRUE; -} - -/********************************************************************** - * CURSORICON_FindBestCursor - * - * Find the cursor closest to the requested size. - * - * FIXME: parameter 'color' ignored. - */ -static int CURSORICON_FindBestCursor( LPCVOID dir, DWORD size, fnGetCIEntry get_entry, - int width, int height, int depth ) -{ - int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1; - - /* Double height to account for AND and XOR masks */ - - height *= 2; - - /* First find the largest one smaller than or equal to the requested size*/ - - maxwidth = maxheight = 0; - for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ ) - { - if ((cx <= width) && (cy <= height) && - (cx > maxwidth) && (cy > maxheight)) - { - bestEntry = i; - maxwidth = cx; - maxheight = cy; - } - } - if (bestEntry != -1) return bestEntry; - - /* Now find the smallest one larger than the requested size */ - - maxwidth = maxheight = 255; - for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ ) - { - if (((cx < maxwidth) && (cy < maxheight)) || (bestEntry == -1)) - { - bestEntry = i; - maxwidth = cx; - maxheight = cy; - } - } - - return bestEntry; -} - -static BOOL CURSORICON_GetResCursorEntry( LPCVOID dir, DWORD size, int n, - int *width, int *height, int *bits ) -{ - const CURSORICONDIR *resdir = dir; - const CURSORRESDIR *cursor; - - if ( resdir->idCount <= n ) - return FALSE; - if ((const char *)&resdir->idEntries[n + 1] - (const char *)dir > size) - return FALSE; - cursor = &resdir->idEntries[n].ResInfo.cursor; - *width = cursor->wWidth; - *height = cursor->wHeight; - *bits = resdir->idEntries[n].wBitCount; - return TRUE; -} - -static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir, DWORD size, - int width, int height, int depth ) -{ - int n; - - n = CURSORICON_FindBestIcon( dir, size, CURSORICON_GetResIconEntry, - width, height, depth ); - if ( n < 0 ) - return NULL; - return &dir->idEntries[n]; -} - -static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir, DWORD size, - int width, int height, int depth ) -{ - int n = CURSORICON_FindBestCursor( dir, size, CURSORICON_GetResCursorEntry, - width, height, depth ); - if ( n < 0 ) - return NULL; - return &dir->idEntries[n]; -} - -static BOOL CURSORICON_GetFileEntry( LPCVOID dir, DWORD size, int n, - int *width, int *height, int *bits ) -{ - const CURSORICONFILEDIR *filedir = dir; - const CURSORICONFILEDIRENTRY *entry; - const BITMAPINFOHEADER *info; - - if ( filedir->idCount <= n ) - return FALSE; - if ((const char *)&filedir->idEntries[n + 1] - (const char *)dir > size) - return FALSE; - entry = &filedir->idEntries[n]; - info = (const BITMAPINFOHEADER *)((const char *)dir + entry->dwDIBOffset); - if ((const char *)(info + 1) - (const char *)dir > size) return FALSE; - *width = entry->bWidth; - *height = entry->bHeight; - *bits = info->biBitCount; - return TRUE; -} - -static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir, DWORD size, - int width, int height, int depth ) -{ - int n = CURSORICON_FindBestCursor( dir, size, CURSORICON_GetFileEntry, - width, height, depth ); - if ( n < 0 ) - return NULL; - return &dir->idEntries[n]; -} - -static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir, DWORD size, - int width, int height, int depth ) -{ - int n = CURSORICON_FindBestIcon( dir, size, CURSORICON_GetFileEntry, - width, height, depth ); - if ( n < 0 ) - return NULL; - return &dir->idEntries[n]; -} - -/*********************************************************************** - * create_icon_bitmaps - * - * Create the color, mask and alpha bitmaps from the DIB info. - */ -static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height, - HBITMAP *color, HBITMAP *mask ) -{ - BOOL monochrome = is_dib_monochrome( bmi ); - unsigned int size = bitmap_info_size( bmi, DIB_RGB_COLORS ); - BITMAPINFO *info; - void *color_bits, *mask_bits; - BOOL ret = FALSE; - HDC hdc = 0; - - if (!(info = HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))) - return FALSE; - if (!(hdc = CreateCompatibleDC(NULL))) goto done; - - memcpy( info, bmi, size ); - info->bmiHeader.biHeight /= 2; - - color_bits = (char *)bmi + size; - mask_bits = (char *)color_bits + - get_dib_width_bytes( bmi->bmiHeader.biWidth, - bmi->bmiHeader.biBitCount ) * abs(info->bmiHeader.biHeight); - - if (monochrome) - { - if (!(*mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done; - *color = 0; - - /* copy color data into second half of mask bitmap */ - SelectObject( hdc, *mask ); - StretchDIBits( hdc, 0, height, width, height, - 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight, - color_bits, info, DIB_RGB_COLORS, SRCCOPY ); + HeapFree( GetProcessHeap(), 0, bits ); + HeapFree( GetProcessHeap(), 0, info ); } else { - if (!(*mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done; - if (!(*color = CreateBitmap( width, height, GetDeviceCaps(hdc, PLANES), - GetDeviceCaps(hdc, BITSPIXEL), NULL ))) + StretchBlt( hdc_dst, 0, 0, dst_width, dst_height, hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY ); + SelectObject(hdc, hbmpPrev); + } + + DeleteDC( hdc ); +} + +/*********************************************************************** + * bmi_has_alpha + */ +static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits ) +{ + int i; + BOOL has_alpha = FALSE; + const unsigned char *ptr = bits; + + if (info->bmiHeader.biBitCount != 32) return FALSE; + for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4) + if ((has_alpha = (ptr[3] != 0))) break; + return has_alpha; +} + +/*********************************************************************** + * create_alpha_bitmap + * + * Create the alpha bitmap for a 32-bpp icon that has an alpha channel. + */ +static +HBITMAP +create_alpha_bitmap( + _In_opt_ HBITMAP color, + _In_opt_ BITMAPINFO *src_info, + _In_opt_ const void *color_bits, + _In_ LONG width, + _In_ LONG height) +{ + HBITMAP alpha = NULL, hbmpOld; + HDC hdc = NULL, hdcScreen; + unsigned char *ptr; + void *bits = NULL; + size_t size; + + hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); + if (!hdcScreen) + return NULL; + hdc = CreateCompatibleDC(hdcScreen); + if (!hdc) + { + DeleteDC(hdcScreen); + return NULL; + } + + if (color) + { + BITMAP bm; + BITMAPINFO *info = NULL; + + TRACE("Creating alpha bitmap from existing bitmap.\n"); + + if (!GetObjectW( color, sizeof(bm), &bm )) + goto done; + if (bm.bmBitsPixel != 32) + goto done; + + size = get_dib_image_size(bm.bmWidth, bm.bmHeight, 32); + + info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])); + if(!info) + goto done; + info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + info->bmiHeader.biWidth = bm.bmWidth; + info->bmiHeader.biHeight = -bm.bmHeight; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biSizeImage = size; + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrUsed = 0; + info->bmiHeader.biClrImportant = 0; + + bits = HeapAlloc(GetProcessHeap(), 0, size); + if(!bits) { - DeleteObject( *mask ); + HeapFree(GetProcessHeap(), 0, info); goto done; } - SelectObject( hdc, *color ); - StretchDIBits( hdc, 0, 0, width, height, - 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight, - color_bits, info, DIB_RGB_COLORS, SRCCOPY ); - - /* convert info to monochrome to copy the mask */ - info->bmiHeader.biBitCount = 1; - if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) + if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) { - RGBQUAD *rgb = info->bmiColors; + HeapFree(GetProcessHeap(), 0, info); + goto done; + } + if (!bmi_has_alpha( info, bits )) + { + HeapFree(GetProcessHeap(), 0, info); + goto done; + } - info->bmiHeader.biClrUsed = info->bmiHeader.biClrImportant = 2; - rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00; - rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff; - rgb[0].rgbReserved = rgb[1].rgbReserved = 0; + /* pre-multiply by alpha */ + for (ptr = bits; ptr < ((BYTE*)bits + size); ptr += 4) + { + unsigned int alpha = ptr[3]; + ptr[0] = (ptr[0] * alpha) / 255; + ptr[1] = (ptr[1] * alpha) / 255; + ptr[2] = (ptr[2] * alpha) / 255; + } + + /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */ + alpha = CreateDIBitmap(hdc, NULL, CBM_INIT | 2, bits, info, DIB_RGB_COLORS); + + HeapFree(GetProcessHeap(), 0, info); + } + else + { + WORD bpp; + DWORD compr; + LONG orig_width, orig_height; + + TRACE("Creating alpha bitmap from bitmap info.\n"); + + if(!bmi_has_alpha(src_info, color_bits)) + goto done; + + if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &orig_width, &orig_height, &bpp, &compr)) + goto done; + if(bpp != 32) + goto done; + + size = get_dib_image_size(orig_width, orig_height, bpp); + bits = HeapAlloc(GetProcessHeap(), 0, size); + if(!bits) + goto done; + CopyMemory(bits, color_bits, size); + /* pre-multiply by alpha */ + for (ptr = bits; ptr < ((BYTE*)bits + size); ptr += 4) + { + unsigned int alpha = ptr[3]; + ptr[0] = (ptr[0] * alpha) / 255; + ptr[1] = (ptr[1] * alpha) / 255; + ptr[2] = (ptr[2] * alpha) / 255; + } + + /* Create the bitmap. Set the bitmap info to have the right width and height */ + if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = width; + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = height; } else { - RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)info) + 1); - - rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00; - rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff; + src_info->bmiHeader.biWidth = width; + src_info->bmiHeader.biHeight = height; + } + /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */ + alpha = CreateDIBitmap(hdcScreen, NULL, 2, NULL, src_info, DIB_RGB_COLORS); + /* Restore values */ + if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = orig_width; + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = orig_height; + } + else + { + src_info->bmiHeader.biWidth = orig_width; + src_info->bmiHeader.biHeight = orig_height; + } + if(!alpha) + goto done; + hbmpOld = SelectObject(hdc, alpha); + if(!hbmpOld) + { + DeleteObject(alpha); + alpha = NULL; + goto done; + } + if(!StretchDIBits( hdc, 0, 0, width, height, + 0, 0, orig_width, orig_height, + bits, src_info, DIB_RGB_COLORS, SRCCOPY )) + { + SelectObject(hdc, hbmpOld); + hbmpOld = NULL; + DeleteObject(alpha); + alpha = NULL; + } + else + { + SelectObject(hdc, hbmpOld); } } - SelectObject( hdc, *mask ); - StretchDIBits( hdc, 0, 0, width, height, - 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight, - mask_bits, info, DIB_RGB_COLORS, SRCCOPY ); - ret = TRUE; - done: - if(hdc) DeleteDC( hdc ); - HeapFree( GetProcessHeap(), 0, info ); - return ret; + DeleteDC(hdcScreen); + DeleteDC( hdc ); + if(bits) HeapFree(GetProcessHeap(), 0, bits); + + TRACE("Returning 0x%08x.\n", alpha); + return alpha; } -static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi, - POINT hotspot, BOOL bIcon, - DWORD dwVersion, - INT width, INT height, - UINT cFlag ) +#include "pshpack1.h" + +typedef struct { + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; + WORD xHotspot; + WORD yHotspot; + DWORD dwDIBSize; + DWORD dwDIBOffset; +} CURSORICONFILEDIRENTRY; + +typedef struct { - HBITMAP color = 0, mask = 0; - BOOL do_stretch; - ICONINFO IconInfo; + WORD idReserved; + WORD idType; + WORD idCount; + CURSORICONFILEDIRENTRY idEntries[1]; +} CURSORICONFILEDIR; - if (dwVersion == 0x00020000) +#include "poppack.h" + +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; + + /* Check our file is what it claims to be */ + if ( dwFileSize < sizeof(*dir) ) + return NULL; + + if (dwFileSize < FIELD_OFFSET(CURSORICONFILEDIR, idEntries[dir->idCount])) + 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) { - FIXME_(cursor)("\t2.xx resources are not supported\n"); - return 0; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + fakeDir->idReserved = 0; + fakeDir->idType = dir->idType; + fakeDir->idCount = dir->idCount; + for(i = 0; iidCount; i++) + { + fakeEntry = &fakeDir->idEntries[i]; + entry = &dir->idEntries[i]; + /* Take this as an occasion to perform a size check */ + if ((entry->dwDIBOffset > dwFileSize) + || ((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 */ + if (((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biSize == sizeof(BITMAPCOREHEADER)) + fakeEntry->wBitCount = ((BITMAPCOREHEADER *)((char *)dir + entry->dwDIBOffset))->bcBitCount; + else + 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; } - /* Check bitmap header */ + /* We found it */ + return &dir->idEntries[i-1]; +} - if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) && - (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) || - bmi->bmiHeader.biCompression != BI_RGB) ) +DWORD +get_best_icon_file_offset( + _In_ const LPBYTE dir, + _In_ DWORD dwFileSize, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ BOOL bIcon, + _In_ DWORD fuLoad, + _Out_ POINT *ptHotSpot +) +{ + const CURSORICONFILEDIRENTRY *entry; + + entry = get_best_icon_file_entry((CURSORICONFILEDIR *) dir, dwFileSize, cxDesired, cyDesired, bIcon, fuLoad); + + if(ptHotSpot) { - WARN_(cursor)("\tinvalid resource bitmap header.\n"); - return 0; + ptHotSpot->x = entry->xHotspot; + ptHotSpot->y = entry->yHotspot; } - if (!width) width = bmi->bmiHeader.biWidth; - if (!height) height = bmi->bmiHeader.biHeight/2; - do_stretch = (bmi->bmiHeader.biHeight/2 != height) || - (bmi->bmiHeader.biWidth != width); + if(entry) + return entry->dwDIBOffset; - /* Scale the hotspot */ - if (bIcon) + return 0; +} + + + +/************* IMPLEMENTATION CORE ****************/ + +static BOOL CURSORICON_GetCursorDataFromBMI( + _Inout_ CURSORDATA* pdata, + _In_ const BITMAPINFO *pbmi +) +{ + UINT ubmiSize = bitmap_info_size(pbmi, DIB_RGB_COLORS); + BOOL monochrome = is_dib_monochrome(pbmi); + LONG width, height; + WORD bpp; + DWORD compr; + int ibmpType; + HDC hdc, hdcScreen; + BITMAPINFO* pbmiCopy; + HBITMAP hbmpOld = NULL; + BOOL bResult = FALSE; + const VOID *pvColor, *pvMask; + + ibmpType = DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr); + /* Invalid data */ + if(ibmpType < 0) + return FALSE; + + /* No compression for icons */ + if(compr != BI_RGB) + return FALSE; + + /* If no dimensions were set, use the one from the icon */ + if(!pdata->cx) pdata->cx = width; + if(!pdata->cy) pdata->cy = height < 0 ? -height/2 : height/2; + + /* Fix the hotspot coords */ + if(pdata->rt == (USHORT)((ULONG_PTR)RT_CURSOR)) { - hotspot.x = width / 2; - hotspot.y = height / 2; + if(pdata->cx != width) + pdata->xHotspot = (pdata->xHotspot * pdata->cx) / width; + if(pdata->cy != height/2) + pdata->yHotspot = (pdata->yHotspot * pdata->cy * 2) / height; } - else if (do_stretch) + else { - hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth; - hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2); + pdata->xHotspot = pdata->cx/2; + pdata->yHotspot = pdata->cy/2; } + + hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); + if(!hdcScreen) + return FALSE; + hdc = CreateCompatibleDC(hdcScreen); + if(!hdc) + { + DeleteDC(hdcScreen); + return FALSE; + } + + pbmiCopy = HeapAlloc(GetProcessHeap(), 0, max(ubmiSize, FIELD_OFFSET(BITMAPINFO, bmiColors[3]))); + if(!pbmiCopy) + goto done; + RtlCopyMemory(pbmiCopy, pbmi, ubmiSize); + + /* In an icon/cursor, the BITMAPINFO holds twice the height */ + if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcHeight /= 2; + else + pbmiCopy->bmiHeader.biHeight /= 2; + height /= 2; + + pvColor = (const char*)pbmi + ubmiSize; + pvMask = (const char*)pvColor + + get_dib_image_size(width, height, bpp ); + + /* Set XOR bits */ + if(monochrome) + { + /* Create the 1bpp bitmap which will contain everything */ + pdata->hbmColor = NULL; + pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy * 2, 1, 1, NULL); + if(!pdata->hbmMask) + goto done; + hbmpOld = SelectObject(hdc, pdata->hbmMask); + if(!hbmpOld) + goto done; + + if(!StretchDIBits(hdc, 0, pdata->cy, pdata->cx, pdata->cy, + 0, 0, width, height, + pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) + goto done; + pdata->bpp = 1; + } + else + { + /* Create the bitmap. It has to be compatible with the screen surface */ + pdata->hbmColor = CreateCompatibleBitmap(hdcScreen, pdata->cx, pdata->cy); + if(!pdata->hbmColor) + goto done; + /* Create the 1bpp mask bitmap */ + pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy, 1, 1, NULL); + if(!pdata->hbmMask) + goto done; + hbmpOld = SelectObject(hdc, pdata->hbmColor); + if(!hbmpOld) + goto done; + if(!StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy, + 0, 0, width, height, + pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) + goto done; + pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL); + pdata->hbmAlpha = create_alpha_bitmap(NULL, pbmiCopy, pvColor, pdata->cx, pdata->cy); + + /* Now convert the info to monochrome for the mask bits */ + if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) + { + RGBQUAD *rgb = pbmiCopy->bmiColors; - if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL ); - if (!screen_dc) return 0; + pbmiCopy->bmiHeader.biClrUsed = pbmiCopy->bmiHeader.biClrImportant = 2; + rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00; + rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff; + rgb[0].rgbReserved = rgb[1].rgbReserved = 0; + pbmiCopy->bmiHeader.biBitCount = 1; + } + else + { + RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pbmiCopy) + 1); - if (!create_icon_bitmaps( bmi, width, height, &color, &mask )) return 0; + rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00; + rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff; + ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount = 1; + } + } + /* Set the mask bits */ + if(!SelectObject(hdc, pdata->hbmMask)) + goto done; + bResult = StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy, + 0, 0, width, height, + pvMask, pbmiCopy, DIB_RGB_COLORS, SRCCOPY) != 0; + +done: + DeleteDC(hdcScreen); + if(hbmpOld) SelectObject(hdc, hbmpOld); + DeleteDC(hdc); + if(pbmiCopy) HeapFree(GetProcessHeap(), 0, pbmiCopy); + /* Clean up in case of failure */ + if(!bResult) + { + if(pdata->hbmMask) DeleteObject(pdata->hbmMask); + if(pdata->hbmColor) DeleteObject(pdata->hbmColor); + if(pdata->hbmAlpha) DeleteObject(pdata->hbmAlpha); + } + return bResult; +} - IconInfo.xHotspot = hotspot.x; - IconInfo.yHotspot = hotspot.y; - IconInfo.fIcon = bIcon; - IconInfo.hbmColor = color; - IconInfo.hbmMask = mask; +static BOOL CURSORICON_GetCursorDataFromIconInfo( + _Out_ CURSORDATA* pCursorData, + _In_ ICONINFO* pIconInfo +) +{ + BITMAP bm; - return CreateCursorIconHandle(&IconInfo); + ZeroMemory(pCursorData, sizeof(*pCursorData)); + if(pIconInfo->hbmColor) + { + /* We must convert the color bitmap to screen format */ + HDC hdcScreen, hdcMem; + HBITMAP hbmpPrev; + + /* The mask dictates its dimensions */ + if (!GetObject(pIconInfo->hbmMask, sizeof(bm), &bm)) + return FALSE; + hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); + if(!hdcScreen) + return FALSE; + hdcMem = CreateCompatibleDC(hdcScreen); + if(!hdcMem) + { + DeleteDC(hdcScreen); + return FALSE; + } + pCursorData->hbmColor = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight); + DeleteDC(hdcScreen); + if (!pCursorData->hbmColor) + { + DeleteDC(hdcMem); + return FALSE; + } + hbmpPrev = SelectObject(hdcMem, pCursorData->hbmColor); + if (!hbmpPrev) + { + DeleteDC(hdcMem); + DeleteObject(pCursorData->hbmColor); + return FALSE; + } + stretch_blt_icon( hdcMem, bm.bmWidth, bm.bmHeight, pIconInfo->hbmColor); + SelectObject(hdcMem, hbmpPrev); + DeleteDC(hdcMem); + } + pCursorData->hbmMask = CopyImage(pIconInfo->hbmMask, IMAGE_BITMAP, 0, 0, LR_MONOCHROME); + if(!pCursorData->hbmMask) + return FALSE; + + /* Now, fill some information */ + pCursorData->rt = (USHORT)((ULONG_PTR)(pIconInfo->fIcon ? RT_ICON : RT_CURSOR)); + if(pCursorData->hbmColor) + { + GetObject(pCursorData->hbmColor, sizeof(bm), &bm); + pCursorData->bpp = bm.bmBitsPixel; + pCursorData->cx = bm.bmWidth; + pCursorData->cy = bm.bmHeight; + if(pCursorData->bpp == 32) + pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL, 0, 0); + } + else + { + GetObject(pCursorData->hbmMask, sizeof(bm), &bm); + pCursorData->bpp = 1; + pCursorData->cx = bm.bmWidth; + pCursorData->cy = bm.bmHeight/2; + } + + if(pIconInfo->fIcon) + { + pCursorData->xHotspot = pCursorData->cx/2; + pCursorData->yHotspot = pCursorData->cy/2; + } + else + { + pCursorData->xHotspot = pIconInfo->xHotspot; + pCursorData->yHotspot = pIconInfo->yHotspot; + } + + return TRUE; } -/********************************************************************** - * .ANI cursor support - */ #define RIFF_FOURCC( c0, c1, c2, c3 ) \ ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \ ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) ) @@ -606,10 +822,12 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi, #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 typedef struct { DWORD header_size; DWORD num_frames; @@ -626,6 +844,7 @@ typedef struct { DWORD data_size; const unsigned char *data; } riff_chunk_t; +#include static void dump_ani_header( const ani_header *header ) { @@ -640,25 +859,7 @@ static void dump_ani_header( const ani_header *header ) TRACE(" flags: 0x%08x\n", header->flags); } - -/* - * RIFF: - * DWORD "RIFF" - * DWORD size - * DWORD riff_id - * BYTE[] data - * - * LIST: - * DWORD "LIST" - * DWORD size - * DWORD list_id - * BYTE[] data - * - * CHUNK: - * DWORD chunk_id - * DWORD size - * BYTE[] data - */ +/* 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; @@ -686,1511 +887,1050 @@ static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_ } } - -/* - * .ANI layout: - * - * RIFF:'ACON' RIFF chunk - * |- CHUNK:'anih' Header - * |- CHUNK:'seq ' Sequence information (optional) - * \- LIST:'fram' Frame list - * |- CHUNK:icon Cursor frames - * |- CHUNK:icon - * |- ... - * \- CHUNK:icon - */ -static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size, - INT width, INT height, INT depth ) +static BOOL CURSORICON_GetCursorDataFromANI( + _Inout_ CURSORDATA* pCurData, + _In_ const BYTE *pData, + _In_ DWORD dwDataSize, + _In_ DWORD fuLoad +) { - HCURSOR cursor; - ani_header header = {0}; - LPBYTE frame_bits = 0; - POINT hotspot; - CURSORICONFILEDIRENTRY *entry; - - riff_chunk_t root_chunk = { bits_size, bits }; + 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; - TRACE("bits %p, bits_size %d\n", bits, bits_size); - - if (!bits) return 0; - + /* 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 0; + return FALSE; } + /* Find the header chunk */ riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk ); - if (!anih_chunk.data) + if (!ACON_chunk.data) { - ERR("Failed to get 'anih' chunk.\n"); - return 0; + ERR("Failed to get header chunk.\n"); + return FALSE; } - memcpy( &header, anih_chunk.data, sizeof(header) ); - dump_ani_header( &header ); + 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; } - - /* FIXME: For now, just load the first frame. Before we can load all the - * frames, we need to write the needed code in wineserver, etc. to handle - * cursors. Once this code is written, we can extend it to support .ani - * cursors and then update user32 and winex11.drv to load all frames. - * - * Hopefully this will at least make some games (C&C3, etc.) more playable - * in the meantime. - */ - FIXME("Loading all frames for .ani cursors not implemented.\n"); + icon_chunk = fram_chunk.data; icon_data = fram_chunk.data + (2 * sizeof(DWORD)); - entry = CURSORICON_FindBestIconFile( (CURSORICONFILEDIR *) icon_data, - bits + bits_size - icon_data, - width, height, depth ); - - frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize ); - memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize ); - - if (!header.width || !header.height) + if(pHeader->num_frames > 1) { - header.width = entry->bWidth; - header.height = entry->bHeight; + /* 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); } - hotspot.x = entry->xHotspot; - hotspot.y = entry->yHotspot; + for(i=0; i < pHeader->num_frames; i++) + { + CURSORDATA* pFrameData; + const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD)); + const BITMAPINFO* pbmi; - cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot, - FALSE, 0x00030000, header.width, header.height, 0 ); + if(pHeader->num_frames > 1) + pFrameData = &pCurData->aspcur[i]; + else + pFrameData = pCurData; - HeapFree( GetProcessHeap(), 0, frame_bits ); + 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; + } - return cursor; + /* 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; } -/********************************************************************** - * CreateIconFromResourceEx (USER32.@) - * - * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something - * with cbSize parameter as well. - */ -HICON WINAPI CreateIconFromResourceEx( PBYTE bits, DWORD cbSize, - BOOL bIcon, DWORD dwVersion, - int width, int height, - UINT cFlag ) +static +HBITMAP +BITMAP_LoadImageW( + _In_opt_ HINSTANCE hinst, + _In_ LPCWSTR lpszName, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuLoad +) { - POINT hotspot; - BITMAPINFO *bmi; + const BITMAPINFO* pbmi; + BITMAPINFO* pbmiScaled = NULL; + BITMAPINFO* pbmiCopy = NULL; + const VOID* pvMapping = NULL; + DWORD dwOffset = 0; + HGLOBAL hgRsrc = NULL; + int iBMISize; + PVOID pvBits; + HDC hdcScreen = NULL; + HDC hdc = NULL; + HBITMAP hbmpOld, hbmpRet = NULL; + LONG width, height; + WORD bpp; + DWORD compr; - TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n", - bits, cbSize, dwVersion, width, height, - bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" ); - - if (bIcon) + /* Map the bitmap info */ + if(fuLoad & LR_LOADFROMFILE) { - hotspot.x = width / 2; - hotspot.y = height / 2; - bmi = (BITMAPINFO *)bits; + const BITMAPFILEHEADER* pbmfh; + + pvMapping = map_fileW(lpszName, NULL); + if(!pvMapping) + return NULL; + pbmfh = pvMapping; + if (pbmfh->bfType != 0x4d42 /* 'BM' */) + { + WARN("Invalid/unsupported bitmap format!\n"); + goto end; + } + pbmi = (const BITMAPINFO*)(pbmfh + 1); + + /* Get the image bits */ + if(pbmfh->bfOffBits) + dwOffset = pbmfh->bfOffBits - sizeof(BITMAPFILEHEADER); } - else /* get the hotspot */ + else { - SHORT *pt = (SHORT *)bits; - hotspot.x = pt[0]; - hotspot.y = pt[1]; - bmi = (BITMAPINFO *)(pt + 2); + HRSRC hrsrc; + + /* Caller wants an OEM bitmap */ + if(!hinst) + hinst = User32Instance; + hrsrc = FindResourceW(hinst, lpszName, RT_BITMAP); + if(!hrsrc) + return NULL; + hgRsrc = LoadResource(hinst, hrsrc); + if(!hgRsrc) + return NULL; + pbmi = LockResource(hgRsrc); + if(!pbmi) + return NULL; + } + + /* Fix up values */ + if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == -1) + goto end; + if((width > 65535) || (height > 65535)) + goto end; + if(cxDesired == 0) + cxDesired = width; + if(cyDesired == 0) + cyDesired = height; + else if(height < 0) + cyDesired = -cyDesired; + + iBMISize = bitmap_info_size(pbmi, DIB_RGB_COLORS); + + /* Get a pointer to the image data */ + pvBits = (char*)pbmi + (dwOffset ? dwOffset : iBMISize); + + /* Create a copy of the info describing the bitmap in the file */ + pbmiCopy = HeapAlloc(GetProcessHeap(), 0, iBMISize); + if(!pbmiCopy) + goto end; + CopyMemory(pbmiCopy, pbmi, iBMISize); + + /* Fix it up, if needed */ + if(fuLoad & (LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS)) + { + WORD bpp, incr, numColors; + char* pbmiColors; + RGBTRIPLE* ptr; + COLORREF crWindow, cr3DShadow, cr3DFace, cr3DLight; + BYTE pixel = *((BYTE*)pvBits); + UINT i; + + if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + bpp = ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount; + numColors = 1 << bpp; + /* BITMAPCOREINFO holds RGBTRIPLEs */ + incr = 3; + } + else + { + bpp = pbmiCopy->bmiHeader.biBitCount; + /* BITMAPINFOHEADER holds RGBQUADs */ + incr = 4; + numColors = pbmiCopy->bmiHeader.biClrUsed; + if(numColors > 256) numColors = 256; + if (!numColors && (bpp <= 8)) numColors = 1 << bpp; + } + + if(bpp > 8) + goto create_bitmap; + + pbmiColors = (char*)pbmiCopy + pbmiCopy->bmiHeader.biSize; + + /* Get the relevant colors */ + crWindow = GetSysColor(COLOR_WINDOW); + cr3DShadow = GetSysColor(COLOR_3DSHADOW); + cr3DFace = GetSysColor(COLOR_3DFACE); + cr3DLight = GetSysColor(COLOR_3DLIGHT); + + /* Fix the transparent palette entry */ + if(fuLoad & LR_LOADTRANSPARENT) + { + switch(bpp) + { + case 1: pixel >>= 7; break; + case 4: pixel >>= 4; break; + case 8: break; + default: + FIXME("Unhandled bit depth %d.\n", bpp); + goto create_bitmap; + } + + if(pixel >= numColors) + { + ERR("Wrong pixel passed in.\n"); + goto create_bitmap; + } + + /* If both flags are set, we must use COLOR_3DFACE */ + if(fuLoad & LR_LOADMAP3DCOLORS) crWindow = cr3DFace; + + /* Define the color */ + ptr = (RGBTRIPLE*)(pbmiColors + pixel*incr); + ptr->rgbtBlue = GetBValue(crWindow); + ptr->rgbtGreen = GetGValue(crWindow); + ptr->rgbtRed = GetRValue(crWindow); + goto create_bitmap; + } + + /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */ + for(i = 0; irgbtBlue == ptr->rgbtRed) && (ptr->rgbtBlue == ptr->rgbtGreen)) + { + if(ptr->rgbtBlue == 128) + { + ptr->rgbtBlue = GetBValue(cr3DShadow); + ptr->rgbtGreen = GetGValue(cr3DShadow); + ptr->rgbtRed = GetRValue(cr3DShadow); + } + if(ptr->rgbtBlue == 192) + { + ptr->rgbtBlue = GetBValue(cr3DFace); + ptr->rgbtGreen = GetGValue(cr3DFace); + ptr->rgbtRed = GetRValue(cr3DFace); + } + if(ptr->rgbtBlue == 223) + { + ptr->rgbtBlue = GetBValue(cr3DLight); + ptr->rgbtGreen = GetGValue(cr3DLight); + ptr->rgbtRed = GetRValue(cr3DLight); + } + } + } } - return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion, - width, height, cFlag ); +create_bitmap: + if(fuLoad & LR_CREATEDIBSECTION) + { + /* Allocate the BMI describing the new bitmap */ + pbmiScaled = HeapAlloc(GetProcessHeap(), 0, iBMISize); + if(!pbmiScaled) + goto end; + CopyMemory(pbmiScaled, pbmiCopy, iBMISize); + + /* Fix it up */ + if(pbmiScaled->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + BITMAPCOREHEADER* pbmch = (BITMAPCOREHEADER*)&pbmiScaled->bmiHeader; + pbmch->bcWidth = cxDesired; + pbmch->bcHeight = cyDesired; + } + else + { + pbmiScaled->bmiHeader.biWidth = cxDesired; + pbmiScaled->bmiHeader.biHeight = cyDesired; + /* No compression for DIB sections */ + pbmiScaled->bmiHeader.biCompression = BI_RGB; + } + } + + /* Top-down image */ + if(cyDesired < 0) cyDesired = -cyDesired; + + /* We need a device context */ + hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); + if(!hdcScreen) + goto end; + hdc = CreateCompatibleDC(hdcScreen); + if(!hdc) + goto end; + + /* Now create the bitmap */ + if(fuLoad & LR_CREATEDIBSECTION) + hbmpRet = CreateDIBSection(hdc, pbmiScaled, DIB_RGB_COLORS, NULL, 0, 0); + else + { + if(is_dib_monochrome(pbmiCopy) || (fuLoad & LR_MONOCHROME)) + hbmpRet = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL); + else + hbmpRet = CreateCompatibleBitmap(hdcScreen, cxDesired, cyDesired); + } + + if(!hbmpRet) + goto end; + + hbmpOld = SelectObject(hdc, hbmpRet); + if(!hbmpOld) + goto end; + if(!StretchDIBits(hdc, 0, 0, cxDesired, cyDesired, + 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, + pvBits, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) + { + ERR("StretchDIBits failed!.\n"); + SelectObject(hdc, hbmpOld); + DeleteObject(hbmpRet); + hbmpRet = NULL; + goto end; + } + + SelectObject(hdc, hbmpOld); + +end: + if(hdcScreen) + DeleteDC(hdcScreen); + if(hdc) + DeleteDC(hdc); + if(pbmiScaled) + HeapFree(GetProcessHeap(), 0, pbmiScaled); + if(pbmiCopy) + HeapFree(GetProcessHeap(), 0, pbmiCopy); + if (pvMapping) + UnmapViewOfFile( pvMapping ); + if(hgRsrc) + FreeResource(hgRsrc); + + return hbmpRet; } -/********************************************************************** - * CreateIconFromResource (USER32.@) - */ -HICON WINAPI CreateIconFromResource( PBYTE bits, DWORD cbSize, - BOOL bIcon, DWORD dwVersion) +static +HANDLE +CURSORICON_LoadFromFileW( + _In_ LPCWSTR lpszName, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuLoad, + _In_ BOOL bIcon +) { - return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0); -} - - -static HICON CURSORICON_LoadFromFile( LPCWSTR filename, - INT width, INT height, INT depth, - BOOL fCursor, UINT loadflags) -{ - CURSORICONFILEDIRENTRY *entry; - CURSORICONFILEDIR *dir; + const CURSORICONFILEDIRENTRY *entry; + const CURSORICONFILEDIR *dir; DWORD filesize = 0; - HICON hIcon = 0; LPBYTE bits; - POINT hotspot; + HANDLE hCurIcon = NULL; + CURSORDATA cursorData; - TRACE("loading %s\n", debugstr_w( filename )); + TRACE("loading %s\n", debugstr_w( lpszName )); - bits = map_fileW( filename, &filesize ); + bits = map_fileW( lpszName, &filesize ); if (!bits) - return hIcon; + return NULL; /* Check for .ani. */ if (memcmp( bits, "RIFF", 4 ) == 0) { - hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height, - depth ); + UNIMPLEMENTED; goto end; } dir = (CURSORICONFILEDIR*) bits; - if ( filesize < sizeof(*dir) ) + entry = get_best_icon_file_entry(dir, filesize, cxDesired, cyDesired, bIcon, fuLoad); + if(!entry) goto end; - - if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) ) + + /* Fix dimensions */ + if(!cxDesired) cxDesired = entry->bWidth; + if(!cyDesired) cyDesired = entry->bHeight; + /* A bit of preparation */ + ZeroMemory(&cursorData, sizeof(cursorData)); + if(!bIcon) + { + cursorData.xHotspot = entry->xHotspot; + cursorData.yHotspot = entry->yHotspot; + } + cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR)); + + /* Do the dance */ + if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)(&bits[entry->dwDIBOffset]))) goto end; - - if ( fCursor ) - entry = CURSORICON_FindBestCursorFile( dir, filesize, width, height, depth ); - else - entry = CURSORICON_FindBestIconFile( dir, filesize, width, height, depth ); - - if ( !entry ) + + hCurIcon = NtUserxCreateEmptyCurObject(FALSE); + if(!hCurIcon) goto end; + + /* Tell win32k */ + if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData)) + { + NtUserDestroyCursor(hCurIcon, TRUE); + goto end_error; + } - /* check that we don't run off the end of the file */ - if ( entry->dwDIBOffset > filesize ) - goto end; - if ( entry->dwDIBOffset + entry->dwDIBSize > filesize ) - goto end; - - hotspot.x = entry->xHotspot; - hotspot.y = entry->yHotspot; - hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset], - hotspot, !fCursor, 0x00030000, - width, height, loadflags ); end: - TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon ); - UnmapViewOfFile( bits ); - return hIcon; + UnmapViewOfFile(bits); + return hCurIcon; + + /* Clean up */ +end_error: + DeleteObject(cursorData.hbmMask); + if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); + if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); + UnmapViewOfFile(bits); + + return NULL; } -/********************************************************************** - * CURSORICON_Load - * - * Load a cursor or icon from resource or file. - */ -static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name, - INT width, INT height, INT depth, - BOOL fCursor, UINT loadflags) +static +HANDLE +CURSORICON_LoadImageW( + _In_opt_ HINSTANCE hinst, + _In_ LPCWSTR lpszName, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuLoad, + _In_ BOOL bIcon +) { - HANDLE handle = 0; - HICON hIcon = 0; - HRSRC hRsrc; - //HRSRC hGroupRsrc; - DWORD size; - CURSORICONDIR *dir; - CURSORICONDIRENTRY *dirEntry; - LPBYTE bits; + HRSRC hrsrc; + HANDLE handle, hCurIcon = NULL; + CURSORICONDIR* dir; WORD wResId; - DWORD dwBytesInRes; + LPBYTE bits; + CURSORDATA cursorData; + BOOL bStatus; + UNICODE_STRING ustrRsrc; + UNICODE_STRING ustrModule = {0, 0, NULL}; - TRACE("%p, %s, %dx%d, depth %d, fCursor %d, flags 0x%04x\n", - hInstance, debugstr_w(name), width, height, depth, fCursor, loadflags); + /* Fix width/height */ + if(fuLoad & LR_DEFAULTSIZE) + { + if(!cxDesired) cxDesired = GetSystemMetrics(bIcon ? SM_CXICON : SM_CXCURSOR); + if(!cyDesired) cyDesired = GetSystemMetrics(bIcon ? SM_CYICON : SM_CYCURSOR); + } - if ( loadflags & LR_LOADFROMFILE ) /* Load from file */ - return CURSORICON_LoadFromFile( name, width, height, depth, fCursor, loadflags ); + if(fuLoad & LR_LOADFROMFILE) + { + return CURSORICON_LoadFromFileW(lpszName, cxDesired, cyDesired, fuLoad, bIcon); + } - if (!hInstance) hInstance = User32Instance; /* Load OEM cursor/icon */ + /* Check if caller wants OEM icons */ + if(!hinst) + hinst = User32Instance; - /* don't cache 16-bit instances (FIXME: should never get 16-bit instances in the first place) */ - if ((ULONG_PTR)hInstance >> 16 == 0) loadflags &= ~LR_SHARED; + if(lpszName) + { + /* Prepare the resource name string */ + if(IS_INTRESOURCE(lpszName)) + { + ustrRsrc.Buffer = (LPWSTR)lpszName; + ustrRsrc.Length = 0; + ustrRsrc.MaximumLength = 0; + } + else + RtlInitUnicodeString(&ustrRsrc, lpszName); + } - /* Get directory resource ID */ + if(hinst) + { + DWORD size = MAX_PATH; + /* Get the module name string */ + while (TRUE) + { + DWORD ret; + ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + if (!ustrModule.Buffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + ret = GetModuleFileNameW(hinst, ustrModule.Buffer, size); + if(ret == 0) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + return NULL; + } - if (!(hRsrc = FindResourceW( hInstance, name, - (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) ))) - return 0; - //hGroupRsrc = hRsrc; + /* This API is completely broken... */ + if (ret == size) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + size *= 2; + continue; + } - /* Find the best entry in the directory */ + ustrModule.Buffer[ret] = UNICODE_NULL; + ustrModule.Length = ret * sizeof(WCHAR); + ustrModule.MaximumLength = size * sizeof(WCHAR); + break; + } + } + + if(fuLoad & LR_SHARED) + { + FINDEXISTINGCURICONPARAM param; + + TRACE("Checking for an LR_SHARED cursor/icon.\n"); + /* Ask win32k */ + param.bIcon = bIcon; + param.cx = cxDesired; + param.cy = cyDesired; + hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, ¶m); + if(hCurIcon) + { + /* Woohoo, got it! */ + TRACE("MATCH! %p\n",hCurIcon); + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + return hCurIcon; + } + } + + /* Find resource ID */ + hrsrc = FindResourceW( + hinst, + lpszName, + bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR); + + /* We let FindResource, LoadResource, etc. call SetLastError */ + if(!hrsrc) + goto done; + + handle = LoadResource(hinst, hrsrc); + if(!handle) + goto done; + + dir = LockResource(handle); + if(!dir) + goto done; + + wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad); + FreeResource(handle); + + /* Get the relevant resource pointer */ + hrsrc = FindResourceW( + hinst, + MAKEINTRESOURCEW(wResId), + bIcon ? RT_ICON : RT_CURSOR); + if(!hrsrc) + goto done; + + handle = LoadResource(hinst, hrsrc); + if(!handle) + goto done; + + bits = LockResource(handle); + if(!bits) + { + FreeResource(handle); + goto done; + } + + ZeroMemory(&cursorData, sizeof(cursorData)); + + /* This is from resource */ + cursorData.CURSORF_flags = CURSORF_FROMRESOURCE; + + if(dir->idType == 2) + { + /* idType == 2 for cursor resources */ + SHORT* ptr = (SHORT*)bits; + cursorData.xHotspot = ptr[0]; + cursorData.yHotspot = ptr[1]; + bits += 2*sizeof(SHORT); + } + cursorData.cx = cxDesired; + cursorData.cy = cyDesired; + cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR)); + + /* Get the bitmaps */ + bStatus = CURSORICON_GetCursorDataFromBMI( + &cursorData, + (BITMAPINFO*)bits); - if (!(handle = LoadResource( hInstance, hRsrc ))) return 0; - if (!(dir = LockResource( handle ))) return 0; - size = SizeofResource( hInstance, hRsrc ); - if (fCursor) - dirEntry = CURSORICON_FindBestCursorRes( dir, size, width, height, depth ); - else - dirEntry = CURSORICON_FindBestIconRes( dir, size, width, height, depth ); - if (!dirEntry) return 0; - wResId = dirEntry->wResId; - dwBytesInRes = dirEntry->dwBytesInRes; FreeResource( handle ); - /* Load the resource */ + if(!bStatus) + goto done; - if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId), - (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0; - - /* If shared icon, check whether it was already loaded */ - if ( (loadflags & LR_SHARED) - && (hIcon = NtUserFindExistingCursorIcon( hInstance, hRsrc, 0, 0 ) ) != 0 ) - return hIcon; - - if (!(handle = LoadResource( hInstance, hRsrc ))) return 0; - bits = LockResource( handle ); - hIcon = CreateIconFromResourceEx( bits, dwBytesInRes, - !fCursor, 0x00030000, width, height, loadflags); - FreeResource( handle ); - - /* If shared icon, add to icon cache */ - - if (hIcon && 0 != (loadflags & LR_SHARED)) - { -#if 1 - NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hInstance, hRsrc, - (HRSRC)NULL); -#else - ICONINFO iconInfo; - - if(NtUserGetIconInfo(ResIcon, &iconInfo, NULL, NULL, NULL, FALSE)) - NtUserSetCursorIconData((HICON)hIcon, hinst, NULL, &iconInfo); -#endif - } - - return hIcon; -} - - -/************************************************************************* - * CURSORICON_ExtCopy - * - * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified - * - * PARAMS - * Handle [I] handle to an Image - * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON) - * iDesiredCX [I] The Desired width of the Image - * iDesiredCY [I] The desired height of the Image - * nFlags [I] The flags from CopyImage - * - * RETURNS - * Success: The new handle of the Image - * - * NOTES - * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented. - * LR_MONOCHROME should be implemented by CreateIconFromResourceEx. - * LR_COPYFROMRESOURCE will only work if the Image is in the Cache. - * - * - */ - -static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType, - INT iDesiredCX, INT iDesiredCY, - UINT nFlags) -{ - HICON hNew=0; - - TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n", - hIcon, nType, iDesiredCX, iDesiredCY, nFlags); - - if(hIcon == 0) + /* Create the handle */ + hCurIcon = NtUserxCreateEmptyCurObject(FALSE); + if(!hCurIcon) { - return 0; + goto end_error; } - /* Best Fit or Monochrome */ - if( (nFlags & LR_COPYFROMRESOURCE - && (iDesiredCX > 0 || iDesiredCY > 0)) - || nFlags & LR_MONOCHROME) + if(fuLoad & LR_SHARED) { - TRACE("Copying from resource isn't implemented yet\n"); - hNew = CopyIcon(hIcon); + cursorData.CURSORF_flags |= CURSORF_LRSHARED; + } -#if 0 - ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon); + /* Tell win32k */ + bStatus = NtUserSetCursorIconData(hCurIcon, hinst ? &ustrModule : NULL, lpszName ? &ustrRsrc : NULL, &cursorData); + + if(!bStatus) + { + NtUserDestroyCursor(hCurIcon, TRUE); + goto end_error; + } - /* Not Found in Cache, then do a straight copy - */ - if(pIconCache == NULL) +done: + if(ustrModule.Buffer) + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + return hCurIcon; + +end_error: + if(ustrModule.Buffer) + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + DeleteObject(cursorData.hbmMask); + if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); + if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); + + return NULL; +} + +static +HBITMAP +BITMAP_CopyImage( + _In_ HBITMAP hnd, + _In_ int desiredx, + _In_ int desiredy, + _In_ UINT flags +) +{ + HBITMAP res = NULL; + DIBSECTION ds; + int objSize; + BITMAPINFO * bi; + + objSize = GetObjectW( hnd, sizeof(ds), &ds ); + if (!objSize) return 0; + if ((desiredx < 0) || (desiredy < 0)) return 0; + + if (flags & LR_COPYFROMRESOURCE) + { + FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n"); + } + + if (flags & LR_COPYRETURNORG) + { + FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n"); + } + + if (desiredx == 0) desiredx = ds.dsBm.bmWidth; + if (desiredy == 0) desiredy = ds.dsBm.bmHeight; + + /* Allocate memory for a BITMAPINFOHEADER structure and a + color table. The maximum number of colors in a color table + is 256 which corresponds to a bitmap with depth 8. + Bitmaps with higher depths don't have color tables. */ + bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + if (!bi) return 0; + + bi->bmiHeader.biSize = sizeof(bi->bmiHeader); + bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes; + bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel; + bi->bmiHeader.biCompression = BI_RGB; + + if (flags & LR_CREATEDIBSECTION) + { + /* Create a DIB section. LR_MONOCHROME is ignored */ + void * bits; + HDC dc = CreateCompatibleDC(NULL); + + if (objSize == sizeof(DIBSECTION)) { - hNew = CopyIcon( hIcon ); - if(nFlags & LR_COPYFROMRESOURCE) + /* The source bitmap is a DIB. + Get its attributes to create an exact copy */ + memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER)); + } + + bi->bmiHeader.biWidth = desiredx; + bi->bmiHeader.biHeight = desiredy; + + /* Get the color table or the color masks */ + GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); + + res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0); + DeleteDC(dc); + } + else + { + /* Create a device-dependent bitmap */ + + BOOL monochrome = (flags & LR_MONOCHROME); + + if (objSize == sizeof(DIBSECTION)) + { + /* The source bitmap is a DIB section. + Get its attributes */ + HDC dc = CreateCompatibleDC(NULL); + bi->bmiHeader.biWidth = ds.dsBm.bmWidth; + bi->bmiHeader.biHeight = ds.dsBm.bmHeight; + GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); + DeleteDC(dc); + + if (!monochrome && ds.dsBm.bmBitsPixel == 1) { - TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n"); + /* Look if the colors of the DIB are black and white */ + + monochrome = + (bi->bmiColors[0].rgbRed == 0xff + && bi->bmiColors[0].rgbGreen == 0xff + && bi->bmiColors[0].rgbBlue == 0xff + && bi->bmiColors[0].rgbReserved == 0 + && bi->bmiColors[1].rgbRed == 0 + && bi->bmiColors[1].rgbGreen == 0 + && bi->bmiColors[1].rgbBlue == 0 + && bi->bmiColors[1].rgbReserved == 0) + || + (bi->bmiColors[0].rgbRed == 0 + && bi->bmiColors[0].rgbGreen == 0 + && bi->bmiColors[0].rgbBlue == 0 + && bi->bmiColors[0].rgbReserved == 0 + && bi->bmiColors[1].rgbRed == 0xff + && bi->bmiColors[1].rgbGreen == 0xff + && bi->bmiColors[1].rgbBlue == 0xff + && bi->bmiColors[1].rgbReserved == 0); } } + else if (!monochrome) + { + monochrome = ds.dsBm.bmBitsPixel == 1; + } + + if (monochrome) + { + res = CreateBitmap(desiredx, desiredy, 1, 1, NULL); + } else { - int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX; - LPBYTE pBits; - HANDLE hMem; - HRSRC hRsrc; - DWORD dwBytesInRes; - WORD wResId; - CURSORICONDIR *pDir; - CURSORICONDIRENTRY *pDirEntry; - BOOL bIsIcon = (nType == IMAGE_ICON); - - /* Completing iDesiredCX CY for Monochrome Bitmaps if needed - */ - if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE)) - || (iDesiredCX == 0 && iDesiredCY == 0)) - { - iDesiredCY = GetSystemMetrics(bIsIcon ? - SM_CYICON : SM_CYCURSOR); - iDesiredCX = GetSystemMetrics(bIsIcon ? - SM_CXICON : SM_CXCURSOR); - } - - /* Retrieve the CURSORICONDIRENTRY - */ - if (!(hMem = LoadResource( pIconCache->hModule , - pIconCache->hGroupRsrc))) - { - return 0; - } - if (!(pDir = LockResource( hMem ))) - { - return 0; - } - - /* Find Best Fit - */ - if(bIsIcon) - { - pDirEntry = CURSORICON_FindBestIconRes( - pDir, iDesiredCX, iDesiredCY, 256 ); - } - else - { - pDirEntry = CURSORICON_FindBestCursorRes( - pDir, iDesiredCX, iDesiredCY, 1); - } - - wResId = pDirEntry->wResId; - dwBytesInRes = pDirEntry->dwBytesInRes; - FreeResource(hMem); - - TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n", - wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth, - pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY); - - /* Get the Best Fit - */ - if (!(hRsrc = FindResourceW(pIconCache->hModule , - MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR)))) - { - return 0; - } - if (!(hMem = LoadResource( pIconCache->hModule , hRsrc ))) - { - return 0; - } - - pBits = LockResource( hMem ); - - if(nFlags & LR_DEFAULTSIZE) - { - iTargetCY = GetSystemMetrics(SM_CYICON); - iTargetCX = GetSystemMetrics(SM_CXICON); - } - - /* Create a New Icon with the proper dimension - */ - hNew = CreateIconFromResourceEx( pBits, dwBytesInRes, - bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags); - FreeResource(hMem); + HDC screenDC = GetDC(NULL); + res = CreateCompatibleBitmap(screenDC, desiredx, desiredy); + ReleaseDC(NULL, screenDC); } -#endif - } - else hNew = CopyIcon( hIcon ); - return hNew; -} - - -/*********************************************************************** - * CreateCursor (USER32.@) - */ -HCURSOR WINAPI CreateCursor( HINSTANCE hInstance, - INT xHotSpot, INT yHotSpot, - INT nWidth, INT nHeight, - LPCVOID lpANDbits, LPCVOID lpXORbits ) -{ - ICONINFO info; - HCURSOR hCursor; - - TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n", - nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits); - - info.fIcon = FALSE; - info.xHotspot = xHotSpot; - info.yHotspot = yHotSpot; - info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits ); - info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, lpXORbits ); - hCursor = CreateIconIndirect( &info ); - DeleteObject( info.hbmMask ); - DeleteObject( info.hbmColor ); - return hCursor; -} - - -/*********************************************************************** - * CreateIcon (USER32.@) - * - * Creates an icon based on the specified bitmaps. The bitmaps must be - * provided in a device dependent format and will be resized to - * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color - * depth. The provided bitmaps must be top-down bitmaps. - * Although Windows does not support 15bpp(*) this API must support it - * for Winelib applications. - * - * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp - * format! - * - * RETURNS - * Success: handle to an icon - * Failure: NULL - * - * FIXME: Do we need to resize the bitmaps? - */ -HICON WINAPI CreateIcon( - HINSTANCE hInstance, /* [in] the application's hInstance */ - int nWidth, /* [in] the width of the provided bitmaps */ - int nHeight, /* [in] the height of the provided bitmaps */ - BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */ - BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */ - const BYTE* lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */ - const BYTE* lpXORbits) /* [in] the icon's 'color' bitmap */ -{ - ICONINFO iinfo; - HICON hIcon; - - TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n", - nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits); - - iinfo.fIcon = TRUE; - iinfo.xHotspot = nWidth / 2; - iinfo.yHotspot = nHeight / 2; - if (bPlanes * bBitsPixel > 1) - { - iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits ); - iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits ); - } - else - { - iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpANDbits ); - iinfo.hbmColor = NULL; } - hIcon = CreateIconIndirect( &iinfo ); - - DeleteObject( iinfo.hbmMask ); - if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor ); - - return hIcon; -} - - -/*********************************************************************** - * CopyIcon (USER32.@) - */ -HICON WINAPI CopyIcon( HICON hIcon ) -{ - HICON hRetIcon = NULL; - ICONINFO IconInfo; - - if(GetIconInfo(hIcon, &IconInfo)) + if (res) { - hRetIcon = CreateIconIndirect(&IconInfo); - DeleteObject(IconInfo.hbmColor); - DeleteObject(IconInfo.hbmMask); - } + /* Only copy the bitmap if it's a DIB section or if it's + compatible to the screen */ + BOOL copyContents; - return hRetIcon; -} - - -/*********************************************************************** - * DestroyIcon (USER32.@) - */ -BOOL WINAPI DestroyIcon( HICON hIcon ) -{ - TRACE_(icon)("%p\n", hIcon ); - - return NtUserDestroyCursor(hIcon, 0); -} - - -/*********************************************************************** - * DestroyCursor (USER32.@) - */ -BOOL WINAPI DestroyCursor( HCURSOR hCursor ) -{ - if (GetCursor() == hCursor) - { - WARN_(cursor)("Destroying active cursor!\n" ); - return FALSE; - } - return DestroyIcon( hCursor ); -} - -/*********************************************************************** - * DrawIcon (USER32.@) - */ -BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon ) -{ - return DrawIconEx( hdc, x, y, hIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE ); -} - -/*********************************************************************** - * ShowCursor (USER32.@) - */ -INT WINAPI DECLSPEC_HOTPATCH ShowCursor( BOOL bShow ) -{ - return NtUserxShowCursor(bShow); -} - -/*********************************************************************** - * GetCursor (USER32.@) - */ -HCURSOR WINAPI GetCursor(void) -{ - return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR); -} - - -/*********************************************************************** - * SetSystemCursor (USER32.@) - */ -BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id) -{ - FIXME("(%p,%08x),stub!\n", hcur, id); - return TRUE; -} - - -/********************************************************************** - * LookupIconIdFromDirectoryEx (USER32.@) - */ -INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon, - INT width, INT height, UINT cFlag ) -{ - CURSORICONDIR *dir = (CURSORICONDIR*)xdir; - UINT retVal = 0; - if( dir && !dir->idReserved && (dir->idType & 3) ) - { - CURSORICONDIRENTRY* entry; - - const HDC hdc = GetDC(0); - const int depth = (cFlag & LR_MONOCHROME) ? - 1 : GetDeviceCaps(hdc, BITSPIXEL); - ReleaseDC(0, hdc); - - if( bIcon ) - entry = CURSORICON_FindBestIconRes( dir, ~0u, width, height, depth ); + if (objSize == sizeof(DIBSECTION)) + { + copyContents = TRUE; + } else - entry = CURSORICON_FindBestCursorRes( dir, ~0u, width, height, depth ); - - if( entry ) retVal = entry->wResId; - } - else WARN_(cursor)("invalid resource directory\n"); - return retVal; -} - -/********************************************************************** - * LookupIconIdFromDirectory (USER32.@) - */ -INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon ) -{ - return LookupIconIdFromDirectoryEx( dir, bIcon, - bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR), - bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME ); -} - -/*********************************************************************** - * LoadCursorW (USER32.@) - */ -HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name) -{ - TRACE("%p, %s\n", hInstance, debugstr_w(name)); - - return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -/*********************************************************************** - * LoadCursorA (USER32.@) - */ -HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name) -{ - TRACE("%p, %s\n", hInstance, debugstr_a(name)); - - return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -/*********************************************************************** - * LoadCursorFromFileW (USER32.@) - */ -HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name) -{ - TRACE("%s\n", debugstr_w(name)); - - return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0, - LR_LOADFROMFILE | LR_DEFAULTSIZE ); -} - -/*********************************************************************** - * LoadCursorFromFileA (USER32.@) - */ -HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name) -{ - TRACE("%s\n", debugstr_a(name)); - - return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0, - LR_LOADFROMFILE | LR_DEFAULTSIZE ); -} - -/*********************************************************************** - * LoadIconW (USER32.@) - */ -HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name) -{ - TRACE("%p, %s\n", hInstance, debugstr_w(name)); - - return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -/*********************************************************************** - * LoadIconA (USER32.@) - */ -HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name) -{ - TRACE("%p, %s\n", hInstance, debugstr_a(name)); - - return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -/********************************************************************** - * GetIconInfo (USER32.@) - */ -BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo) -{ - return NtUserGetIconInfo(hIcon, iconinfo, 0, 0, 0, 0); -} - -/* copy an icon bitmap, even when it can't be selected into a DC */ -/* helper for CreateIconIndirect */ -static void stretch_blt_icon( HDC hdc_dst, int dst_x, int dst_y, int dst_width, int dst_height, - HBITMAP src, int width, int height ) -{ - HDC hdc = CreateCompatibleDC( 0 ); - - if (!SelectObject( hdc, src )) /* do it the hard way */ - { - BITMAPINFO *info; - void *bits; - - if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return; - info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - info->bmiHeader.biWidth = width; - info->bmiHeader.biHeight = height; - info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES ); - info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL ); - info->bmiHeader.biCompression = BI_RGB; - info->bmiHeader.biSizeImage = height * get_dib_width_bytes( width, info->bmiHeader.biBitCount ); - info->bmiHeader.biXPelsPerMeter = 0; - info->bmiHeader.biYPelsPerMeter = 0; - info->bmiHeader.biClrUsed = 0; - info->bmiHeader.biClrImportant = 0; - bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ); - if (bits && GetDIBits( hdc, src, 0, height, bits, info, DIB_RGB_COLORS )) - StretchDIBits( hdc_dst, dst_x, dst_y, dst_width, dst_height, - 0, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY ); - - HeapFree( GetProcessHeap(), 0, bits ); - HeapFree( GetProcessHeap(), 0, info ); - } - else StretchBlt( hdc_dst, dst_x, dst_y, dst_width, dst_height, hdc, 0, 0, width, height, SRCCOPY ); - - DeleteDC( hdc ); -} - -/********************************************************************** - * CreateIconIndirect (USER32.@) - */ -HICON WINAPI CreateIconIndirect(PICONINFO iconinfo) -{ - BITMAP bmpXor, bmpAnd; - HBITMAP color = 0, mask; - int width, height; - HDC hdc; - ICONINFO iinfo; - - TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n", - iconinfo->hbmColor, iconinfo->hbmMask, - iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon); - - if (!iconinfo->hbmMask) return 0; - - GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd ); - TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n", - bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes, - bmpAnd.bmPlanes, bmpAnd.bmBitsPixel); - - if (iconinfo->hbmColor) - { - GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor ); - TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n", - bmpXor.bmWidth, bmpXor.bmHeight, bmpXor.bmWidthBytes, - bmpXor.bmPlanes, bmpXor.bmBitsPixel); - - // the size of the mask bitmap always determines the icon size! - width = bmpAnd.bmWidth; - height = bmpAnd.bmHeight; - if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1 ) { - color = CreateBitmap( width, height, bmpXor.bmPlanes, bmpXor.bmBitsPixel, NULL ); - if(!color) + HDC screenDC = GetDC(NULL); + int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL); + ReleaseDC(NULL, screenDC); + + copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth); + } + + if (copyContents) + { + /* The source bitmap may already be selected in a device context, + use GetDIBits/StretchDIBits and not StretchBlt */ + + HDC dc; + void * bits; + + dc = CreateCompatibleDC(NULL); + + bi->bmiHeader.biWidth = ds.dsBm.bmWidth; + bi->bmiHeader.biHeight = ds.dsBm.bmHeight; + bi->bmiHeader.biSizeImage = 0; + bi->bmiHeader.biClrUsed = 0; + bi->bmiHeader.biClrImportant = 0; + + /* Fill in biSizeImage */ + GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); + bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage); + + if (bits) { - ERR("Unable to create color bitmap!\n"); - return NULL; + HBITMAP oldBmp; + + /* Get the image bits of the source bitmap */ + GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS); + + /* Copy it to the destination bitmap */ + oldBmp = SelectObject(dc, res); + StretchDIBits(dc, 0, 0, desiredx, desiredy, + 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, + bits, bi, DIB_RGB_COLORS, SRCCOPY); + SelectObject(dc, oldBmp); + + HeapFree(GetProcessHeap(), 0, bits); } - mask = CreateBitmap( width, height, 1, 1, NULL ); - if(!mask) - { - ERR("Unable to create mask bitmap!\n"); - DeleteObject(color); - return NULL; - } + + DeleteDC(dc); } - else - { - mask = CreateBitmap( width, height * 2, 1, 1, NULL ); - if(!mask) - { - ERR("Unable to create mask bitmap!\n"); - return NULL; - } - } - } - else - { - width = bmpAnd.bmWidth; - height = bmpAnd.bmHeight; - mask = CreateBitmap( width, height, 1, 1, NULL ); - } - hdc = CreateCompatibleDC( 0 ); - SelectObject( hdc, mask ); - stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmMask, bmpAnd.bmWidth, bmpAnd.bmHeight ); - - if (color) - { - SelectObject( hdc, color ); - stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmColor, width, height ); - } - else if (iconinfo->hbmColor) - { - stretch_blt_icon( hdc, 0, height, width, height, iconinfo->hbmColor, width, height ); - } - else height /= 2; - - DeleteDC( hdc ); - - iinfo.hbmColor = color ; - iinfo.hbmMask = mask ; - iinfo.fIcon = iconinfo->fIcon; - if (iinfo.fIcon) - { - iinfo.xHotspot = width / 2; - iinfo.yHotspot = height / 2; - } - else - { - iinfo.xHotspot = iconinfo->xHotspot; - iinfo.yHotspot = iconinfo->yHotspot; - } - - return CreateCursorIconHandle(&iinfo); -} - -/****************************************************************************** - * DrawIconEx (USER32.@) Draws an icon or cursor on device context - * - * NOTES - * Why is this using SM_CXICON instead of SM_CXCURSOR? - * - * PARAMS - * hdc [I] Handle to device context - * x0 [I] X coordinate of upper left corner - * y0 [I] Y coordinate of upper left corner - * hIcon [I] Handle to icon to draw - * cxWidth [I] Width of icon - * cyWidth [I] Height of icon - * istep [I] Index of frame in animated cursor - * hbr [I] Handle to background brush - * flags [I] Icon-drawing flags - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DrawIconEx( HDC hdc, INT xLeft, INT yTop, HICON hIcon, - INT cxWidth, INT cyWidth, UINT istepIfAniCur, - HBRUSH hbrFlickerFreeDraw, UINT diFlags ) -{ - return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, - istepIfAniCur, hbrFlickerFreeDraw, diFlags, - 0, 0); -} - -/*********************************************************************** - * DIB_FixColorsToLoadflags - * - * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS - * are in loadflags - */ -static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix) -{ - int colors; - COLORREF c_W, c_S, c_F, c_L, c_C; - int incr,i; - RGBQUAD *ptr; - int bitmap_type; - LONG width; - LONG height; - WORD bpp; - DWORD compr; - - if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1)) - { - WARN_(resource)("Invalid bitmap\n"); - return; - } - - if (bpp > 8) return; - - if (bitmap_type == 0) /* BITMAPCOREHEADER */ - { - incr = 3; - colors = 1 << bpp; - } - else - { - incr = 4; - colors = bmi->bmiHeader.biClrUsed; - if (colors > 256) colors = 256; - if (!colors && (bpp <= 8)) colors = 1 << bpp; - } - - c_W = GetSysColor(COLOR_WINDOW); - c_S = GetSysColor(COLOR_3DSHADOW); - c_F = GetSysColor(COLOR_3DFACE); - c_L = GetSysColor(COLOR_3DLIGHT); - - if (loadflags & LR_LOADTRANSPARENT) { - switch (bpp) { - case 1: pix = pix >> 7; break; - case 4: pix = pix >> 4; break; - case 8: break; - default: - WARN_(resource)("(%d): Unsupported depth\n", bpp); - return; - } - if (pix >= colors) { - WARN_(resource)("pixel has color index greater than biClrUsed!\n"); - return; - } - if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F; - ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr); - ptr->rgbBlue = GetBValue(c_W); - ptr->rgbGreen = GetGValue(c_W); - ptr->rgbRed = GetRValue(c_W); - } - if (loadflags & LR_LOADMAP3DCOLORS) - for (i=0; ibmiColors+i*incr); - c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue); - if (c_C == RGB(128, 128, 128)) { - ptr->rgbRed = GetRValue(c_S); - ptr->rgbGreen = GetGValue(c_S); - ptr->rgbBlue = GetBValue(c_S); - } else if (c_C == RGB(192, 192, 192)) { - ptr->rgbRed = GetRValue(c_F); - ptr->rgbGreen = GetGValue(c_F); - ptr->rgbBlue = GetBValue(c_F); - } else if (c_C == RGB(223, 223, 223)) { - ptr->rgbRed = GetRValue(c_L); - ptr->rgbGreen = GetGValue(c_L); - ptr->rgbBlue = GetBValue(c_L); - } - } -} - - -/********************************************************************** - * BITMAP_Load - */ -static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name, - INT desiredx, INT desiredy, UINT loadflags ) -{ - HBITMAP hbitmap = 0, orig_bm; - HRSRC hRsrc; - HGLOBAL handle; - char *ptr = NULL; - BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL; - int size; - BYTE pix; - char *bits; - LONG width, height, new_width, new_height; - WORD bpp_dummy; - DWORD compr_dummy, offbits = 0; - INT bm_type; - HDC screen_mem_dc = NULL; - - if (!(loadflags & LR_LOADFROMFILE)) - { - if (!instance) + if (flags & LR_COPYDELETEORG) { - /* OEM bitmap: try to load the resource from user32.dll */ - instance = User32Instance; + DeleteObject(hnd); } - - if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0; - if (!(handle = LoadResource( instance, hRsrc ))) return 0; - - if ((info = LockResource( handle )) == NULL) return 0; } - else - { - BITMAPFILEHEADER * bmfh; - - if (!(ptr = map_fileW( name, NULL ))) return 0; - info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER)); - bmfh = (BITMAPFILEHEADER *)ptr; - if (bmfh->bfType != 0x4d42 /* 'BM' */) - { - WARN("Invalid/unsupported bitmap format!\n"); - goto end_close; - } - if (bmfh->bfOffBits) offbits = bmfh->bfOffBits - sizeof(BITMAPFILEHEADER); - } - - size = bitmap_info_size(info, DIB_RGB_COLORS); - fix_info = HeapAlloc(GetProcessHeap(), 0, size); - scaled_info = HeapAlloc(GetProcessHeap(), 0, size); - - if (!fix_info || !scaled_info) goto end; - memcpy(fix_info, info, size); - - pix = *((LPBYTE)info + size); - DIB_FixColorsToLoadflags(fix_info, loadflags, pix); - - memcpy(scaled_info, fix_info, size); - bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height, - &bpp_dummy, &compr_dummy); - if(desiredx != 0) - new_width = desiredx; - else - new_width = width; - - if(desiredy != 0) - new_height = height > 0 ? desiredy : -desiredy; - else - new_height = height; - - if (bm_type == 0) - { - BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader; - core->bcWidth = new_width; - core->bcHeight = new_height; - } - else if (bm_type == 1) - { - /* Some sanity checks for BITMAPINFO (not applicable to BITMAPCOREINFO) */ - if (info->bmiHeader.biHeight > 65535 || info->bmiHeader.biWidth > 65535) { - WARN("Broken BitmapInfoHeader!\n"); - goto end; - } - - scaled_info->bmiHeader.biWidth = new_width; - scaled_info->bmiHeader.biHeight = new_height; - } - else - goto end; - - if (new_height < 0) new_height = -new_height; - - if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL ); - if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end; - - bits = (char *)info + (offbits ? offbits : size); - - if (loadflags & LR_CREATEDIBSECTION) - { - scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */ - hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0); - } - else - { - if (is_dib_monochrome(fix_info)) - hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL); - else - hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height); - } - - orig_bm = SelectObject(screen_mem_dc, hbitmap); - StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY); - SelectObject(screen_mem_dc, orig_bm); - -end: - if (screen_mem_dc) DeleteDC(screen_mem_dc); - HeapFree(GetProcessHeap(), 0, scaled_info); - HeapFree(GetProcessHeap(), 0, fix_info); -end_close: - if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr ); - - return hbitmap; -} - -/********************************************************************** - * LoadImageA (USER32.@) - * - * See LoadImageW. - */ -HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type, - INT desiredx, INT desiredy, UINT loadflags) -{ - HANDLE res; - LPWSTR u_name; - - if (IS_INTRESOURCE(name)) - return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags); - - _SEH2_TRY - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 ); - u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len ); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - SetLastError( ERROR_INVALID_PARAMETER ); - _SEH2_YIELD(return 0); - } - _SEH2_END - res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags); - HeapFree(GetProcessHeap(), 0, u_name); + HeapFree(GetProcessHeap(), 0, bi); return res; } - -/****************************************************************************** - * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap - * - * PARAMS - * hinst [I] Handle of instance that contains image - * name [I] Name of image - * type [I] Type of image - * desiredx [I] Desired width - * desiredy [I] Desired height - * loadflags [I] Load flags - * - * RETURNS - * Success: Handle to newly loaded image - * Failure: NULL - * - * FIXME: Implementation lacks some features, see LR_ defines in winuser.h - */ -HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type, - INT desiredx, INT desiredy, UINT loadflags ) +static +HICON +CURSORICON_CopyImage( + _In_ HICON hicon, + _In_ BOOL bIcon, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuFlags +) { - TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n", - hinst,debugstr_w(name),type,desiredx,desiredy,loadflags); - - if (loadflags & LR_DEFAULTSIZE) { - if (type == IMAGE_ICON) { - if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON); - if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON); - } else if (type == IMAGE_CURSOR) { - if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR); - if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR); - } - } - if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED; - switch (type) { - case IMAGE_BITMAP: - return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags ); - - case IMAGE_ICON: - if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL ); - if (screen_dc) + HICON ret = NULL; + ICONINFO ii; + CURSORDATA CursorData; + + if (fuFlags & LR_COPYFROMRESOURCE) + { + /* Get the icon module/resource names */ + UNICODE_STRING ustrModule; + UNICODE_STRING ustrRsrc; + HMODULE hModule; + + ustrModule.MaximumLength = 0; + ustrRsrc.MaximumLength = 0; + + /* Get the buffer size */ + if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE)) { - return CURSORICON_Load(hinst, name, desiredx, desiredy, - GetDeviceCaps(screen_dc, BITSPIXEL), - FALSE, loadflags); + return NULL; } - break; - case IMAGE_CURSOR: - return CURSORICON_Load(hinst, name, desiredx, desiredy, - 1, TRUE, loadflags); - } - return 0; -} - -/****************************************************************************** - * CopyImage (USER32.@) Creates new image and copies attributes to it - * - * PARAMS - * hnd [I] Handle to image to copy - * type [I] Type of image to copy - * desiredx [I] Desired width of new image - * desiredy [I] Desired height of new image - * flags [I] Copy flags - * - * RETURNS - * Success: Handle to newly created image - * Failure: NULL - * - * BUGS - * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps, - * all other versions (95/2000/XP have been tested) ignore it. - * - * NOTES - * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for - * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise - * the copy will have the same depth as the screen. - * The content of the image will only be copied if the bit depth of the - * original image is compatible with the bit depth of the screen, or - * if the source is a DIB section. - * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present. - */ -HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx, - INT desiredy, UINT flags ) -{ - TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n", - hnd, type, desiredx, desiredy, flags); - - switch (type) - { - case IMAGE_BITMAP: + ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength); + if (!ustrModule.Buffer) { - HBITMAP res = NULL; - DIBSECTION ds; - int objSize; - BITMAPINFO * bi; - - objSize = GetObjectW( hnd, sizeof(ds), &ds ); - if (!objSize) return 0; - if ((desiredx < 0) || (desiredy < 0)) return 0; - - if (flags & LR_COPYFROMRESOURCE) - { - FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n"); - } - - if (desiredx == 0) desiredx = ds.dsBm.bmWidth; - if (desiredy == 0) desiredy = ds.dsBm.bmHeight; - - /* Allocate memory for a BITMAPINFOHEADER structure and a - color table. The maximum number of colors in a color table - is 256 which corresponds to a bitmap with depth 8. - Bitmaps with higher depths don't have color tables. */ - bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - if (!bi) return 0; - - bi->bmiHeader.biSize = sizeof(bi->bmiHeader); - bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes; - bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel; - bi->bmiHeader.biCompression = BI_RGB; - - if (flags & LR_CREATEDIBSECTION) - { - /* Create a DIB section. LR_MONOCHROME is ignored */ - void * bits; - HDC dc = CreateCompatibleDC(NULL); - - if (objSize == sizeof(DIBSECTION)) - { - /* The source bitmap is a DIB. - Get its attributes to create an exact copy */ - memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER)); - } - - /* Get the color table or the color masks */ - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); - - bi->bmiHeader.biWidth = desiredx; - bi->bmiHeader.biHeight = desiredy; - bi->bmiHeader.biSizeImage = 0; - - res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0); - DeleteDC(dc); - } - else - { - /* Create a device-dependent bitmap */ - - BOOL monochrome = (flags & LR_MONOCHROME); - - if (objSize == sizeof(DIBSECTION)) - { - /* The source bitmap is a DIB section. - Get its attributes */ - HDC dc = CreateCompatibleDC(NULL); - bi->bmiHeader.biSize = sizeof(bi->bmiHeader); - bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel; - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); - DeleteDC(dc); - - if (!monochrome && ds.dsBm.bmBitsPixel == 1) - { - /* Look if the colors of the DIB are black and white */ - - monochrome = - (bi->bmiColors[0].rgbRed == 0xff - && bi->bmiColors[0].rgbGreen == 0xff - && bi->bmiColors[0].rgbBlue == 0xff - && bi->bmiColors[0].rgbReserved == 0 - && bi->bmiColors[1].rgbRed == 0 - && bi->bmiColors[1].rgbGreen == 0 - && bi->bmiColors[1].rgbBlue == 0 - && bi->bmiColors[1].rgbReserved == 0) - || - (bi->bmiColors[0].rgbRed == 0 - && bi->bmiColors[0].rgbGreen == 0 - && bi->bmiColors[0].rgbBlue == 0 - && bi->bmiColors[0].rgbReserved == 0 - && bi->bmiColors[1].rgbRed == 0xff - && bi->bmiColors[1].rgbGreen == 0xff - && bi->bmiColors[1].rgbBlue == 0xff - && bi->bmiColors[1].rgbReserved == 0); - } - } - else if (!monochrome) - { - monochrome = ds.dsBm.bmBitsPixel == 1; - } - - if (monochrome) - { - res = CreateBitmap(desiredx, desiredy, 1, 1, NULL); - } - else - { - HDC screenDC = GetDC(NULL); - res = CreateCompatibleBitmap(screenDC, desiredx, desiredy); - ReleaseDC(NULL, screenDC); - } - } - - if (res) - { - /* Only copy the bitmap if it's a DIB section or if it's - compatible to the screen */ - BOOL copyContents; - - if (objSize == sizeof(DIBSECTION)) - { - copyContents = TRUE; - } - else - { - HDC screenDC = GetDC(NULL); - int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL); - ReleaseDC(NULL, screenDC); - - copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth); - } - - if (copyContents) - { - /* The source bitmap may already be selected in a device context, - use GetDIBits/StretchDIBits and not StretchBlt */ - - HDC dc; - void * bits; - - dc = CreateCompatibleDC(NULL); - - bi->bmiHeader.biWidth = ds.dsBm.bmWidth; - bi->bmiHeader.biHeight = ds.dsBm.bmHeight; - bi->bmiHeader.biSizeImage = 0; - bi->bmiHeader.biClrUsed = 0; - bi->bmiHeader.biClrImportant = 0; - - /* Fill in biSizeImage */ - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); - bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage); - - if (bits) - { - HBITMAP oldBmp; - - /* Get the image bits of the source bitmap */ - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS); - - /* Copy it to the destination bitmap */ - oldBmp = SelectObject(dc, res); - StretchDIBits(dc, 0, 0, desiredx, desiredy, - 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, - bits, bi, DIB_RGB_COLORS, SRCCOPY); - SelectObject(dc, oldBmp); - - HeapFree(GetProcessHeap(), 0, bits); - } - - DeleteDC(dc); - } - - if (flags & LR_COPYDELETEORG) - { - DeleteObject(hnd); - } - } - HeapFree(GetProcessHeap(), 0, bi); - return res; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; } - case IMAGE_ICON: - return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags); - case IMAGE_CURSOR: - /* Should call CURSORICON_ExtCopy but more testing - * needs to be done before we change this - */ - if (flags) FIXME("Flags are ignored\n"); - return CopyCursor(hnd); + + if (ustrRsrc.MaximumLength) + { + ustrRsrc.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrRsrc.MaximumLength); + if (!ustrRsrc.Buffer) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + } + + if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE)) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + if (!IS_INTRESOURCE(ustrRsrc.Buffer)) + HeapFree(GetProcessHeap(), 0, ustrRsrc.Buffer); + return NULL; + } + + /* NULL-terminate our strings */ + ustrModule.Buffer[ustrModule.Length/sizeof(WCHAR)] = UNICODE_NULL; + if (!IS_INTRESOURCE(ustrRsrc.Buffer)) + ustrRsrc.Buffer[ustrRsrc.Length/sizeof(WCHAR)] = UNICODE_NULL; + + TRACE("Got module %S, resource %p (%S).\n", ustrModule.Buffer, + ustrRsrc.Buffer, IS_INTRESOURCE(ustrRsrc.Buffer) ? L"" : ustrRsrc.Buffer); + + /* Get the module handle */ + if (!GetModuleHandleExW(0, ustrModule.Buffer, &hModule)) + { + /* This should never happen */ + ERR("Invalid handle?.\n"); + SetLastError(ERROR_INVALID_PARAMETER); + goto leave; + } + + /* Call the relevant function */ + ret = CURSORICON_LoadImageW( + hModule, + ustrRsrc.Buffer, + cxDesired, + cyDesired, + fuFlags & (LR_DEFAULTSIZE | LR_SHARED), + bIcon); + + FreeLibrary(hModule); + + /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */ + leave: + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + if (!IS_INTRESOURCE(ustrRsrc.Buffer)) + HeapFree(GetProcessHeap(), 0, ustrRsrc.Buffer); + + TRACE("Returning 0x%08x.\n", ret); + + return ret; } - return 0; -} - - -/****************************************************************************** - * LoadBitmapW (USER32.@) Loads bitmap from the executable file - * - * RETURNS - * Success: Handle to specified bitmap - * Failure: NULL - */ -HBITMAP WINAPI LoadBitmapW( - HINSTANCE instance, /* [in] Handle to application instance */ - LPCWSTR name) /* [in] Address of bitmap resource name */ -{ - return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 ); -} - -/********************************************************************** - * LoadBitmapA (USER32.@) - * - * See LoadBitmapW. - */ -HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name ) -{ - return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 ); -} - -HCURSOR -CursorIconToCursor(HICON hIcon, - BOOL SemiTransparent) -{ - UNIMPLEMENTED; - return 0; -} - -/* - * @implemented - */ -BOOL -WINAPI -DECLSPEC_HOTPATCH -SetCursorPos(int X, int Y) -{ - return NtUserxSetCursorPos(X,Y); -} - -/* - * @implemented - */ -BOOL -WINAPI -DECLSPEC_HOTPATCH -GetCursorPos(LPPOINT lpPoint) -{ - BOOL res; - /* Windows doesn't check if lpPoint == NULL, we do */ - if(!lpPoint) + + /* This is a regular copy */ + if (fuFlags & ~(LR_COPYDELETEORG | LR_SHARED)) + FIXME("Unimplemented flags: 0x%08x\n", fuFlags); + + if (!GetIconInfo(hicon, &ii)) { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + ERR("GetIconInfo failed.\n"); + return NULL; } - res = NtUserxGetCursorPos(lpPoint); + /* This is CreateIconIndirect with the LR_SHARED coat added */ + if (!CURSORICON_GetCursorDataFromIconInfo(&CursorData, &ii)) + goto Leave; - return res; -} + if (fuFlags & LR_SHARED) + CursorData.CURSORF_flags |= CURSORF_LRSHARED; -/* INTERNAL ******************************************************************/ + ret = NtUserxCreateEmptyCurObject(FALSE); + if (!ret) + goto Leave; -/* This callback routine is called directly after switching to gui mode */ -NTSTATUS -WINAPI -User32SetupDefaultCursors(PVOID Arguments, - ULONG ArgumentLength) -{ - BOOL *DefaultCursor = (BOOL*)Arguments; - HCURSOR hCursor; - - if(*DefaultCursor) + if (!NtUserSetCursorIconData(ret, NULL, NULL, &CursorData)) { - /* set default cursor */ - hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); - SetCursor(hCursor); + NtUserDestroyCursor(ret, TRUE); + goto Leave; } - else - { - /* FIXME load system cursor scheme */ - SetCursor(0); - hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); - SetCursor(hCursor); - } - - return(ZwCallbackReturn(&hCursor, sizeof(HCURSOR), STATUS_SUCCESS)); -} - -BOOL get_icon_size(HICON hIcon, SIZE *size) -{ - ICONINFO info; - BITMAP bitmap; - - if (!GetIconInfo(hIcon, &info)) return FALSE; - if (!GetObject(info.hbmMask, sizeof(bitmap), &bitmap)) return FALSE; - - size->cx = bitmap.bmWidth; - size->cy = bitmap.bmHeight; - - /* Black and white icons store both the XOR and AND bitmap in hbmMask */ - if (!info.hbmColor) - { - size->cy /= 2; - } - else - { - DeleteObject(info.hbmColor); - } - - DeleteObject(info.hbmMask); - - return TRUE; + +Leave: + DeleteObject(ii.hbmMask); + if (ii.hbmColor) DeleteObject(ii.hbmColor); + + if (ret && (fuFlags & LR_COPYDELETEORG)) + DestroyIcon(hicon); + + return ret; } NTSTATUS WINAPI @@ -2209,10 +1949,717 @@ User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength) return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS); } + +/************* PUBLIC FUNCTIONS *******************/ + +HANDLE WINAPI CopyImage( + _In_ HANDLE hImage, + _In_ UINT uType, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuFlags +) +{ + TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n", + hImage, uType, cxDesired, cyDesired, fuFlags); + switch(uType) + { + case IMAGE_BITMAP: + return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags); + case IMAGE_CURSOR: + case IMAGE_ICON: + return CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags); + default: + SetLastError(ERROR_INVALID_PARAMETER); + break; + } + return NULL; +} + +HICON WINAPI CopyIcon( + _In_ HICON hIcon +) +{ + return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0); +} + +BOOL WINAPI DrawIcon( + _In_ HDC hDC, + _In_ int X, + _In_ int Y, + _In_ HICON hIcon +) +{ + return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE); +} + +BOOL WINAPI DrawIconEx( + _In_ HDC hdc, + _In_ int xLeft, + _In_ int yTop, + _In_ HICON hIcon, + _In_ int cxWidth, + _In_ int cyWidth, + _In_ UINT istepIfAniCur, + _In_opt_ HBRUSH hbrFlickerFreeDraw, + _In_ UINT diFlags +) +{ + return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, + istepIfAniCur, hbrFlickerFreeDraw, diFlags, + 0, 0); +} + +BOOL WINAPI GetIconInfo( + _In_ HICON hIcon, + _Out_ PICONINFO piconinfo +) +{ + return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE); +} + +BOOL WINAPI DestroyIcon( + _In_ HICON hIcon +) +{ + return NtUserDestroyCursor(hIcon, FALSE); +} + +HICON WINAPI LoadIconA( + _In_opt_ HINSTANCE hInstance, + _In_ LPCSTR lpIconName +) +{ + TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName)); + + return LoadImageA(hInstance, + lpIconName, + IMAGE_ICON, + 0, + 0, + LR_SHARED | LR_DEFAULTSIZE ); +} + +HICON WINAPI LoadIconW( + _In_opt_ HINSTANCE hInstance, + _In_ LPCWSTR lpIconName +) +{ + TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName)); + + return LoadImageW(hInstance, + lpIconName, + IMAGE_ICON, + 0, + 0, + LR_SHARED | LR_DEFAULTSIZE ); +} + +HCURSOR WINAPI LoadCursorA( + _In_opt_ HINSTANCE hInstance, + _In_ LPCSTR lpCursorName +) +{ + TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName)); + + return LoadImageA(hInstance, + lpCursorName, + IMAGE_CURSOR, + 0, + 0, + LR_SHARED | LR_DEFAULTSIZE ); +} + +HCURSOR WINAPI LoadCursorW( + _In_opt_ HINSTANCE hInstance, + _In_ LPCWSTR lpCursorName +) +{ + TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName)); + + return LoadImageW(hInstance, + lpCursorName, + IMAGE_CURSOR, + 0, + 0, + LR_SHARED | LR_DEFAULTSIZE ); +} + +HCURSOR WINAPI LoadCursorFromFileA( + _In_ LPCSTR lpFileName +) +{ + TRACE("%s\n", debugstr_a(lpFileName)); + + return LoadImageA(NULL, + lpFileName, + IMAGE_CURSOR, + 0, + 0, + LR_LOADFROMFILE | LR_DEFAULTSIZE ); +} + +HCURSOR WINAPI LoadCursorFromFileW( + _In_ LPCWSTR lpFileName +) +{ + TRACE("%s\n", debugstr_w(lpFileName)); + + return LoadImageW(NULL, + lpFileName, + IMAGE_CURSOR, + 0, + 0, + LR_LOADFROMFILE | LR_DEFAULTSIZE ); +} + +HBITMAP WINAPI LoadBitmapA( + _In_opt_ HINSTANCE hInstance, + _In_ LPCSTR lpBitmapName +) +{ + TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName)); + + return LoadImageA(hInstance, + lpBitmapName, + IMAGE_BITMAP, + 0, + 0, + 0); +} + +HBITMAP WINAPI LoadBitmapW( + _In_opt_ HINSTANCE hInstance, + _In_ LPCWSTR lpBitmapName +) +{ + TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName)); + + return LoadImageW(hInstance, + lpBitmapName, + IMAGE_BITMAP, + 0, + 0, + 0); +} + +HANDLE WINAPI LoadImageA( + _In_opt_ HINSTANCE hinst, + _In_ LPCSTR lpszName, + _In_ UINT uType, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuLoad +) +{ + HANDLE res; + LPWSTR u_name; + DWORD len; + + if (IS_INTRESOURCE(lpszName)) + return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad); + + len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 ); + u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len ); + + res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad); + HeapFree(GetProcessHeap(), 0, u_name); + return res; +} + +HANDLE WINAPI LoadImageW( + _In_opt_ HINSTANCE hinst, + _In_ LPCWSTR lpszName, + _In_ UINT uType, + _In_ int cxDesired, + _In_ int cyDesired, + _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 */ + switch(uType) + { + case IMAGE_BITMAP: + return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad); + case IMAGE_CURSOR: + case IMAGE_ICON: + return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON); + default: + SetLastError(ERROR_INVALID_PARAMETER); + break; + } + return NULL; +} + +int WINAPI LookupIconIdFromDirectory( + _In_ PBYTE presbits, + _In_ BOOL fIcon +) +{ + return LookupIconIdFromDirectoryEx( presbits, fIcon, + fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR), + fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME ); +} + +int WINAPI LookupIconIdFromDirectoryEx( + _In_ PBYTE presbits, + _In_ BOOL fIcon, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT Flags +) +{ + WORD bppDesired; + CURSORICONDIR* dir = (CURSORICONDIR*)presbits; + CURSORICONDIRENTRY* entry; + int i, numMatch = 0, iIndex = -1; + WORD width, height, BitCount = 0; + BOOL notPaletted = FALSE; + ULONG bestScore = 0xFFFFFFFF, score; + + TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags); + + if(!(dir && !dir->idReserved && (dir->idType & 3))) + { + WARN("Invalid resource.\n"); + return 0; + } + + if(Flags & LR_MONOCHROME) + bppDesired = 1; + else + { + HDC icScreen; + icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL); + if(!icScreen) + return FALSE; + + bppDesired = GetDeviceCaps(icScreen, BITSPIXEL); + DeleteDC(icScreen); + } + + if(!cxDesired) + cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256; + if(!cyDesired) + cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR) : 256; + + /* Find the best match for the desired size */ + for(i = 0; i < dir->idCount; i++) + { + entry = &dir->idEntries[i]; + width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; + /* Height is twice as big in cursor resources */ + height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; + /* 0 represents 256 */ + if(!width) width = 256; + if(!height) height = 256; + /* Calculate the "score" (lower is better) */ + score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); + if( score > bestScore) + continue; + /* Bigger than requested lowers the score */ + if(width > cxDesired) + score -= width - cxDesired; + if(height > cyDesired) + score -= height - cyDesired; + if(score > bestScore) + continue; + if(score == bestScore) + { + if(entry->wBitCount > BitCount) + BitCount = entry->wBitCount; + numMatch++; + continue; + } + iIndex = i; + numMatch = 1; + bestScore = score; + BitCount = entry->wBitCount; + } + + if(numMatch == 1) + { + /* Only one entry fits the asked dimensions */ + return dir->idEntries[iIndex].wResId; + } + + /* Avoid paletted icons on non-paletted device */ + if (bppDesired > 8 && BitCount > 8) + notPaletted = TRUE; + + BitCount = 0; + iIndex = -1; + /* Now find the entry with the best depth */ + for(i = 0; i < dir->idCount; i++) + { + entry = &dir->idEntries[i]; + width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; + height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; + /* 0 represents 256 */ + if(!width) width = 256; + if(!height) height = 256; + /* Check if this is the best match we had */ + score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); + if(width > cxDesired) + score -= width - cxDesired; + if(height > cyDesired) + score -= height - cyDesired; + if(score != bestScore) + continue; + /* Exact match? */ + if(entry->wBitCount == bppDesired) + return entry->wResId; + /* We take the highest possible but smaller than the display depth */ + if((entry->wBitCount > BitCount) && (entry->wBitCount < bppDesired)) + { + /* Avoid paletted icons on non paletted devices */ + if ((entry->wBitCount <= 8) && notPaletted) + continue; + iIndex = i; + BitCount = entry->wBitCount; + } + } + + if(iIndex >= 0) + return dir->idEntries[iIndex].wResId; + + /* No inferior or equal depth available. Get the smallest bigger one */ + BitCount = 0xFFFF; + iIndex = -1; + for(i = 0; i < dir->idCount; i++) + { + entry = &dir->idEntries[i]; + width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; + height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; + /* 0 represents 256 */ + if(!width) width = 256; + if(!height) height = 256; + /* Check if this is the best match we had */ + score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); + if(width > cxDesired) + score -= width - cxDesired; + if(height > cyDesired) + score -= height - cyDesired; + if(score != bestScore) + continue; + /* Check the bit depth */ + if(entry->wBitCount < BitCount) + { + if((entry->wBitCount <= 8) && notPaletted) + continue; + iIndex = i; + BitCount = entry->wBitCount; + } + } + if (iIndex >= 0) + return dir->idEntries[iIndex].wResId; + + return 0; +} + +HICON WINAPI CreateIcon( + _In_opt_ HINSTANCE hInstance, + _In_ int nWidth, + _In_ int nHeight, + _In_ BYTE cPlanes, + _In_ BYTE cBitsPixel, + _In_ const BYTE *lpbANDbits, + _In_ const BYTE *lpbXORbits +) +{ + ICONINFO iinfo; + HICON hIcon; + + TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n", + nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits); + + iinfo.fIcon = TRUE; + iinfo.xHotspot = nWidth / 2; + iinfo.yHotspot = nHeight / 2; + if (cPlanes * cBitsPixel > 1) + { + iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits ); + iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits ); + } + else + { + iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits ); + iinfo.hbmColor = NULL; + } + + hIcon = CreateIconIndirect( &iinfo ); + + DeleteObject( iinfo.hbmMask ); + if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor ); + + return hIcon; +} + +HICON WINAPI CreateIconFromResource( + _In_ PBYTE presbits, + _In_ DWORD dwResSize, + _In_ BOOL fIcon, + _In_ DWORD dwVer +) +{ + return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE | LR_SHARED); +} + +HICON WINAPI CreateIconFromResourceEx( + _In_ PBYTE pbIconBits, + _In_ DWORD cbIconBits, + _In_ BOOL fIcon, + _In_ DWORD dwVersion, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT uFlags +) +{ + CURSORDATA cursorData; + HICON hIcon; + BOOL isAnimated; + + TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags); + + if(uFlags & LR_DEFAULTSIZE) + { + if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR); + if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR); + } + + ZeroMemory(&cursorData, sizeof(cursorData)); + cursorData.cx = cxDesired; + cursorData.cy = cyDesired; + 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) + { + WORD* pt = (WORD*)pbIconBits; + cursorData.xHotspot = *pt++; + cursorData.yHotspot = *pt++; + pbIconBits = (PBYTE)pt; + } + + if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits)) + { + ERR("Couldn't fill the CURSORDATA structure.\n"); + if (ResHandle) + FreeResource(ResHandle); + return NULL; + } + if (ResHandle) + FreeResource(ResHandle); + isAnimated = FALSE; + } + + if (uFlags & LR_SHARED) + cursorData.CURSORF_flags |= CURSORF_LRSHARED; + + hIcon = NtUserxCreateEmptyCurObject(isAnimated); + if (!hIcon) + goto end_error; + + if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData)) + { + ERR("NtUserSetCursorIconData failed.\n"); + NtUserDestroyCursor(hIcon, TRUE); + goto end_error; + } + + if(isAnimated) + HeapFree(GetProcessHeap(), 0, cursorData.aspcur); + + return hIcon; + + /* Clean up */ +end_error: + if(isAnimated) + HeapFree(GetProcessHeap(), 0, cursorData.aspcur); + DeleteObject(cursorData.hbmMask); + if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); + if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); + + return NULL; +} + +HICON WINAPI CreateIconIndirect( + _In_ PICONINFO piconinfo +) +{ + /* As simple as creating a handle, and let win32k deal with the bitmaps */ + HICON hiconRet; + CURSORDATA cursorData; + + TRACE("%p.\n", piconinfo); + + ZeroMemory(&cursorData, sizeof(cursorData)); + + if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo)) + return NULL; + + hiconRet = NtUserxCreateEmptyCurObject(FALSE); + if(!hiconRet) + goto end_error; + + if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, &cursorData)) + { + NtUserDestroyCursor(hiconRet, FALSE); + goto end_error; + } + + TRACE("Returning 0x%08x.\n", hiconRet); + + return hiconRet; + +end_error: + /* Clean up */ + DeleteObject(cursorData.hbmMask); + if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); + if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); + + return NULL; +} + +HCURSOR WINAPI CreateCursor( + _In_opt_ HINSTANCE hInst, + _In_ int xHotSpot, + _In_ int yHotSpot, + _In_ int nWidth, + _In_ int nHeight, + _In_ const VOID *pvANDPlane, + _In_ const VOID *pvXORPlane +) +{ + ICONINFO info; + HCURSOR hCursor; + + TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n", + nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane); + + info.fIcon = FALSE; + info.xHotspot = xHotSpot; + info.yHotspot = yHotSpot; + info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane ); + info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane ); + hCursor = CreateIconIndirect( &info ); + DeleteObject( info.hbmMask ); + DeleteObject( info.hbmColor ); + return hCursor; +} + +BOOL WINAPI SetSystemCursor( + _In_ HCURSOR hcur, + _In_ DWORD id +) +{ + if (hcur == NULL) + { + hcur = LoadImageW( 0, MAKEINTRESOURCE(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ); + if (hcur == NULL) + { + return FALSE; + } + } + return NtUserSetSystemCursor(hcur,id); +} + +BOOL WINAPI SetCursorPos( + _In_ int X, + _In_ int Y +) +{ + return NtUserxSetCursorPos(X,Y); +} + +BOOL WINAPI GetCursorPos( + _Out_ LPPOINT lpPoint +) +{ + return NtUserxGetCursorPos(lpPoint); +} + +int WINAPI ShowCursor( + _In_ BOOL bShow +) +{ + return NtUserxShowCursor(bShow); +} + +HCURSOR WINAPI GetCursor(void) +{ + return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR); +} + +BOOL WINAPI DestroyCursor( + _In_ HCURSOR hCursor +) +{ + 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); } - diff --git a/reactos/win32ss/user/user32/windows/cursoricon_new.c b/reactos/win32ss/user/user32/windows/cursoricon_new.c deleted file mode 100644 index c0b29e331c8..00000000000 --- a/reactos/win32ss/user/user32/windows/cursoricon_new.c +++ /dev/null @@ -1,2665 +0,0 @@ -/* - * PROJECT: ReactOS user32.dll - * COPYRIGHT: GPL - See COPYING in the top level directory - * FILE: win32ss/user//user32/windows/cursoricon.c - * PURPOSE: cursor and icons implementation - * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org) - */ - -#include - -#include - -WINE_DEFAULT_DEBUG_CHANNEL(cursor); -WINE_DECLARE_DEBUG_CHANNEL(icon); -//WINE_DECLARE_DEBUG_CHANNEL(resource); - -/* We only use Wide string functions */ -#undef MAKEINTRESOURCE -#define MAKEINTRESOURCE MAKEINTRESOURCEW - -/************* USER32 INTERNAL FUNCTIONS **********/ - -VOID LoadSystemCursors(VOID) -{ - if (!gpsi->hIconSmWindows) - { - ERR("Loading System Cursors\n"); - NtUserSetSystemCursor(LoadImageW( 0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_NORMAL); - NtUserSetSystemCursor(LoadImageW( 0, IDC_IBEAM, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_IBEAM); - NtUserSetSystemCursor(LoadImageW( 0, IDC_WAIT, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_WAIT); - NtUserSetSystemCursor(LoadImageW( 0, IDC_CROSS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_CROSS); - NtUserSetSystemCursor(LoadImageW( 0, IDC_UPARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_UP); - NtUserSetSystemCursor(LoadImageW( 0, IDC_ICON, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_ICON); - NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZE); - NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENWSE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENWSE); - NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENESW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENESW); - NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEWE, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZEWE); - NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENS, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENS); - NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEALL, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZEALL); - NtUserSetSystemCursor(LoadImageW( 0, IDC_NO, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_NO); - NtUserSetSystemCursor(LoadImageW( 0, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_HAND); - NtUserSetSystemCursor(LoadImageW( 0, IDC_APPSTARTING, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_APPSTARTING); - NtUserSetSystemCursor(LoadImageW( 0, IDC_HELP, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_HELP); - } -} - -/* This callback routine is called directly after switching to gui mode */ -NTSTATUS -WINAPI -User32SetupDefaultCursors(PVOID Arguments, - ULONG ArgumentLength) -{ - BOOL *DefaultCursor = (BOOL*)Arguments; - HCURSOR hCursor; - - /* Load system cursors first */ - LoadSystemCursors(); - - if(*DefaultCursor) - { - /* set default cursor */ - hCursor = LoadCursorW(0, IDC_ARROW); - SetCursor(hCursor); - } - else - { - /* FIXME load system cursor scheme */ - SetCursor(0); - hCursor = LoadCursorW(0, IDC_ARROW); - SetCursor(hCursor); - } - - return(ZwCallbackReturn(&hCursor, sizeof(HCURSOR), STATUS_SUCCESS)); -} - -BOOL get_icon_size(HICON hIcon, SIZE *size) -{ - return NtUserGetIconSize(hIcon, 0, &size->cx, &size->cy); -} - -HCURSOR CursorIconToCursor(HICON hIcon, BOOL SemiTransparent) -{ - UNIMPLEMENTED; - return NULL; -} - -/************* IMPLEMENTATION HELPERS ******************/ - -static const WCHAR DISPLAYW[] = L"DISPLAY"; - -static void *map_fileW( LPCWSTR name, LPDWORD filesize ) -{ - HANDLE hFile, hMapping; - LPVOID ptr = NULL; - - hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 ); - if (hFile != INVALID_HANDLE_VALUE) - { - hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); - if (hMapping) - { - ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 ); - CloseHandle( hMapping ); - if (filesize) - *filesize = GetFileSize( hFile, NULL ); - } - CloseHandle( hFile ); - } - return ptr; -} - -static int get_dib_image_size( int width, int height, int depth ) -{ - return (((width * depth + 31) / 8) & ~3) * abs( height ); -} - -static BOOL is_dib_monochrome( const BITMAPINFO* info ) -{ - if (info->bmiHeader.biBitCount != 1) return FALSE; - - if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors; - - /* Check if the first color is black */ - if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0)) - { - rgb++; - - /* Check if the second color is white */ - return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff) - && (rgb->rgbtBlue == 0xff)); - } - else return FALSE; - } - else /* assume BITMAPINFOHEADER */ - { - const RGBQUAD *rgb = info->bmiColors; - - /* Check if the first color is black */ - if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && - (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0)) - { - rgb++; - - /* Check if the second color is white */ - return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff) - && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0)); - } - else return FALSE; - } -} - -static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) -{ - unsigned int colors, size, masks = 0; - - if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; - colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; - return sizeof(BITMAPCOREHEADER) + colors * - ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD)); - } - else /* assume BITMAPINFOHEADER */ - { - colors = info->bmiHeader.biClrUsed; - if (colors > 256) /* buffer overflow otherwise */ - colors = 256; - if (!colors && (info->bmiHeader.biBitCount <= 8)) - colors = 1 << info->bmiHeader.biBitCount; - if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; - size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); - return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD)); - } -} - -static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, - LONG *height, WORD *bpp, DWORD *compr ) -{ - if (header->biSize == sizeof(BITMAPCOREHEADER)) - { - const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header; - *width = core->bcWidth; - *height = core->bcHeight; - *bpp = core->bcBitCount; - *compr = 0; - return 0; - } - else if (header->biSize == sizeof(BITMAPINFOHEADER) || - header->biSize == sizeof(BITMAPV4HEADER) || - header->biSize == sizeof(BITMAPV5HEADER)) - { - *width = header->biWidth; - *height = header->biHeight; - *bpp = header->biBitCount; - *compr = header->biCompression; - return 1; - } - ERR("(%d): unknown/wrong size for header\n", header->biSize ); - return -1; -} - -/* copy an icon bitmap, even when it can't be selected into a DC */ -/* helper for CreateIconIndirect */ -static void stretch_blt_icon(HDC hdc_dst, int dst_width, int dst_height, HBITMAP src) -{ - HDC hdc = CreateCompatibleDC( 0 ); - BITMAP bm; - HBITMAP hbmpPrev; - - GetObjectW(src, sizeof(bm), &bm); - - hbmpPrev = SelectObject(hdc, src); - - if (!hbmpPrev) /* do it the hard way */ - { - BITMAPINFO *info; - void *bits; - - if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return; - info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - info->bmiHeader.biWidth = bm.bmWidth; - info->bmiHeader.biHeight = bm.bmHeight; - info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES ); - info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL ); - info->bmiHeader.biCompression = BI_RGB; - info->bmiHeader.biSizeImage = get_dib_image_size( bm.bmWidth, bm.bmHeight, info->bmiHeader.biBitCount ); - info->bmiHeader.biXPelsPerMeter = 0; - info->bmiHeader.biYPelsPerMeter = 0; - info->bmiHeader.biClrUsed = 0; - info->bmiHeader.biClrImportant = 0; - bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ); - if (bits && GetDIBits( hdc, src, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) - StretchDIBits( hdc_dst, 0, 0, dst_width, dst_height, - 0, 0, bm.bmWidth, bm.bmHeight, bits, info, DIB_RGB_COLORS, SRCCOPY ); - - HeapFree( GetProcessHeap(), 0, bits ); - HeapFree( GetProcessHeap(), 0, info ); - } - else - { - StretchBlt( hdc_dst, 0, 0, dst_width, dst_height, hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY ); - SelectObject(hdc, hbmpPrev); - } - - DeleteDC( hdc ); -} - -/*********************************************************************** - * bmi_has_alpha - */ -static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits ) -{ - int i; - BOOL has_alpha = FALSE; - const unsigned char *ptr = bits; - - if (info->bmiHeader.biBitCount != 32) return FALSE; - for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4) - if ((has_alpha = (ptr[3] != 0))) break; - return has_alpha; -} - -/*********************************************************************** - * create_alpha_bitmap - * - * Create the alpha bitmap for a 32-bpp icon that has an alpha channel. - */ -static -HBITMAP -create_alpha_bitmap( - _In_opt_ HBITMAP color, - _In_opt_ BITMAPINFO *src_info, - _In_opt_ const void *color_bits, - _In_ LONG width, - _In_ LONG height) -{ - HBITMAP alpha = NULL, hbmpOld; - HDC hdc = NULL, hdcScreen; - unsigned char *ptr; - void *bits = NULL; - size_t size; - - hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); - if (!hdcScreen) - return NULL; - hdc = CreateCompatibleDC(hdcScreen); - if (!hdc) - { - DeleteDC(hdcScreen); - return NULL; - } - - if (color) - { - BITMAP bm; - BITMAPINFO *info = NULL; - - TRACE("Creating alpha bitmap from existing bitmap.\n"); - - if (!GetObjectW( color, sizeof(bm), &bm )) - goto done; - if (bm.bmBitsPixel != 32) - goto done; - - size = get_dib_image_size(bm.bmWidth, bm.bmHeight, 32); - - info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])); - if(!info) - goto done; - info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - info->bmiHeader.biWidth = bm.bmWidth; - info->bmiHeader.biHeight = -bm.bmHeight; - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biBitCount = 32; - info->bmiHeader.biCompression = BI_RGB; - info->bmiHeader.biSizeImage = size; - info->bmiHeader.biXPelsPerMeter = 0; - info->bmiHeader.biYPelsPerMeter = 0; - info->bmiHeader.biClrUsed = 0; - info->bmiHeader.biClrImportant = 0; - - bits = HeapAlloc(GetProcessHeap(), 0, size); - if(!bits) - { - HeapFree(GetProcessHeap(), 0, info); - goto done; - } - if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) - { - HeapFree(GetProcessHeap(), 0, info); - goto done; - } - if (!bmi_has_alpha( info, bits )) - { - HeapFree(GetProcessHeap(), 0, info); - goto done; - } - - /* pre-multiply by alpha */ - for (ptr = bits; ptr < ((BYTE*)bits + size); ptr += 4) - { - unsigned int alpha = ptr[3]; - ptr[0] = (ptr[0] * alpha) / 255; - ptr[1] = (ptr[1] * alpha) / 255; - ptr[2] = (ptr[2] * alpha) / 255; - } - - /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */ - alpha = CreateDIBitmap(hdc, NULL, CBM_INIT | 2, bits, info, DIB_RGB_COLORS); - - HeapFree(GetProcessHeap(), 0, info); - } - else - { - WORD bpp; - DWORD compr; - LONG orig_width, orig_height; - - TRACE("Creating alpha bitmap from bitmap info.\n"); - - if(!bmi_has_alpha(src_info, color_bits)) - goto done; - - if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &orig_width, &orig_height, &bpp, &compr)) - goto done; - if(bpp != 32) - goto done; - - size = get_dib_image_size(orig_width, orig_height, bpp); - bits = HeapAlloc(GetProcessHeap(), 0, size); - if(!bits) - goto done; - CopyMemory(bits, color_bits, size); - /* pre-multiply by alpha */ - for (ptr = bits; ptr < ((BYTE*)bits + size); ptr += 4) - { - unsigned int alpha = ptr[3]; - ptr[0] = (ptr[0] * alpha) / 255; - ptr[1] = (ptr[1] * alpha) / 255; - ptr[2] = (ptr[2] * alpha) / 255; - } - - /* Create the bitmap. Set the bitmap info to have the right width and height */ - if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = width; - ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = height; - } - else - { - src_info->bmiHeader.biWidth = width; - src_info->bmiHeader.biHeight = height; - } - /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */ - alpha = CreateDIBitmap(hdcScreen, NULL, 2, NULL, src_info, DIB_RGB_COLORS); - /* Restore values */ - if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = orig_width; - ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = orig_height; - } - else - { - src_info->bmiHeader.biWidth = orig_width; - src_info->bmiHeader.biHeight = orig_height; - } - if(!alpha) - goto done; - hbmpOld = SelectObject(hdc, alpha); - if(!hbmpOld) - { - DeleteObject(alpha); - alpha = NULL; - goto done; - } - if(!StretchDIBits( hdc, 0, 0, width, height, - 0, 0, orig_width, orig_height, - bits, src_info, DIB_RGB_COLORS, SRCCOPY )) - { - SelectObject(hdc, hbmpOld); - hbmpOld = NULL; - DeleteObject(alpha); - alpha = NULL; - } - else - { - SelectObject(hdc, hbmpOld); - } - } - -done: - DeleteDC(hdcScreen); - DeleteDC( hdc ); - if(bits) HeapFree(GetProcessHeap(), 0, bits); - - TRACE("Returning 0x%08x.\n", 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" - -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; - - /* Check our file is what it claims to be */ - if ( dwFileSize < sizeof(*dir) ) - return NULL; - - if (dwFileSize < FIELD_OFFSET(CURSORICONFILEDIR, idEntries[dir->idCount])) - 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; iidCount; i++) - { - fakeEntry = &fakeDir->idEntries[i]; - entry = &dir->idEntries[i]; - /* Take this as an occasion to perform a size check */ - if ((entry->dwDIBOffset > dwFileSize) - || ((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 */ - if (((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biSize == sizeof(BITMAPCOREHEADER)) - fakeEntry->wBitCount = ((BITMAPCOREHEADER *)((char *)dir + entry->dwDIBOffset))->bcBitCount; - else - 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]; -} - -DWORD -get_best_icon_file_offset( - _In_ const LPBYTE dir, - _In_ DWORD dwFileSize, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ BOOL bIcon, - _In_ DWORD fuLoad, - _Out_ POINT *ptHotSpot -) -{ - const CURSORICONFILEDIRENTRY *entry; - - entry = get_best_icon_file_entry((CURSORICONFILEDIR *) dir, dwFileSize, cxDesired, cyDesired, bIcon, fuLoad); - - if(ptHotSpot) - { - ptHotSpot->x = entry->xHotspot; - ptHotSpot->y = entry->yHotspot; - } - - if(entry) - return entry->dwDIBOffset; - - return 0; -} - - - -/************* IMPLEMENTATION CORE ****************/ - -static BOOL CURSORICON_GetCursorDataFromBMI( - _Inout_ CURSORDATA* pdata, - _In_ const BITMAPINFO *pbmi -) -{ - UINT ubmiSize = bitmap_info_size(pbmi, DIB_RGB_COLORS); - BOOL monochrome = is_dib_monochrome(pbmi); - LONG width, height; - WORD bpp; - DWORD compr; - int ibmpType; - HDC hdc, hdcScreen; - BITMAPINFO* pbmiCopy; - HBITMAP hbmpOld = NULL; - BOOL bResult = FALSE; - const VOID *pvColor, *pvMask; - - ibmpType = DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr); - /* Invalid data */ - if(ibmpType < 0) - return FALSE; - - /* No compression for icons */ - if(compr != BI_RGB) - return FALSE; - - /* If no dimensions were set, use the one from the icon */ - if(!pdata->cx) pdata->cx = width; - if(!pdata->cy) pdata->cy = height < 0 ? -height/2 : height/2; - - /* Fix the hotspot coords */ - if(pdata->rt == (USHORT)((ULONG_PTR)RT_CURSOR)) - { - if(pdata->cx != width) - pdata->xHotspot = (pdata->xHotspot * pdata->cx) / width; - if(pdata->cy != height/2) - pdata->yHotspot = (pdata->yHotspot * pdata->cy * 2) / height; - } - else - { - pdata->xHotspot = pdata->cx/2; - pdata->yHotspot = pdata->cy/2; - } - - hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); - if(!hdcScreen) - return FALSE; - hdc = CreateCompatibleDC(hdcScreen); - if(!hdc) - { - DeleteDC(hdcScreen); - return FALSE; - } - - pbmiCopy = HeapAlloc(GetProcessHeap(), 0, max(ubmiSize, FIELD_OFFSET(BITMAPINFO, bmiColors[3]))); - if(!pbmiCopy) - goto done; - RtlCopyMemory(pbmiCopy, pbmi, ubmiSize); - - /* In an icon/cursor, the BITMAPINFO holds twice the height */ - if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcHeight /= 2; - else - pbmiCopy->bmiHeader.biHeight /= 2; - height /= 2; - - pvColor = (const char*)pbmi + ubmiSize; - pvMask = (const char*)pvColor + - get_dib_image_size(width, height, bpp ); - - /* Set XOR bits */ - if(monochrome) - { - /* Create the 1bpp bitmap which will contain everything */ - pdata->hbmColor = NULL; - pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy * 2, 1, 1, NULL); - if(!pdata->hbmMask) - goto done; - hbmpOld = SelectObject(hdc, pdata->hbmMask); - if(!hbmpOld) - goto done; - - if(!StretchDIBits(hdc, 0, pdata->cy, pdata->cx, pdata->cy, - 0, 0, width, height, - pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) - goto done; - pdata->bpp = 1; - } - else - { - /* Create the bitmap. It has to be compatible with the screen surface */ - pdata->hbmColor = CreateCompatibleBitmap(hdcScreen, pdata->cx, pdata->cy); - if(!pdata->hbmColor) - goto done; - /* Create the 1bpp mask bitmap */ - pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy, 1, 1, NULL); - if(!pdata->hbmMask) - goto done; - hbmpOld = SelectObject(hdc, pdata->hbmColor); - if(!hbmpOld) - goto done; - if(!StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy, - 0, 0, width, height, - pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) - goto done; - pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL); - pdata->hbmAlpha = create_alpha_bitmap(NULL, pbmiCopy, pvColor, pdata->cx, pdata->cy); - - /* Now convert the info to monochrome for the mask bits */ - if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) - { - RGBQUAD *rgb = pbmiCopy->bmiColors; - - pbmiCopy->bmiHeader.biClrUsed = pbmiCopy->bmiHeader.biClrImportant = 2; - rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00; - rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff; - rgb[0].rgbReserved = rgb[1].rgbReserved = 0; - pbmiCopy->bmiHeader.biBitCount = 1; - } - else - { - RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pbmiCopy) + 1); - - rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00; - rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff; - ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount = 1; - } - } - /* Set the mask bits */ - if(!SelectObject(hdc, pdata->hbmMask)) - goto done; - bResult = StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy, - 0, 0, width, height, - pvMask, pbmiCopy, DIB_RGB_COLORS, SRCCOPY) != 0; - -done: - DeleteDC(hdcScreen); - if(hbmpOld) SelectObject(hdc, hbmpOld); - DeleteDC(hdc); - if(pbmiCopy) HeapFree(GetProcessHeap(), 0, pbmiCopy); - /* Clean up in case of failure */ - if(!bResult) - { - if(pdata->hbmMask) DeleteObject(pdata->hbmMask); - if(pdata->hbmColor) DeleteObject(pdata->hbmColor); - if(pdata->hbmAlpha) DeleteObject(pdata->hbmAlpha); - } - return bResult; -} - -static BOOL CURSORICON_GetCursorDataFromIconInfo( - _Out_ CURSORDATA* pCursorData, - _In_ ICONINFO* pIconInfo -) -{ - BITMAP bm; - - ZeroMemory(pCursorData, sizeof(*pCursorData)); - if(pIconInfo->hbmColor) - { - /* We must convert the color bitmap to screen format */ - HDC hdcScreen, hdcMem; - HBITMAP hbmpPrev; - - /* The mask dictates its dimensions */ - if (!GetObject(pIconInfo->hbmMask, sizeof(bm), &bm)) - return FALSE; - hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); - if(!hdcScreen) - return FALSE; - hdcMem = CreateCompatibleDC(hdcScreen); - if(!hdcMem) - { - DeleteDC(hdcScreen); - return FALSE; - } - pCursorData->hbmColor = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight); - DeleteDC(hdcScreen); - if (!pCursorData->hbmColor) - { - DeleteDC(hdcMem); - return FALSE; - } - hbmpPrev = SelectObject(hdcMem, pCursorData->hbmColor); - if (!hbmpPrev) - { - DeleteDC(hdcMem); - DeleteObject(pCursorData->hbmColor); - return FALSE; - } - stretch_blt_icon( hdcMem, bm.bmWidth, bm.bmHeight, pIconInfo->hbmColor); - SelectObject(hdcMem, hbmpPrev); - DeleteDC(hdcMem); - } - pCursorData->hbmMask = CopyImage(pIconInfo->hbmMask, IMAGE_BITMAP, 0, 0, LR_MONOCHROME); - if(!pCursorData->hbmMask) - return FALSE; - - /* Now, fill some information */ - pCursorData->rt = (USHORT)((ULONG_PTR)(pIconInfo->fIcon ? RT_ICON : RT_CURSOR)); - if(pCursorData->hbmColor) - { - GetObject(pCursorData->hbmColor, sizeof(bm), &bm); - pCursorData->bpp = bm.bmBitsPixel; - pCursorData->cx = bm.bmWidth; - pCursorData->cy = bm.bmHeight; - if(pCursorData->bpp == 32) - pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL, 0, 0); - } - else - { - GetObject(pCursorData->hbmMask, sizeof(bm), &bm); - pCursorData->bpp = 1; - pCursorData->cx = bm.bmWidth; - pCursorData->cy = bm.bmHeight/2; - } - - if(pIconInfo->fIcon) - { - pCursorData->xHotspot = pCursorData->cx/2; - pCursorData->yHotspot = pCursorData->cy/2; - } - else - { - pCursorData->xHotspot = pIconInfo->xHotspot; - pCursorData->yHotspot = pIconInfo->yHotspot; - } - - 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 -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 - -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 -HBITMAP -BITMAP_LoadImageW( - _In_opt_ HINSTANCE hinst, - _In_ LPCWSTR lpszName, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT fuLoad -) -{ - const BITMAPINFO* pbmi; - BITMAPINFO* pbmiScaled = NULL; - BITMAPINFO* pbmiCopy = NULL; - const VOID* pvMapping = NULL; - DWORD dwOffset = 0; - HGLOBAL hgRsrc = NULL; - int iBMISize; - PVOID pvBits; - HDC hdcScreen = NULL; - HDC hdc = NULL; - HBITMAP hbmpOld, hbmpRet = NULL; - LONG width, height; - WORD bpp; - DWORD compr; - - /* Map the bitmap info */ - if(fuLoad & LR_LOADFROMFILE) - { - const BITMAPFILEHEADER* pbmfh; - - pvMapping = map_fileW(lpszName, NULL); - if(!pvMapping) - return NULL; - pbmfh = pvMapping; - if (pbmfh->bfType != 0x4d42 /* 'BM' */) - { - WARN("Invalid/unsupported bitmap format!\n"); - goto end; - } - pbmi = (const BITMAPINFO*)(pbmfh + 1); - - /* Get the image bits */ - if(pbmfh->bfOffBits) - dwOffset = pbmfh->bfOffBits - sizeof(BITMAPFILEHEADER); - } - else - { - HRSRC hrsrc; - - /* Caller wants an OEM bitmap */ - if(!hinst) - hinst = User32Instance; - hrsrc = FindResourceW(hinst, lpszName, RT_BITMAP); - if(!hrsrc) - return NULL; - hgRsrc = LoadResource(hinst, hrsrc); - if(!hgRsrc) - return NULL; - pbmi = LockResource(hgRsrc); - if(!pbmi) - return NULL; - } - - /* Fix up values */ - if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == -1) - goto end; - if((width > 65535) || (height > 65535)) - goto end; - if(cxDesired == 0) - cxDesired = width; - if(cyDesired == 0) - cyDesired = height; - else if(height < 0) - cyDesired = -cyDesired; - - iBMISize = bitmap_info_size(pbmi, DIB_RGB_COLORS); - - /* Get a pointer to the image data */ - pvBits = (char*)pbmi + (dwOffset ? dwOffset : iBMISize); - - /* Create a copy of the info describing the bitmap in the file */ - pbmiCopy = HeapAlloc(GetProcessHeap(), 0, iBMISize); - if(!pbmiCopy) - goto end; - CopyMemory(pbmiCopy, pbmi, iBMISize); - - /* Fix it up, if needed */ - if(fuLoad & (LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS)) - { - WORD bpp, incr, numColors; - char* pbmiColors; - RGBTRIPLE* ptr; - COLORREF crWindow, cr3DShadow, cr3DFace, cr3DLight; - BYTE pixel = *((BYTE*)pvBits); - UINT i; - - if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - bpp = ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount; - numColors = 1 << bpp; - /* BITMAPCOREINFO holds RGBTRIPLEs */ - incr = 3; - } - else - { - bpp = pbmiCopy->bmiHeader.biBitCount; - /* BITMAPINFOHEADER holds RGBQUADs */ - incr = 4; - numColors = pbmiCopy->bmiHeader.biClrUsed; - if(numColors > 256) numColors = 256; - if (!numColors && (bpp <= 8)) numColors = 1 << bpp; - } - - if(bpp > 8) - goto create_bitmap; - - pbmiColors = (char*)pbmiCopy + pbmiCopy->bmiHeader.biSize; - - /* Get the relevant colors */ - crWindow = GetSysColor(COLOR_WINDOW); - cr3DShadow = GetSysColor(COLOR_3DSHADOW); - cr3DFace = GetSysColor(COLOR_3DFACE); - cr3DLight = GetSysColor(COLOR_3DLIGHT); - - /* Fix the transparent palette entry */ - if(fuLoad & LR_LOADTRANSPARENT) - { - switch(bpp) - { - case 1: pixel >>= 7; break; - case 4: pixel >>= 4; break; - case 8: break; - default: - FIXME("Unhandled bit depth %d.\n", bpp); - goto create_bitmap; - } - - if(pixel >= numColors) - { - ERR("Wrong pixel passed in.\n"); - goto create_bitmap; - } - - /* If both flags are set, we must use COLOR_3DFACE */ - if(fuLoad & LR_LOADMAP3DCOLORS) crWindow = cr3DFace; - - /* Define the color */ - ptr = (RGBTRIPLE*)(pbmiColors + pixel*incr); - ptr->rgbtBlue = GetBValue(crWindow); - ptr->rgbtGreen = GetGValue(crWindow); - ptr->rgbtRed = GetRValue(crWindow); - goto create_bitmap; - } - - /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */ - for(i = 0; irgbtBlue == ptr->rgbtRed) && (ptr->rgbtBlue == ptr->rgbtGreen)) - { - if(ptr->rgbtBlue == 128) - { - ptr->rgbtBlue = GetBValue(cr3DShadow); - ptr->rgbtGreen = GetGValue(cr3DShadow); - ptr->rgbtRed = GetRValue(cr3DShadow); - } - if(ptr->rgbtBlue == 192) - { - ptr->rgbtBlue = GetBValue(cr3DFace); - ptr->rgbtGreen = GetGValue(cr3DFace); - ptr->rgbtRed = GetRValue(cr3DFace); - } - if(ptr->rgbtBlue == 223) - { - ptr->rgbtBlue = GetBValue(cr3DLight); - ptr->rgbtGreen = GetGValue(cr3DLight); - ptr->rgbtRed = GetRValue(cr3DLight); - } - } - } - } - -create_bitmap: - if(fuLoad & LR_CREATEDIBSECTION) - { - /* Allocate the BMI describing the new bitmap */ - pbmiScaled = HeapAlloc(GetProcessHeap(), 0, iBMISize); - if(!pbmiScaled) - goto end; - CopyMemory(pbmiScaled, pbmiCopy, iBMISize); - - /* Fix it up */ - if(pbmiScaled->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - BITMAPCOREHEADER* pbmch = (BITMAPCOREHEADER*)&pbmiScaled->bmiHeader; - pbmch->bcWidth = cxDesired; - pbmch->bcHeight = cyDesired; - } - else - { - pbmiScaled->bmiHeader.biWidth = cxDesired; - pbmiScaled->bmiHeader.biHeight = cyDesired; - /* No compression for DIB sections */ - pbmiScaled->bmiHeader.biCompression = BI_RGB; - } - } - - /* Top-down image */ - if(cyDesired < 0) cyDesired = -cyDesired; - - /* We need a device context */ - hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); - if(!hdcScreen) - goto end; - hdc = CreateCompatibleDC(hdcScreen); - if(!hdc) - goto end; - - /* Now create the bitmap */ - if(fuLoad & LR_CREATEDIBSECTION) - hbmpRet = CreateDIBSection(hdc, pbmiScaled, DIB_RGB_COLORS, NULL, 0, 0); - else - { - if(is_dib_monochrome(pbmiCopy) || (fuLoad & LR_MONOCHROME)) - hbmpRet = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL); - else - hbmpRet = CreateCompatibleBitmap(hdcScreen, cxDesired, cyDesired); - } - - if(!hbmpRet) - goto end; - - hbmpOld = SelectObject(hdc, hbmpRet); - if(!hbmpOld) - goto end; - if(!StretchDIBits(hdc, 0, 0, cxDesired, cyDesired, - 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, - pvBits, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) - { - ERR("StretchDIBits failed!.\n"); - SelectObject(hdc, hbmpOld); - DeleteObject(hbmpRet); - hbmpRet = NULL; - goto end; - } - - SelectObject(hdc, hbmpOld); - -end: - if(hdcScreen) - DeleteDC(hdcScreen); - if(hdc) - DeleteDC(hdc); - if(pbmiScaled) - HeapFree(GetProcessHeap(), 0, pbmiScaled); - if(pbmiCopy) - HeapFree(GetProcessHeap(), 0, pbmiCopy); - if (pvMapping) - UnmapViewOfFile( pvMapping ); - if(hgRsrc) - FreeResource(hgRsrc); - - return hbmpRet; -} - - -static -HANDLE -CURSORICON_LoadFromFileW( - _In_ LPCWSTR lpszName, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT fuLoad, - _In_ BOOL bIcon -) -{ - const CURSORICONFILEDIRENTRY *entry; - const CURSORICONFILEDIR *dir; - DWORD filesize = 0; - LPBYTE bits; - HANDLE hCurIcon = NULL; - CURSORDATA cursorData; - - TRACE("loading %s\n", debugstr_w( lpszName )); - - bits = map_fileW( lpszName, &filesize ); - if (!bits) - return NULL; - - /* Check for .ani. */ - if (memcmp( bits, "RIFF", 4 ) == 0) - { - UNIMPLEMENTED; - goto end; - } - - dir = (CURSORICONFILEDIR*) bits; - entry = get_best_icon_file_entry(dir, filesize, cxDesired, cyDesired, bIcon, fuLoad); - if(!entry) - goto end; - - /* Fix dimensions */ - if(!cxDesired) cxDesired = entry->bWidth; - if(!cyDesired) cyDesired = entry->bHeight; - /* A bit of preparation */ - ZeroMemory(&cursorData, sizeof(cursorData)); - if(!bIcon) - { - cursorData.xHotspot = entry->xHotspot; - cursorData.yHotspot = entry->yHotspot; - } - cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR)); - - /* Do the dance */ - if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)(&bits[entry->dwDIBOffset]))) - goto end; - - hCurIcon = NtUserxCreateEmptyCurObject(FALSE); - if(!hCurIcon) - goto end; - - /* Tell win32k */ - if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData)) - { - NtUserDestroyCursor(hCurIcon, TRUE); - goto end_error; - } - -end: - UnmapViewOfFile(bits); - return hCurIcon; - - /* Clean up */ -end_error: - DeleteObject(cursorData.hbmMask); - if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); - if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); - UnmapViewOfFile(bits); - - return NULL; -} - -static -HANDLE -CURSORICON_LoadImageW( - _In_opt_ HINSTANCE hinst, - _In_ LPCWSTR lpszName, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT fuLoad, - _In_ BOOL bIcon -) -{ - HRSRC hrsrc; - HANDLE handle, hCurIcon = NULL; - CURSORICONDIR* dir; - WORD wResId; - LPBYTE bits; - CURSORDATA cursorData; - BOOL bStatus; - UNICODE_STRING ustrRsrc; - UNICODE_STRING ustrModule = {0, 0, NULL}; - - /* Fix width/height */ - if(fuLoad & LR_DEFAULTSIZE) - { - if(!cxDesired) cxDesired = GetSystemMetrics(bIcon ? SM_CXICON : SM_CXCURSOR); - if(!cyDesired) cyDesired = GetSystemMetrics(bIcon ? SM_CYICON : SM_CYCURSOR); - } - - if(fuLoad & LR_LOADFROMFILE) - { - return CURSORICON_LoadFromFileW(lpszName, cxDesired, cyDesired, fuLoad, bIcon); - } - - /* Check if caller wants OEM icons */ - if(!hinst) - hinst = User32Instance; - - if(lpszName) - { - /* Prepare the resource name string */ - if(IS_INTRESOURCE(lpszName)) - { - ustrRsrc.Buffer = (LPWSTR)lpszName; - ustrRsrc.Length = 0; - ustrRsrc.MaximumLength = 0; - } - else - RtlInitUnicodeString(&ustrRsrc, lpszName); - } - - if(hinst) - { - DWORD size = MAX_PATH; - /* Get the module name string */ - while (TRUE) - { - DWORD ret; - ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); - if (!ustrModule.Buffer) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return NULL; - } - ret = GetModuleFileNameW(hinst, ustrModule.Buffer, size); - if(ret == 0) - { - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - return NULL; - } - - /* This API is completely broken... */ - if (ret == size) - { - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - size *= 2; - continue; - } - - ustrModule.Buffer[ret] = UNICODE_NULL; - ustrModule.Length = ret * sizeof(WCHAR); - ustrModule.MaximumLength = size * sizeof(WCHAR); - break; - } - } - - if(fuLoad & LR_SHARED) - { - FINDEXISTINGCURICONPARAM param; - - TRACE("Checking for an LR_SHARED cursor/icon.\n"); - /* Ask win32k */ - param.bIcon = bIcon; - param.cx = cxDesired; - param.cy = cyDesired; - hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, ¶m); - if(hCurIcon) - { - /* Woohoo, got it! */ - TRACE("MATCH! %p\n",hCurIcon); - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - return hCurIcon; - } - } - - /* Find resource ID */ - hrsrc = FindResourceW( - hinst, - lpszName, - bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR); - - /* We let FindResource, LoadResource, etc. call SetLastError */ - if(!hrsrc) - goto done; - - handle = LoadResource(hinst, hrsrc); - if(!handle) - goto done; - - dir = LockResource(handle); - if(!dir) - goto done; - - wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad); - FreeResource(handle); - - /* Get the relevant resource pointer */ - hrsrc = FindResourceW( - hinst, - MAKEINTRESOURCEW(wResId), - bIcon ? RT_ICON : RT_CURSOR); - if(!hrsrc) - goto done; - - handle = LoadResource(hinst, hrsrc); - if(!handle) - goto done; - - bits = LockResource(handle); - if(!bits) - { - FreeResource(handle); - goto done; - } - - ZeroMemory(&cursorData, sizeof(cursorData)); - - /* This is from resource */ - cursorData.CURSORF_flags = CURSORF_FROMRESOURCE; - - if(dir->idType == 2) - { - /* idType == 2 for cursor resources */ - SHORT* ptr = (SHORT*)bits; - cursorData.xHotspot = ptr[0]; - cursorData.yHotspot = ptr[1]; - bits += 2*sizeof(SHORT); - } - cursorData.cx = cxDesired; - cursorData.cy = cyDesired; - cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR)); - - /* Get the bitmaps */ - bStatus = CURSORICON_GetCursorDataFromBMI( - &cursorData, - (BITMAPINFO*)bits); - - FreeResource( handle ); - - if(!bStatus) - goto done; - - /* Create the handle */ - hCurIcon = NtUserxCreateEmptyCurObject(FALSE); - if(!hCurIcon) - { - goto end_error; - } - - if(fuLoad & LR_SHARED) - { - cursorData.CURSORF_flags |= CURSORF_LRSHARED; - } - - /* Tell win32k */ - bStatus = NtUserSetCursorIconData(hCurIcon, hinst ? &ustrModule : NULL, lpszName ? &ustrRsrc : NULL, &cursorData); - - if(!bStatus) - { - NtUserDestroyCursor(hCurIcon, TRUE); - goto end_error; - } - -done: - if(ustrModule.Buffer) - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - return hCurIcon; - -end_error: - if(ustrModule.Buffer) - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - DeleteObject(cursorData.hbmMask); - if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); - if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); - - return NULL; -} - -static -HBITMAP -BITMAP_CopyImage( - _In_ HBITMAP hnd, - _In_ int desiredx, - _In_ int desiredy, - _In_ UINT flags -) -{ - HBITMAP res = NULL; - DIBSECTION ds; - int objSize; - BITMAPINFO * bi; - - objSize = GetObjectW( hnd, sizeof(ds), &ds ); - if (!objSize) return 0; - if ((desiredx < 0) || (desiredy < 0)) return 0; - - if (flags & LR_COPYFROMRESOURCE) - { - FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n"); - } - - if (flags & LR_COPYRETURNORG) - { - FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n"); - } - - if (desiredx == 0) desiredx = ds.dsBm.bmWidth; - if (desiredy == 0) desiredy = ds.dsBm.bmHeight; - - /* Allocate memory for a BITMAPINFOHEADER structure and a - color table. The maximum number of colors in a color table - is 256 which corresponds to a bitmap with depth 8. - Bitmaps with higher depths don't have color tables. */ - bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - if (!bi) return 0; - - bi->bmiHeader.biSize = sizeof(bi->bmiHeader); - bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes; - bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel; - bi->bmiHeader.biCompression = BI_RGB; - - if (flags & LR_CREATEDIBSECTION) - { - /* Create a DIB section. LR_MONOCHROME is ignored */ - void * bits; - HDC dc = CreateCompatibleDC(NULL); - - if (objSize == sizeof(DIBSECTION)) - { - /* The source bitmap is a DIB. - Get its attributes to create an exact copy */ - memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER)); - } - - bi->bmiHeader.biWidth = desiredx; - bi->bmiHeader.biHeight = desiredy; - - /* Get the color table or the color masks */ - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); - - res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0); - DeleteDC(dc); - } - else - { - /* Create a device-dependent bitmap */ - - BOOL monochrome = (flags & LR_MONOCHROME); - - if (objSize == sizeof(DIBSECTION)) - { - /* The source bitmap is a DIB section. - Get its attributes */ - HDC dc = CreateCompatibleDC(NULL); - bi->bmiHeader.biWidth = ds.dsBm.bmWidth; - bi->bmiHeader.biHeight = ds.dsBm.bmHeight; - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); - DeleteDC(dc); - - if (!monochrome && ds.dsBm.bmBitsPixel == 1) - { - /* Look if the colors of the DIB are black and white */ - - monochrome = - (bi->bmiColors[0].rgbRed == 0xff - && bi->bmiColors[0].rgbGreen == 0xff - && bi->bmiColors[0].rgbBlue == 0xff - && bi->bmiColors[0].rgbReserved == 0 - && bi->bmiColors[1].rgbRed == 0 - && bi->bmiColors[1].rgbGreen == 0 - && bi->bmiColors[1].rgbBlue == 0 - && bi->bmiColors[1].rgbReserved == 0) - || - (bi->bmiColors[0].rgbRed == 0 - && bi->bmiColors[0].rgbGreen == 0 - && bi->bmiColors[0].rgbBlue == 0 - && bi->bmiColors[0].rgbReserved == 0 - && bi->bmiColors[1].rgbRed == 0xff - && bi->bmiColors[1].rgbGreen == 0xff - && bi->bmiColors[1].rgbBlue == 0xff - && bi->bmiColors[1].rgbReserved == 0); - } - } - else if (!monochrome) - { - monochrome = ds.dsBm.bmBitsPixel == 1; - } - - if (monochrome) - { - res = CreateBitmap(desiredx, desiredy, 1, 1, NULL); - } - else - { - HDC screenDC = GetDC(NULL); - res = CreateCompatibleBitmap(screenDC, desiredx, desiredy); - ReleaseDC(NULL, screenDC); - } - } - - if (res) - { - /* Only copy the bitmap if it's a DIB section or if it's - compatible to the screen */ - BOOL copyContents; - - if (objSize == sizeof(DIBSECTION)) - { - copyContents = TRUE; - } - else - { - HDC screenDC = GetDC(NULL); - int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL); - ReleaseDC(NULL, screenDC); - - copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth); - } - - if (copyContents) - { - /* The source bitmap may already be selected in a device context, - use GetDIBits/StretchDIBits and not StretchBlt */ - - HDC dc; - void * bits; - - dc = CreateCompatibleDC(NULL); - - bi->bmiHeader.biWidth = ds.dsBm.bmWidth; - bi->bmiHeader.biHeight = ds.dsBm.bmHeight; - bi->bmiHeader.biSizeImage = 0; - bi->bmiHeader.biClrUsed = 0; - bi->bmiHeader.biClrImportant = 0; - - /* Fill in biSizeImage */ - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); - bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage); - - if (bits) - { - HBITMAP oldBmp; - - /* Get the image bits of the source bitmap */ - GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS); - - /* Copy it to the destination bitmap */ - oldBmp = SelectObject(dc, res); - StretchDIBits(dc, 0, 0, desiredx, desiredy, - 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, - bits, bi, DIB_RGB_COLORS, SRCCOPY); - SelectObject(dc, oldBmp); - - HeapFree(GetProcessHeap(), 0, bits); - } - - DeleteDC(dc); - } - - if (flags & LR_COPYDELETEORG) - { - DeleteObject(hnd); - } - } - HeapFree(GetProcessHeap(), 0, bi); - return res; -} - -static -HICON -CURSORICON_CopyImage( - _In_ HICON hicon, - _In_ BOOL bIcon, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT fuFlags -) -{ - HICON ret = NULL; - ICONINFO ii; - CURSORDATA CursorData; - - if (fuFlags & LR_COPYFROMRESOURCE) - { - /* Get the icon module/resource names */ - UNICODE_STRING ustrModule; - UNICODE_STRING ustrRsrc; - HMODULE hModule; - - ustrModule.MaximumLength = 0; - ustrRsrc.MaximumLength = 0; - - /* Get the buffer size */ - if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE)) - { - return NULL; - } - - ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength); - if (!ustrModule.Buffer) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return NULL; - } - - if (ustrRsrc.MaximumLength) - { - ustrRsrc.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrRsrc.MaximumLength); - if (!ustrRsrc.Buffer) - { - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return NULL; - } - } - - if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE)) - { - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - if (!IS_INTRESOURCE(ustrRsrc.Buffer)) - HeapFree(GetProcessHeap(), 0, ustrRsrc.Buffer); - return NULL; - } - - /* NULL-terminate our strings */ - ustrModule.Buffer[ustrModule.Length/sizeof(WCHAR)] = UNICODE_NULL; - if (!IS_INTRESOURCE(ustrRsrc.Buffer)) - ustrRsrc.Buffer[ustrRsrc.Length/sizeof(WCHAR)] = UNICODE_NULL; - - TRACE("Got module %S, resource %p (%S).\n", ustrModule.Buffer, - ustrRsrc.Buffer, IS_INTRESOURCE(ustrRsrc.Buffer) ? L"" : ustrRsrc.Buffer); - - /* Get the module handle */ - if (!GetModuleHandleExW(0, ustrModule.Buffer, &hModule)) - { - /* This should never happen */ - ERR("Invalid handle?.\n"); - SetLastError(ERROR_INVALID_PARAMETER); - goto leave; - } - - /* Call the relevant function */ - ret = CURSORICON_LoadImageW( - hModule, - ustrRsrc.Buffer, - cxDesired, - cyDesired, - fuFlags & (LR_DEFAULTSIZE | LR_SHARED), - bIcon); - - FreeLibrary(hModule); - - /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */ - leave: - HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); - if (!IS_INTRESOURCE(ustrRsrc.Buffer)) - HeapFree(GetProcessHeap(), 0, ustrRsrc.Buffer); - - TRACE("Returning 0x%08x.\n", ret); - - return ret; - } - - /* This is a regular copy */ - if (fuFlags & ~(LR_COPYDELETEORG | LR_SHARED)) - FIXME("Unimplemented flags: 0x%08x\n", fuFlags); - - if (!GetIconInfo(hicon, &ii)) - { - ERR("GetIconInfo failed.\n"); - return NULL; - } - - /* This is CreateIconIndirect with the LR_SHARED coat added */ - if (!CURSORICON_GetCursorDataFromIconInfo(&CursorData, &ii)) - goto Leave; - - if (fuFlags & LR_SHARED) - CursorData.CURSORF_flags |= CURSORF_LRSHARED; - - ret = NtUserxCreateEmptyCurObject(FALSE); - if (!ret) - goto Leave; - - if (!NtUserSetCursorIconData(ret, NULL, NULL, &CursorData)) - { - NtUserDestroyCursor(ret, TRUE); - goto Leave; - } - -Leave: - DeleteObject(ii.hbmMask); - if (ii.hbmColor) DeleteObject(ii.hbmColor); - - if (ret && (fuFlags & LR_COPYDELETEORG)) - DestroyIcon(hicon); - - return ret; -} - -NTSTATUS WINAPI -User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength) -{ - PCOPYIMAGE_CALLBACK_ARGUMENTS Common; - HANDLE Result; - Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Arguments; - - Result = CopyImage(Common->hImage, - Common->uType, - Common->cxDesired, - Common->cyDesired, - Common->fuFlags); - - return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS); -} - - -/************* PUBLIC FUNCTIONS *******************/ - -HANDLE WINAPI CopyImage( - _In_ HANDLE hImage, - _In_ UINT uType, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT fuFlags -) -{ - TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n", - hImage, uType, cxDesired, cyDesired, fuFlags); - switch(uType) - { - case IMAGE_BITMAP: - return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags); - case IMAGE_CURSOR: - case IMAGE_ICON: - return CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags); - default: - SetLastError(ERROR_INVALID_PARAMETER); - break; - } - return NULL; -} - -HICON WINAPI CopyIcon( - _In_ HICON hIcon -) -{ - return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0); -} - -BOOL WINAPI DrawIcon( - _In_ HDC hDC, - _In_ int X, - _In_ int Y, - _In_ HICON hIcon -) -{ - return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE); -} - -BOOL WINAPI DrawIconEx( - _In_ HDC hdc, - _In_ int xLeft, - _In_ int yTop, - _In_ HICON hIcon, - _In_ int cxWidth, - _In_ int cyWidth, - _In_ UINT istepIfAniCur, - _In_opt_ HBRUSH hbrFlickerFreeDraw, - _In_ UINT diFlags -) -{ - return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, - istepIfAniCur, hbrFlickerFreeDraw, diFlags, - 0, 0); -} - -BOOL WINAPI GetIconInfo( - _In_ HICON hIcon, - _Out_ PICONINFO piconinfo -) -{ - return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE); -} - -BOOL WINAPI DestroyIcon( - _In_ HICON hIcon -) -{ - return NtUserDestroyCursor(hIcon, FALSE); -} - -HICON WINAPI LoadIconA( - _In_opt_ HINSTANCE hInstance, - _In_ LPCSTR lpIconName -) -{ - TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName)); - - return LoadImageA(hInstance, - lpIconName, - IMAGE_ICON, - 0, - 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -HICON WINAPI LoadIconW( - _In_opt_ HINSTANCE hInstance, - _In_ LPCWSTR lpIconName -) -{ - TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName)); - - return LoadImageW(hInstance, - lpIconName, - IMAGE_ICON, - 0, - 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -HCURSOR WINAPI LoadCursorA( - _In_opt_ HINSTANCE hInstance, - _In_ LPCSTR lpCursorName -) -{ - TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName)); - - return LoadImageA(hInstance, - lpCursorName, - IMAGE_CURSOR, - 0, - 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -HCURSOR WINAPI LoadCursorW( - _In_opt_ HINSTANCE hInstance, - _In_ LPCWSTR lpCursorName -) -{ - TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName)); - - return LoadImageW(hInstance, - lpCursorName, - IMAGE_CURSOR, - 0, - 0, - LR_SHARED | LR_DEFAULTSIZE ); -} - -HCURSOR WINAPI LoadCursorFromFileA( - _In_ LPCSTR lpFileName -) -{ - TRACE("%s\n", debugstr_a(lpFileName)); - - return LoadImageA(NULL, - lpFileName, - IMAGE_CURSOR, - 0, - 0, - LR_LOADFROMFILE | LR_DEFAULTSIZE ); -} - -HCURSOR WINAPI LoadCursorFromFileW( - _In_ LPCWSTR lpFileName -) -{ - TRACE("%s\n", debugstr_w(lpFileName)); - - return LoadImageW(NULL, - lpFileName, - IMAGE_CURSOR, - 0, - 0, - LR_LOADFROMFILE | LR_DEFAULTSIZE ); -} - -HBITMAP WINAPI LoadBitmapA( - _In_opt_ HINSTANCE hInstance, - _In_ LPCSTR lpBitmapName -) -{ - TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName)); - - return LoadImageA(hInstance, - lpBitmapName, - IMAGE_BITMAP, - 0, - 0, - 0); -} - -HBITMAP WINAPI LoadBitmapW( - _In_opt_ HINSTANCE hInstance, - _In_ LPCWSTR lpBitmapName -) -{ - TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName)); - - return LoadImageW(hInstance, - lpBitmapName, - IMAGE_BITMAP, - 0, - 0, - 0); -} - -HANDLE WINAPI LoadImageA( - _In_opt_ HINSTANCE hinst, - _In_ LPCSTR lpszName, - _In_ UINT uType, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT fuLoad -) -{ - HANDLE res; - LPWSTR u_name; - DWORD len; - - if (IS_INTRESOURCE(lpszName)) - return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad); - - len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 ); - u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len ); - - res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad); - HeapFree(GetProcessHeap(), 0, u_name); - return res; -} - -HANDLE WINAPI LoadImageW( - _In_opt_ HINSTANCE hinst, - _In_ LPCWSTR lpszName, - _In_ UINT uType, - _In_ int cxDesired, - _In_ int cyDesired, - _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 */ - switch(uType) - { - case IMAGE_BITMAP: - return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad); - case IMAGE_CURSOR: - case IMAGE_ICON: - return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON); - default: - SetLastError(ERROR_INVALID_PARAMETER); - break; - } - return NULL; -} - -int WINAPI LookupIconIdFromDirectory( - _In_ PBYTE presbits, - _In_ BOOL fIcon -) -{ - return LookupIconIdFromDirectoryEx( presbits, fIcon, - fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR), - fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME ); -} - -int WINAPI LookupIconIdFromDirectoryEx( - _In_ PBYTE presbits, - _In_ BOOL fIcon, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT Flags -) -{ - WORD bppDesired; - CURSORICONDIR* dir = (CURSORICONDIR*)presbits; - CURSORICONDIRENTRY* entry; - int i, numMatch = 0, iIndex = -1; - WORD width, height, BitCount = 0; - BOOL notPaletted = FALSE; - ULONG bestScore = 0xFFFFFFFF, score; - - TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags); - - if(!(dir && !dir->idReserved && (dir->idType & 3))) - { - WARN("Invalid resource.\n"); - return 0; - } - - if(Flags & LR_MONOCHROME) - bppDesired = 1; - else - { - HDC icScreen; - icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL); - if(!icScreen) - return FALSE; - - bppDesired = GetDeviceCaps(icScreen, BITSPIXEL); - DeleteDC(icScreen); - } - - if(!cxDesired) - cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256; - if(!cyDesired) - cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR) : 256; - - /* Find the best match for the desired size */ - for(i = 0; i < dir->idCount; i++) - { - entry = &dir->idEntries[i]; - width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; - /* Height is twice as big in cursor resources */ - height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; - /* 0 represents 256 */ - if(!width) width = 256; - if(!height) height = 256; - /* Calculate the "score" (lower is better) */ - score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); - if( score > bestScore) - continue; - /* Bigger than requested lowers the score */ - if(width > cxDesired) - score -= width - cxDesired; - if(height > cyDesired) - score -= height - cyDesired; - if(score > bestScore) - continue; - if(score == bestScore) - { - if(entry->wBitCount > BitCount) - BitCount = entry->wBitCount; - numMatch++; - continue; - } - iIndex = i; - numMatch = 1; - bestScore = score; - BitCount = entry->wBitCount; - } - - if(numMatch == 1) - { - /* Only one entry fits the asked dimensions */ - return dir->idEntries[iIndex].wResId; - } - - /* Avoid paletted icons on non-paletted device */ - if (bppDesired > 8 && BitCount > 8) - notPaletted = TRUE; - - BitCount = 0; - iIndex = -1; - /* Now find the entry with the best depth */ - for(i = 0; i < dir->idCount; i++) - { - entry = &dir->idEntries[i]; - width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; - height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; - /* 0 represents 256 */ - if(!width) width = 256; - if(!height) height = 256; - /* Check if this is the best match we had */ - score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); - if(width > cxDesired) - score -= width - cxDesired; - if(height > cyDesired) - score -= height - cyDesired; - if(score != bestScore) - continue; - /* Exact match? */ - if(entry->wBitCount == bppDesired) - return entry->wResId; - /* We take the highest possible but smaller than the display depth */ - if((entry->wBitCount > BitCount) && (entry->wBitCount < bppDesired)) - { - /* Avoid paletted icons on non paletted devices */ - if ((entry->wBitCount <= 8) && notPaletted) - continue; - iIndex = i; - BitCount = entry->wBitCount; - } - } - - if(iIndex >= 0) - return dir->idEntries[iIndex].wResId; - - /* No inferior or equal depth available. Get the smallest bigger one */ - BitCount = 0xFFFF; - iIndex = -1; - for(i = 0; i < dir->idCount; i++) - { - entry = &dir->idEntries[i]; - width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; - height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; - /* 0 represents 256 */ - if(!width) width = 256; - if(!height) height = 256; - /* Check if this is the best match we had */ - score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); - if(width > cxDesired) - score -= width - cxDesired; - if(height > cyDesired) - score -= height - cyDesired; - if(score != bestScore) - continue; - /* Check the bit depth */ - if(entry->wBitCount < BitCount) - { - if((entry->wBitCount <= 8) && notPaletted) - continue; - iIndex = i; - BitCount = entry->wBitCount; - } - } - if (iIndex >= 0) - return dir->idEntries[iIndex].wResId; - - return 0; -} - -HICON WINAPI CreateIcon( - _In_opt_ HINSTANCE hInstance, - _In_ int nWidth, - _In_ int nHeight, - _In_ BYTE cPlanes, - _In_ BYTE cBitsPixel, - _In_ const BYTE *lpbANDbits, - _In_ const BYTE *lpbXORbits -) -{ - ICONINFO iinfo; - HICON hIcon; - - TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n", - nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits); - - iinfo.fIcon = TRUE; - iinfo.xHotspot = nWidth / 2; - iinfo.yHotspot = nHeight / 2; - if (cPlanes * cBitsPixel > 1) - { - iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits ); - iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits ); - } - else - { - iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits ); - iinfo.hbmColor = NULL; - } - - hIcon = CreateIconIndirect( &iinfo ); - - DeleteObject( iinfo.hbmMask ); - if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor ); - - return hIcon; -} - -HICON WINAPI CreateIconFromResource( - _In_ PBYTE presbits, - _In_ DWORD dwResSize, - _In_ BOOL fIcon, - _In_ DWORD dwVer -) -{ - return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE | LR_SHARED); -} - -HICON WINAPI CreateIconFromResourceEx( - _In_ PBYTE pbIconBits, - _In_ DWORD cbIconBits, - _In_ BOOL fIcon, - _In_ DWORD dwVersion, - _In_ int cxDesired, - _In_ int cyDesired, - _In_ UINT uFlags -) -{ - CURSORDATA cursorData; - HICON hIcon; - BOOL isAnimated; - - TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags); - - if(uFlags & LR_DEFAULTSIZE) - { - if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR); - if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR); - } - - ZeroMemory(&cursorData, sizeof(cursorData)); - cursorData.cx = cxDesired; - cursorData.cy = cyDesired; - 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) - { - WORD* pt = (WORD*)pbIconBits; - cursorData.xHotspot = *pt++; - cursorData.yHotspot = *pt++; - pbIconBits = (PBYTE)pt; - } - - if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits)) - { - ERR("Couldn't fill the CURSORDATA structure.\n"); - if (ResHandle) - FreeResource(ResHandle); - return NULL; - } - if (ResHandle) - FreeResource(ResHandle); - isAnimated = FALSE; - } - - if (uFlags & LR_SHARED) - cursorData.CURSORF_flags |= CURSORF_LRSHARED; - - hIcon = NtUserxCreateEmptyCurObject(isAnimated); - if (!hIcon) - goto end_error; - - if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData)) - { - ERR("NtUserSetCursorIconData failed.\n"); - NtUserDestroyCursor(hIcon, TRUE); - goto end_error; - } - - if(isAnimated) - HeapFree(GetProcessHeap(), 0, cursorData.aspcur); - - return hIcon; - - /* Clean up */ -end_error: - if(isAnimated) - HeapFree(GetProcessHeap(), 0, cursorData.aspcur); - DeleteObject(cursorData.hbmMask); - if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); - if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); - - return NULL; -} - -HICON WINAPI CreateIconIndirect( - _In_ PICONINFO piconinfo -) -{ - /* As simple as creating a handle, and let win32k deal with the bitmaps */ - HICON hiconRet; - CURSORDATA cursorData; - - TRACE("%p.\n", piconinfo); - - ZeroMemory(&cursorData, sizeof(cursorData)); - - if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo)) - return NULL; - - hiconRet = NtUserxCreateEmptyCurObject(FALSE); - if(!hiconRet) - goto end_error; - - if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, &cursorData)) - { - NtUserDestroyCursor(hiconRet, FALSE); - goto end_error; - } - - TRACE("Returning 0x%08x.\n", hiconRet); - - return hiconRet; - -end_error: - /* Clean up */ - DeleteObject(cursorData.hbmMask); - if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); - if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); - - return NULL; -} - -HCURSOR WINAPI CreateCursor( - _In_opt_ HINSTANCE hInst, - _In_ int xHotSpot, - _In_ int yHotSpot, - _In_ int nWidth, - _In_ int nHeight, - _In_ const VOID *pvANDPlane, - _In_ const VOID *pvXORPlane -) -{ - ICONINFO info; - HCURSOR hCursor; - - TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n", - nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane); - - info.fIcon = FALSE; - info.xHotspot = xHotSpot; - info.yHotspot = yHotSpot; - info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane ); - info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane ); - hCursor = CreateIconIndirect( &info ); - DeleteObject( info.hbmMask ); - DeleteObject( info.hbmColor ); - return hCursor; -} - -BOOL WINAPI SetSystemCursor( - _In_ HCURSOR hcur, - _In_ DWORD id -) -{ - if (hcur == NULL) - { - hcur = LoadImageW( 0, MAKEINTRESOURCE(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ); - if (hcur == NULL) - { - return FALSE; - } - } - return NtUserSetSystemCursor(hcur,id); -} - -BOOL WINAPI SetCursorPos( - _In_ int X, - _In_ int Y -) -{ - return NtUserxSetCursorPos(X,Y); -} - -BOOL WINAPI GetCursorPos( - _Out_ LPPOINT lpPoint -) -{ - return NtUserxGetCursorPos(lpPoint); -} - -int WINAPI ShowCursor( - _In_ BOOL bShow -) -{ - return NtUserxShowCursor(bShow); -} - -HCURSOR WINAPI GetCursor(void) -{ - return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR); -} - -BOOL WINAPI DestroyCursor( - _In_ HCURSOR hCursor -) -{ - 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); -} diff --git a/reactos/win32ss/w32ksvc.h b/reactos/win32ss/w32ksvc.h index f0d97187e17..e15e832335b 100644 --- a/reactos/win32ss/w32ksvc.h +++ b/reactos/win32ss/w32ksvc.h @@ -379,11 +379,7 @@ SVC_(UserEnumDisplaySettings, 4) SVC_(UserEvent, 1) SVC_(UserExcludeUpdateRgn, 2) SVC_(UserFillWindow, 4) -#ifdef NEW_CURSORICON SVC_(UserFindExistingCursorIcon, 3) -#else -SVC_(UserFindExistingCursorIcon, 4) -#endif SVC_(UserFindWindowEx, 5) SVC_(UserFlashWindowEx, 1) SVC_(UserGetAltTabInfo, 6) @@ -519,11 +515,7 @@ SVC_(UserSetClipboardViewer, 1) SVC_(UserSetConsoleReserveKeys, 2) SVC_(UserSetCursor, 1) SVC_(UserSetCursorContents, 2) -#ifdef NEW_CURSORICON SVC_(UserSetCursorIconData, 4) -#else -SVC_(UserSetCursorIconData, 6) -#endif SVC_(UserSetDbgTag, 2) SVC_(UserSetFocus, 1) SVC_(UserSetImeHotKey, 5)