Author: jgardou Date: Sun Nov 4 12:56:44 2012 New Revision: 57672
URL: http://svn.reactos.org/svn/reactos?rev=57672&view=rev Log: [USER32] - Implement LookupIconIdFromDirectoryEx. - Implement CopyImage - Finish Implementing LoadImage - Implement various functions. [WIN32SS] - Add a first working implementation for LR_SHARED cursors and icons.User32 support is there, but more work is needed in win32k.
Modified: trunk/reactos/win32ss/CMakeLists.txt trunk/reactos/win32ss/include/ntuser.h trunk/reactos/win32ss/include/ntusrtyp.h trunk/reactos/win32ss/user/ntuser/class.c trunk/reactos/win32ss/user/ntuser/class.h trunk/reactos/win32ss/user/ntuser/cursoricon.c trunk/reactos/win32ss/user/ntuser/cursoricon.h trunk/reactos/win32ss/user/ntuser/cursoricon_new.c trunk/reactos/win32ss/user/ntuser/simplecall.c trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c
Modified: trunk/reactos/win32ss/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/CMakeLists.txt?rev=... ============================================================================== --- trunk/reactos/win32ss/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/win32ss/CMakeLists.txt [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -9,6 +9,10 @@
if(USE_DIBLIB) add_subdirectory(gdi/diblib) +endif() + +if(USE_NEW_CURSORICON) + add_definitions(-DNEW_CURSORICON) endif()
add_subdirectory(gdi/gdi32) @@ -190,7 +194,6 @@ endif()
if(USE_NEW_CURSORICON) - add_definitions(-DNEW_CURSORICON) list(APPEND SOURCE user/ntuser/cursoricon_new.c) else() list(APPEND SOURCE user/ntuser/cursoricon.c)
Modified: trunk/reactos/win32ss/include/ntuser.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/include/ntuser.h?re... ============================================================================== --- trunk/reactos/win32ss/include/ntuser.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/include/ntuser.h [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -1659,8 +1659,8 @@ BOOL NTAPI NtUserDestroyCursor( - HANDLE Handle, - DWORD Unknown); + _In_ HANDLE Handle, + _In_ BOOL bForce);
DWORD NTAPI @@ -1818,14 +1818,6 @@ HDC hDC, HBRUSH hBrush);
-HICON -NTAPI -NtUserFindExistingCursorIcon( - HMODULE hModule, - HRSRC hRsrc, - LONG cx, - LONG cy); - HWND NTAPI NtUserFindWindowEx( @@ -1998,12 +1990,12 @@ BOOL NTAPI NtUserGetIconInfo( - HANDLE hCurIcon, - PICONINFO IconInfo, - PUNICODE_STRING lpInstName, - PUNICODE_STRING lpResName, - LPDWORD pbpp, - BOOL bInternal); + _In_ HANDLE hCurIcon, + _Out_opt_ PICONINFO IconInfo, + _Out_opt_ PUNICODE_STRING lpInstName, + _Out_opt_ PUNICODE_STRING lpResName, + _Out_opt_ LPDWORD pbpp, + _In_ BOOL bInternal);
BOOL NTAPI @@ -2743,9 +2735,17 @@ NTAPI NtUserSetCursorIconData( _In_ HCURSOR hCursor, - _In_ HINSTANCE hinst, - _In_ HRSRC hrsrc, + _In_ PUNICODE_STRING pustrModule, + _In_ PUNICODE_STRING puSrcName, _In_ PICONINFO pii); + +HICON +NTAPI +NtUserFindExistingCursorIcon( + _In_ PUNICODE_STRING pustrModule, + _In_ PUNICODE_STRING pustrRsrc, + _In_ LONG cxDesired, + _In_ LONG cyDesired); #else BOOL NTAPI @@ -2756,6 +2756,14 @@ HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc); + +HICON +NTAPI +NtUserFindExistingCursorIcon( + HMODULE hModule, + HRSRC hRsrc, + LONG cx, + LONG cy); #endif
DWORD
Modified: trunk/reactos/win32ss/include/ntusrtyp.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/include/ntusrtyp.h?... ============================================================================== --- trunk/reactos/win32ss/include/ntusrtyp.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/include/ntusrtyp.h [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -88,8 +88,9 @@
typedef struct { union - { ICONRESDIR icon; - CURSORDIR cursor; + { + ICONRESDIR icon; + CURSORDIR cursor; } ResInfo; WORD wPlanes; WORD wBitCount;
Modified: trunk/reactos/win32ss/user/ntuser/class.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/class.c... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/class.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/class.c [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -124,7 +124,7 @@ _Must_inspect_result_ NTSTATUS NTAPI -CaptureUnicodeStringOrAtom( +ProbeAndCaptureUnicodeStringOrAtom( _Out_ PUNICODE_STRING pustrOut, __in_data_source(USER_MODE) _In_ PUNICODE_STRING pustrUnsafe) { @@ -2294,7 +2294,7 @@ NTSTATUS Status; BOOL Ret;
- Status = CaptureUnicodeStringOrAtom(&SafeClassName, ClassNameOrAtom); + Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassNameOrAtom); if (!NT_SUCCESS(Status)) { ERR("Error capturing the class name\n"); @@ -2346,7 +2346,7 @@ } _SEH2_END;
- Status = CaptureUnicodeStringOrAtom(&SafeClassName, ClassName); + Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName); if (!NT_SUCCESS(Status)) { ERR("Error capturing the class name\n"); @@ -2480,7 +2480,7 @@ RTL_ATOM ClassAtom = 0; NTSTATUS Status;
- Status = CaptureUnicodeStringOrAtom(&SafeClassName, ClassName); + Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName); if (!NT_SUCCESS(Status)) { ERR("Error capturing the class name\n");
Modified: trunk/reactos/win32ss/user/ntuser/class.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/class.h... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/class.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/class.h [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -59,4 +59,11 @@
ULONG_PTR FASTCALL UserGetCPD(PVOID,GETCPD,ULONG_PTR);
+_Must_inspect_result_ +NTSTATUS +NTAPI +ProbeAndCaptureUnicodeStringOrAtom( + _Out_ PUNICODE_STRING pustrOut, + __in_data_source(USER_MODE) _In_ PUNICODE_STRING pustrUnsafe); + /* EOF */
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursori... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/cursoricon.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/cursoricon.c [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -204,7 +204,7 @@ }
PCURICON_OBJECT -IntCreateCurIconHandle() +IntCreateCurIconHandle(DWORD dwNumber) { PCURICON_OBJECT CurIcon; HANDLE hCurIcon; @@ -613,8 +613,8 @@ BOOL APIENTRY NtUserDestroyCursor( - HANDLE hCurIcon, - DWORD Unknown) + _In_ HANDLE hCurIcon, + _In_ BOOL bForce) { PCURICON_OBJECT CurIcon; BOOL ret;
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursori... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/cursoricon.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/cursoricon.h [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -22,8 +22,8 @@ LIST_ENTRY ListEntry; HANDLE Self; LIST_ENTRY ProcessList; - HMODULE hModule; - HRSRC hRsrc; + UNICODE_STRING ustrModule; + UNICODE_STRING ustrRsrc; SIZE Size; BYTE Shadow; BOOL bIcon; @@ -88,7 +88,7 @@ } SYSTEM_CURSORINFO, *PSYSTEM_CURSORINFO;
BOOL InitCursorImpl(VOID); -PCURICON_OBJECT IntCreateCurIconHandle(VOID); +PCURICON_OBJECT IntCreateCurIconHandle(DWORD dwNumber); VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process);
BOOL UserDrawIconEx(HDC hDc, INT xLeft, INT yTop, PCURICON_OBJECT pIcon, INT cxWidth,
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon_new.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursori... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/cursoricon_new.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/cursoricon_new.c [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -169,47 +169,59 @@ return TRUE; }
-PCURICON_OBJECT FASTCALL -IntFindExistingCurIconObject(HMODULE hModule, - HRSRC hRsrc, LONG cx, LONG cy) +static +PCURICON_OBJECT +FASTCALL +IntFindExistingCurIconObject( + PUNICODE_STRING pustrModule, + PUNICODE_STRING pustrRsrc, + LONG cxDesired, + LONG cyDesired) { PCURICON_OBJECT CurIcon;
LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry) { - - // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) // <- huh???? -// UserReferenceObject( CurIcon); -// { - if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc)) - { - if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy))) + /* See if module names match */ + if(RtlCompareUnicodeString(pustrModule, &CurIcon->ustrModule, TRUE) == 0) + { + /* They do. Now see if this is the same resource */ + if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer) && IS_INTRESOURCE(pustrRsrc->Buffer)) { -// UserDereferenceObject(CurIcon); + if(CurIcon->ustrRsrc.Buffer != pustrRsrc->Buffer) + continue; + } + else if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer) || IS_INTRESOURCE(pustrRsrc->Buffer)) continue; + else if(RtlCompareUnicodeString(pustrRsrc, &CurIcon->ustrRsrc, TRUE) != 0) + continue; + + if ((cxDesired == CurIcon->Size.cx) &&(cyDesired == CurIcon->Size.cy)) + { + if (! ReferenceCurIconByProcess(CurIcon)) + { + return NULL; + } + + return CurIcon; } - if (! ReferenceCurIconByProcess(CurIcon)) - { - return NULL; - } - - return CurIcon; - } -// } -// UserDereferenceObject(CurIcon); - + } }
return NULL; }
PCURICON_OBJECT -IntCreateCurIconHandle() +IntCreateCurIconHandle(DWORD dwNumber) { PCURICON_OBJECT CurIcon; + BOOLEAN bIcon = dwNumber == 0; HANDLE hCurIcon; - - CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT)); + + if(dwNumber == 0) + dwNumber = 1; + + CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, FIELD_OFFSET(CURICON_OBJECT, aFrame[dwNumber]));
if (!CurIcon) { @@ -218,6 +230,7 @@ }
CurIcon->Self = hCurIcon; + CurIcon->bIcon = bIcon; InitializeListHead(&CurIcon->ProcessList);
if (! ReferenceCurIconByProcess(CurIcon)) @@ -234,7 +247,7 @@ }
BOOLEAN FASTCALL -IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi) +IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi, BOOLEAN bForce) { PSYSTEM_CURSORINFO CurInfo; HBITMAP bmpMask, bmpColor, bmpAlpha; @@ -261,7 +274,17 @@ { /* This object doesn't belong to this process */ EngSetLastError(ERROR_INVALID_HANDLE); + /* Caller expects us to dereference! */ + UserDereferenceObject(CurIcon); return FALSE; + } + + /* We found our process, but we're told to not destroy it in case it is shared */ + if((CurIcon->ustrModule.Buffer != NULL) && !bForce) + { + /* Tests show this is a valid call */ + UserDereferenceObject(CurIcon); + return TRUE; }
ExFreeToPagedLookasideList(pgProcessLookasideList, Current); @@ -314,6 +337,11 @@ GreDeleteObject(bmpAlpha); CurIcon->aFrame[0].hbmAlpha = NULL; } + + if(!IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer)) + ExFreePoolWithTag(CurIcon->ustrRsrc.Buffer, TAG_STRING); + if(CurIcon->ustrModule.Buffer) + ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode);
/* We were given a pointer, no need to keep the reference anylonger! */ UserDereferenceObject(CurIcon); @@ -331,7 +359,7 @@ LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry) { UserReferenceObject(CurIcon); - IntDestroyCurIconObject(CurIcon, Win32Process); + IntDestroyCurIconObject(CurIcon, Win32Process, TRUE); } }
@@ -342,12 +370,12 @@ 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; @@ -356,66 +384,145 @@ 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 (!IconInfo) - { - EngSetLastError(ERROR_INVALID_PARAMETER); + if (!(CurIcon = UserGetCurIconObject(hCurIcon))) + { + WARN("UserGetIconObject(0x%08x) Failed.\n", hCurIcon); + UserLeave(); + return FALSE; + } + + /* Give back the icon information */ + if(IconInfo) + { + /* Fill data */ + ii.fIcon = CurIcon->bIcon; + ii.xHotspot = CurIcon->ptlHotspot.x; + ii.yHotspot = CurIcon->ptlHotspot.y; + + /* Copy bitmaps */ + ii.hbmMask = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmMask); + GreSetObjectOwner(ii.hbmMask, GDI_OBJ_HMGR_POWNED); + ii.hbmColor = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmColor); + GreSetObjectOwner(ii.hbmColor, GDI_OBJ_HMGR_POWNED); + + if (pbpp) + { + PSURFACE psurfBmp; + + psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].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)); + + 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; }
- if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { + /* Give back the module name */ + if(lpModule) + { + if(!CurIcon->ustrModule.Buffer) + { + EngSetLastError(ERROR_INVALID_HANDLE); + goto leave; + } + /* Copy what we can */ + _SEH2_TRY + { + ProbeForWrite(lpModule, sizeof(UNICODE_STRING), 1); + ProbeForWrite(lpModule->Buffer, lpModule->MaximumLength, 1); + lpModule->Length = min(lpModule->MaximumLength, CurIcon->ustrModule.Length); + RtlCopyMemory(lpModule->Buffer, CurIcon->ustrModule.Buffer, lpModule->Length); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END + } + + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); goto leave; }
- /* Fill data */ - ii.fIcon = CurIcon->bIcon; - ii.xHotspot = CurIcon->ptlHotspot.x; - ii.yHotspot = CurIcon->ptlHotspot.y; - - /* Copy bitmaps */ - ii.hbmMask = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmMask); - ii.hbmColor = BITMAP_CopyBitmap(CurIcon->aFrame[0].hbmColor); - - if (pbpp) - { - PSURFACE psurfBmp; - - psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].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)); - - 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 + if(lpResName) + { + if(!CurIcon->ustrRsrc.Buffer) + { + EngSetLastError(ERROR_INVALID_HANDLE); + goto leave; + } + /* Copy it */ + _SEH2_TRY + { + ProbeForWrite(lpResName, sizeof(UNICODE_STRING), 1); + if(IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer)) + { + lpResName->Buffer = CurIcon->ustrRsrc.Buffer; + lpResName->Length = 0; + } + else + { + lpResName->Length = min(lpResName->MaximumLength, CurIcon->ustrRsrc.Length); + RtlCopyMemory(lpResName->Buffer, CurIcon->ustrRsrc.Buffer, lpResName->Length); + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END + } + + if (!NT_SUCCESS(Status)) + { SetLastNtError(Status); - + goto leave; + } + + Ret = TRUE; + +leave: UserDereferenceObject(CurIcon);
-leave: TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret); UserLeave();
@@ -623,8 +730,8 @@ BOOL APIENTRY NtUserDestroyCursor( - HANDLE hCurIcon, - DWORD Unknown) + _In_ HANDLE hCurIcon, + _In_ BOOL bForce) { PCURICON_OBJECT CurIcon; BOOL ret; @@ -638,7 +745,7 @@ RETURN(FALSE); }
- ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process()); + ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process(), bForce); /* Note: IntDestroyCurIconObject will remove our reference for us! */
RETURN(ret); @@ -654,36 +761,40 @@ * @implemented */ HICON -APIENTRY +NTAPI NtUserFindExistingCursorIcon( - HMODULE hModule, - HRSRC hRsrc, - LONG cx, - LONG cy) + _In_ PUNICODE_STRING pustrModule, + _In_ PUNICODE_STRING pustrRsrc, + _In_ LONG cxDesired, + _In_ LONG cyDesired) { PCURICON_OBJECT CurIcon; - HANDLE Ret = (HANDLE)0; - DECLARE_RETURN(HICON); + HICON Ret = NULL; + UNICODE_STRING ustrModuleSafe, ustrRsrcSafe; + NTSTATUS Status;
TRACE("Enter NtUserFindExistingCursorIcon\n"); + + /* Capture resource name (it can be an INTRESOURCE == ATOM) */ + Status = ProbeAndCaptureUnicodeStringOrAtom(&ustrRsrcSafe, pustrRsrc); + if(!NT_SUCCESS(Status)) + return NULL; + Status = ProbeAndCaptureUnicodeString(&ustrModuleSafe, UserMode, pustrModule); + if(!NT_SUCCESS(Status)) + goto done; + UserEnterExclusive(); - - CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy); + CurIcon = IntFindExistingCurIconObject(&ustrModuleSafe, &ustrRsrcSafe, cxDesired, cyDesired); if (CurIcon) - { Ret = CurIcon->Self; - -// IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref? - RETURN(Ret); - } - - EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); - RETURN((HANDLE)0); - -CLEANUP: - TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_); UserLeave(); - END_CLEANUP; + +done: + if(!IS_INTRESOURCE(ustrRsrcSafe.Buffer)) + ExFreePoolWithTag(ustrRsrcSafe.Buffer, TAG_STRING); + ReleaseCapturedUnicodeString(&ustrModuleSafe, UserMode); + + return Ret; }
@@ -920,12 +1031,6 @@
done:
- if(!Ret) - { - IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process()); - CurIcon = NULL; - } - if (CurIcon) { UserDereferenceObject(CurIcon); @@ -942,32 +1047,34 @@ /* * @implemented */ -#ifdef NEW_CURSORICON BOOL APIENTRY NtUserSetCursorIconData( - _In_ HCURSOR Handle, - _In_ HINSTANCE hinst, - _In_ HRSRC hrsrc, - _In_ PICONINFO pIconInfo) + _In_ HCURSOR Handle, + _In_opt_ PUNICODE_STRING pustrModule, + _In_opt_ PUNICODE_STRING pustrRsrc, + _In_ PICONINFO pIconInfo) { PCURICON_OBJECT CurIcon; PSURFACE psurfBmp; NTSTATUS Status = STATUS_SUCCESS; BOOL Ret = FALSE; - DECLARE_RETURN(BOOL); ICONINFO ii; - + TRACE("Enter NtUserSetCursorIconData\n"); + + /* If a module name is provided, we need a resource name, and vice versa */ + if((pustrModule && !pustrRsrc) || (!pustrModule && pustrRsrc)) + return FALSE; + UserEnterExclusive();
if (!(CurIcon = UserGetCurIconObject(Handle))) { - RETURN(FALSE); - } - - CurIcon->hModule = hinst; - CurIcon->hRsrc =hrsrc; + UserLeave(); + EngSetLastError(ERROR_INVALID_HANDLE); + return FALSE; + }
_SEH2_TRY { @@ -1014,28 +1121,37 @@
if (CurIcon->aFrame[0].hbmColor) { - if ((psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor))) - { - CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; - CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy; - SURFACE_ShareUnlockSurface(psurfBmp); - GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC); - } - else + psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmColor); + if(!psurfBmp) goto done; + + CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; + CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy; + SURFACE_ShareUnlockSurface(psurfBmp); + GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_PUBLIC); } else { - if ((psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].hbmMask))) - { - CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx; - CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy/2; - SURFACE_ShareUnlockSurface(psurfBmp); - } - else + psurfBmp = SURFACE_ShareLockSurface(CurIcon->aFrame[0].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->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC); + + if(pustrModule) + { + /* We use this convenient function, because INTRESOURCEs and ATOMs are the same */ + Status = ProbeAndCaptureUnicodeStringOrAtom(&CurIcon->ustrRsrc, pustrRsrc); + if(!NT_SUCCESS(Status)) + goto done; + Status = ProbeAndCaptureUnicodeString(&CurIcon->ustrModule, UserMode, pustrModule); + if(!NT_SUCCESS(Status)) + goto done; + }
Ret = TRUE;
@@ -1055,97 +1171,17 @@ GreDeleteObject(CurIcon->aFrame[0].hbmColor); CurIcon->aFrame[0].hbmColor = NULL; } - } - RETURN(Ret); - -CLEANUP: - TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_); + if(!IS_INTRESOURCE(CurIcon->ustrRsrc.Buffer)) + ExFreePoolWithTag(CurIcon->ustrRsrc.Buffer, TAG_STRING); + if(CurIcon->ustrModule.Buffer) + ReleaseCapturedUnicodeString(&CurIcon->ustrModule, UserMode); + } + + 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; - BOOL Ret = FALSE; - DECLARE_RETURN(BOOL); - - TRACE("Enter NtUserSetCursorIconData\n"); - UserEnterExclusive(); - - if (!(CurIcon = UserGetCurIconObject(hCurIcon))) - { - RETURN(FALSE); - } - - CurIcon->hModule = hModule; - CurIcon->hRsrc = hRsrc; - CurIcon->hGroupRsrc = hGroupRsrc; - - /* Copy fields */ - if (fIcon) - { - Status = MmCopyFromCaller(&CurIcon->bIcon, fIcon, sizeof(BOOL)); - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - goto done; - } - } - else - { - if (!Hotspot) - Ret = TRUE; - } - - if (Hotspot) - { - Status = MmCopyFromCaller(&CurIcon->ptlHotspot, Hotspot, sizeof(POINT)); - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - goto done; - } - } - - if (!fIcon && !Hotspot) - { - Ret = TRUE; - } - -done: - if(Ret) - { - /* This icon is shared now */ - GreSetObjectOwner(CurIcon->aFrame[0].hbmMask, GDI_OBJ_HMGR_PUBLIC); - if(CurIcon->aFrame[0].hbmColor) - { - GreSetObjectOwner(CurIcon->aFrame[0].hbmColor, GDI_OBJ_HMGR_PUBLIC); - } - if(CurIcon->aFrame[0].hbmAlpha) - { - GreSetObjectOwner(CurIcon->aFrame[0].hbmAlpha, GDI_OBJ_HMGR_PUBLIC); - } - } - UserDereferenceObject(CurIcon); - RETURN(Ret); - - -CLEANUP: - TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_); - UserLeave(); - END_CLEANUP; -} -#endif + + return Ret; +}
/* Mostly inspired from wine code. * We use low level functions because: @@ -1167,7 +1203,7 @@ HBRUSH hbrFlickerFreeDraw, UINT diFlags) { - PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen; + PSURFACE psurfDest, psurfMask, psurfColor; //, psurfOffScreen = NULL; PDC pdc = NULL; BOOL Ret = FALSE; HBITMAP hbmMask, hbmColor, hbmAlpha; @@ -1215,6 +1251,35 @@ 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; + } + /* 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, rcDest); + + /* 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->Size.cx, pIcon->Size.cy);
@@ -1239,7 +1304,8 @@ }
/* 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) { @@ -1252,21 +1318,18 @@ if(!pbrush) { ERR("Failed to get brush object.\n"); - SURFACE_ShareUnlockSurface(psurfMask); - if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor); - return FALSE; - } - + 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 */ @@ -1292,52 +1355,45 @@ 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->rosdc.CombinedClip; + /* 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, rcDest); - - /* Get the clip object */ pdcClipObj = pdc->rosdc.CombinedClip; - - /* 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 */ @@ -1460,36 +1516,23 @@ }
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, rcDest); - /* Get the clip object */ 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); @@ -1509,18 +1552,20 @@
EXLATEOBJ_vCleanup(&exlo); } +#endif Cleanup: if(pdc) { DC_vFinishBlit(pdc, NULL); DC_UnlockDc(pdc); } - -Cleanup2: + +#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); @@ -1554,7 +1599,7 @@
if (!(pIcon = UserGetCurIconObject(hIcon))) { - ERR("UserGetCurIconObject() failed!\n"); + ERR("UserGetCurIconObject(0x%08x) failed!\n", hIcon); UserLeave(); return FALSE; }
Modified: trunk/reactos/win32ss/user/ntuser/simplecall.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/simplec... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/simplecall.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/simplecall.c [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -248,7 +248,7 @@ PCURICON_OBJECT CurIcon; DWORD_PTR Result ;
- if (!(CurIcon = IntCreateCurIconHandle())) + if (!(CurIcon = IntCreateCurIconHandle((DWORD)Param))) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); RETURN(0);
Modified: trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/user32/windows... ============================================================================== --- trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c [iso-8859-1] Sun Nov 4 12:56:44 2012 @@ -11,7 +11,7 @@ #include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(cursor); -//WINE_DECLARE_DEBUG_CHANNEL(icon); +WINE_DECLARE_DEBUG_CHANNEL(icon); //WINE_DECLARE_DEBUG_CHANNEL(resource);
/************* USER32 INTERNAL FUNCTIONS **********/ @@ -54,6 +54,30 @@ }
/************* 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 ) { @@ -121,6 +145,32 @@ } }
+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; +} + /************* IMPLEMENTATION CORE ****************/
static BOOL CURSORICON_GetIconInfoFromBMI( @@ -132,28 +182,35 @@ { 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;
- /* Check for invalid data */ - if ( (pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) && - pbmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) || - pbmi->bmiHeader.biCompression != BI_RGB ) - { - WARN("Invalid resource bitmap header.\n"); - return FALSE; - } + 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;
/* Fix the hotspot coords */ - if(cxDesired != pbmi->bmiHeader.biWidth) - pii->xHotspot = (pii->xHotspot * cxDesired) / pbmi->bmiHeader.biWidth; - if(cxDesired != (pbmi->bmiHeader.biHeight/2)) - pii->yHotspot = (pii->yHotspot * cyDesired * 2) / pbmi->bmiHeader.biHeight; - - hdcScreen = CreateDCW(L"DISPLAY", NULL, NULL, NULL); + if(!pii->fIcon) + { + if(cxDesired != pbmi->bmiHeader.biWidth) + pii->xHotspot = (pii->xHotspot * cxDesired) / pbmi->bmiHeader.biWidth; + if(cxDesired != (pbmi->bmiHeader.biHeight/2)) + pii->yHotspot = (pii->yHotspot * cyDesired * 2) / pbmi->bmiHeader.biHeight; + } + + hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); if(!hdcScreen) return FALSE; hdc = CreateCompatibleDC(hdcScreen); @@ -167,8 +224,13 @@ if(!pbmiCopy) goto done; RtlCopyMemory(pbmiCopy, pbmi, ubmiSize); - pbmiCopy->bmiHeader.biHeight /= 2; - + + /* 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; + pvColor = (const char*)pbmi + ubmiSize; pvMask = (const char*)pvColor + get_dib_image_size(pbmi->bmiHeader.biWidth, pbmiCopy->bmiHeader.biHeight, pbmi->bmiHeader.biBitCount ); @@ -250,7 +312,7 @@ }
static -HANDLE +HBITMAP BITMAP_LoadImageW( _In_opt_ HINSTANCE hinst, _In_ LPCWSTR lpszName, @@ -259,8 +321,400 @@ _In_ UINT fuLoad ) { - UNIMPLEMENTED; - return NULL; + const BITMAPINFO* pbmi; + BITMAPINFO* pbmiScaled = NULL; + BITMAPINFO* pbmiCopy = NULL; + const VOID* pvMapping; + DWORD dwOffset = 0; + HGLOBAL hgRsrc; + int iBMISize; + PVOID pvBits; + HDC hdcScreen = NULL; + HDC hdc = NULL; + HBITMAP hbmpRet, hbmpOld; + + /* 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, (LPWSTR)RT_BITMAP); + if(!hrsrc) + return NULL; + hgRsrc = LoadResource(hinst, hrsrc); + if(!hgRsrc) + return NULL; + pbmi = LockResource(hgRsrc); + if(!pbmi) + return NULL; + } + + /* See if we must scale the bitmap */ + 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; i<numColors; i++) + { + ptr = (RGBTRIPLE*)(pbmiColors + i*incr); + if((ptr->rgbtBlue == 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; + if(cxDesired == 0) + cxDesired = pbmch->bcWidth; + if(cyDesired == 0) + cyDesired == pbmch->bcHeight; + else if(pbmch->bcHeight < 0) + cyDesired = -cyDesired; + + pbmch->bcWidth = cxDesired; + pbmch->bcHeight = cyDesired; + } + else + { + if ((pbmi->bmiHeader.biHeight > 65535) || (pbmi->bmiHeader.biWidth > 65535)) { + WARN("Broken BITMAPINFO!\n"); + goto end; + } + + if(cxDesired == 0) + cxDesired = pbmi->bmiHeader.biWidth; + if(cyDesired == 0) + cyDesired = pbmi->bmiHeader.biHeight; + else if(pbmi->bmiHeader.biHeight < 0) + cyDesired = -cyDesired; + + pbmiScaled->bmiHeader.biWidth = cxDesired; + pbmiScaled->bmiHeader.biHeight = cyDesired; + /* No compression for DIB sections */ + if(fuLoad & LR_CREATEDIBSECTION) + 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.biWidth, + 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 (fuLoad & LR_LOADFROMFILE) + UnmapViewOfFile( pvMapping ); + else + FreeResource(hgRsrc); + + return hbmpRet; +} + +#include "pshpack1.h" + +typedef struct { + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; + WORD xHotspot; + WORD yHotspot; + DWORD dwDIBSize; + DWORD dwDIBOffset; +} CURSORICONFILEDIRENTRY; + +typedef struct +{ + WORD idReserved; + WORD idType; + WORD idCount; + CURSORICONFILEDIRENTRY idEntries[1]; +} CURSORICONFILEDIR; + +#include "poppack.h" + +static +HANDLE +CURSORICON_LoadFromFileW( + _In_ LPCWSTR lpszName, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuLoad, + _In_ BOOL bIcon +) +{ + CURSORICONDIR* fakeDir; + CURSORICONDIRENTRY* fakeEntry; + CURSORICONFILEDIRENTRY *entry; + CURSORICONFILEDIR *dir; + DWORD filesize = 0; + LPBYTE bits; + HANDLE hRet = NULL; + WORD i; + ICONINFO ii; + + 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; + if ( filesize < sizeof(*dir) ) + goto end; + + if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) ) + goto end; + + /* + * Cute little hack: + * We allocate a buffer, fake it as if it was a pointer to a resource in a module, + * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use + */ + fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR, idEntries[dir->idCount])); + if(!fakeDir) + goto end; + fakeDir->idReserved = 0; + fakeDir->idType = dir->idType; + fakeDir->idCount = dir->idCount; + for(i = 0; i<dir->idCount; i++) + { + fakeEntry = &fakeDir->idEntries[i]; + entry = &dir->idEntries[i]; + /* Take this as an occasion to perform a size check */ + if((entry->dwDIBOffset + entry->dwDIBSize) > filesize) + goto end; + /* File icon/cursors are not like resource ones */ + if(bIcon) + { + fakeEntry->ResInfo.icon.bWidth = entry->bWidth; + fakeEntry->ResInfo.icon.bHeight = entry->bHeight; + fakeEntry->ResInfo.icon.bColorCount = 0; + fakeEntry->ResInfo.icon.bReserved = 0; + } + else + { + fakeEntry->ResInfo.cursor.wWidth = entry->bWidth; + fakeEntry->ResInfo.cursor.wHeight = entry->bHeight; + } + /* Let's assume there's always one plane */ + fakeEntry->wPlanes = 1; + /* We must get the bitcount from the BITMAPINFOHEADER itself */ + fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biBitCount; + fakeEntry->dwBytesInRes = entry->dwDIBSize; + fakeEntry->wResId = i + 1; + } + + /* Now call LookupIconIdFromResourceEx */ + i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME); + /* We don't need this anymore */ + HeapFree(GetProcessHeap(), 0, fakeDir); + if(i == 0) + { + WARN("Unable to get a fit entry index.\n"); + goto end; + } + + /* Get our entry */ + entry = &dir->idEntries[i-1]; + /* A bit of preparation */ + ii.xHotspot = entry->xHotspot; + ii.yHotspot = entry->yHotspot; + ii.fIcon = bIcon; + + /* Do the dance */ + if(!CURSORICON_GetIconInfoFromBMI(&ii, (BITMAPINFO*)&bits[entry->dwDIBOffset], cxDesired, cyDesired)) + goto end; + + /* Create the icon. NOTE: there's no LR_SHARED icons if they are created from file */ + hRet = CreateIconIndirect(&ii); + + /* Clean up */ + DeleteObject(ii.hbmMask); + DeleteObject(ii.hbmColor); + +end: + UnmapViewOfFile(bits); + return hRet; }
static @@ -274,24 +728,79 @@ _In_ BOOL bIcon ) { - HRSRC hrsrc, hrsrc2; - HANDLE handle, hCurIcon; + HRSRC hrsrc; + HANDLE handle, hCurIcon = NULL; CURSORICONDIR* dir; WORD wResId; LPBYTE bits; ICONINFO ii; 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) { - UNIMPLEMENTED; - return NULL; + return CURSORICON_LoadFromFileW(lpszName, cxDesired, cyDesired, fuLoad, bIcon); }
/* Check if caller wants OEM icons */ if(!hinst) hinst = User32Instance;
+ if(fuLoad & LR_SHARED) + { + DWORD size = MAX_PATH; + + TRACE("Checking for an LR_SHARED cursor/icon.\n"); + /* Prepare the resource name string */ + if(IS_INTRESOURCE(lpszName)) + { + ustrRsrc.Buffer = (LPWSTR)lpszName; + ustrRsrc.Length = 0; + ustrRsrc.MaximumLength = 0; + } + else + RtlInitUnicodeString(&ustrRsrc, lpszName); + + /* Prepare the module name string */ + ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + /* Get it */ + do + { + DWORD ret = GetModuleFileName(hinst, ustrModule.Buffer, size); + if(ret == 0) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + return NULL; + } + if(ret < size) + { + ustrModule.Length = ret; + ustrModule.MaximumLength = size; + break; + } + size *= 2; + ustrModule.Buffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, size*sizeof(WCHAR)); + } while(TRUE); + + /* Ask win32k */ + hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, cxDesired, cyDesired); + if(hCurIcon) + { + /* Woohoo, got it! */ + TRACE("MATCH!\n"); + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + return hCurIcon; + } + } + /* Find resource ID */ hrsrc = FindResourceW( hinst, @@ -300,57 +809,45 @@
/* We let FindResource, LoadResource, etc. call SetLastError */ if(!hrsrc) - return 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 LR_SHARED is set, we must check for the cache */ - hCurIcon = NtUserFindExistingCursorIcon(hinst, hrsrc, cxDesired, cyDesired); - if(hCurIcon) - return hCurIcon; + goto done;
handle = LoadResource(hinst, hrsrc); if(!handle) - return NULL; + goto done;
dir = LockResource(handle); - if(!dir) return NULL; - - /* For now, take the first entry */ - wResId = dir->idEntries[0].wResId; + if(!dir) + goto done; + + wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME); FreeResource(handle);
/* Get the relevant resource pointer */ - hrsrc2 = FindResourceW( + hrsrc = FindResourceW( hinst, MAKEINTRESOURCEW(wResId), (LPWSTR)(bIcon ? RT_ICON : RT_CURSOR)); - if(!hrsrc2) - return NULL; - - handle = LoadResource(hinst, hrsrc2); + if(!hrsrc) + goto done; + + handle = LoadResource(hinst, hrsrc); if(!handle) - return NULL; + goto done;
bits = LockResource(handle); if(!bits) { FreeResource(handle); - return NULL; - } - - /* Get the hospot */ + goto done; + } + + /* Get the hotspot */ if(bIcon) { ii.xHotspot = cxDesired/2; ii.yHotspot = cyDesired/2; } - else + if(!bIcon) { SHORT* ptr = (SHORT*)bits; ii.xHotspot = ptr[0]; @@ -369,16 +866,20 @@ FreeResource( handle );
if(!bStatus) - return NULL; + goto done;
/* Create the handle */ hCurIcon = NtUserxCreateEmptyCurObject(bIcon ? 0 : 1); if(!hCurIcon) - return NULL; + { + DeleteObject(ii.hbmMask); + if(ii.hbmColor) DeleteObject(ii.hbmColor); + goto done; + }
/* Tell win32k */ if(fuLoad & LR_SHARED) - bStatus = NtUserSetCursorIconData(hCurIcon, hinst, hrsrc, &ii); + bStatus = NtUserSetCursorIconData(hCurIcon, &ustrModule, &ustrRsrc, &ii); else bStatus = NtUserSetCursorIconData(hCurIcon, NULL, NULL, &ii);
@@ -389,9 +890,332 @@ }
DeleteObject(ii.hbmMask); - DeleteObject(ii.hbmColor); - + if(ii.hbmColor) DeleteObject(ii.hbmColor); + +done: + if(ustrModule.Buffer) + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); return hCurIcon; +} + +static +HBITMAP +BITMAP_CopyImage( + _In_ HBITMAP hbmp, + _In_ int cxDesired, + _In_ int cyDesired, + _In_ UINT fuFlags +) +{ + HBITMAP res = NULL; + DIBSECTION ds; + int objSize; + BITMAPINFO * bi; + + objSize = GetObjectW( hbmp, sizeof(ds), &ds ); + if (!objSize) return 0; + if ((cxDesired < 0) || (cyDesired < 0)) return 0; + + if (fuFlags & LR_COPYFROMRESOURCE) + { + FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n"); + } + + if (fuFlags & LR_COPYRETURNORG) + { + FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n"); + } + + if (cxDesired == 0) cxDesired = ds.dsBm.bmWidth; + if (cyDesired == 0) cyDesired = 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 (fuFlags & 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, hbmp, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS); + + bi->bmiHeader.biWidth = cxDesired; + bi->bmiHeader.biHeight = cyDesired; + bi->bmiHeader.biSizeImage = 0; + + res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0); + DeleteDC(dc); + } + else + { + /* Create a device-dependent bitmap */ + + BOOL monochrome = (fuFlags & 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, hbmp, 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(cxDesired, cyDesired, 1, 1, NULL); + } + else + { + HDC screenDC = GetDC(NULL); + res = CreateCompatibleBitmap(screenDC, cxDesired, cyDesired); + 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, hbmp, 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, hbmp, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS); + + /* Copy it to the destination bitmap */ + oldBmp = SelectObject(dc, res); + StretchDIBits(dc, 0, 0, cxDesired, cyDesired, + 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, + bits, bi, DIB_RGB_COLORS, SRCCOPY); + SelectObject(dc, oldBmp); + + HeapFree(GetProcessHeap(), 0, bits); + } + + DeleteDC(dc); + } + + if (fuFlags & LR_COPYDELETEORG) + { + DeleteObject(hbmp); + } + } + 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; + + if(fuFlags & LR_COPYFROMRESOURCE) + { + /* Get the icon module/resource names */ + UNICODE_STRING ustrModule; + UNICODE_STRING ustrRsrc; + PVOID pvBuf; + HMODULE hModule; + + ustrModule.MaximumLength = MAX_PATH; + ustrRsrc.MaximumLength = 256; + + ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength * sizeof(WCHAR)); + if(!ustrModule.Buffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */ + pvBuf = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WCHAR)); + if(!pvBuf) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + ustrRsrc.Buffer = pvBuf; + + do + { + if(!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE)) + { + HeapFree(GetProcessHeap(), 0, ustrModule.Buffer); + HeapFree(GetProcessHeap(), 0, pvBuf); + return NULL; + } + + if((ustrModule.Length < ustrModule.MaximumLength) && (ustrRsrc.Length < ustrRsrc.MaximumLength)) + { + /* Buffers were big enough */ + break; + } + + /* Find which buffer were too small */ + if(ustrModule.Length == ustrModule.MaximumLength) + { + PWSTR newBuffer; + ustrModule.MaximumLength *= 2; + newBuffer = HeapReAlloc(GetProcessHeap(), 0, ustrModule.Buffer, ustrModule.MaximumLength * sizeof(WCHAR)); + if(!ustrModule.Buffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto leave; + } + ustrModule.Buffer = newBuffer; + } + + if(ustrRsrc.Length == ustrRsrc.MaximumLength) + { + ustrRsrc.MaximumLength *= 2; + pvBuf = HeapReAlloc(GetProcessHeap(), 0, ustrRsrc.Buffer, ustrRsrc.MaximumLength * sizeof(WCHAR)); + if(!pvBuf) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto leave; + } + ustrRsrc.Buffer = pvBuf; + } + } while(TRUE); + + /* NULL-terminate our strings */ + ustrModule.Buffer[ustrModule.Length] = 0; + if(!IS_INTRESOURCE(ustrRsrc.Buffer)) + ustrRsrc.Buffer[ustrRsrc.Length] = 0; + + /* Get the module handle */ + if(!GetModuleHandleExW(0, ustrModule.Buffer, &hModule)) + { + /* This hould never happen */ + SetLastError(ERROR_INVALID_PARAMETER); + goto leave; + } + + /* Call the relevant function */ + ret = CURSORICON_LoadImageW(hModule, ustrRsrc.Buffer, cxDesired, cyDesired, bIcon, fuFlags & LR_DEFAULTSIZE); + + 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); + HeapFree(GetProcessHeap(), 0, pvBuf); + + return ret; + } + + /* This is a regular copy */ + if(fuFlags & ~LR_COPYDELETEORG) + FIXME("Unimplemented flags: 0x%08x\n", fuFlags); + + if(!GetIconInfo(hicon, &ii)) + { + ERR("GetIconInfo failed.\n"); + return NULL; + } + + ret = CreateIconIndirect(&ii); + + DeleteObject(ii.hbmMask); + if(ii.hbmColor) DeleteObject(ii.hbmColor); + + if(ret && (fuFlags & LR_COPYDELETEORG)) + DestroyIcon(hicon); + + return hicon; }
/************* PUBLIC FUNCTIONS *******************/ @@ -404,7 +1228,19 @@ _In_ UINT fuFlags ) { - UNIMPLEMENTED; + 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; }
@@ -438,8 +1274,9 @@ _In_ UINT diFlags ) { - UNIMPLEMENTED; - return FALSE; + return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, + istepIfAniCur, hbrFlickerFreeDraw, diFlags, + 0, 0); }
BOOL WINAPI GetIconInfo( @@ -447,16 +1284,14 @@ _Out_ PICONINFO piconinfo ) { - UNIMPLEMENTED; - return FALSE; + return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE); }
BOOL WINAPI DestroyIcon( _In_ HICON hIcon ) { - UNIMPLEMENTED; - return FALSE; + return NtUserDestroyCursor(hIcon, FALSE); }
HICON WINAPI LoadIconA( @@ -631,8 +1466,9 @@ _In_ BOOL fIcon ) { - UNIMPLEMENTED; - return 0; + 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( @@ -643,8 +1479,134 @@ _In_ UINT Flags ) { - UNIMPLEMENTED; - return 0; + WORD bppDesired; + CURSORICONDIR* dir = (CURSORICONDIR*)presbits; + CURSORICONDIRENTRY* entry; + int i, numMatch, iIndex = -1; + WORD width, height; + USHORT bitcount; + ULONG cxyDiff, cxyDiffTmp; + + 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; + } + + /* idType == 2 is for cursors, 1 for icons */ + /*if(fIcon) + { + if(dir->idType == 2) + { + WARN("An icon was asked for a cursor resource.\n"); + return 0; + } + } + else if(dir->idType == 1) + { + WARN("A cursor was asked for an icon 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); + } + + /* Find the best match for the desired size */ + cxyDiff = 0xFFFFFFFF; + numMatch = 0; + 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; + /* Let it be a 1-norm */ + cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired)); + if( cxyDiffTmp > cxyDiff) + continue; + if( cxyDiffTmp == cxyDiff) + { + numMatch++; + continue; + } + iIndex = i; + numMatch = 1; + cxyDiff = cxyDiffTmp; + } + + if(numMatch == 1) + { + /* Only one entry fit the asked dimensions */ + return dir->idEntries[iIndex].wResId; + } + + 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 */ + cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired)); + if(cxyDiffTmp != cxyDiff) + 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)) + { + iIndex = i; + bitcount = entry->wBitCount; + } + } + + if(iIndex >= 0) + return dir->idEntries[iIndex].wResId; + + /* No inferior or equal depth available. Get the smallest one */ + bitcount = 0x7FFF; + 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 */ + cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired)); + if(cxyDiffTmp != cxyDiff) + continue; + /* Check the bit depth */ + if(entry->wBitCount < bitcount) + { + iIndex = i; + bitcount = entry->wBitCount; + } + } + + return dir->idEntries[iIndex].wResId; }
HICON WINAPI CreateIcon( @@ -657,8 +1619,32 @@ _In_ const BYTE *lpbXORbits ) { - UNIMPLEMENTED; - return NULL; + 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( @@ -681,16 +1667,60 @@ _In_ UINT uFlags ) { - UNIMPLEMENTED; - return NULL; + ICONINFO ii; + HICON hIcon; + + if(uFlags) + FIXME("uFlags 0x%08x ignored.\n", uFlags); + + if(fIcon) + { + ii.xHotspot = cxDesired/2; + ii.yHotspot = cyDesired/2; + } + else + { + WORD* pt = (WORD*)pbIconBits; + ii.xHotspot = *pt++; + ii.yHotspot = *pt++; + pbIconBits = (PBYTE)pt; + } + ii.fIcon = fIcon; + + if(!CURSORICON_GetIconInfoFromBMI(&ii, (BITMAPINFO*)pbIconBits, cxDesired, cyDesired)) + return NULL; + + hIcon = CreateIconIndirect(&ii); + + /* Clean up */ + DeleteObject(ii.hbmMask); + if(ii.hbmColor) DeleteObject(ii.hbmColor); + + return hIcon; }
HICON WINAPI CreateIconIndirect( _In_ PICONINFO piconinfo ) { - UNIMPLEMENTED; - return NULL; + /* As simple as creating a handle, and let win32k deal with the bitmaps */ + HICON hiconRet; + + TRACE("%p.\n", piconinfo); + + hiconRet = NtUserxCreateEmptyCurObject(piconinfo->fIcon ? 0 : 1); + if(!hiconRet) + return NULL; + + if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, piconinfo)) + { + NtUserDestroyCursor(hiconRet, FALSE); + hiconRet = NULL; + } + + TRACE("Returning 0x%08x.\n", hiconRet); + + return hiconRet; }
HCURSOR WINAPI CreateCursor( @@ -703,8 +1733,21 @@ _In_ const VOID *pvXORPlane ) { - UNIMPLEMENTED; - return NULL; + 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( @@ -729,8 +1772,7 @@ _Out_ LPPOINT lpPoint ) { - UNIMPLEMENTED; - return FALSE; + return NtUserxGetCursorPos(lpPoint); }
int WINAPI ShowCursor( @@ -751,6 +1793,5 @@ _In_ HCURSOR hCursor ) { - UNIMPLEMENTED; - return FALSE; -} + return NtUserDestroyCursor(hCursor, FALSE); +}