You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5059 lines
152 KiB
5059 lines
152 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: clres.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Resource Loading/Creation Routines
|
|
*
|
|
* History:
|
|
* 24-Sep-1990 MikeKe From win30
|
|
* 19-Sep-1995 ChrisWil Win95/NT merge.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* Constants.
|
|
*/
|
|
#define BPP01_MAXCOLORS 2
|
|
#define BPP04_MAXCOLORS 16
|
|
#define BPP08_MAXCOLORS 256
|
|
#define ICON_DEFAULTDEPTH 8
|
|
#define ICON_MAXWIDTH 256
|
|
#define ICON_MAXHEIGHT 256
|
|
|
|
#define RESCLR_BLACK 0x00000000
|
|
#define RESCLR_WHITE 0x00FFFFFF
|
|
|
|
typedef struct {
|
|
ACCEL accel;
|
|
WORD padding;
|
|
} RESOURCE_ACCEL, *PRESOURCE_ACCEL;
|
|
|
|
/*
|
|
* Bitmap resource IDs
|
|
*/
|
|
#define BMR_ICON 1
|
|
#define BMR_BITMAP 2
|
|
#define BMR_CURSOR 3
|
|
|
|
typedef struct _OLDCURSOR {
|
|
BYTE bType;
|
|
BYTE bFormat;
|
|
WORD xHotSpot; // 0 for icons
|
|
WORD yHotSpot; // 0 for icons
|
|
WORD cx;
|
|
WORD cy;
|
|
WORD cxBytes;
|
|
WORD wReserved2;
|
|
BYTE abBitmap[1];
|
|
} OLDCURSOR, *POLDCURSOR;
|
|
typedef OLDCURSOR UNALIGNED *UPOLDCURSOR;
|
|
|
|
/*
|
|
* Local Macros.
|
|
*/
|
|
#define GETINITDC() \
|
|
(gfSystemInitialized ? NtUserGetDC(NULL) : CreateDCW(L"DISPLAY", L"", NULL, NULL))
|
|
|
|
#define RELEASEINITDC(hdc) \
|
|
(gfSystemInitialized ? ReleaseDC(NULL, hdc) : DeleteDC(hdc))
|
|
|
|
#define ISRIFFFORMAT(p) \
|
|
(((UNALIGNED RTAG *)(p))->ckID == FOURCC_RIFF)
|
|
|
|
#define MR_FAILFOR40 0x01
|
|
#define MR_MONOCHROME 0x02
|
|
|
|
|
|
typedef struct tagMAPRES {
|
|
WORD idDisp; // display driver ID
|
|
WORD idUser; // USER ID
|
|
BYTE bFlags; // Flags
|
|
BYTE bReserved; // unused
|
|
} MAPRES, *LPMAPRES, *PMAPRES;
|
|
|
|
|
|
HBITMAP CopyBmp(HBITMAP hbmpOrg, int cxNew, int cyNew, UINT LR_flags);
|
|
|
|
/***************************************************************************\
|
|
* SplFindResource
|
|
*
|
|
* Check whether the hInstance passed is that of the present display driver;
|
|
* if so, it will call the GetDriverResourceId() in the display to allow
|
|
* it to map the given id/name to a new id/name. Then it will call
|
|
* FindResource9) in KERNEL.
|
|
*
|
|
* 13-Nov-1995 SanfordS Added mapping for DEFAULT constants.
|
|
\***************************************************************************/
|
|
|
|
HANDLE SplFindResource(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
LPCWSTR lpType)
|
|
{
|
|
return FINDRESOURCEW(hmod, lpName, lpType);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SplFreeResource
|
|
*
|
|
* Really frees a resource that is shared (won't be touched again unless
|
|
* LR_COPYFROMRESOURCE is used) or system.
|
|
*
|
|
* 13-Nov-1995 SanfordS Added mapping for DEFAULT constants.
|
|
\***************************************************************************/
|
|
VOID SplFreeResource(
|
|
HANDLE hRes,
|
|
HINSTANCE hmod,
|
|
UINT lrFlags)
|
|
{
|
|
if (!FREERESOURCE(hRes, hmod) &&
|
|
((hmod == hmodUser) || (lrFlags & LR_SHARED))) {
|
|
FREERESOURCE(hRes, hmod);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* WowGetModuleFileName
|
|
*
|
|
* This converts a WOW or non-WOW module handle to a string form that
|
|
* can be restored even for WOW handles.
|
|
*
|
|
* Returns: fSuccess
|
|
*
|
|
* 29-Nov-1995 SanfordS Created.
|
|
\***********************************************************************/
|
|
|
|
BOOL WowGetModuleFileName(
|
|
HMODULE hModule,
|
|
LPWSTR pwsz,
|
|
DWORD cchMax)
|
|
{
|
|
if (!GetModuleFileName(hModule, pwsz, cchMax)) {
|
|
|
|
if (cchMax < 10) {
|
|
RIPMSG0(RIP_WARNING, "WowGetModuleFileName: exceeded Char-Max");
|
|
return FALSE;
|
|
}
|
|
|
|
wsprintf(pwsz, TEXT("\001%08lx"), hModule);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* WowGetModuleHandle
|
|
*
|
|
* This restores the string form of a module handle created by
|
|
* WowGetModuleFileName to the original handle.
|
|
*
|
|
* Returns: fSuccess
|
|
*
|
|
* 29-Nov-1995 Created SanfordS
|
|
\***********************************************************************/
|
|
|
|
HMODULE WowGetModuleHandle(
|
|
LPCWSTR pwsz)
|
|
{
|
|
HMODULE hMod = NULL;
|
|
DWORD digit;
|
|
|
|
if (pwsz[0] == TEXT('\001')) {
|
|
|
|
/*
|
|
* Cant seem to link to swscanf without CRT0 problems so just
|
|
* do it by hand.
|
|
*/
|
|
while (*(++pwsz)) {
|
|
|
|
if (*pwsz == TEXT(' '))
|
|
continue;
|
|
|
|
digit = *pwsz - TEXT('0');
|
|
|
|
if (digit > 9)
|
|
digit += (DWORD)(TEXT('0') - TEXT('a') + 10);
|
|
|
|
(ULONG_PTR)hMod <<= 4;
|
|
(ULONG_PTR)hMod += digit;
|
|
}
|
|
|
|
} else {
|
|
|
|
hMod = GetModuleHandle(pwsz);
|
|
}
|
|
|
|
return hMod;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateAcceleratorTableA (API)
|
|
*
|
|
* Creates an accel table, returns handle to accel table.
|
|
*
|
|
* 02-May-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HACCEL, WINAPI, CreateAcceleratorTableA, LPACCEL, paccel, int, cAccel)
|
|
HACCEL WINAPI CreateAcceleratorTableA(
|
|
LPACCEL paccel,
|
|
int cAccel)
|
|
{
|
|
int nAccel = cAccel;
|
|
LPACCEL pAccelT = paccel;
|
|
|
|
/*
|
|
* Convert any character keys from ANSI to Unicode.
|
|
*/
|
|
while (nAccel--) {
|
|
|
|
if ((pAccelT->fVirt & FVIRTKEY) == 0) {
|
|
|
|
if (!NT_SUCCESS(RtlMultiByteToUnicodeN((LPWSTR)&(pAccelT->key),
|
|
sizeof(WCHAR),
|
|
NULL,
|
|
(LPSTR)&(pAccelT->key),
|
|
sizeof(CHAR)))) {
|
|
pAccelT->key = 0xFFFF;
|
|
}
|
|
}
|
|
|
|
pAccelT++;
|
|
}
|
|
|
|
return NtUserCreateAcceleratorTable(paccel, cAccel);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CopyAcceleratorTableA (API)
|
|
*
|
|
* Copies an accel table
|
|
*
|
|
* 02-May-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, CopyAcceleratorTableA, HACCEL, hacc, LPACCEL, paccel, int, length)
|
|
int CopyAcceleratorTableA(
|
|
HACCEL hacc,
|
|
LPACCEL paccel,
|
|
int length)
|
|
{
|
|
int retval;
|
|
|
|
retval = NtUserCopyAcceleratorTable(hacc, paccel, length);
|
|
|
|
/*
|
|
* If we are doing a copy and we succeeded then convert the accelerator
|
|
*/
|
|
if ((paccel != NULL) && (retval > 0)) {
|
|
|
|
/*
|
|
* Translate UNICODE character keys to ANSI
|
|
*/
|
|
int nAccel = retval;
|
|
LPACCEL pAccelT = paccel;
|
|
|
|
while (nAccel--) {
|
|
if ((pAccelT->fVirt & FVIRTKEY) == 0) {
|
|
if (!NT_SUCCESS(RtlUnicodeToMultiByteN((PCHAR)&(pAccelT->key),
|
|
sizeof(WCHAR),
|
|
NULL,
|
|
(PWSTR)&(pAccelT->key),
|
|
sizeof(pAccelT->key)))) {
|
|
pAccelT->key = 0;
|
|
}
|
|
}
|
|
pAccelT++;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FindAccResource
|
|
*
|
|
* Resource accelerator tables are to be loaded only once to be compatible
|
|
* with Win95. So we keep track of the addresses we've loaded tables from
|
|
* and the corresponding handle.
|
|
*
|
|
* This function finds an entry in the table. It returns the address
|
|
* of the pacNext pointer that contains the requested entry.
|
|
*
|
|
* 01/31/97 GerardoB Created.
|
|
\***************************************************************************/
|
|
PACCELCACHE * FindAccResource (HACCEL hAccel, PVOID pRes)
|
|
{
|
|
/************************************
|
|
* The caller must own gcsAccelCache *
|
|
*************************************/
|
|
|
|
PACCELCACHE * ppacNext = &gpac;
|
|
PACCELCACHE pac;
|
|
|
|
/*
|
|
* This is meant to search by handle or by pointer, not both
|
|
* So at least one of the parameters must be NULL.
|
|
*/
|
|
UserAssert(!(hAccel && pRes));
|
|
/*
|
|
* Walk the table
|
|
*/
|
|
while (*ppacNext != NULL) {
|
|
pac = *ppacNext;
|
|
if ((pac->pRes == pRes) || (pac->hAccel == hAccel)) {
|
|
/*
|
|
* Found it. Validate this entry before returning.
|
|
*/
|
|
UserAssert(pac->dwLockCount != 0);
|
|
UserAssert(HMValidateHandleNoDesktop(pac->hAccel, TYPE_ACCELTABLE));
|
|
break;
|
|
}
|
|
|
|
ppacNext = &(pac->pacNext);
|
|
}
|
|
|
|
return ppacNext;
|
|
}
|
|
/***************************************************************************\
|
|
* AddAccResource
|
|
*
|
|
* This is called everytime LoadAcc loads a new table. It adds an entry
|
|
* (handle and resource address) to the global list and sets the lock count
|
|
* to 1.
|
|
*
|
|
* 01/31/97 GerardoB Created.
|
|
\***************************************************************************/
|
|
VOID AddAccResource(
|
|
HACCEL hAccel,
|
|
PVOID pRes)
|
|
{
|
|
PACCELCACHE pac;
|
|
|
|
UserAssert(HMValidateHandleNoDesktop(hAccel, TYPE_ACCELTABLE));
|
|
UserAssert(pRes != NULL);
|
|
|
|
/*
|
|
* Allocate and initialize a new entry.
|
|
*/
|
|
pac = (PACCELCACHE)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(ACCELCACHE));
|
|
if (pac != NULL) {
|
|
pac->dwLockCount = 1;
|
|
pac->hAccel = hAccel;
|
|
pac->pRes = pRes;
|
|
|
|
/*
|
|
* Make it the new head of the list
|
|
*/
|
|
RtlEnterCriticalSection(&gcsAccelCache);
|
|
pac->pacNext = gpac;
|
|
gpac = pac;
|
|
RtlLeaveCriticalSection(&gcsAccelCache);
|
|
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DestroyAcceleratorTable
|
|
*
|
|
* 01/31/97 GerardoB Created.
|
|
\***************************************************************************/
|
|
BOOL DestroyAcceleratorTable (HACCEL hAccel)
|
|
{
|
|
BOOL fUnlocked = TRUE;
|
|
PACCELCACHE *ppacNext, pac;
|
|
|
|
/*
|
|
* If we added this table to our list, decrement the lock count
|
|
*/
|
|
RtlEnterCriticalSection(&gcsAccelCache);
|
|
ppacNext = FindAccResource(hAccel, NULL);
|
|
if (*ppacNext != NULL) {
|
|
pac = *ppacNext;
|
|
/*
|
|
* Found it. Decrement lock count.
|
|
*/
|
|
UserAssert(pac->dwLockCount != 0);
|
|
fUnlocked = (--pac->dwLockCount == 0);
|
|
/*
|
|
* If noboby else wants this around, unlink it and nuke it.
|
|
*/
|
|
if (fUnlocked) {
|
|
*ppacNext = pac->pacNext;
|
|
UserLocalFree(pac);
|
|
}
|
|
}
|
|
RtlLeaveCriticalSection(&gcsAccelCache);
|
|
|
|
/*
|
|
* If not totally deref'ed, return FALSE (win95 compat).
|
|
*/
|
|
if (fUnlocked) {
|
|
return NtUserDestroyAcceleratorTable(hAccel);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
/***************************************************************************\
|
|
* LoadAcc (Worker)
|
|
*
|
|
* This is the worker-routine for loading accelerator tables.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
#define FACCEL_VALID (FALT | FCONTROL | FNOINVERT | FSHIFT | FVIRTKEY | FLASTKEY)
|
|
|
|
HANDLE LoadAcc(
|
|
HINSTANCE hmod,
|
|
HANDLE hrl)
|
|
{
|
|
PACCELCACHE * ppacNext;
|
|
HANDLE handle = NULL;
|
|
|
|
if (hrl != NULL) {
|
|
|
|
if (hrl = LOADRESOURCE(hmod, hrl)) {
|
|
|
|
PRESOURCE_ACCEL paccel;
|
|
|
|
if ((paccel = (PRESOURCE_ACCEL)LOCKRESOURCE(hrl, hmod)) != NULL) {
|
|
|
|
int nAccel = 0;
|
|
int i;
|
|
LPACCEL paccelT;
|
|
|
|
/*
|
|
* Check if we've already loaded accelerators from this
|
|
* same address
|
|
*/
|
|
RtlEnterCriticalSection(&gcsAccelCache);
|
|
ppacNext = FindAccResource(NULL, paccel);
|
|
if (*ppacNext != NULL) {
|
|
(*ppacNext)->dwLockCount++;
|
|
handle = (*ppacNext)->hAccel;
|
|
}
|
|
RtlLeaveCriticalSection(&gcsAccelCache);
|
|
/*
|
|
* If we found this table on the global list,
|
|
* return the same handle (Win95 compat)
|
|
*/
|
|
if (handle != NULL) {
|
|
goto UnlockAndFree;
|
|
}
|
|
|
|
while (!((paccel[nAccel].accel.fVirt) & FLASTKEY)) {
|
|
|
|
if (paccel[nAccel].accel.fVirt & ~FACCEL_VALID) {
|
|
RIPMSG0(RIP_WARNING, "LoadAcc: Invalid Parameter");
|
|
goto UnlockAndFree;
|
|
}
|
|
|
|
nAccel++;
|
|
}
|
|
|
|
if (paccel[nAccel].accel.fVirt & ~FACCEL_VALID) {
|
|
RIPMSG0(RIP_WARNING, "LoadAcc: Invalid Parameter");
|
|
goto UnlockAndFree;
|
|
}
|
|
|
|
/*
|
|
* Since the accelerator table is coming from a resource, each
|
|
* element has an extra WORD of padding which we strip here
|
|
* to conform with the public (and internal) ACCEL structure.
|
|
*/
|
|
paccelT = UserLocalAlloc(0, sizeof(ACCEL) * (nAccel + 1));
|
|
if (paccelT == NULL) {
|
|
goto UnlockAndFree;
|
|
}
|
|
for (i = 0; i < nAccel + 1; i++) {
|
|
paccelT[i] = paccel[i].accel;
|
|
}
|
|
|
|
handle = NtUserCreateAcceleratorTable(paccelT,
|
|
nAccel + 1);
|
|
|
|
UserLocalFree(paccelT);
|
|
|
|
/*
|
|
* Add this handle/address to the global table so
|
|
* we won't load it twice.
|
|
*/
|
|
if (handle != NULL) {
|
|
AddAccResource(handle, paccel);
|
|
}
|
|
UnlockAndFree:
|
|
|
|
UNLOCKRESOURCE(hrl, hmod);
|
|
}
|
|
|
|
FREERESOURCE(hrl, hmod);
|
|
}
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadAcceleratorsA (API)
|
|
* LoadAcceleratorsW (API)
|
|
*
|
|
*
|
|
* 24-Sep-1990 MikeKe From Win30
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HACCEL, WINAPI, LoadAcceleratorsA, HINSTANCE, hmod, LPCSTR, lpAccName)
|
|
HACCEL WINAPI LoadAcceleratorsA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpAccName)
|
|
{
|
|
HANDLE hRes;
|
|
|
|
hRes = FINDRESOURCEA((HANDLE)hmod, lpAccName, (LPSTR)RT_ACCELERATOR);
|
|
|
|
return (HACCEL)LoadAcc(hmod, hRes);
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HACCEL, WINAPI, LoadAcceleratorsW, HINSTANCE, hmod, LPCWSTR, lpAccName)
|
|
HACCEL WINAPI LoadAcceleratorsW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpAccName)
|
|
{
|
|
HANDLE hRes;
|
|
|
|
hRes = FINDRESOURCEW((HANDLE)hmod, lpAccName, RT_ACCELERATOR);
|
|
|
|
return (HACCEL)LoadAcc(hmod, hRes);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadStringA (API)
|
|
* LoadStringW (API)
|
|
*
|
|
*
|
|
* 05-Apr-1991 ScottLu Fixed to work with client/server.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, int, WINAPI, LoadStringA, HINSTANCE, hmod, UINT, wID, LPSTR, lpAnsiBuffer, int, cchBufferMax)
|
|
int WINAPI LoadStringA(
|
|
HINSTANCE hmod,
|
|
UINT wID,
|
|
LPSTR lpAnsiBuffer,
|
|
int cchBufferMax)
|
|
{
|
|
LPWSTR lpUniBuffer;
|
|
INT cchUnicode;
|
|
INT cbAnsi = 0;
|
|
|
|
/*
|
|
* LoadStringOrError appends a NULL but does not include it in the
|
|
* return count-of-bytes
|
|
*/
|
|
cchUnicode = LoadStringOrError((HANDLE)hmod,
|
|
wID,
|
|
(LPWSTR)&lpUniBuffer,
|
|
0,
|
|
0);
|
|
|
|
if (cchUnicode) {
|
|
|
|
cbAnsi = WCSToMB(lpUniBuffer,
|
|
cchUnicode,
|
|
&lpAnsiBuffer,
|
|
cchBufferMax - 1,
|
|
FALSE);
|
|
|
|
cbAnsi = min(cbAnsi, cchBufferMax - 1);
|
|
}
|
|
|
|
/*
|
|
* Append a NULL but do not include it in the count returned
|
|
*/
|
|
lpAnsiBuffer[cbAnsi] = 0;
|
|
return cbAnsi;
|
|
}
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, int, WINAPI, LoadStringW, HINSTANCE, hmod, UINT, wID, LPWSTR, lpBuffer, int, cchBufferMax)
|
|
int WINAPI LoadStringW(
|
|
HINSTANCE hmod,
|
|
UINT wID,
|
|
LPWSTR lpBuffer,
|
|
int cchBufferMax)
|
|
{
|
|
return LoadStringOrError((HANDLE)hmod,
|
|
wID,
|
|
lpBuffer,
|
|
cchBufferMax,
|
|
0);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SkipIDorString
|
|
*
|
|
* Skips string (or ID) and returns the next aligned WORD.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
PBYTE SkipIDorString(
|
|
LPBYTE pb)
|
|
{
|
|
if (*((LPWORD)pb) == 0xFFFF)
|
|
return (pb + 4);
|
|
|
|
while (*((PWCHAR)pb)++ != 0);
|
|
|
|
return pb;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetSizeDialogTemplate
|
|
*
|
|
* This gets called by thank produced stubs. It returns the size of a
|
|
* dialog template.
|
|
*
|
|
* 07-Apr-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
DWORD GetSizeDialogTemplate(
|
|
HINSTANCE hmod,
|
|
LPCDLGTEMPLATE pdt)
|
|
{
|
|
UINT cdit;
|
|
LPBYTE pb;
|
|
BOOL fChicago;
|
|
LPDLGTEMPLATE2 pdt2;
|
|
|
|
if (HIWORD(pdt->style) == 0xFFFF) {
|
|
|
|
pdt2 = (LPDLGTEMPLATE2)pdt;
|
|
fChicago = TRUE;
|
|
|
|
/*
|
|
* Fail if the app is passing invalid style bits.
|
|
*/
|
|
if (pdt2->style & ~(DS_VALID40 | 0xffff0000)) {
|
|
RIPMSG0(RIP_WARNING, "Bad dialog style bits - please remove");
|
|
return 0;
|
|
}
|
|
|
|
pb = (LPBYTE)(((LPDLGTEMPLATE2)pdt) + 1);
|
|
|
|
} else {
|
|
|
|
fChicago = FALSE;
|
|
|
|
/*
|
|
* Check if invalid style bits are being passed. Fail if the app
|
|
* is a new app ( >= VER40).
|
|
* This is to ensure that we are compatible with Chicago.
|
|
*/
|
|
if ((pdt->style & ~(DS_VALID40 | 0xffff0000)) &&
|
|
(GETEXPWINVER(hmod) >= VER40)) {
|
|
|
|
/*
|
|
* It's a new app with invalid style bits - fail.
|
|
*/
|
|
RIPMSG0(RIP_WARNING, "Bad dialog style bits - please remove");
|
|
return 0;
|
|
}
|
|
|
|
pb = (LPBYTE)(pdt + 1);
|
|
}
|
|
|
|
/*
|
|
* If there is a menu ordinal, add 4 bytes skip it. Otherwise it is a
|
|
* string or just a 0.
|
|
*/
|
|
pb = SkipIDorString(pb);
|
|
|
|
/*
|
|
* Skip window class and window text, adjust to next word boundary.
|
|
*/
|
|
pb = SkipIDorString(pb);
|
|
pb = SkipIDorString(pb);
|
|
|
|
/*
|
|
* Skip font type, size and name, adjust to next dword boundary.
|
|
*/
|
|
if ((fChicago ? pdt2->style : pdt->style) & DS_SETFONT) {
|
|
pb += fChicago ? sizeof(DWORD) + sizeof(WORD): sizeof(WORD);
|
|
pb = SkipIDorString(pb);
|
|
}
|
|
pb = (LPBYTE)(((ULONG_PTR)pb + 3) & ~3);
|
|
|
|
/*
|
|
* Loop through dialog items now...
|
|
*/
|
|
cdit = fChicago ? pdt2->cDlgItems : pdt->cdit;
|
|
|
|
while (cdit-- != 0) {
|
|
|
|
UINT cbCreateParams;
|
|
|
|
pb += fChicago ? sizeof(DLGITEMTEMPLATE2) : sizeof(DLGITEMTEMPLATE);
|
|
|
|
/*
|
|
* Skip the dialog control class name.
|
|
*/
|
|
pb = SkipIDorString(pb);
|
|
|
|
/*
|
|
* Look at window text now.
|
|
*/
|
|
pb = SkipIDorString(pb);
|
|
|
|
cbCreateParams = *((LPWORD)pb);
|
|
|
|
/*
|
|
* skip any CreateParams which include the generated size WORD.
|
|
*/
|
|
if (cbCreateParams)
|
|
pb += cbCreateParams;
|
|
|
|
pb += sizeof(WORD);
|
|
|
|
/*
|
|
* Point at the next dialog item. (DWORD aligned)
|
|
*/
|
|
pb = (LPBYTE)(((ULONG_PTR)pb + 3) & ~3);
|
|
}
|
|
|
|
/*
|
|
* Return template size.
|
|
*/
|
|
return (DWORD)(pb - (LPBYTE)pdt);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DialogBoxIndirectParamA (API)
|
|
* DialogBoxIndirectParamW (API)
|
|
*
|
|
* Creates the dialog and goes into a modal loop processing input for it.
|
|
*
|
|
* 05-Apr-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, INT_PTR, WINAPI, DialogBoxIndirectParamA, HINSTANCE, hmod, LPCDLGTEMPLATEA, lpDlgTemplate, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
INT_PTR WINAPI DialogBoxIndirectParamA(
|
|
HINSTANCE hmod,
|
|
LPCDLGTEMPLATEA lpDlgTemplate,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
return DialogBoxIndirectParamAorW(hmod,
|
|
(LPCDLGTEMPLATEW)lpDlgTemplate,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
SCDLG_ANSI);
|
|
}
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, INT_PTR, WINAPI, DialogBoxIndirectParamW, HINSTANCE, hmod, LPCDLGTEMPLATEW, lpDlgTemplate, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
INT_PTR WINAPI DialogBoxIndirectParamW(
|
|
HINSTANCE hmod,
|
|
LPCDLGTEMPLATEW lpDlgTemplate,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
return DialogBoxIndirectParamAorW(hmod,
|
|
lpDlgTemplate,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
0);
|
|
}
|
|
|
|
|
|
FUNCLOG6(LOG_GENERAL, INT_PTR, WINAPI, DialogBoxIndirectParamAorW, HINSTANCE, hmod, LPCDLGTEMPLATEW, lpDlgTemplate, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam, UINT, fAnsiFlags)
|
|
INT_PTR WINAPI DialogBoxIndirectParamAorW(
|
|
HINSTANCE hmod,
|
|
LPCDLGTEMPLATEW lpDlgTemplate,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam,
|
|
UINT fAnsiFlags)
|
|
{
|
|
DWORD cb;
|
|
|
|
/*
|
|
* The server routine destroys the menu if it fails.
|
|
*/
|
|
cb = GetSizeDialogTemplate(hmod, lpDlgTemplate);
|
|
|
|
if (!cb) {
|
|
RIPMSG0(RIP_WARNING, "DialogBoxIndirectParam: Invalid Paramter");
|
|
return -1;
|
|
}
|
|
|
|
return InternalDialogBox(hmod,
|
|
(LPDLGTEMPLATE)lpDlgTemplate,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
SCDLG_CLIENT | (fAnsiFlags & (SCDLG_ANSI | SCDLG_16BIT)));
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateDialogIndirectParamA (API)
|
|
* CreateDialogIndirectParamW (API)
|
|
*
|
|
* Creates a dialog given a template and return s the window handle.
|
|
* fAnsi determines if the dialog has an ANSI or UNICODE lpDialogFunc
|
|
*
|
|
* 05-Apr-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, HWND, WINAPI, CreateDialogIndirectParamA, HINSTANCE, hmod, LPCDLGTEMPLATEA, lpDlgTemplate, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
HWND WINAPI CreateDialogIndirectParamA(
|
|
HINSTANCE hmod,
|
|
LPCDLGTEMPLATEA lpDlgTemplate,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
return CreateDialogIndirectParamAorW(hmod,
|
|
(LPCDLGTEMPLATE)lpDlgTemplate,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
SCDLG_ANSI);
|
|
}
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, HWND, WINAPI, CreateDialogIndirectParamW, HINSTANCE, hmod, LPCDLGTEMPLATEW, lpDlgTemplate, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
HWND WINAPI CreateDialogIndirectParamW(
|
|
HINSTANCE hmod,
|
|
LPCDLGTEMPLATEW lpDlgTemplate,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
return CreateDialogIndirectParamAorW(hmod,
|
|
(LPCDLGTEMPLATE)lpDlgTemplate,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
0);
|
|
}
|
|
|
|
|
|
FUNCLOG6(LOG_GENERAL, HWND, WINAPI, CreateDialogIndirectParamAorW, HANDLE, hmod, LPCDLGTEMPLATE, lpDlgTemplate, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam, UINT, fAnsi)
|
|
HWND WINAPI CreateDialogIndirectParamAorW(
|
|
HANDLE hmod,
|
|
LPCDLGTEMPLATE lpDlgTemplate,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam,
|
|
UINT fAnsi)
|
|
{
|
|
DWORD cb;
|
|
HWND hwndRet;
|
|
|
|
/*
|
|
* The server routine destroys the menu if it fails.
|
|
*/
|
|
cb = GetSizeDialogTemplate(hmod, lpDlgTemplate);
|
|
|
|
if (!cb) {
|
|
RIPMSG0(RIP_WARNING, "CreateDialogIndirect: Invalid Parameter");
|
|
return NULL;
|
|
}
|
|
|
|
hwndRet = InternalCreateDialog(hmod,
|
|
(LPDLGTEMPLATE)lpDlgTemplate,
|
|
cb,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
SCDLG_CLIENT | (fAnsi & (SCDLG_ANSI|SCDLG_16BIT)));
|
|
|
|
return hwndRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DialogBoxParamA (API)
|
|
* DialogBoxParamW (API)
|
|
*
|
|
* Loads the resource, creates the dialog and goes into a modal loop processing
|
|
* input for it.
|
|
*
|
|
* 05-Apr-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, INT_PTR, WINAPI, DialogBoxParamA, HINSTANCE, hmod, LPCSTR, lpName, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
INT_PTR WINAPI DialogBoxParamA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
HANDLE h;
|
|
PVOID p;
|
|
INT_PTR i = -1;
|
|
|
|
if (h = FINDRESOURCEA(hmod, (LPSTR)lpName, (LPSTR)RT_DIALOG)) {
|
|
|
|
if (h = LOADRESOURCE(hmod, h)) {
|
|
|
|
if (p = LOCKRESOURCE(h, hmod)) {
|
|
|
|
i = DialogBoxIndirectParamAorW(hmod,
|
|
p,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
SCDLG_ANSI);
|
|
|
|
UNLOCKRESOURCE(h, hmod);
|
|
}
|
|
|
|
FREERESOURCE(h, hmod);
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, INT_PTR, WINAPI, DialogBoxParamW, HINSTANCE, hmod, LPCWSTR, lpName, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
INT_PTR WINAPI DialogBoxParamW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
HANDLE h;
|
|
PVOID p;
|
|
INT_PTR i = -1;
|
|
|
|
if (h = FINDRESOURCEW(hmod, lpName, RT_DIALOG)) {
|
|
|
|
if (p = LoadResource(hmod, h)) {
|
|
|
|
i = DialogBoxIndirectParamAorW(hmod,
|
|
p,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
0);
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateDialogParamA (API)
|
|
* CreateDialogParamW (API)
|
|
*
|
|
* Loads the resource, creates a dialog from that template, return s the
|
|
* window handle.
|
|
*
|
|
* 05-Apr-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, HWND, WINAPI, CreateDialogParamA, HINSTANCE, hmod, LPCSTR, lpName, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
HWND WINAPI CreateDialogParamA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
HANDLE h;
|
|
LPDLGTEMPLATEA p;
|
|
HWND hwnd = NULL;
|
|
|
|
if (h = FINDRESOURCEA(hmod, lpName, (LPSTR)RT_DIALOG)) {
|
|
|
|
if (h = LOADRESOURCE(hmod, h)) {
|
|
|
|
if (p = (LPDLGTEMPLATEA)LOCKRESOURCE(h, hmod)) {
|
|
|
|
hwnd = CreateDialogIndirectParamAorW(hmod,
|
|
(LPCDLGTEMPLATE)p,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
SCDLG_ANSI);
|
|
|
|
UNLOCKRESOURCE(h, hmod);
|
|
}
|
|
|
|
FREERESOURCE(h, hmod);
|
|
}
|
|
}
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, HWND, WINAPI, CreateDialogParamW, HINSTANCE, hmod, LPCWSTR, lpName, HWND, hwndOwner, DLGPROC, lpDialogFunc, LPARAM, dwInitParam)
|
|
HWND WINAPI CreateDialogParamW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
HWND hwndOwner,
|
|
DLGPROC lpDialogFunc,
|
|
LPARAM dwInitParam)
|
|
{
|
|
HANDLE h;
|
|
PVOID p;
|
|
HWND hwnd = NULL;
|
|
|
|
if (h = FINDRESOURCEW(hmod, lpName, RT_DIALOG)) {
|
|
|
|
if (h = LOADRESOURCE(hmod, h)) {
|
|
|
|
if (p = LOCKRESOURCE(h, hmod)) {
|
|
|
|
hwnd = CreateDialogIndirectParamAorW(hmod,
|
|
p,
|
|
hwndOwner,
|
|
lpDialogFunc,
|
|
dwInitParam,
|
|
0);
|
|
|
|
UNLOCKRESOURCE(h, hmod);
|
|
}
|
|
|
|
FREERESOURCE(h, hmod);
|
|
}
|
|
}
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DestroyCursor (API)
|
|
*
|
|
* Client wrapper for NtUserDestroyCursor.
|
|
*
|
|
* 28-Nov-1994 JimA Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG1(LOG_GENERAL, BOOL, WINAPI, DestroyCursor, HCURSOR, hcur)
|
|
BOOL WINAPI DestroyCursor(
|
|
HCURSOR hcur)
|
|
{
|
|
return NtUserDestroyCursor(hcur, CURSOR_CALLFROMCLIENT);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateIcoCur
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HICON CreateIcoCur(
|
|
PCURSORDATA lpi)
|
|
{
|
|
HCURSOR hcur;
|
|
|
|
UserAssert(lpi->hbmColor || lpi->hbmMask);
|
|
|
|
hcur = (HCURSOR)NtUserCallOneParam((lpi->CURSORF_flags & CURSORF_GLOBAL),
|
|
SFI__CREATEEMPTYCURSOROBJECT);
|
|
|
|
if (hcur == NULL)
|
|
return NULL;
|
|
|
|
#if DBG
|
|
{
|
|
BITMAP bmMask;
|
|
BITMAP bmColor;
|
|
|
|
UserAssert(GetObject(KHBITMAP_TO_HBITMAP(lpi->hbmMask), sizeof(BITMAP), &bmMask));
|
|
|
|
/* Bug 252902 - joejo
|
|
* Since the width and height of the mask bitmap is set below
|
|
* we really don't need to assert on the width/height check. Throwing
|
|
* a warning should be good enough.
|
|
*/
|
|
if (bmMask.bmWidth != (LONG)lpi->cx) {
|
|
RIPMSG1(RIP_WARNING, "Mask width not equal to requested width: lpi %#p", lpi);
|
|
}
|
|
|
|
if (bmMask.bmHeight != (LONG)lpi->cy) {
|
|
RIPMSG1(RIP_WARNING, "Mask height not equal to requested height: lpi %#p", lpi);
|
|
}
|
|
|
|
if (lpi->hbmColor) {
|
|
UserAssert(GetObject(KHBITMAP_TO_HBITMAP(lpi->hbmColor), sizeof(BITMAP), &bmColor));
|
|
UserAssert(bmMask.bmHeight == bmColor.bmHeight * 2);
|
|
UserAssert(bmMask.bmWidth == bmColor.bmWidth);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (_SetCursorIconData(hcur, lpi))
|
|
return hcur;
|
|
|
|
NtUserDestroyCursor(hcur, CURSOR_ALWAYSDESTROY);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateIcoCurIndirect
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
HCURSOR CreateIcoCurIndirect(
|
|
PCURSORDATA pcurCreate,
|
|
UINT cPlanes,
|
|
UINT cBitsPixel,
|
|
CONST BYTE *lpANDbits,
|
|
CONST BYTE *lpXORbits)
|
|
{
|
|
int cbBits;
|
|
HCURSOR hcurNew;
|
|
BOOL bColor;
|
|
UINT cx;
|
|
UINT cy;
|
|
LPBYTE pBits = NULL;
|
|
|
|
/*
|
|
* Allocate CURSOR structure.
|
|
*/
|
|
hcurNew = (HCURSOR)NtUserCallOneParam(0, SFI__CREATEEMPTYCURSOROBJECT);
|
|
if (hcurNew == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* If there is no Color bitmap, create a single buffer that contains both
|
|
* the AND and XOR bits. The AND bitmap is always MonoChrome
|
|
*/
|
|
bColor = (cPlanes | cBitsPixel) > 1;
|
|
|
|
if (!bColor) {
|
|
cbBits = (((pcurCreate->cx + 0x0F) & ~0x0F) >> 3) * pcurCreate->cy;
|
|
|
|
pBits = (LPBYTE)UserLocalAlloc(HEAP_ZERO_MEMORY, cbBits * 2);
|
|
if (pBits == NULL) {
|
|
NtUserDestroyCursor(hcurNew, CURSOR_ALWAYSDESTROY);
|
|
return NULL;
|
|
}
|
|
|
|
RtlCopyMemory(pBits, lpANDbits, cbBits);
|
|
RtlCopyMemory(pBits + cbBits, lpXORbits, cbBits);
|
|
lpANDbits = pBits;
|
|
}
|
|
|
|
/*
|
|
* Create hbmMask (it's always MonoChrome).
|
|
*/
|
|
cx = pcurCreate->cx;
|
|
cy = pcurCreate->cy * 2;
|
|
|
|
pcurCreate->hbmMask = CreateBitmap(cx, cy, 1, 1, lpANDbits);
|
|
|
|
if (pcurCreate->hbmMask == NULL) {
|
|
|
|
/*
|
|
* If this is a COLOR icon/cursor, lpANDBits doesn't need to be
|
|
* pcurCreate->cy * 2; indeed, we don't use this double height at all.
|
|
* This is a bug that will be fixed post 4.0.
|
|
* For now, let's try to handle the case where the CreateBitmap call
|
|
* failed because the caller didn't pass in a double height AND mask
|
|
* (Win95 doesn't have this bug)
|
|
*/
|
|
if (bColor) {
|
|
RIPMSG0(RIP_WARNING,
|
|
"CreateIcoCurIndirect: Retrying hbmMask creation.");
|
|
|
|
cbBits = (((pcurCreate->cx + 0x0F) & ~0x0F) >> 3) * pcurCreate->cy;
|
|
pBits = (LPBYTE)UserLocalAlloc(HEAP_ZERO_MEMORY, cbBits*2);
|
|
if (pBits == NULL) {
|
|
NtUserDestroyCursor(hcurNew, CURSOR_ALWAYSDESTROY);
|
|
return NULL;
|
|
}
|
|
|
|
RtlCopyMemory(pBits, lpANDbits, cbBits);
|
|
pcurCreate->hbmMask = CreateBitmap(cx, cy, 1, 1, pBits);
|
|
UserLocalFree(pBits);
|
|
|
|
pBits = NULL;
|
|
}
|
|
|
|
if (pcurCreate->hbmMask == NULL) {
|
|
|
|
/*
|
|
* CreateBitmap() failed. Clean-up and get out of here.
|
|
*/
|
|
NtUserDestroyCursor(hcurNew, CURSOR_ALWAYSDESTROY);
|
|
|
|
if (pBits != NULL) {
|
|
UserLocalFree(pBits);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Create hbmColor or NULL it so that CallOEMCursor doesn't think we are
|
|
* color.
|
|
*/
|
|
if (bColor) {
|
|
pcurCreate->hbmColor = CreateBitmap(cx,
|
|
cy / 2,
|
|
cPlanes,
|
|
cBitsPixel,
|
|
lpXORbits);
|
|
|
|
if (pcurCreate->hbmColor == NULL) {
|
|
|
|
/*
|
|
* CreateBitmap() failed. Clean-up and get out of here.
|
|
*/
|
|
DeleteObject(KHBITMAP_TO_HBITMAP(pcurCreate->hbmMask));
|
|
NtUserDestroyCursor(hcurNew, CURSOR_ALWAYSDESTROY);
|
|
return NULL;
|
|
}
|
|
|
|
pcurCreate->bpp = (cPlanes * cBitsPixel);
|
|
|
|
} else {
|
|
pcurCreate->hbmColor = NULL;
|
|
pcurCreate->bpp = 1;
|
|
}
|
|
|
|
/*
|
|
* Load contents into the cursor/icon object
|
|
*/
|
|
pcurCreate->cy = cy;
|
|
pcurCreate->lpModName = NULL;
|
|
pcurCreate->lpName = NULL;
|
|
pcurCreate->rt = 0;
|
|
pcurCreate->CURSORF_flags = 0;
|
|
|
|
if (_SetCursorIconData(hcurNew, pcurCreate)) {
|
|
if (pBits != NULL) {
|
|
UserLocalFree(pBits);
|
|
}
|
|
return hcurNew;
|
|
}
|
|
|
|
/*
|
|
* Could not set up cursor/icon, so free resources.
|
|
*/
|
|
NtUserDestroyCursor(hcurNew, CURSOR_ALWAYSDESTROY);
|
|
DeleteObject(KHBITMAP_TO_HBITMAP(pcurCreate->hbmMask));
|
|
|
|
if (pcurCreate->hbmColor) {
|
|
DeleteObject(KHBITMAP_TO_HBITMAP(pcurCreate->hbmColor));
|
|
}
|
|
|
|
if (pBits != NULL) {
|
|
UserLocalFree(pBits);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateCursor (API)
|
|
*
|
|
* History:
|
|
* 26-Feb-1991 MikeKe Created.
|
|
* 01-Aug-1991 IanJa Init cur.pszModname or DestroyCursor will work
|
|
\***************************************************************************/
|
|
HCURSOR WINAPI CreateCursor(
|
|
HINSTANCE hModule,
|
|
int iXhotspot,
|
|
int iYhotspot,
|
|
int iWidth,
|
|
int iHeight,
|
|
LPBYTE lpANDplane,
|
|
LPBYTE lpXORplane)
|
|
{
|
|
CURSORDATA cur;
|
|
UNREFERENCED_PARAMETER(hModule);
|
|
|
|
if ((iXhotspot < 0) || (iXhotspot > iWidth) ||
|
|
(iYhotspot < 0) || (iYhotspot > iHeight)) {
|
|
return 0;
|
|
}
|
|
|
|
RtlZeroMemory(&cur, sizeof(cur));
|
|
cur.xHotspot = (SHORT)iXhotspot;
|
|
cur.yHotspot = (SHORT)iYhotspot;
|
|
cur.cx = (DWORD)iWidth;
|
|
cur.cy = (DWORD)iHeight;
|
|
|
|
return CreateIcoCurIndirect(&cur, 1, 1, lpANDplane, lpXORplane);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateIcon (API)
|
|
*
|
|
* History:
|
|
* 26-Feb-1991 MikeKe Created.
|
|
* 01-Aug-1991 IanJa Init cur.pszModname so DestroyIcon will work
|
|
\***************************************************************************/
|
|
HICON WINAPI CreateIcon(
|
|
HINSTANCE hModule,
|
|
int iWidth,
|
|
int iHeight,
|
|
BYTE planes,
|
|
BYTE bpp,
|
|
CONST BYTE *lpANDplane,
|
|
CONST BYTE *lpXORplane)
|
|
{
|
|
CURSORDATA cur;
|
|
UNREFERENCED_PARAMETER(hModule);
|
|
|
|
RtlZeroMemory(&cur, sizeof(cur));
|
|
cur.xHotspot = (SHORT)(iWidth / 2);
|
|
cur.yHotspot = (SHORT)(iHeight / 2);
|
|
cur.cx = (DWORD)iWidth;
|
|
cur.cy = (DWORD)iHeight;
|
|
|
|
return CreateIcoCurIndirect(&cur, planes, bpp, lpANDplane, lpXORplane);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateIconIndirect (API)
|
|
*
|
|
* Creates an icon or cursor from an ICONINFO structure. Does not destroy
|
|
* cursor/icon bitmaps.
|
|
*
|
|
* 24-Jul-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
FUNCLOG1(LOG_GENERAL, HICON, WINAPI, CreateIconIndirect, PICONINFO, piconinfo)
|
|
HICON WINAPI CreateIconIndirect(
|
|
PICONINFO piconinfo)
|
|
{
|
|
HCURSOR hcur;
|
|
CURSORDATA cur;
|
|
BITMAP bmMask;
|
|
BITMAP bmColor;
|
|
HBITMAP hbmpBits2, hbmpMem;
|
|
HDC hdcMem;
|
|
UINT LR_flags = LR_DEFAULTCOLOR;
|
|
|
|
/*
|
|
* Make sure the bitmaps are real, and get their dimensions.
|
|
*/
|
|
if (!GetObjectW(piconinfo->hbmMask, sizeof(BITMAP), &bmMask))
|
|
return NULL;
|
|
|
|
if (piconinfo->hbmColor != NULL) {
|
|
if (GetObjectW(piconinfo->hbmColor, sizeof(BITMAP), &bmColor)) {
|
|
if (bmColor.bmPlanes == 1 && bmColor.bmBitsPixel == 32) {
|
|
/*
|
|
* The color bitmap is a single plane, 32bpp image. As such,
|
|
* it might contain an alpha channel, so we have to preserve
|
|
* it as a DIB.
|
|
*/
|
|
LR_flags |= LR_CREATEREALDIB;
|
|
}
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Allocate CURSOR structure.
|
|
*/
|
|
hcur = (HCURSOR)NtUserCallOneParam(0, SFI__CREATEEMPTYCURSOROBJECT);
|
|
if (hcur == NULL)
|
|
return NULL;
|
|
|
|
/*
|
|
* Internally, USER stores the height as 2 icons high - because when
|
|
* loading bits from a resource, in both b/w and color icons, the
|
|
* bits are stored on top of one another (AND/XOR mask, AND/COLOR bitmap).
|
|
* When bitmaps are passed in to CreateIconIndirect(), they are passed
|
|
* as two bitmaps in the color case, and one bitmap (with the stacked
|
|
* masks) in the black and white case. Adjust cur.cy so it is 2 icons
|
|
* high in both cases.
|
|
*/
|
|
|
|
RtlZeroMemory(&cur, sizeof(cur));
|
|
cur.cx = bmMask.bmWidth;
|
|
|
|
if (piconinfo->hbmColor == NULL) {
|
|
|
|
cur.cy = bmMask.bmHeight;
|
|
cur.bpp = 1;
|
|
|
|
} else {
|
|
cur.cy = bmMask.bmHeight * 2;
|
|
cur.bpp = (DWORD)(bmColor.bmBitsPixel * bmColor.bmPlanes);
|
|
cur.hbmColor = CopyBmp(piconinfo->hbmColor, 0, 0, LR_flags);
|
|
|
|
if (cur.hbmColor == NULL) {
|
|
RIPMSG0(RIP_WARNING, "CreateIconIndirect: Failed to copy piconinfo->hbmColor");
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* hbmMask must always be double height, even for color icons.
|
|
* So cy might be equal to bmMask.bmHeight * 2 at this point.
|
|
* If this is the case, the second half of hbmMask won't be initilized;
|
|
* nobody is supposed to use it but GDI expects it there when checking the
|
|
* bitmap dimensions (for cursors)
|
|
*/
|
|
cur.hbmMask = CreateBitmap(cur.cx, cur.cy, 1, 1, NULL);
|
|
|
|
if (cur.hbmMask == NULL) {
|
|
RIPMSG0(RIP_WARNING, "CreateIconIndirect: Failed to create cur.hbmMask");
|
|
goto CleanUp;
|
|
}
|
|
|
|
RtlEnterCriticalSection(&gcsHdc);
|
|
|
|
|
|
if (hdcMem = CreateCompatibleDC (ghdcBits2)) {
|
|
|
|
hbmpMem = SelectObject(hdcMem, KHBITMAP_TO_HBITMAP(cur.hbmMask));
|
|
hbmpBits2 = SelectObject(ghdcBits2, piconinfo->hbmMask);
|
|
|
|
BitBlt(hdcMem,
|
|
0,
|
|
0,
|
|
bmMask.bmWidth,
|
|
bmMask.bmHeight,
|
|
ghdcBits2,
|
|
0,
|
|
0,
|
|
SRCCOPY);
|
|
|
|
SelectObject(hdcMem, hbmpMem);
|
|
SelectObject(ghdcBits2, hbmpBits2);
|
|
DeleteDC (hdcMem);
|
|
|
|
} else {
|
|
|
|
RtlLeaveCriticalSection(&gcsHdc);
|
|
RIPMSG0(RIP_WARNING, "CreateIconIndirect: CreateCompatibleDC failed");
|
|
goto CleanUp;
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&gcsHdc);
|
|
|
|
/*
|
|
* rt and Hotspot
|
|
*/
|
|
if (piconinfo->fIcon) {
|
|
cur.rt = PTR_TO_ID(RT_ICON);
|
|
cur.xHotspot = (SHORT)(cur.cx / 2);
|
|
cur.yHotspot = (SHORT)(cur.cy / 4);
|
|
} else {
|
|
cur.rt = PTR_TO_ID(RT_CURSOR);
|
|
cur.xHotspot = ((SHORT)piconinfo->xHotspot);
|
|
cur.yHotspot = ((SHORT)piconinfo->yHotspot);
|
|
}
|
|
|
|
|
|
if (_SetCursorIconData(hcur, &cur)) {
|
|
return hcur;
|
|
}
|
|
|
|
CleanUp:
|
|
/*
|
|
* Note that if this fails, the bitmaps have NOT been made public.
|
|
*/
|
|
if (cur.hbmMask != NULL) {
|
|
DeleteObject(KHBITMAP_TO_HBITMAP(cur.hbmMask));
|
|
}
|
|
if (cur.hbmColor != NULL) {
|
|
DeleteObject(KHBITMAP_TO_HBITMAP(cur.hbmColor));
|
|
}
|
|
|
|
NtUserDestroyCursor(hcur, CURSOR_ALWAYSDESTROY);
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetIconInfo (API)
|
|
*
|
|
* Returns icon information, including bitmaps.
|
|
*
|
|
* 24-Jul-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, WINAPI, GetIconInfo, HICON, hicon, PICONINFO, piconinfo)
|
|
BOOL WINAPI GetIconInfo(
|
|
HICON hicon,
|
|
PICONINFO piconinfo)
|
|
{
|
|
return NtUserGetIconInfo(hicon, piconinfo, NULL, NULL, NULL, FALSE);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetCursorFrameInfo (API)
|
|
*
|
|
* Returns cursor information.
|
|
*
|
|
* 24-Jul-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, HCURSOR, WINAPI, GetCursorFrameInfo, HCURSOR, hcur, LPWSTR, lpName, int, iFrame, LPDWORD, pjifRate, LPINT, pccur)
|
|
HCURSOR WINAPI GetCursorFrameInfo(
|
|
HCURSOR hcur,
|
|
LPWSTR lpName,
|
|
int iFrame,
|
|
LPDWORD pjifRate,
|
|
LPINT pccur)
|
|
{
|
|
/*
|
|
* Caller wants us to return the version of this cursor that is stored
|
|
* in the display driver.
|
|
*/
|
|
if (hcur == NULL) {
|
|
|
|
return LoadIcoCur(NULL,
|
|
lpName,
|
|
RT_CURSOR,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE);
|
|
}
|
|
|
|
return NtUserGetCursorFrameInfo(hcur, iFrame, pjifRate, pccur);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* _FreeResource (API)
|
|
* _LockResource (API)
|
|
* _UnlockResource (API)
|
|
*
|
|
* These are dummy routines that need to exist for the apfnResCallNative
|
|
* array, which is used when calling the run-time libraries.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI _FreeResource(
|
|
HANDLE hResData,
|
|
HINSTANCE hModule)
|
|
{
|
|
UNREFERENCED_PARAMETER(hResData);
|
|
UNREFERENCED_PARAMETER(hModule);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LPSTR WINAPI _LockResource(
|
|
HANDLE hResData,
|
|
HINSTANCE hModule)
|
|
{
|
|
UNREFERENCED_PARAMETER(hModule);
|
|
|
|
return (LPSTR)(hResData);
|
|
}
|
|
|
|
BOOL WINAPI _UnlockResource(
|
|
HANDLE hResData,
|
|
HINSTANCE hModule)
|
|
{
|
|
UNREFERENCED_PARAMETER(hResData);
|
|
UNREFERENCED_PARAMETER(hModule);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LookupIconIdFromDirectory (API)
|
|
*
|
|
* This searches through an icon directory for the icon that best fits the
|
|
* current display device.
|
|
*
|
|
* 24-07-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, int, WINAPI, LookupIconIdFromDirectory, PBYTE, presbits, BOOL, fIcon)
|
|
int WINAPI LookupIconIdFromDirectory(
|
|
PBYTE presbits,
|
|
BOOL fIcon)
|
|
{
|
|
return LookupIconIdFromDirectoryEx(presbits, fIcon, 0, 0, 0);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LookupIconIdFromDirectoryEx (API)
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, int, WINAPI, LookupIconIdFromDirectoryEx, PBYTE, presbits, BOOL, fIcon, int, cxDesired, int, cyDesired, UINT, LR_flags)
|
|
int WINAPI LookupIconIdFromDirectoryEx(
|
|
PBYTE presbits,
|
|
BOOL fIcon,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
ConnectIfNecessary(0);
|
|
|
|
return RtlGetIdFromDirectory(presbits,
|
|
fIcon,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags,
|
|
NULL);
|
|
}
|
|
/***************************************************************************\
|
|
* LoadCursorIconFromResource (API)
|
|
*
|
|
* Loads animated icon/cursor from a pointer to a resource
|
|
*
|
|
* 02-20-1996 GerardoB Created.
|
|
\***************************************************************************/
|
|
HANDLE LoadCursorIconFromResource(
|
|
PBYTE presbits,
|
|
LPCWSTR lpName,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
BOOL fAni;
|
|
FILEINFO fi;
|
|
LPWSTR lpwszRT;
|
|
|
|
fi.pFileMap = presbits;
|
|
fi.pFilePtr = fi.pFileMap;
|
|
fi.pFileEnd = fi.pFileMap + sizeof (RTAG) + ((RTAG *)presbits)->ckSize;
|
|
fi.pszName = lpName;
|
|
|
|
return LoadCursorIconFromFileMap(&fi,
|
|
&lpwszRT,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags,
|
|
&fAni);
|
|
}
|
|
/***************************************************************************\
|
|
* CreateIconFromResource (API)
|
|
*
|
|
* Takes resource bits and creates either an icon or cursor.
|
|
*
|
|
* 24-07-1991 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG4(LOG_GENERAL, HICON, WINAPI, CreateIconFromResource, PBYTE, presbits, DWORD, dwResSize, BOOL, fIcon, DWORD, dwVer)
|
|
HICON WINAPI CreateIconFromResource(
|
|
PBYTE presbits,
|
|
DWORD dwResSize,
|
|
BOOL fIcon,
|
|
DWORD dwVer)
|
|
{
|
|
return CreateIconFromResourceEx(presbits,
|
|
dwResSize,
|
|
fIcon,
|
|
dwVer,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE | LR_SHARED);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateIconFromResourceEx (API)
|
|
*
|
|
* Takes resource bits and creates either an icon or cursor.
|
|
*
|
|
* 30-Aug-1994 FritzS Created
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG7(LOG_GENERAL, HICON, WINAPI, CreateIconFromResourceEx, PBYTE, presbits, DWORD, dwResSize, BOOL, fIcon, DWORD, dwVer, int, cxDesired, int, cyDesired, UINT, LR_flags)
|
|
HICON WINAPI CreateIconFromResourceEx(
|
|
PBYTE presbits,
|
|
DWORD dwResSize,
|
|
BOOL fIcon,
|
|
DWORD dwVer,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
UNREFERENCED_PARAMETER(dwResSize);
|
|
|
|
/*
|
|
* NT Specific code to validate the version.
|
|
*/
|
|
if ((dwVer < 0x00020000) || (dwVer > 0x00030000)) {
|
|
RIPMSG0(RIP_WARNING, "CreateIconFromResourceEx: Invalid Paramter");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Set desired size of resource based on flags and/or true
|
|
* dimensions passed in.
|
|
*/
|
|
cxDesired = GetIcoCurWidth(cxDesired , fIcon, LR_flags, 0);
|
|
cyDesired = GetIcoCurHeight(cyDesired, fIcon, LR_flags, 0);
|
|
|
|
if (ISRIFFFORMAT(presbits)) {
|
|
return LoadCursorIconFromResource (presbits, NULL, cxDesired, cyDesired, LR_flags);
|
|
} else {
|
|
return ConvertDIBIcon((LPBITMAPINFOHEADER)presbits,
|
|
NULL,
|
|
NULL,
|
|
fIcon,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* Convert1BppToMonoBitmap
|
|
*
|
|
* This routine converts a 1bpp bitmap to a true monochrome surface. This
|
|
* is done for bitmaps which need to do foreground/background color matching
|
|
* at output time. Otherwise, a 1bpp will just match to its palette.
|
|
*
|
|
* NOTE: This routine deletes the original bitmap if successful. If failure
|
|
* we'll return the original bitmap.
|
|
*
|
|
* History:
|
|
* 17-Apr-1996 ChrisWil Created
|
|
\***************************************************************************/
|
|
|
|
HBITMAP Convert1BppToMonoBitmap(
|
|
HDC hdcSrc,
|
|
HBITMAP hbm1Bpp)
|
|
{
|
|
HBITMAP hbmMono = hbm1Bpp;
|
|
HBITMAP hbmDst;
|
|
HBITMAP hbmS;
|
|
HBITMAP hbmD;
|
|
HDC hdcDst;
|
|
BITMAP bm;
|
|
|
|
if (hdcDst = CreateCompatibleDC(hdcSrc)) {
|
|
|
|
GetObject(hbm1Bpp, sizeof(BITMAP), &bm);
|
|
|
|
if (hbmDst = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL)) {
|
|
|
|
hbmS = SelectBitmap(hdcSrc, hbm1Bpp);
|
|
hbmD = SelectBitmap(hdcDst, hbmDst);
|
|
|
|
BitBlt(hdcDst,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
hdcSrc,
|
|
0,
|
|
0,
|
|
SRCCOPY);
|
|
|
|
SelectBitmap(hdcSrc, hbmS);
|
|
SelectBitmap(hdcDst, hbmD);
|
|
|
|
hbmMono = hbmDst;
|
|
DeleteObject(hbm1Bpp);
|
|
}
|
|
|
|
DeleteDC(hdcDst);
|
|
}
|
|
|
|
return hbmMono;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateScreenBitmap
|
|
*
|
|
* This routine creates a screen bitmap. We use the CreateDIBitmap call
|
|
* to do compatible color-matching with Win95. Also, note that this
|
|
* routine takes in WORD aligned bits.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HBITMAP CreateScreenBitmap(
|
|
int cx,
|
|
int cy,
|
|
UINT planes,
|
|
UINT bpp,
|
|
LPSTR lpBits,
|
|
LPBOOL pf1Bpp)
|
|
{
|
|
HDC hdcScreen;
|
|
HBITMAP hbm = NULL;
|
|
DWORD dwCount;
|
|
|
|
static struct {
|
|
BITMAPINFOHEADER bi;
|
|
DWORD ct[16];
|
|
} dib4Vga = {{sizeof(BITMAPINFOHEADER),
|
|
0,
|
|
0,
|
|
1,
|
|
4,
|
|
BI_RGB,
|
|
0,
|
|
0,
|
|
0,
|
|
16,
|
|
0
|
|
},
|
|
{0x00000000,
|
|
0x00800000,
|
|
0x00008000,
|
|
0x00808000,
|
|
0x00000080,
|
|
0x00800080,
|
|
0x00008080,
|
|
0x00C0C0C0,
|
|
0x00808080,
|
|
0x00FF0000,
|
|
0x0000FF00,
|
|
0x00FFFF00,
|
|
0x000000FF,
|
|
0x00FF00FF,
|
|
0x0000FFFF,
|
|
0x00FFFFFF
|
|
}
|
|
};
|
|
|
|
static struct {
|
|
BITMAPINFOHEADER bi;
|
|
DWORD ct[2];
|
|
} dib1Vga = {{sizeof(BITMAPINFOHEADER),
|
|
0,
|
|
0,
|
|
1,
|
|
1,
|
|
BI_RGB,
|
|
0,
|
|
0,
|
|
0,
|
|
2,
|
|
0
|
|
},
|
|
{0x00000000,
|
|
0x00FFFFFF
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
* Create the surface.
|
|
*/
|
|
if (hdcScreen = GETINITDC()) {
|
|
|
|
/*
|
|
* This appears to mess up color to mono conversion by losing all
|
|
* the data and forcing all non-forground colors to black.
|
|
* (try copyimage with IDC_WARNING_DEFAULT)
|
|
* This is what win95 does but their system works. The scary thing
|
|
* (according to marke) is that win95 may have changed GDI to make
|
|
* this work.
|
|
*
|
|
* In order to get nearest-color-matching compatible with Win95,
|
|
* we're going to need to use the CreateDIBitmap() for mono-surfaces.
|
|
* This code-path will do nearest-color, rather than color-matching.
|
|
*/
|
|
if ((bpp == 1) && (planes == 1)) {
|
|
|
|
dib1Vga.bi.biWidth = cx;
|
|
dib1Vga.bi.biHeight = cy;
|
|
|
|
hbm = CreateDIBitmap(hdcScreen,
|
|
(LPBITMAPINFOHEADER)&dib1Vga,
|
|
CBM_CREATEDIB,
|
|
NULL,
|
|
(LPBITMAPINFO)&dib1Vga,
|
|
DIB_RGB_COLORS);
|
|
|
|
*pf1Bpp = TRUE;
|
|
|
|
} else {
|
|
|
|
if (((planes == 0) || (planes == gpsi->Planes)) &&
|
|
((bpp == 0) || (bpp == gpsi->BitsPixel))) {
|
|
|
|
hbm = CreateCompatibleBitmap(hdcScreen, cx, cy);
|
|
|
|
} else {
|
|
|
|
dib4Vga.bi.biBitCount = planes * bpp ? planes * bpp : gpsi->BitCount;
|
|
|
|
#if 0 // We use to do the dib-section create, but this breaks icons
|
|
// when they are made public (can't make a dibsection public). So
|
|
// we now wil create this as a real-dib.
|
|
//
|
|
{
|
|
DWORD dwDummy;
|
|
|
|
dib4Vga.bi.biWidth = cx;
|
|
dib4Vga.bi.biHeight = -cy; // top-down DIB (like a DDB)
|
|
|
|
hbm = CreateDIBSection(hdcScreen,
|
|
(LPBITMAPINFO)&dib4Vga,
|
|
DIB_RGB_COLORS,
|
|
(LPVOID)&dwDummy,
|
|
0,
|
|
0);
|
|
}
|
|
#else
|
|
dib4Vga.bi.biWidth = cx;
|
|
dib4Vga.bi.biHeight = cy;
|
|
|
|
hbm = CreateDIBitmap(hdcScreen,
|
|
(LPBITMAPINFOHEADER)&dib4Vga,
|
|
CBM_CREATEDIB,
|
|
NULL,
|
|
(LPBITMAPINFO)&dib4Vga,
|
|
DIB_RGB_COLORS);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
RELEASEINITDC(hdcScreen);
|
|
}
|
|
|
|
if (hbm && lpBits) {
|
|
|
|
BITMAP bm;
|
|
|
|
GetObject(hbm, sizeof(BITMAP), &bm);
|
|
dwCount = (DWORD)(UINT)(bm.bmWidthBytes * bm.bmPlanes) * (DWORD)(UINT)cy;
|
|
SetBitmapBits(hbm, dwCount, lpBits);
|
|
}
|
|
|
|
return hbm;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadBmp (Worker)
|
|
*
|
|
* This routine decides whether the bitmap to be loaded is in old or new (DIB)
|
|
* format and calls appropriate handlers.
|
|
*
|
|
* History:
|
|
* 24-Sep-1990 MikeKe From Win30.
|
|
* 18-Jun-1991 ChuckWh Added local bitmap handle support.
|
|
* 05-Sep-1995 ChrisWil Port/Change for Chicago functionality.
|
|
\***************************************************************************/
|
|
HBITMAP LoadBmp(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT flags)
|
|
{
|
|
HBITMAP hbmp = NULL;
|
|
BOOL fFree = FALSE, f1Bpp = FALSE;
|
|
|
|
/***************************************************************************\
|
|
* Bitmap Resource Table
|
|
*
|
|
* As of WIN4.0, most system bitmaps are rendered instead of grabbed from the
|
|
* display driver. However, a lot of apps, especially those that fake their
|
|
* own MDI, do LoadBitmap(NULL, OBM_...) to grab a system bitmap. So we
|
|
* hook those requests here and copy our rendered bitmaps into a newly-
|
|
* created bitmap. Note that this is actually faster than loading from a
|
|
* resource table!
|
|
*
|
|
* BOGUS -- give 'em old close buttons, not new cool X's
|
|
*
|
|
\***************************************************************************/
|
|
#define MAX_BMPMAP 32
|
|
|
|
CONST static MAPRES MapOemBmp[MAX_BMPMAP] = {
|
|
|
|
{OBM_BTNCORNERS , OBI_RADIOMASK , },
|
|
{OBM_BTSIZE , OBI_NCGRIP , },
|
|
{OBM_CHECK , OBI_MENUCHECK , MR_MONOCHROME },
|
|
{OBM_CHECKBOXES , OBI_CHECK , },
|
|
{OBM_COMBO , OBI_DNARROW , },
|
|
{OBM_DNARROW , OBI_DNARROW , },
|
|
{OBM_DNARROWD , OBI_DNARROW_D , },
|
|
{OBM_DNARROWI , OBI_DNARROW_I , },
|
|
{OBM_LFARROW , OBI_LFARROW , },
|
|
{OBM_LFARROWD , OBI_LFARROW_D , },
|
|
{OBM_LFARROWI , OBI_LFARROW_I , },
|
|
|
|
/*
|
|
* Use MONO bitmaps in future once flat/mono controls are worked out.
|
|
*/
|
|
{OBM_OLD_DNARROW, OBI_DNARROW , MR_FAILFOR40 },
|
|
{OBM_OLD_LFARROW, OBI_LFARROW , MR_FAILFOR40 },
|
|
{OBM_OLD_REDUCE , OBI_REDUCE_MBAR , MR_FAILFOR40 },
|
|
{OBM_OLD_RESTORE, OBI_RESTORE_MBAR , MR_FAILFOR40 },
|
|
{OBM_OLD_RGARROW, OBI_RGARROW , MR_FAILFOR40 },
|
|
{OBM_OLD_UPARROW, OBI_UPARROW , MR_FAILFOR40 },
|
|
{OBM_OLD_ZOOM , OBI_ZOOM , MR_FAILFOR40 },
|
|
|
|
{OBM_MNARROW , OBI_MENUARROW , MR_MONOCHROME },
|
|
{OBM_REDUCE , OBI_REDUCE_MBAR , },
|
|
{OBM_REDUCED , OBI_REDUCE_MBAR_D , },
|
|
{OBM_RESTORE , OBI_RESTORE_MBAR , },
|
|
{OBM_RESTORED , OBI_RESTORE_MBAR_D , },
|
|
{OBM_RGARROW , OBI_RGARROW , },
|
|
{OBM_RGARROWD , OBI_RGARROW_D , },
|
|
{OBM_RGARROWI , OBI_RGARROW_I , },
|
|
{OBM_SIZE , OBI_NCGRIP , },
|
|
{OBM_UPARROW , OBI_UPARROW , },
|
|
{OBM_UPARROWD , OBI_UPARROW_D , },
|
|
{OBM_UPARROWI , OBI_UPARROW_I , },
|
|
{OBM_ZOOM , OBI_ZOOM , },
|
|
{OBM_ZOOMD , OBI_ZOOM_D , }
|
|
};
|
|
|
|
|
|
/*
|
|
* If hmod is valid, load the client-side bits.
|
|
*/
|
|
if (hmod == NULL) {
|
|
|
|
HBITMAP hOldBmp;
|
|
WORD bm;
|
|
WORD wID;
|
|
BOOL fCombo;
|
|
BOOL fCheckBoxes;
|
|
int i;
|
|
RECT rc;
|
|
BOOL fSysMenu = FALSE;
|
|
BOOL fMenu = FALSE;
|
|
BOOL fMono = FALSE;
|
|
|
|
hmod = hmodUser;
|
|
|
|
/*
|
|
* Since the resource is coming from USER32, we only
|
|
* deal with ID types.
|
|
*/
|
|
wID = PTR_TO_ID(lpName);
|
|
|
|
switch(wID) {
|
|
case OBM_OLD_CLOSE:
|
|
if (GETAPPVER() >= VER40) {
|
|
goto FailOldLoad;
|
|
}
|
|
|
|
/*
|
|
* fall through to the Close case.
|
|
*/
|
|
|
|
case OBM_CLOSE:
|
|
/* the new look for the system menu is to use the window's
|
|
* class icon -- but since here we don't know which window
|
|
* they'll be using this for, fall back on the good ole'
|
|
* windows logo icon
|
|
*/
|
|
cxDesired = (SYSMET(CXMENUSIZE) + SYSMET(CXEDGE)) * 2;
|
|
cyDesired = SYSMET(CYMENUSIZE) + (2 * SYSMET(CYEDGE));
|
|
fSysMenu = TRUE;
|
|
break;
|
|
|
|
case OBM_TRUETYPE: {
|
|
|
|
PVOID p;
|
|
HANDLE h;
|
|
int nOffset;
|
|
|
|
/*
|
|
* Offset into resource.
|
|
*/
|
|
if (gpsi->dmLogPixels == 120) {
|
|
nOffset = OFFSET_120_DPI;
|
|
} else {
|
|
nOffset = OFFSET_96_DPI;
|
|
}
|
|
|
|
lpName = (LPWSTR)(MAX_RESOURCE_INDEX -
|
|
((ULONG_PTR)lpName) + nOffset);
|
|
|
|
if (h = FINDRESOURCEW(hmod, (LPWSTR)lpName, RT_BITMAP)) {
|
|
|
|
if (h = LOADRESOURCE(hmod, h)) {
|
|
|
|
if (p = LOCKRESOURCE(h, hmod)) {
|
|
|
|
|
|
hbmp = (HBITMAP)ObjectFromDIBResource(hmod,
|
|
lpName,
|
|
RT_BITMAP,
|
|
cxDesired,
|
|
cyDesired,
|
|
flags);
|
|
|
|
UNLOCKRESOURCE(h, hmod);
|
|
}
|
|
|
|
FREERESOURCE(h, hmod);
|
|
}
|
|
}
|
|
|
|
goto LoadBmpDone;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fCombo = (wID == OBM_COMBO);
|
|
fCheckBoxes = (wID == OBM_CHECKBOXES);
|
|
|
|
/*
|
|
* hard loop to check for mapping.
|
|
*/
|
|
for (i=0; (i < MAX_BMPMAP) && (MapOemBmp[i].idDisp != wID); i++);
|
|
|
|
if (i == MAX_BMPMAP)
|
|
goto LoadForReal;
|
|
|
|
if ((MapOemBmp[i].bFlags & MR_FAILFOR40) &&
|
|
(GETAPPVER() >= VER40)) {
|
|
|
|
FailOldLoad:
|
|
RIPMSG0(RIP_WARNING, "LoadBitmap: old IDs not allowed for 4.0 apps");
|
|
return NULL;
|
|
}
|
|
|
|
if (MapOemBmp[i].bFlags & MR_MONOCHROME)
|
|
fMono = TRUE;
|
|
|
|
bm = MapOemBmp[i].idUser;
|
|
|
|
if ((bm == OBI_REDUCE_MBAR) || (bm == OBI_RESTORE_MBAR))
|
|
fMenu = TRUE;
|
|
|
|
cxDesired = gpsi->oembmi[bm].cx;
|
|
cyDesired = gpsi->oembmi[bm].cy;
|
|
|
|
if (fMenu)
|
|
cyDesired += (2 * SYSMET(CYEDGE));
|
|
|
|
if (fCheckBoxes) {
|
|
cxDesired *= NUM_BUTTON_STATES;
|
|
cyDesired *= NUM_BUTTON_TYPES;
|
|
} else if (fCombo) {
|
|
cxDesired -= (2 * SYSMET(CXEDGE));
|
|
cyDesired -= (2 * SYSMET(CYEDGE));
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Creates DIB section or color compatible.
|
|
*/
|
|
if (fMono) {
|
|
|
|
/*
|
|
* Create mono-bitmaps as DIBs on NT. On Win95 this is
|
|
* called as:
|
|
*
|
|
* hbmp = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL);
|
|
*
|
|
* However, due to color-matching differences, we need to
|
|
* use dibs to get the nearest-color-matching. At the
|
|
* end of this routine we will convert to a true-mono so that
|
|
* foreground/background matching can be performed normally.
|
|
*/
|
|
hbmp = CreateScreenBitmap(cxDesired, cyDesired, 1, 1, NULL, &f1Bpp);
|
|
|
|
} else {
|
|
|
|
hbmp = CreateScreenBitmap(cxDesired, cyDesired, 0, 0, NULL, &f1Bpp);
|
|
}
|
|
|
|
if (hbmp == NULL)
|
|
goto LoadBmpDone;
|
|
|
|
RtlEnterCriticalSection(&gcsHdc);
|
|
hOldBmp = SelectBitmap(ghdcBits2, hbmp);
|
|
UserAssert(GetBkColor(ghdcBits2) == RGB(255,255,255));
|
|
UserAssert(GetTextColor(ghdcBits2) == RGB(0, 0, 0));
|
|
|
|
rc.top = 0;
|
|
rc.left = 0;
|
|
rc.bottom = cyDesired;
|
|
rc.right = cxDesired;
|
|
|
|
if (fMono) {
|
|
PatBlt(ghdcBits2, 0, 0, cxDesired, cyDesired, WHITENESS);
|
|
} else {
|
|
FillRect(ghdcBits2,
|
|
&rc,
|
|
((fMenu | fSysMenu) ? SYSHBR(MENU) : SYSHBR(WINDOW)));
|
|
}
|
|
|
|
if (fSysMenu) {
|
|
int x = SYSMET(CXEDGE);
|
|
|
|
cxDesired /= 2;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
DrawIconEx(ghdcBits2,
|
|
x,
|
|
SYSMET(CYEDGE),
|
|
KHICON_TO_HICON(gpsi->hIconSmWindows),
|
|
cxDesired - 2 * SYSMET(CXEDGE),
|
|
SYSMET(CYMENUSIZE) - SYSMET(CYEDGE),
|
|
0,
|
|
NULL,
|
|
DI_NORMAL);
|
|
|
|
x += cxDesired;
|
|
}
|
|
} else if (fCombo) {
|
|
/*
|
|
* Revisit when we start using TTF -- that'll take care of this
|
|
* hack.
|
|
*/
|
|
rc.top = -SYSMET(CYEDGE);
|
|
rc.bottom += SYSMET(CYEDGE);
|
|
rc.left = -SYSMET(CXEDGE);
|
|
rc.right += SYSMET(CXEDGE);
|
|
|
|
DrawFrameControl(ghdcBits2,
|
|
&rc,
|
|
DFC_SCROLL,
|
|
DFCS_SCROLLDOWN);
|
|
|
|
} else if (fCheckBoxes) {
|
|
int wType, wState, x;
|
|
DWORD clrTextSave, clrBkSave;
|
|
int y = 0;
|
|
|
|
for (wType = 0; wType < NUM_BUTTON_TYPES; wType++) {
|
|
x = 0;
|
|
|
|
cxDesired = gpsi->oembmi[bm].cx;
|
|
cyDesired = gpsi->oembmi[bm].cy;
|
|
|
|
if (wType == 1) {
|
|
|
|
/*
|
|
* BOGUS UGLINESS -- will be fixed once the Graphics dudes
|
|
* get me the icon TTF -- I'll revisit this then and make
|
|
* REAL
|
|
*/
|
|
clrTextSave = SetTextColor(ghdcBits2, RESCLR_BLACK);
|
|
clrBkSave = SetBkColor (ghdcBits2, RESCLR_WHITE);
|
|
|
|
for (wState = 0; wState < NUM_BUTTON_STATES; wState++) {
|
|
NtUserBitBltSysBmp(ghdcBits2,
|
|
x,
|
|
y,
|
|
cxDesired,
|
|
cyDesired,
|
|
gpsi->oembmi[OBI_RADIOMASK].x,
|
|
gpsi->oembmi[OBI_RADIOMASK].y,
|
|
SRCAND);
|
|
|
|
NtUserBitBltSysBmp(ghdcBits2,
|
|
x,
|
|
y,
|
|
cxDesired,
|
|
cyDesired,
|
|
gpsi->oembmi[bm].x,
|
|
gpsi->oembmi[bm].y,
|
|
SRCINVERT);
|
|
x += cxDesired;
|
|
bm++;
|
|
}
|
|
|
|
SetTextColor(ghdcBits2, clrTextSave);
|
|
SetBkColor(ghdcBits2, clrBkSave);
|
|
} else {
|
|
for (wState = 0; wState < NUM_BUTTON_STATES; wState++) {
|
|
|
|
BitBltSysBmp(ghdcBits2, x, y, bm);
|
|
x += cxDesired;
|
|
bm++;
|
|
}
|
|
|
|
/*
|
|
* Skip OBI_*_CDI.
|
|
*/
|
|
bm++;
|
|
}
|
|
|
|
y += cyDesired;
|
|
}
|
|
} else {
|
|
BitBltSysBmp(ghdcBits2, 0, fMenu ? SYSMET(CYEDGE) : 0, bm);
|
|
}
|
|
|
|
SelectBitmap(ghdcBits2, hOldBmp);
|
|
|
|
/*
|
|
* If the bitmap was created as a 1bpp, we need to convert to a
|
|
* true mono-bitmap. GDI performs different color-matching depending
|
|
* upon this case.
|
|
*/
|
|
if (f1Bpp && hbmp)
|
|
hbmp = Convert1BppToMonoBitmap(ghdcBits2, hbmp);
|
|
|
|
RtlLeaveCriticalSection(&gcsHdc);
|
|
|
|
} else {
|
|
|
|
LoadForReal:
|
|
|
|
hbmp = (HBITMAP)ObjectFromDIBResource(hmod,
|
|
lpName,
|
|
RT_BITMAP,
|
|
cxDesired,
|
|
cyDesired,
|
|
flags);
|
|
}
|
|
|
|
LoadBmpDone:
|
|
|
|
return hbmp;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadBitmapA (API)
|
|
* LoadBitmapW (API)
|
|
*
|
|
* Loads a bitmap from client. If hmod == NULL, loads a bitmap from the
|
|
* system.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HBITMAP, WINAPI, LoadBitmapA, HINSTANCE, hmod, LPCSTR, lpName)
|
|
HBITMAP WINAPI LoadBitmapA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName)
|
|
{
|
|
LPWSTR lpUniName;
|
|
HBITMAP hRet;
|
|
|
|
if (ID(lpName))
|
|
return LoadBmp(hmod, (LPCWSTR)lpName, 0, 0, 0);
|
|
|
|
if (!MBToWCS(lpName, -1, &lpUniName, -1, TRUE))
|
|
return NULL;
|
|
|
|
hRet = LoadBmp(hmod, lpUniName, 0, 0, 0);
|
|
|
|
UserLocalFree(lpUniName);
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HBITMAP, WINAPI, LoadBitmapW, HINSTANCE, hmod, LPCWSTR, lpName)
|
|
HBITMAP WINAPI LoadBitmapW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName)
|
|
{
|
|
return LoadBmp(hmod, lpName, 0, 0, 0);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadCursorA (API)
|
|
* LoadCursorW (API)
|
|
*
|
|
* Loads a cursor from client. If hmod == NULL, loads a cursor from the
|
|
* system.
|
|
*
|
|
* 05-Apr-1991 ScottLu Rewrote to work with client server.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HCURSOR, WINAPI, LoadCursorA, HINSTANCE, hmod, LPCSTR, lpName)
|
|
HCURSOR WINAPI LoadCursorA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName)
|
|
{
|
|
HCURSOR hRet;
|
|
LPWSTR lpUniName;
|
|
|
|
if (ID(lpName))
|
|
return LoadCursorW(hmod, (LPWSTR)lpName);
|
|
|
|
if (!MBToWCS(lpName, -1, &lpUniName, -1, TRUE))
|
|
return NULL;
|
|
|
|
hRet = LoadCursorW(hmod, lpUniName);
|
|
|
|
UserLocalFree(lpUniName);
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HCURSOR, WINAPI, LoadCursorW, HINSTANCE, hmod, LPCWSTR, lpName)
|
|
HCURSOR WINAPI LoadCursorW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName)
|
|
{
|
|
|
|
return LoadIcoCur(hmod,
|
|
lpName,
|
|
RT_CURSOR,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE | LR_SHARED);
|
|
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadIconA (API)
|
|
* LoadIconW (API)
|
|
*
|
|
* Loads an icon from client. If hmod == NULL, loads an icon from the
|
|
* system.
|
|
*
|
|
* 05-Apr-1991 ScottLu Rewrote to work with client server.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HICON, WINAPI, LoadIconA, HINSTANCE, hmod, LPCSTR, lpName)
|
|
HICON WINAPI LoadIconA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName)
|
|
{
|
|
HICON hRet;
|
|
LPWSTR lpUniName;
|
|
|
|
if (ID(lpName))
|
|
return LoadIconW(hmod, (LPWSTR)lpName);
|
|
|
|
if (!MBToWCS(lpName, -1, &lpUniName, -1, TRUE))
|
|
return NULL;
|
|
|
|
hRet = LoadIconW(hmod, lpUniName);
|
|
|
|
UserLocalFree(lpUniName);
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, HICON, WINAPI, LoadIconW, HINSTANCE, hmod, LPCWSTR, lpName)
|
|
HICON WINAPI LoadIconW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName)
|
|
{
|
|
return LoadIcoCur(hmod,
|
|
lpName,
|
|
RT_ICON,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE | LR_SHARED);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadImageA (API)
|
|
* LoadImageW (API)
|
|
*
|
|
* Loads a bitmap, icon or cursor resource from client. If hmod == NULL,
|
|
* then it will load from system-resources.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG6(LOG_GENERAL, HANDLE, WINAPI, LoadImageA, HINSTANCE, hmod, LPCSTR, lpName, UINT, type, int, cxDesired, int, cyDesired, UINT, flags)
|
|
HANDLE WINAPI LoadImageA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName,
|
|
UINT type,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT flags)
|
|
{
|
|
LPWSTR lpUniName;
|
|
HANDLE hRet;
|
|
|
|
if (ID(lpName))
|
|
return LoadImageW(hmod,
|
|
(LPCWSTR)lpName,
|
|
type,
|
|
cxDesired,
|
|
cyDesired,
|
|
flags);
|
|
|
|
if (!MBToWCS(lpName, -1, &lpUniName, -1, TRUE))
|
|
return NULL;
|
|
|
|
hRet = LoadImageW(hmod, lpUniName, type, cxDesired, cyDesired, flags);
|
|
|
|
UserLocalFree(lpUniName);
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
FUNCLOG6(LOG_GENERAL, HANDLE, WINAPI, LoadImageW, HINSTANCE, hmod, LPCWSTR, lpName, UINT, IMAGE_code, int, cxDesired, int, cyDesired, UINT, flags)
|
|
HANDLE WINAPI LoadImageW(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
UINT IMAGE_code,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT flags)
|
|
{
|
|
/*
|
|
* If we specified LR_LOADFROMFILE, then we can tweak the
|
|
* flags to turn off LR_SHARED.
|
|
*/
|
|
if (flags & LR_LOADFROMFILE)
|
|
flags &= ~LR_SHARED;
|
|
|
|
switch (IMAGE_code) {
|
|
case IMAGE_BITMAP:
|
|
return (HANDLE)LoadBmp(hmod, lpName, cxDesired, cyDesired, flags);
|
|
|
|
case IMAGE_CURSOR:
|
|
#if 0 //CHRISWIL : oemInfo.fColorCursors doesn't exist on NT.
|
|
if (!oemInfo.fColorCursors)
|
|
flags |= LR_MONOCHROME;
|
|
#endif
|
|
|
|
case IMAGE_ICON:
|
|
|
|
/*
|
|
* On WinNT 3.51, an app can successfully load a
|
|
* USER icon without specifying LR_SHARED. We enable
|
|
* these apps to succeed, but make 4.0 apps conform to
|
|
* Windows95 behavior.
|
|
*/
|
|
|
|
if (!hmod && GETEXPWINVER(NULL) < VER40) {
|
|
flags |= LR_SHARED;
|
|
}
|
|
|
|
return (HANDLE)LoadIcoCur(hmod,
|
|
lpName,
|
|
((IMAGE_code == IMAGE_ICON) ? RT_ICON : RT_CURSOR),
|
|
cxDesired,
|
|
cyDesired,
|
|
flags);
|
|
|
|
default:
|
|
RIPMSG0(RIP_WARNING, "LoadImage: invalid IMAGE_code");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetIconIdEx
|
|
*
|
|
* This one accepts width, height, and other flags. Just not exported right
|
|
* now.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
UINT GetIconIdEx(
|
|
HINSTANCE hmod,
|
|
HANDLE hrsd,
|
|
LPCWSTR lpszType,
|
|
DWORD cxDesired,
|
|
DWORD cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
int idIcon = 0;
|
|
LPNEWHEADER lpnh;
|
|
|
|
if (lpnh = (LPNEWHEADER)LOCKRESOURCE(hrsd, hmod)) {
|
|
|
|
/*
|
|
* Do a sanity check on this data structure. Otherwise we'll GP FAULT
|
|
* when extracting an icon from a corrupted area. Fix for B#9290.
|
|
* SANKAR, 08/13/91
|
|
*/
|
|
if ((lpnh->Reserved == 0) &&
|
|
((lpnh->ResType == IMAGE_ICON) || (lpnh->ResType == IMAGE_CURSOR))) {
|
|
|
|
idIcon = LookupIconIdFromDirectoryEx((PBYTE)lpnh,
|
|
(lpszType == RT_ICON),
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
}
|
|
|
|
UNLOCKRESOURCE(hrsd, hmod);
|
|
}
|
|
|
|
return idIcon;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadDib (Worker)
|
|
*
|
|
* This is the worker-routine for loading a resource and returning a handle
|
|
* to the object as a dib.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HANDLE LoadDIB(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
LPWSTR type,
|
|
DWORD cxDesired,
|
|
DWORD cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
HANDLE hDir;
|
|
UINT idIcon;
|
|
LPWSTR lpszGroupType;
|
|
HANDLE hRes = NULL;
|
|
|
|
switch (PTR_TO_ID(type)) {
|
|
|
|
case PTR_TO_ID(RT_ICON):
|
|
case PTR_TO_ID(RT_CURSOR):
|
|
|
|
lpszGroupType = RT_GROUP_CURSOR + (type - RT_CURSOR);
|
|
|
|
/*
|
|
* For WOW support, OIC_ICON and OIC_SIZE need to be supported.
|
|
* Since these resources match other existing resources, we map
|
|
* them here so we produce results that emulates
|
|
* behavor as if we had the actual resources in USER.
|
|
*
|
|
* Note that obsolete mapping of lpName in LoadIcoCur prevents
|
|
* win4.0 apps from getting here.
|
|
*/
|
|
if (hmod == hmodUser) {
|
|
|
|
switch ((ULONG_PTR)lpName) {
|
|
case OCR_SIZE:
|
|
lpName = (LPCWSTR)OCR_SIZEALL_DEFAULT;
|
|
break;
|
|
|
|
case OCR_ICON:
|
|
lpName = (LPCWSTR)OCR_ICON_DEFAULT;
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* The resource is actually a directory which contains multiple
|
|
* individual image resources we must choose from.
|
|
* Locate the directory
|
|
*/
|
|
if (hDir = SplFindResource(hmod, lpName, (LPCWSTR)lpszGroupType)) {
|
|
|
|
/*
|
|
* Load the directory.
|
|
*/
|
|
if (hDir = LOADRESOURCE(hmod, hDir)) {
|
|
|
|
/*
|
|
* Get the name of the best individual image.
|
|
*/
|
|
if (idIcon = GetIconIdEx(hmod,
|
|
hDir,
|
|
type,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags)) {
|
|
|
|
/*
|
|
* NOTE: Don't free the directory resource!!! - ChipA.
|
|
* We can't call SplFindResource here, because idIcon
|
|
* is internal to us and GetDriverResourceId()
|
|
* doesn't know how to map it.
|
|
*/
|
|
hRes = FINDRESOURCEW(hmod, MAKEINTRESOURCE(idIcon), type);
|
|
}
|
|
|
|
/*
|
|
* BOGUS:
|
|
* It would be very cool if we could loop through all the
|
|
* items in the directory and free 'em too. Free the ones
|
|
* except for the one we're about to load, that is.
|
|
*
|
|
* Free directory resources TWICE so they get really freed.
|
|
*/
|
|
SplFreeResource(hDir, hmod, LR_flags);
|
|
}
|
|
} else {
|
|
/*
|
|
* Failed to load a regular icon\cursor.
|
|
* Try to load an animated icon/cursor with the same name
|
|
*/
|
|
hRes = SplFindResource(hmod, lpName,
|
|
PTR_TO_ID(type) == PTR_TO_ID(RT_CURSOR) ? RT_ANICURSOR : RT_ANIICON);
|
|
}
|
|
break;
|
|
|
|
case PTR_TO_ID(RT_BITMAP):
|
|
hRes = SplFindResource(hmod, lpName, RT_BITMAP);
|
|
break;
|
|
|
|
default:
|
|
RIPMSG0(RIP_WARNING, "LoadDIB: Invalid resource type");
|
|
break;
|
|
}
|
|
|
|
if (hRes)
|
|
hRes = LOADRESOURCE(hmod, hRes);
|
|
|
|
return hRes;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LoadIcoCur (Worker)
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HICON LoadIcoCur(
|
|
HINSTANCE hmod,
|
|
LPCWSTR pszResName,
|
|
LPWSTR type,
|
|
DWORD cxDesired,
|
|
DWORD cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
HICON hico;
|
|
LPWSTR pszModName;
|
|
WCHAR achModName[MAX_PATH];
|
|
|
|
ConnectIfNecessary(0);
|
|
|
|
/*
|
|
* Setup module name and handles for lookup.
|
|
*/
|
|
if (hmod == NULL) {
|
|
|
|
hmod = hmodUser;
|
|
pszModName = szUSER32;
|
|
|
|
} else {
|
|
|
|
WowGetModuleFileName(hmod,
|
|
achModName,
|
|
sizeof(achModName) / sizeof(WCHAR));
|
|
|
|
pszModName = achModName;
|
|
}
|
|
|
|
if (LR_flags & LR_CREATEDIBSECTION)
|
|
LR_flags = (LR_flags & ~LR_CREATEDIBSECTION) | LR_CREATEREALDIB;
|
|
|
|
/*
|
|
* Setup defaults.
|
|
*/
|
|
if ((hmod == hmodUser) && !IS_PTR(pszResName)) {
|
|
|
|
int imapMax;
|
|
LPMAPRES lpMapRes;
|
|
|
|
/*
|
|
* Map some old OEM IDs for people.
|
|
*/
|
|
if (type == RT_ICON) {
|
|
|
|
static MAPRES MapOemOic[] = {
|
|
{OCR_ICOCUR, OIC_WINLOGO, MR_FAILFOR40}
|
|
};
|
|
|
|
lpMapRes = MapOemOic;
|
|
imapMax = 1;
|
|
|
|
} else {
|
|
|
|
static MAPRES MapOemOcr[] = {
|
|
{OCR_ICON, OCR_ICON, MR_FAILFOR40},
|
|
{OCR_SIZE, OCR_SIZE, MR_FAILFOR40}
|
|
};
|
|
|
|
lpMapRes = MapOemOcr;
|
|
imapMax = 2;
|
|
}
|
|
|
|
while (--imapMax >= 0) {
|
|
|
|
if (lpMapRes->idDisp == PTR_TO_ID(pszResName)) {
|
|
|
|
if ((lpMapRes->bFlags & MR_FAILFOR40) &&
|
|
GETAPPVER() >= VER40) {
|
|
|
|
RIPMSG1(RIP_WARNING,
|
|
"LoadIcoCur: Old ID 0x%x not allowed for 4.0 apps",
|
|
PTR_TO_ID(pszResName));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
pszResName = MAKEINTRESOURCE(lpMapRes->idUser);
|
|
break;
|
|
}
|
|
|
|
++lpMapRes;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Determine size of requested object.
|
|
*/
|
|
cxDesired = GetIcoCurWidth(cxDesired , (type == RT_ICON), LR_flags, 0);
|
|
cyDesired = GetIcoCurHeight(cyDesired, (type == RT_ICON), LR_flags, 0);
|
|
|
|
/*
|
|
* See if this is a cached icon/cursor, and grab it if we have one
|
|
* already.
|
|
*/
|
|
if (LR_flags & LR_SHARED) {
|
|
|
|
CURSORFIND cfSearch;
|
|
|
|
/*
|
|
* Note that win95 fails to load any USER resources unless
|
|
* LR_SHARED is specified - so we do too. Also, win95 will
|
|
* ignore your cx, cy and LR_flag parameters and just give
|
|
* you whats in the cache so we do too.
|
|
* A shame but thats life...
|
|
*
|
|
* Setup search criteria. Since this is a load, we will have
|
|
* no source-cursor to lookup. Find something respectable.
|
|
*/
|
|
cfSearch.hcur = (HCURSOR)NULL;
|
|
cfSearch.rt = PtrToUlong(type);
|
|
|
|
if (hmod == hmodUser) {
|
|
|
|
cfSearch.cx = 0;
|
|
cfSearch.cy = 0;
|
|
cfSearch.bpp = 0;
|
|
|
|
} else {
|
|
|
|
cfSearch.cx = cxDesired;
|
|
cfSearch.cy = cyDesired;
|
|
|
|
/*
|
|
* On NT we have a more strict cache-lookup. By passing in (zero), we
|
|
* will tell the cache-lookup to ignore the bpp. This fixes a problem
|
|
* in Crayola Art Studio where the coloring-book cursor was being created
|
|
* as an invisible cursor. This lookup is compatible with Win95.
|
|
*/
|
|
#if 0
|
|
cfSearch.bpp = GetIcoCurBpp(LR_flags);
|
|
#else
|
|
cfSearch.bpp = 0;
|
|
#endif
|
|
}
|
|
|
|
hico = FindExistingCursorIcon(pszModName, pszResName, &cfSearch);
|
|
|
|
if (hico != NULL)
|
|
goto IcoCurFound;
|
|
}
|
|
|
|
#ifdef LATER // SanfordS
|
|
/*
|
|
* We need to handle the case where a configurable icon has been
|
|
* loaded from some arbitrary module or file and someone now wants
|
|
* to load the same thing in a different size or color content.
|
|
*
|
|
* A cheezier alternative is to just call CopyImage on what we
|
|
* found.
|
|
*/
|
|
if (hmod == hmodUser) {
|
|
hico = FindExistingCursorIcon(NULL,
|
|
szUSER,
|
|
type,
|
|
pszResName,
|
|
0,
|
|
0,
|
|
0);
|
|
if (hico != NULL) {
|
|
/*
|
|
* Find out where the original came from and load it.
|
|
* This may require some redesign to remember the
|
|
* filename that LR_LOADFROMFILE images came from.
|
|
*/
|
|
_GetIconInfo(....);
|
|
return LoadIcoCur(....);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
hico = (HICON)ObjectFromDIBResource(hmod,
|
|
pszResName,
|
|
type,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
|
|
IcoCurFound:
|
|
|
|
return hico;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ObjectFromDIBResource
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
HANDLE ObjectFromDIBResource(
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
LPWSTR type,
|
|
DWORD cxDesired,
|
|
DWORD cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
HANDLE hObj = NULL;
|
|
|
|
if (LR_flags & LR_LOADFROMFILE) {
|
|
|
|
hObj = RtlLoadObjectFromDIBFile(lpName,
|
|
type,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
} else {
|
|
|
|
HANDLE hdib;
|
|
|
|
hdib = LoadDIB(hmod, lpName, type, cxDesired, cyDesired, LR_flags);
|
|
|
|
if (hdib != NULL) {
|
|
|
|
LPBITMAPINFOHEADER lpbih;
|
|
|
|
/*
|
|
* We cast the resource-bits to a BITMAPINFOHEADER. If the
|
|
* resource is a CURSOR type, then there are actually two
|
|
* WORDs preceeding the BITMAPINFOHDEADER indicating the
|
|
* hot-spot. Be careful in assuming you have a real
|
|
* dib in this case.
|
|
*/
|
|
if(lpbih = (LPBITMAPINFOHEADER)LOCKRESOURCE(hdib, hmod)) {
|
|
|
|
switch (PTR_TO_ID(type)) {
|
|
case PTR_TO_ID(RT_BITMAP):
|
|
/*
|
|
* Create a physical bitmap from the DIB.
|
|
*/
|
|
hObj = ConvertDIBBitmap(lpbih,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags,
|
|
NULL,
|
|
NULL);
|
|
break;
|
|
|
|
case PTR_TO_ID(RT_ICON):
|
|
case PTR_TO_ID(RT_CURSOR):
|
|
case PTR_TO_ID(RT_ANICURSOR):
|
|
case PTR_TO_ID(RT_ANIICON):
|
|
/*
|
|
* Animated icon\cursors resources use the RIFF format
|
|
*/
|
|
if (ISRIFFFORMAT(lpbih)) {
|
|
hObj = LoadCursorIconFromResource ((PBYTE)lpbih, lpName, cxDesired, cyDesired, LR_flags);
|
|
} else {
|
|
/*
|
|
* Create the object from the DIB.
|
|
*/
|
|
hObj = ConvertDIBIcon(lpbih,
|
|
hmod,
|
|
lpName,
|
|
(type == RT_ICON),
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
}
|
|
break;
|
|
}
|
|
|
|
UNLOCKRESOURCE(hdib, hmod);
|
|
}
|
|
|
|
/*
|
|
* DO THIS TWICE! The resource compiler always makes icon images
|
|
* (RT_ICON) in a group icon discardable, whether the group dude
|
|
* is or not! So the first free won't really free the thing;
|
|
* it'll just set the ref count to 0 and let the discard logic
|
|
* go on its merry way.
|
|
*
|
|
* We take care of shared guys, so we don't need this dib no more.
|
|
* Don't need this DIB no more no more, no more no more no more
|
|
* don't need this DIB no more.
|
|
*/
|
|
SplFreeResource(hdib, hmod, LR_flags);
|
|
}
|
|
}
|
|
|
|
return hObj;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* BitmapFromDIB
|
|
*
|
|
* Creates a bitmap-handle from a DIB-Spec. This function supports the
|
|
* LR_CREATEDIBSECTION flag, sets proper color depth, and stretches the
|
|
* DIBs as requested.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HBITMAP BitmapFromDIB(
|
|
int cxNew,
|
|
int cyNew,
|
|
WORD bPlanesNew,
|
|
WORD bBitsPixelNew,
|
|
UINT LR_flags,
|
|
int cxOld,
|
|
int cyOld,
|
|
LPSTR lpBits,
|
|
LPBITMAPINFO lpbi,
|
|
HPALETTE hpal)
|
|
{
|
|
HBITMAP hbmpNew = NULL;
|
|
BOOL fStretch;
|
|
BOOL f1Bpp = FALSE;
|
|
|
|
RtlEnterCriticalSection(&gcsHdc);
|
|
|
|
if (cxNew == 0)
|
|
cxNew = cxOld;
|
|
|
|
if (cyNew == 0)
|
|
cyNew = cyOld;
|
|
|
|
fStretch = ((cxNew != cxOld) || (cyNew != cyOld));
|
|
|
|
/*
|
|
* If LR_flags indicate DIB-Section, then return that as the
|
|
* bitmap handle.
|
|
*/
|
|
if (LR_flags & (LR_CREATEDIBSECTION | LR_CREATEREALDIB)) {
|
|
|
|
int cxTemp;
|
|
int cyTemp;
|
|
BOOL fOldFormat;
|
|
LPVOID dwDummy;
|
|
DWORD dwTemp;
|
|
|
|
#define lpbch ((LPBITMAPCOREHEADER)lpbi)
|
|
|
|
fOldFormat = ((WORD)lpbi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER));
|
|
|
|
if (fOldFormat) {
|
|
|
|
cxTemp = lpbch->bcWidth;
|
|
cyTemp = lpbch->bcHeight;
|
|
|
|
lpbch->bcWidth = (WORD)cxNew;
|
|
lpbch->bcHeight = (WORD)cyNew;
|
|
|
|
} else {
|
|
|
|
cxTemp = lpbi->bmiHeader.biWidth;
|
|
cyTemp = lpbi->bmiHeader.biHeight;
|
|
dwTemp = lpbi->bmiHeader.biCompression;
|
|
|
|
lpbi->bmiHeader.biWidth = cxNew;
|
|
lpbi->bmiHeader.biHeight = cyNew;
|
|
|
|
if (dwTemp != BI_BITFIELDS)
|
|
lpbi->bmiHeader.biCompression = BI_RGB;
|
|
}
|
|
|
|
if (LR_flags & LR_CREATEREALDIB) {
|
|
hbmpNew = CreateDIBitmap(ghdcBits2,
|
|
(LPBITMAPINFOHEADER)lpbi,
|
|
CBM_CREATEDIB,
|
|
NULL,
|
|
lpbi,
|
|
DIB_RGB_COLORS);
|
|
} else {
|
|
hbmpNew = CreateDIBSection(ghdcBits2,
|
|
lpbi,
|
|
DIB_RGB_COLORS,
|
|
&dwDummy,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
if (fOldFormat) {
|
|
lpbch->bcWidth = (WORD)cxTemp;
|
|
lpbch->bcHeight = (WORD)cyTemp;
|
|
} else {
|
|
lpbi->bmiHeader.biWidth = cxTemp;
|
|
lpbi->bmiHeader.biHeight = cyTemp;
|
|
lpbi->bmiHeader.biCompression = dwTemp;
|
|
}
|
|
#undef lpbch
|
|
}
|
|
|
|
if (hbmpNew == NULL) {
|
|
|
|
hbmpNew = CreateScreenBitmap(cxNew,
|
|
cyNew,
|
|
bPlanesNew,
|
|
bBitsPixelNew,
|
|
NULL,
|
|
&f1Bpp);
|
|
}
|
|
|
|
if (hbmpNew) {
|
|
|
|
int nStretchMode;
|
|
DWORD rgbBk;
|
|
DWORD rgbText;
|
|
HBITMAP hbmpT;
|
|
BOOL fFail;
|
|
|
|
/*
|
|
* We need to select in appropriate bitmap immediately! That way,
|
|
* if we need to handle palette realization, the color matching
|
|
* will work properly.
|
|
*/
|
|
hbmpT = SelectBitmap(ghdcBits2, hbmpNew);
|
|
|
|
/*
|
|
* Setup for stretching
|
|
*/
|
|
if (fStretch) {
|
|
nStretchMode = SetBestStretchMode(ghdcBits2,
|
|
bPlanesNew,
|
|
bBitsPixelNew);
|
|
}
|
|
|
|
rgbBk = SetBkColor(ghdcBits2, RESCLR_WHITE);
|
|
rgbText = SetTextColor(ghdcBits2, RESCLR_BLACK);
|
|
|
|
/*
|
|
* Realize the palette.
|
|
*/
|
|
if (hpal) {
|
|
#if DBG
|
|
UserAssert(TEST_PUSIF(PUSIF_PALETTEDISPLAY));
|
|
#endif // DBG
|
|
|
|
hpal = SelectPalette(ghdcBits2, hpal, FALSE);
|
|
RealizePalette(ghdcBits2);
|
|
}
|
|
|
|
if (fStretch) {
|
|
|
|
fFail = SmartStretchDIBits(ghdcBits2,
|
|
0,
|
|
0,
|
|
cxNew,
|
|
cyNew,
|
|
0,
|
|
0,
|
|
cxOld,
|
|
cyOld,
|
|
lpBits,
|
|
lpbi,
|
|
DIB_RGB_COLORS,
|
|
SRCCOPY) <= 0;
|
|
} else {
|
|
|
|
fFail = SetDIBits(ghdcBits2,
|
|
hbmpNew,
|
|
0,
|
|
cyNew,
|
|
lpBits,
|
|
lpbi,
|
|
DIB_RGB_COLORS) <= 0;
|
|
}
|
|
|
|
/*
|
|
* Unrealize the palette
|
|
*/
|
|
if (hpal) {
|
|
SelectPalette(ghdcBits2, hpal, TRUE);
|
|
RealizePalette(ghdcBits2);
|
|
}
|
|
|
|
/*
|
|
* Cleanup after stretching
|
|
*/
|
|
SetTextColor(ghdcBits2, rgbText);
|
|
SetBkColor(ghdcBits2, rgbBk);
|
|
if (fStretch)
|
|
SetStretchBltMode(ghdcBits2, nStretchMode);
|
|
|
|
SelectBitmap(ghdcBits2, hbmpT);
|
|
|
|
/*
|
|
* If the SetDIBits() of StretchDIBits() failed, it is probably because
|
|
* GDI or the driver did not like the DIB format. This may happen if
|
|
* the file is truncated and we are using a memory mapped file to read
|
|
* the DIB in. In this case, an exception gets thrown in GDI, that it
|
|
* traps and will return failure from the GDI call.
|
|
*/
|
|
|
|
if (fFail) {
|
|
DeleteObject(hbmpNew);
|
|
hbmpNew = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the bitmap was created as a 1bpp, we need to convert to a
|
|
* true mono-bitmap. GDI performs different color-matching depending
|
|
* upon this case.
|
|
*/
|
|
if (f1Bpp && hbmpNew)
|
|
hbmpNew = Convert1BppToMonoBitmap(ghdcBits2, hbmpNew);
|
|
|
|
RtlLeaveCriticalSection(&gcsHdc);
|
|
return hbmpNew;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* HowManyColors
|
|
*
|
|
* Aug-01-2000 DwayneN - Fixed high color support
|
|
\***************************************************************************/
|
|
|
|
DWORD HowManyColors(
|
|
IN UPBITMAPINFOHEADER upbih,
|
|
IN BOOL fOldFormat,
|
|
OUT OPTIONAL LPBYTE *ppColorTable)
|
|
{
|
|
#define upbch ((UPBITMAPCOREHEADER)upbih)
|
|
|
|
if (fOldFormat) {
|
|
if (ppColorTable != NULL) {
|
|
*ppColorTable = (LPBYTE)(upbch + 1);
|
|
}
|
|
if (upbch->bcBitCount <= 8)
|
|
return (1 << upbch->bcBitCount);
|
|
} else {
|
|
if (ppColorTable != NULL) {
|
|
*ppColorTable = (LPBYTE)(upbih + 1);
|
|
}
|
|
|
|
if (upbih->biClrUsed) {
|
|
/*
|
|
* If the bitmap header explicitly provides the number of colors
|
|
* in the color table, use it.
|
|
*/
|
|
return (DWORD)upbih->biClrUsed;
|
|
} else if (upbih->biBitCount <= 8) {
|
|
/*
|
|
* If the bitmap header describes a pallete-bassed bitmap
|
|
* (8bpp or less) then the color table must be big enough
|
|
* to hold all palette indecies.
|
|
*/
|
|
return (1 << upbih->biBitCount);
|
|
} else {
|
|
/*
|
|
* Finally, if the bitmap header describes a highcolor+ bitmap
|
|
* (anything over 8bpp, but typically 16bpp, 24bpp, or 32bpp)
|
|
* there isn't a need for a color table. However, 16bpp and
|
|
* 32bpp bitmaps are special cases since it is not obvious how
|
|
* they should be split into triplets (Red, Green, and Blue). For
|
|
* instance, 16bpp bitmaps can have 6 red bits, 5 green bits, and
|
|
* 5 blue bits. Or some other combination. To specify this, the
|
|
* 16bpp and 32bpp bitmaps provide BI_BITFIELDS in the
|
|
* biCompression field. This indicates that the color table will
|
|
* have 3 DWORDS that describe the masks for the red, green, and
|
|
* blue components of entry in the bitmap. If this isn't
|
|
* specified, then GDI assumes "555" for 16bpp and "XBGR" for
|
|
* 32bpp. 24bpp bitmaps are always "XBGR" and consume a 32-bit
|
|
* entry in the form of an RGBQUAD.
|
|
*/
|
|
if (upbih->biCompression == BI_BITFIELDS) {
|
|
if ((upbih->biBitCount != 16) && (upbih->biBitCount != 32)) {
|
|
RIPMSG1(RIP_WARNING, "HowManyColors: biCompression==BI_BITFIELDS on a %dbpp bitmap!", upbih->biBitCount);
|
|
}
|
|
|
|
return 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Evidently, there is no color table.
|
|
*/
|
|
return 0;
|
|
|
|
#undef upbch
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ChangeDibColors
|
|
*
|
|
* Given a DIB, processes LR_MONOCHROME, LR_LOADTRANSPARENT and
|
|
* LR_LOADMAP3DCOLORS flags on the given header and colortable.
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
VOID ChangeDibColors(
|
|
IN LPBITMAPINFOHEADER lpbih,
|
|
IN UINT LR_flags)
|
|
{
|
|
LPDWORD lpColorTable;
|
|
DWORD rgb;
|
|
UINT iColor;
|
|
UINT cColors;
|
|
|
|
cColors = HowManyColors(lpbih, FALSE, &(LPBYTE)lpColorTable);
|
|
|
|
/*
|
|
* NT Bug 366661: Don't check the color count here b/c we will do different
|
|
* things depending on what type of change we are performing. For example,
|
|
* when loading hi-color/true-color icons, we always need to do the
|
|
* monochrome conversion in order to properly get an icon-mask.
|
|
*/
|
|
|
|
/*
|
|
* LR_MONOCHROME is the only option that handles PM dibs.
|
|
*/
|
|
if (LR_flags & LR_MONOCHROME) {
|
|
/*
|
|
* LR_MONOCHROME is the only option that handles PM dibs.
|
|
*
|
|
* DO THIS NO MATTER WHETHER WE HAVE A COLOR TABLE! We need
|
|
* to do this for mono conversion and for > 8 BPP
|
|
* icons/cursors. In CopyDibHdr, we already made a copy of
|
|
* the header big enough to hold 2 colors even on high-color+
|
|
* bpp images.
|
|
*/
|
|
lpbih->biBitCount = lpbih->biPlanes = 1;
|
|
lpbih->biCompression = 0;
|
|
lpColorTable[0] = RESCLR_BLACK;
|
|
lpColorTable[1] = RESCLR_WHITE;
|
|
} else if (LR_flags & LR_LOADTRANSPARENT) {
|
|
|
|
LPBYTE pb;
|
|
|
|
/*
|
|
* No color table! Do nothing.
|
|
*/
|
|
if (cColors == 0) {
|
|
RIPMSG0(RIP_WARNING, "ChangeDibColors: DIB doesn't have a color table");
|
|
return;
|
|
}
|
|
|
|
pb = (LPBYTE)(lpColorTable + cColors);
|
|
|
|
/*
|
|
* Change the first pixel's color table entry to RGB_WINDOW
|
|
* Gosh, I love small-endian
|
|
*/
|
|
if (lpbih->biCompression == 0)
|
|
iColor = (UINT)pb[0];
|
|
else
|
|
/*
|
|
* RLE bitmap, will start with cnt,clr or 0,cnt,clr
|
|
*/
|
|
iColor = (UINT)(pb[0] == 0 ? pb[2] : pb[1]);
|
|
|
|
switch (cColors) {
|
|
case BPP01_MAXCOLORS:
|
|
iColor &= 0x01;
|
|
break;
|
|
|
|
case BPP04_MAXCOLORS:
|
|
iColor &= 0x0F;
|
|
break;
|
|
|
|
case BPP08_MAXCOLORS:
|
|
iColor &= 0xFF;
|
|
break;
|
|
}
|
|
|
|
rgb = (LR_flags & LR_LOADMAP3DCOLORS ? SYSRGB(3DFACE) : SYSRGB(WINDOW));
|
|
|
|
lpColorTable[iColor] = RGBX(rgb);
|
|
|
|
} else if (LR_flags & LR_LOADMAP3DCOLORS) {
|
|
|
|
/*
|
|
* Fix up the color table, mapping shades of grey to the current
|
|
* 3D colors.
|
|
*/
|
|
for (iColor = 0; iColor < cColors; iColor++) {
|
|
|
|
switch (*lpColorTable & 0x00FFFFFF) {
|
|
|
|
case RGBX(RGB(223, 223, 223)):
|
|
rgb = SYSRGB(3DLIGHT);
|
|
goto ChangeColor;
|
|
|
|
case RGBX(RGB(192, 192, 192)):
|
|
rgb = SYSRGB(3DFACE);
|
|
goto ChangeColor;
|
|
|
|
case RGBX(RGB(128, 128, 128)):
|
|
rgb = SYSRGB(3DSHADOW);
|
|
|
|
/*
|
|
* NOTE: byte-order is different in DIBs than in RGBs
|
|
*/
|
|
ChangeColor:
|
|
*lpColorTable = RGBX(rgb);
|
|
break;
|
|
}
|
|
lpColorTable++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ConvertDIBIcon
|
|
*
|
|
* Called when a cursor/icon in DIB format is loaded. This converts the
|
|
* cursor/icon into the old format and returns the resource handle. IE,
|
|
* grabs the DIB bits and transforms them into physical bitmap bits.
|
|
*
|
|
*
|
|
* DIB Formats for icons/cursors 101
|
|
*
|
|
* Old Win 3.0 format icons/cursors start with an OLDICON/OLDCURSOR header
|
|
* followed by a double high monochrome DIB. The height refered to in the
|
|
* header is the icon/cursor height, not the DIB height which is twice as
|
|
* high. The XOR mask is in the first-half of the DIB bits.
|
|
*
|
|
* Old PM format icons/cursors start with a BITMAPCOREHEADER and
|
|
* are identical to the current win 3.1/NT format thereafter.
|
|
*
|
|
* Current NT/Chicago/Win 3.1 format icons/cursors start with
|
|
* a BITAMPINFOHEADER. The height of this header refers to the height
|
|
* of the first bitmap which may either be color or truely monochrome.
|
|
* If its color, it is followed by the monochrome AND mask bits imediately
|
|
* after the color bits. If it is truely monochrome, the AND and XOR
|
|
* masks are totally contained in the first DIB bits and no more bits
|
|
* follow.
|
|
*
|
|
* 5-Oct-1994 SanfordS Recreated
|
|
\***************************************************************************/
|
|
|
|
HICON ConvertDIBIcon(
|
|
LPBITMAPINFOHEADER lpbih,
|
|
HINSTANCE hmod,
|
|
LPCWSTR lpName,
|
|
BOOL fIcon,
|
|
DWORD cxNew,
|
|
DWORD cyNew,
|
|
UINT LR_flags)
|
|
{
|
|
LPBITMAPINFOHEADER lpbihNew = NULL;
|
|
LPSTR lpBitsNextMask = NULL;
|
|
HICON hicoNew = NULL;
|
|
BOOL fOldFormat = FALSE;
|
|
CURSORDATA cur;
|
|
WCHAR achModName[MAX_PATH];
|
|
|
|
/*
|
|
* Because Icons/Cursors always get public bitmaps, we cannot use
|
|
* LR_CREATEDIBSECTION on them.
|
|
*/
|
|
if (LR_flags & LR_CREATEDIBSECTION) {
|
|
LR_flags = (LR_flags & ~LR_CREATEDIBSECTION) | LR_CREATEREALDIB;
|
|
}
|
|
|
|
RtlZeroMemory(&cur, sizeof(cur));
|
|
|
|
if (!fIcon) {
|
|
/*
|
|
* Cursors have an extra two words preceeding the BITMAPINFOHEADER
|
|
* indicating the hot-spot. After doing the increments, the
|
|
* pointer should be at the dib-header.
|
|
*/
|
|
cur.xHotspot = (short)(int)*(((LPWORD)lpbih)++);
|
|
cur.yHotspot = (short)(int)*(((LPWORD)lpbih)++);
|
|
}
|
|
|
|
/*
|
|
* If the color bitmap is a single plane, 32bpp image, it might
|
|
* contain an alpha channel, so we have to preserve it as a DIB.
|
|
*/
|
|
if (lpbih->biPlanes == 1 && lpbih->biBitCount == 32) {
|
|
LR_flags |= LR_CREATEREALDIB;
|
|
}
|
|
|
|
/*
|
|
* Get the XOR/Color mask.
|
|
* The XOR bits are first in the DIB because the header info
|
|
* pertains to them.
|
|
* The AND mask is always monochrome.
|
|
*/
|
|
lpBitsNextMask = NULL; // not passing lpBits in.
|
|
cur.hbmColor = ConvertDIBBitmap(lpbih,
|
|
cxNew,
|
|
cyNew,
|
|
LR_flags,
|
|
&lpbihNew,
|
|
&lpBitsNextMask);
|
|
if (cur.hbmColor == NULL)
|
|
return NULL;
|
|
|
|
if (hmod == NULL) {
|
|
cur.lpModName = NULL;
|
|
} else {
|
|
cur.CURSORF_flags = CURSORF_FROMRESOURCE;
|
|
if (hmod == hmodUser) {
|
|
cur.lpModName = szUSER32;
|
|
} else {
|
|
WowGetModuleFileName(hmod,
|
|
achModName,
|
|
sizeof(achModName) / sizeof(WCHAR));
|
|
cur.lpModName = achModName;
|
|
}
|
|
}
|
|
cur.rt = (fIcon ? PTR_TO_ID(RT_ICON) : PTR_TO_ID(RT_CURSOR));
|
|
cur.lpName = (LPWSTR)lpName;
|
|
cur.bpp = lpbihNew->biBitCount * lpbihNew->biPlanes;
|
|
|
|
if (cxNew == 0)
|
|
cxNew = lpbihNew->biWidth;
|
|
|
|
if (cyNew == 0)
|
|
cyNew = lpbihNew->biHeight / 2;
|
|
|
|
if (!fIcon) {
|
|
|
|
cur.xHotspot = MultDiv(cur.xHotspot,
|
|
cxNew,
|
|
lpbihNew->biWidth);
|
|
cur.yHotspot = MultDiv(cur.yHotspot,
|
|
cyNew,
|
|
lpbihNew->biHeight / 2);
|
|
} else {
|
|
|
|
/*
|
|
* For an icon the hot spot is the center of the icon
|
|
*/
|
|
cur.xHotspot = (INT)(cxNew) / 2;
|
|
cur.yHotspot = (INT)(cyNew) / 2;
|
|
}
|
|
|
|
/*
|
|
* Setup header for monochrome DIB. Note that we use the COPY.
|
|
*/
|
|
ChangeDibColors(lpbihNew, LR_MONOCHROME);
|
|
|
|
if (lpBitsNextMask != NULL) {
|
|
cur.hbmMask = BitmapFromDIB(cxNew,
|
|
cyNew * 2,
|
|
1,
|
|
1,
|
|
0,
|
|
lpbihNew->biWidth,
|
|
lpbihNew->biHeight,
|
|
lpBitsNextMask,
|
|
(LPBITMAPINFO)lpbihNew,
|
|
NULL);
|
|
|
|
if (cur.hbmMask == NULL) {
|
|
DeleteObject(KHBITMAP_TO_HBITMAP(cur.hbmColor));
|
|
UserLocalFree(lpbihNew);
|
|
return NULL;
|
|
}
|
|
|
|
} else {
|
|
cur.hbmMask = cur.hbmColor;
|
|
cur.hbmColor = NULL;
|
|
}
|
|
|
|
cur.cx = cxNew;
|
|
cur.cy = cyNew * 2;
|
|
|
|
/*
|
|
* Free our dib header copy allocated by ConvertDIBBitmap
|
|
*/
|
|
UserLocalFree(lpbihNew);
|
|
|
|
if (LR_flags & LR_SHARED)
|
|
cur.CURSORF_flags |= CURSORF_LRSHARED;
|
|
|
|
if (LR_flags & LR_GLOBAL)
|
|
cur.CURSORF_flags |= CURSORF_GLOBAL;
|
|
|
|
if (LR_flags & LR_ACONFRAME)
|
|
cur.CURSORF_flags |= CURSORF_ACONFRAME;
|
|
|
|
return CreateIcoCur(&cur);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* TrulyMonochrome
|
|
*
|
|
* Checks to see if a DIB colro table is truly monochrome. ie: the color
|
|
* table has black & white entries only.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL TrulyMonochrome(
|
|
LPVOID lpColorTable,
|
|
BOOL fOldFormat)
|
|
{
|
|
#define lpRGB ((UNALIGNED LONG *)lpColorTable)
|
|
#define lpRGBw ((UNALIGNED WORD *)lpColorTable)
|
|
|
|
if (fOldFormat) {
|
|
|
|
/*
|
|
* Honey - its triplets.
|
|
*/
|
|
if (lpRGBw[0] == 0x0000)
|
|
return (lpRGBw[1] == 0xFF00) && (lpRGBw[2] == 0xFFFF);
|
|
else if (lpRGBw[0] == 0xFFFF)
|
|
return (lpRGBw[1] == 0x00FF) && (lpRGBw[2] == 0x0000);
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Honey - its quadruplets!
|
|
*/
|
|
if (lpRGB[0] == RESCLR_BLACK)
|
|
return (lpRGB[1] == RESCLR_WHITE);
|
|
else if (lpRGB[0] == RESCLR_WHITE)
|
|
return (lpRGB[1] == RESCLR_BLACK);
|
|
}
|
|
|
|
#undef lpRGB
|
|
#undef lpRGBw
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CopyDibHdr
|
|
*
|
|
* Copies and converts a DIB resource header
|
|
*
|
|
* Handles conversion of OLDICON, OLDCURSOR and BITMAPCOREHEADER
|
|
* structures to BITMAPINFOHEADER headers.
|
|
*
|
|
* Note: fSingleHeightMasks is set for OLDICON and OLDCURSOR formats.
|
|
* This identifies that a monochrome AND/Color mask
|
|
* is NOT double height as it is in the newer formats.
|
|
*
|
|
* NOTE: On the off chance that LR_LOADTRANSPARENT is used, we want to
|
|
* copy a DWORD of the bits. Since DIB bits are DWORD aligned, we know
|
|
* at least a DWORD is there, even if the thing is a 1x1 mono bmp.
|
|
*
|
|
* The returned buffer is allocated in this function and needs to be
|
|
* freed by the caller.
|
|
*
|
|
* 22-Oct-1995 SanfordS Revised
|
|
\***************************************************************************/
|
|
|
|
LPBITMAPINFOHEADER CopyDibHdr(
|
|
IN UPBITMAPINFOHEADER upbih,
|
|
OUT LPSTR *lplpBits,
|
|
OUT LPBOOL lpfMono)
|
|
{
|
|
|
|
#define upbch ((UPBITMAPCOREHEADER)upbih)
|
|
DWORD cColors;
|
|
DWORD cMinColors;
|
|
DWORD i;
|
|
LPBITMAPINFOHEADER lpbihNew;
|
|
DWORD cbAlloc;
|
|
LPBYTE lpColorTable;
|
|
struct {
|
|
BITMAPINFOHEADER bih;
|
|
DWORD rgb[256];
|
|
DWORD dwBuffer;
|
|
} Fake;
|
|
|
|
switch (upbih->biSize) {
|
|
case sizeof(BITMAPINFOHEADER):
|
|
/*
|
|
* Cool. No conversion needed.
|
|
*/
|
|
cColors = HowManyColors(upbih, FALSE, &lpColorTable);
|
|
*lplpBits = (LPSTR)(((LPDWORD)lpColorTable) + cColors);
|
|
break;
|
|
|
|
case sizeof(BITMAPCOREHEADER):
|
|
/*
|
|
* Convert the BITMAPCOREHEADER to a BITMAPINFOHEADER
|
|
*/
|
|
Fake.bih.biSize = sizeof(BITMAPINFOHEADER);
|
|
Fake.bih.biWidth = upbch->bcWidth;
|
|
Fake.bih.biHeight = upbch->bcHeight;
|
|
Fake.bih.biPlanes = upbch->bcPlanes;
|
|
Fake.bih.biBitCount = upbch->bcBitCount;
|
|
Fake.bih.biCompression =
|
|
Fake.bih.biXPelsPerMeter =
|
|
Fake.bih.biYPelsPerMeter =
|
|
Fake.bih.biClrImportant = 0;
|
|
Fake.bih.biClrUsed = cColors = HowManyColors(upbih, TRUE, &lpColorTable);
|
|
Fake.bih.biSizeImage = BitmapWidth(Fake.bih.biWidth, Fake.bih.biBitCount) * Fake.bih.biHeight;
|
|
|
|
/*
|
|
* Copy and convert tripplet color table to rgbQuad color table.
|
|
*/
|
|
for (i = 0; i < cColors; i++, lpColorTable += 3) {
|
|
|
|
Fake.rgb[i] = lpColorTable[0] +
|
|
(lpColorTable[1] << 8) +
|
|
(lpColorTable[2] << 16);
|
|
}
|
|
|
|
Fake.rgb[i] = *(DWORD UNALIGNED *)lpColorTable; // For LR_LOADTRANSPARENT
|
|
upbih = (UPBITMAPINFOHEADER)&Fake;
|
|
*lplpBits = lpColorTable;
|
|
break;
|
|
|
|
default:
|
|
|
|
#define upOldIcoCur ((UPOLDCURSOR)upbih)
|
|
|
|
if (upOldIcoCur->bType == BMR_ICON ||
|
|
upOldIcoCur->bType == BMR_CURSOR) {
|
|
/*
|
|
* Convert OLDICON/OLDCURSOR header to BITMAPINFHEADER
|
|
*/
|
|
RIPMSG0(RIP_WARNING, "USER32:Converting a OLD header. - email sanfords if you see this");
|
|
Fake.bih.biSize = sizeof(BITMAPINFOHEADER);
|
|
Fake.bih.biWidth = upOldIcoCur->cx;
|
|
Fake.bih.biHeight = upOldIcoCur->cy * 2;
|
|
Fake.bih.biPlanes =
|
|
Fake.bih.biBitCount = 1;
|
|
Fake.bih.biCompression =
|
|
Fake.bih.biXPelsPerMeter =
|
|
Fake.bih.biYPelsPerMeter =
|
|
Fake.bih.biClrImportant = 0;
|
|
Fake.bih.biClrUsed = cColors = BPP01_MAXCOLORS;
|
|
Fake.bih.biSizeImage = BitmapWidth(upOldIcoCur->cx, 1) * upOldIcoCur->cy;
|
|
Fake.rgb[0] = RESCLR_BLACK;
|
|
Fake.rgb[1] = RESCLR_WHITE;
|
|
upbih = (LPBITMAPINFOHEADER)&Fake;
|
|
*lplpBits = upOldIcoCur->abBitmap;
|
|
Fake.rgb[2] = *((LPDWORD)*lplpBits); // For LR_LOADTRANSPARENT
|
|
|
|
} else {
|
|
|
|
RIPMSG0(RIP_WARNING, "ConvertDIBBitmap: not a valid format");
|
|
return NULL;
|
|
}
|
|
|
|
#undef pOldIcoCur
|
|
|
|
break;
|
|
}
|
|
|
|
*lpfMono = (cColors == BPP01_MAXCOLORS) &&
|
|
TrulyMonochrome((LPBYTE)upbih + sizeof(BITMAPINFOHEADER), FALSE);
|
|
|
|
/*
|
|
* Note: We have to allocate at least 2 color entries so that we have
|
|
* room in the color table to define black and white for monochrome
|
|
* conversions. See ChangeDibColors() and ConvertDIBIcon().
|
|
*/
|
|
cMinColors = cColors >= 2 ? cColors : 2;
|
|
|
|
/*
|
|
* LR_LOADTRANSPARENT needs to examine the first pixel to determine the
|
|
* transparent color. This routine splits the bitmap header away
|
|
* from the actual bitmap bits. However, the routines that process the
|
|
* LR_LOADTRANSPARENT style expect the first pixel to immediately follow
|
|
* the bitmap header. Above we copied the first pixel of the bitmap
|
|
* bits right after the color table. Now we just need to make room for
|
|
* it in our buffer.
|
|
*/
|
|
cMinColors++;
|
|
|
|
cbAlloc = sizeof(BITMAPINFOHEADER) + (cMinColors * sizeof(RGBQUAD));
|
|
|
|
if (lpbihNew = UserLocalAlloc(0, cbAlloc)) {
|
|
RtlCopyMemory(lpbihNew, upbih, cbAlloc);
|
|
}
|
|
|
|
return lpbihNew;
|
|
|
|
#undef upbch
|
|
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ConvertDIBBitmap
|
|
*
|
|
* This takes a BITMAPCOREHEADER, OLDICON, OLDCURSOR or BITMAPINFOHEADER DIB
|
|
* specification and creates a physical object from it.
|
|
* Handles Color fixups, DIB sections, color depth, and stretching options.
|
|
*
|
|
* Passes back: (if lplpbih is not NULL)
|
|
* lplpbih = copy of given header converted to BITMAPINFOHEADER form.
|
|
* lplpBits = pointer to next mask bits, or NULL if no second mask.
|
|
* Caller must free lplpbih returned.
|
|
*
|
|
* If lplpBits is not NULL and points to a non-NULL value, it supplies
|
|
* the location of the DIB bits allowing the header to be from a different
|
|
* location.
|
|
*
|
|
* 04-Oct-1995 SanfordS Recreated.
|
|
\***************************************************************************/
|
|
|
|
HBITMAP ConvertDIBBitmap(
|
|
IN UPBITMAPINFOHEADER upbih,
|
|
IN DWORD cxDesired,
|
|
IN DWORD cyDesired,
|
|
IN UINT LR_flags,
|
|
OUT OPTIONAL LPBITMAPINFOHEADER *lplpbih,
|
|
IN OUT OPTIONAL LPSTR *lplpBits)
|
|
{
|
|
LPBITMAPINFOHEADER lpbihNew;
|
|
BOOL fMono, fMonoGiven;
|
|
BYTE bPlanesDesired;
|
|
BYTE bppDesired;
|
|
LPSTR lpBits;
|
|
HBITMAP hBmpRet;
|
|
|
|
/*
|
|
* Make a copy of the DIB-Header. This returns a pointer
|
|
* which was allocated, so it must be freed later.
|
|
* The also converts the header to BITMAPINFOHEADER format.
|
|
*/
|
|
if ((lpbihNew = CopyDibHdr(upbih, &lpBits, &fMono)) == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* When loading a DIB file, we may need to use a different
|
|
* bits pointer. See RtlRes.c/RtlLoadObjectFromDIBFile.
|
|
*/
|
|
if (lplpBits && *lplpBits) {
|
|
lpBits = *lplpBits;
|
|
}
|
|
|
|
fMonoGiven = fMono;
|
|
|
|
if (!fMono) {
|
|
|
|
if (LR_flags & (LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS))
|
|
ChangeDibColors(lpbihNew, LR_flags & ~LR_MONOCHROME);
|
|
|
|
if (LR_flags & LR_CREATEREALDIB) {
|
|
bPlanesDesired = (BYTE) lpbihNew->biPlanes;
|
|
bppDesired = (BYTE) lpbihNew->biBitCount;
|
|
} else {
|
|
bPlanesDesired = gpsi->Planes;
|
|
bppDesired = gpsi->BitsPixel;
|
|
}
|
|
|
|
fMono = LR_flags & LR_MONOCHROME;
|
|
}
|
|
|
|
if (fMono) {
|
|
bPlanesDesired =
|
|
bppDesired = 1;
|
|
}
|
|
|
|
/*
|
|
* HACK area
|
|
*/
|
|
if (lplpbih != NULL) {
|
|
|
|
/*
|
|
* pass back the translated/copied header
|
|
*/
|
|
*lplpbih = lpbihNew;
|
|
|
|
/*
|
|
* When loading icon/cursors on a system with multiple monitors
|
|
* with different color depths, always convert to VGA color.
|
|
*
|
|
* dwaynen - 1/12/2001
|
|
* Note: This used to also check the SM_SAMEDISPLAYFORMAT metric. If
|
|
* the display formats (on a multi-mon system) were different, it
|
|
* would force the bpp to 4, We have removed this code because we
|
|
* suspect that it isn't really needed.
|
|
* Refer to bug 258022.
|
|
*
|
|
if (!fMono && !SYSMET(SAMEDISPLAYFORMAT)) {
|
|
bPlanesDesired = 1;
|
|
bppDesired = 4;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
* Return a ponter to the bits following this set of bits
|
|
* if there are any there.
|
|
*
|
|
* Note that the header given with an ICON DIB always reflects
|
|
* twice the height of the icon desired but the COLOR bitmap
|
|
* (if there is one) will only be half that high. We need to
|
|
* fixup cyDesired for monochrome icons so that the mask isnt
|
|
* stretched to half the height its supposed to be. Color
|
|
* bitmaps, however, must have the header corrected to reflect
|
|
* the bits actual height which is half what the header said.
|
|
* The correction must later be backed out so that the returned
|
|
* header reflects the dimensions of the XOR mask that immediately
|
|
* follows the color mask.
|
|
*/
|
|
if (fMonoGiven) {
|
|
|
|
*lplpBits = NULL;
|
|
|
|
if (cyDesired)
|
|
cyDesired <<= 1; // mono icon bitmaps are double high.
|
|
|
|
} else {
|
|
|
|
UserAssert(!(lpbihNew->biHeight & 1));
|
|
lpbihNew->biHeight >>= 1; // color icon headers are off by 2
|
|
|
|
/*
|
|
* Gross calculation! We subtract the XOR part of the mask
|
|
* for this calculation so that we submit a double-high mask.
|
|
* The first half of this is garbage, but for icons its not
|
|
* used. This may be a bug for cursor use of icons.
|
|
*/
|
|
*lplpBits = lpBits +
|
|
(BitmapWidth(lpbihNew->biWidth, lpbihNew->biBitCount) -
|
|
BitmapWidth(lpbihNew->biWidth, 1)) *
|
|
lpbihNew->biHeight;
|
|
}
|
|
}
|
|
|
|
if (cxDesired == 0)
|
|
cxDesired = lpbihNew->biWidth;
|
|
|
|
if (cyDesired == 0)
|
|
cyDesired = lpbihNew->biHeight;
|
|
|
|
hBmpRet = BitmapFromDIB(cxDesired,
|
|
cyDesired,
|
|
bPlanesDesired,
|
|
bppDesired,
|
|
LR_flags,
|
|
lpbihNew->biWidth,
|
|
lpbihNew->biHeight,
|
|
lpBits,
|
|
(LPBITMAPINFO)lpbihNew,
|
|
NULL);
|
|
|
|
if (lplpbih == NULL || hBmpRet == NULL) {
|
|
UserLocalFree(lpbihNew);
|
|
} else if (!fMonoGiven) {
|
|
lpbihNew->biHeight <<= 1; // restore header for next mask
|
|
}
|
|
|
|
return hBmpRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* MyAbs
|
|
*
|
|
* Calcules my weighted absolute value of the difference between 2 nums.
|
|
* This of course normalizes values to >= zero. But it can also "punish" the
|
|
* returned value by a factor of two if valueHave < valueWant. This is
|
|
* because you get worse results trying to extrapolate from less info up then
|
|
* interpolating from more info down.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
UINT MyAbs(
|
|
int valueHave,
|
|
int valueWant,
|
|
BOOL fPunish)
|
|
{
|
|
int diff = (valueHave - valueWant);
|
|
|
|
if (diff < 0)
|
|
diff = (fPunish ? -2 : -1) * diff;
|
|
|
|
return (UINT)diff;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* Magnitude
|
|
*
|
|
* Used by the color-delta calculations. The reason is that num colors is
|
|
* always a power of 2. So we use the log 2 of the want vs. have values
|
|
* to avoid having weirdly huge sets.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
UINT Magnitude(
|
|
int nValue)
|
|
{
|
|
if (nValue < 4)
|
|
return 1;
|
|
else if (nValue < 8)
|
|
return 2;
|
|
else if (nValue < 16)
|
|
return 3;
|
|
else if (nValue < 256)
|
|
return 4;
|
|
else
|
|
return 8;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetResourceBpp
|
|
*
|
|
* Extract the bpp for a icon/cursor resource. Handle low and high-color
|
|
* formats.
|
|
*
|
|
\***************************************************************************/
|
|
UINT GetResourceBpp(LPRESDIR lprd, BOOL fIcon)
|
|
{
|
|
UINT bpp = 0;
|
|
|
|
if (fIcon) {
|
|
if (lprd->Icon.ColorCount != 0) {
|
|
bpp = Magnitude(lprd->Icon.ColorCount);
|
|
TAGMSG2(DBGTAG_Icon, "GetResourceBpp: icon color count = %d, bpp = %d", lprd->Icon.ColorCount, bpp);
|
|
} else {
|
|
bpp = lprd->BitCount;
|
|
TAGMSG1(DBGTAG_Icon, "GetResourceBpp: icon bpp = %d", bpp);
|
|
}
|
|
} else {
|
|
/*
|
|
* NTRAID#NTBUG9-360375-2001/04/05-dwaynen
|
|
* This seems really suspicious to me.
|
|
* Forcing bppNew to 1.
|
|
* Cursors provide a hotspot where an icon provides bit-depth
|
|
* information. So we just set the bppNew to 1, since we don't
|
|
* have any better ideas. We just hope that there is only
|
|
* one cursor candidate, otherwise our scoring logic is broken.
|
|
* Also this is broken when we try to load a cursor resource
|
|
* as an icon. We won't match color depth properly!
|
|
*/
|
|
bpp = 1;
|
|
TAGMSG1(DBGTAG_Icon, "GetResourceBpp: cursor bpp = %d", bpp);
|
|
}
|
|
|
|
/*
|
|
* Nothing has 0 bpp.
|
|
*/
|
|
if(bpp == 0) {
|
|
bpp = ICON_DEFAULTDEPTH;
|
|
TAGMSG1(DBGTAG_Icon, "GetResourceBpp: icon color depth unknown! Assuming %d!", bpp);
|
|
}
|
|
|
|
return bpp;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* MatchImage
|
|
*
|
|
* This function takes LPINTs for width & height in case of "real size".
|
|
* For this option, we use dimensions of 1st icon in resdir as size to
|
|
* load, instead of system metrics.
|
|
*
|
|
* Returns a number that measures how "far away" the given image is
|
|
* from a desired one. The value is 0 for an exact match. Note that our
|
|
* formula has the following properties:
|
|
* (1) Differences in width/height count much more than differences in
|
|
* color format.
|
|
* (2) Bigger images are better than smaller, since shrinking produces
|
|
* better results than stretching.
|
|
* (3) Color matching is done by the difference in bit depth. No
|
|
* preference is given to having a candidate equally different
|
|
* above and below the target.
|
|
*
|
|
* The formula is the sum of the following terms:
|
|
* abs(bppCandidate - bppTarget)
|
|
* abs(cxCandidate - cxTarget), times 2 if the image is
|
|
* narrower than what we'd like. This is because we will get a
|
|
* better result when consolidating more information into a smaller
|
|
* space, than when extrapolating from less information to more.
|
|
* abs(cxCandidate - cxTarget), times 2 if the image is
|
|
* shorter than what we'd like. This is for the same reason as
|
|
* the width.
|
|
*
|
|
* Let's step through an example. Suppose we want a 4bpp (16 color),
|
|
* 32x32 image. We would choose the various candidates in the following order:
|
|
*
|
|
* Candidate Score Formula
|
|
*
|
|
* 32x32x4bpp = 0 abs(32-32)*1 + abs(32-32)*1 + 2*abs(4-4)*1
|
|
* 32x32x2bpp = 4
|
|
* 32x32x8bpp = 8
|
|
* 32x32x16bpp = 24
|
|
* 48x48x4bpp = 32
|
|
* 48x48x2bpp = 36
|
|
* 48x48x8bpp = 40
|
|
* 32x32x32bpp = 56
|
|
* 48x48x16bpp = 56 abs(48-32)*1 + abs(48-32)*1 + 2*abs(16-4)*1
|
|
* 16x16x4bpp = 64
|
|
* 16x16x2bpp = 68 abs(16-32)*2 + abs(16-32)*2 + 2*abs(2-4)*1
|
|
* 16x16x8bpp = 72
|
|
* 48x48x32bpp = 88 abs(48-32)*1 + abs(48-32)*1 + 2*abs(32-4)*1
|
|
* 16x16x16bpp = 88
|
|
* 16x16x32bpp = 104
|
|
*
|
|
\***************************************************************************/
|
|
|
|
UINT MatchImage(
|
|
LPRESDIR lprd,
|
|
LPINT lpcxWant,
|
|
LPINT lpcyWant,
|
|
UINT bppWant,
|
|
BOOL fIcon)
|
|
{
|
|
UINT bppNew;
|
|
int cxNew;
|
|
int cyNew;
|
|
UINT score;
|
|
|
|
cxNew = lprd->Icon.Width;
|
|
cyNew = lprd->Icon.Height;
|
|
bppNew = GetResourceBpp(lprd, fIcon);
|
|
|
|
if (!fIcon) {
|
|
/*
|
|
* NTRAID#NTBUG9-360375-2001/04/05-dwaynen
|
|
*
|
|
* This seems really suspicious to me.
|
|
* Cutting the height in half.
|
|
* This is because cursors store a 2X height for legacy reasons.
|
|
* Unfortunately, this code path can also be used to load an
|
|
* icon resource AS a cursor. Maybe we should only do this for
|
|
* cursor resources. But how to tell?
|
|
*/
|
|
cyNew >>= 1;
|
|
}
|
|
|
|
/*
|
|
* 0 really means maximum size (256) or colors (256).
|
|
*/
|
|
if (!cxNew) {
|
|
cxNew = ICON_MAXWIDTH;
|
|
TAGMSG1(DBGTAG_Icon, "MatchImage: icon width unknown! Assuming %d!", cxNew);
|
|
}
|
|
|
|
if (!*lpcxWant) {
|
|
*lpcxWant = cxNew;
|
|
}
|
|
|
|
if (!cyNew) {
|
|
cyNew = ICON_MAXHEIGHT;
|
|
TAGMSG1(DBGTAG_Icon, "MatchImage: icon height unknown! Assuming %d!", cyNew);
|
|
}
|
|
|
|
if (!*lpcyWant) {
|
|
*lpcyWant = cyNew;
|
|
}
|
|
|
|
/*
|
|
* Here are the rules for our "match" formula:
|
|
* (1) A close size match is much preferable to a color match
|
|
* (2) Bigger icons are better than smaller
|
|
* (3) The smaller the difference in bit depths the better
|
|
*/
|
|
score = 2*MyAbs(bppNew, bppWant, FALSE) +
|
|
MyAbs(cxNew, *lpcxWant, TRUE) +
|
|
MyAbs(cyNew, *lpcyWant, TRUE);
|
|
|
|
TAGMSG4(DBGTAG_Icon, "MatchImage: Candidate Summary: cx=%d, cy=%d, bpp=%d, score=%d", cxNew, cyNew, bppNew, score);
|
|
|
|
return score;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetBestImage
|
|
*
|
|
* Among the different forms of images, choose the one that best matches the
|
|
* color format & dimensions of the request.
|
|
*
|
|
* Here are the rules for our "match" formula:
|
|
* (1) A close size match is much preferable to a color match
|
|
* (2) Bigger icons are better than smaller
|
|
* (3) Closer bit depths are better
|
|
*
|
|
* Here are some additional rules:
|
|
* (4) A tie is broken by choosing the one with the largest bpp.
|
|
* (5) A further tie is broken by choosing the first in the resource.
|
|
* (6) If we find an identical match, we return immediately.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
UINT GetBestImage(
|
|
LPRESDIR lprd,
|
|
UINT uCount,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT bppDesired,
|
|
BOOL fIcon)
|
|
{
|
|
UINT i;
|
|
UINT iBest = 0;
|
|
UINT score;
|
|
UINT scoreBest = (UINT)-1;
|
|
UINT bppBest;
|
|
UINT bppCandidate;
|
|
|
|
TAGMSG0(DBGTAG_Icon, "GetBestImage: Icon dir has %d candidates.");
|
|
TAGMSG4(DBGTAG_Icon, "GetBestImage: Looking for cx=%d, cy=%d, bpp=%d, fIcon=%s", cxDesired, cyDesired, bppDesired, fIcon ? "TRUE" : "FALSE");
|
|
|
|
/*
|
|
* If the bpp was not specified, grab the primary monitor's color depth.
|
|
*/
|
|
if (bppDesired == 0) {
|
|
bppDesired = (UINT)gpsi->BitCount;
|
|
TAGMSG1(DBGTAG_Icon, "GetBestImage: Using screen bpp=%d", bppDesired);
|
|
}
|
|
|
|
/*
|
|
* 10/18/2000 - dwaynen
|
|
*
|
|
* We no longer do the following, because we now pass along the
|
|
* actuall bpp, instead of a color count. The old code (commented out
|
|
* below) used to crop the supported bpp to 8, and to convert the bpp
|
|
* into an actual color count. We used to pass the color count because
|
|
* the resource format (see ICONDIR) stores the color count in a byte,
|
|
* and we would simply compare the desired colors against the available
|
|
* colors. If an icon had 256 colors, it actually just stored a 0 in
|
|
* the ICONDIR::ColorCount field. The problem is obvious, what about
|
|
* icons/cursors with more than 256 colors?
|
|
*
|
|
* Fortunately, the resource format also stores the bits-per-pixel (bpp).
|
|
* So, we now pass along the desired bpp, instead of the desired color
|
|
* count, to do our matching against.
|
|
*
|
|
* Old code and comments below:
|
|
* --------
|
|
*
|
|
* Get desired number of colors in # value, not bits value. Note that
|
|
* we do NOT allow you to have 16- or 32- or 24- bit color icons.
|
|
*
|
|
* the icon resources can be 16, 24, 32 bpp, but the restable only has
|
|
* a color count, so a HiColor icon would have a max value in the
|
|
* restable. we treat a 0 in the color count as "max colors"
|
|
*
|
|
|
|
if (bpp > 8)
|
|
bpp = 8;
|
|
|
|
bpp = 1 << bpp;
|
|
*/
|
|
|
|
/*
|
|
* Loop through resource entries, saving the "closest" item so far. Most
|
|
* of the real work is in MatchImage(), which uses a fabricated formula
|
|
* to give us the results that we desire. Namely, an image as close in
|
|
* size to what we want preferring bigger over smaller, then an image
|
|
* with the right color format
|
|
*/
|
|
for (i = 0; i < uCount; i++, lprd++) {
|
|
TAGMSG1(DBGTAG_Icon, "GetBestImage: Checking candidate %d...", i);
|
|
bppCandidate = GetResourceBpp(lprd, fIcon);
|
|
|
|
/*
|
|
* Get "matching" value. How close are we to what we want?
|
|
*/
|
|
score = MatchImage(lprd, &cxDesired, &cyDesired, bppDesired, fIcon);
|
|
|
|
TAGMSG0(DBGTAG_Icon, "---------------------------------------------");
|
|
|
|
if (score == 0) {
|
|
/*
|
|
* We've found an exact match!
|
|
*/
|
|
TAGMSG1(DBGTAG_Icon, "GetBestImage: Found exact match: candidate=%d", i);
|
|
iBest = i;
|
|
break;
|
|
} else if (score < scoreBest) {
|
|
/*
|
|
* We've found a better match than the current alternative.
|
|
*/
|
|
scoreBest = score;
|
|
iBest = i;
|
|
bppBest = bppCandidate;
|
|
} else if (score == scoreBest) {
|
|
/*
|
|
* Tie breaker: choose the higher color depth. If that fails, choose first one.
|
|
*/
|
|
if (bppBest < bppCandidate) {
|
|
iBest = i;
|
|
bppBest = bppCandidate;
|
|
}
|
|
}
|
|
}
|
|
|
|
TAGMSG2(DBGTAG_Icon, "GetBestImage: Using best match: candidate=%d, score=%d", iBest, scoreBest);
|
|
return iBest;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetIcoCurWidth
|
|
*
|
|
* When zero is passed in for a dimension, calculates what size we should
|
|
* really used. Done in a couple o' places, so made it a FN().
|
|
*
|
|
\***************************************************************************/
|
|
|
|
_inline DWORD GetIcoCurWidth(
|
|
DWORD cxOrg,
|
|
BOOL fIcon,
|
|
UINT lrFlags,
|
|
DWORD cxDes)
|
|
{
|
|
if (cxOrg) {
|
|
return cxOrg;
|
|
} else if (lrFlags & LR_DEFAULTSIZE) {
|
|
return (fIcon ? SYSMET(CXICON) : SYSMET(CXCURSOR));
|
|
} else {
|
|
return cxDes;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetIcoCurHeight
|
|
*
|
|
* Vertical counterpart to GetWidth().
|
|
*
|
|
\***************************************************************************/
|
|
|
|
_inline DWORD GetIcoCurHeight(
|
|
DWORD cyOrg,
|
|
BOOL fIcon,
|
|
UINT lrFlags,
|
|
DWORD cyDes)
|
|
{
|
|
if (cyOrg) {
|
|
return cyOrg;
|
|
} else if (lrFlags & LR_DEFAULTSIZE) {
|
|
return (fIcon ? SYSMET(CYICON) : SYSMET(CYCURSOR));
|
|
} else {
|
|
return cyDes;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetIcoCurBpp
|
|
*
|
|
* Returns best match Bpp based on lr-flags.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
_inline DWORD GetIcoCurBpp(
|
|
UINT lrFlags)
|
|
{
|
|
if (lrFlags & LR_MONOCHROME) {
|
|
|
|
#if DBG
|
|
if (lrFlags & LR_VGACOLOR) {
|
|
RIPMSG0(RIP_WARNING, "lrFlags has both MONOCHROME and VGACOLOR; assuming MONOCHROME");
|
|
}
|
|
#endif
|
|
return 1;
|
|
|
|
} else if (TEST_PUSIF(PUSIF_PALETTEDISPLAY) || (lrFlags & LR_VGACOLOR)) {
|
|
/*
|
|
* dwaynen - 1/12/2001
|
|
* Note: This used to also check the SM_SAMEDISPLAYFORMAT metric. If
|
|
* the display formats (on a multi-mon system) were different, it
|
|
* would also return 4, We have removed this code because we suspect
|
|
* that it isn't really needed.
|
|
* Refer to bug 258022.
|
|
*
|
|
* || !SYSMET(SAMEDISPLAYFORMAT)
|
|
*
|
|
*/
|
|
|
|
return 4;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* WOWFindResourceExWCover
|
|
*
|
|
* The WOW FindResource routines expect an ansi string so we have to
|
|
* convert the calling string IFF it is not an ID
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HANDLE WOWFindResourceExWCover(
|
|
HANDLE hmod,
|
|
LPCWSTR rt,
|
|
LPCWSTR lpUniName,
|
|
WORD LangId)
|
|
{
|
|
LPSTR lpAnsiName;
|
|
HANDLE hRes;
|
|
|
|
if (ID(lpUniName))
|
|
return FINDRESOURCEEXA(hmod, (LPSTR)lpUniName, (LPSTR)rt, LangId);
|
|
|
|
/*
|
|
* Otherwise convert the name of the menu then call LoadMenu
|
|
*/
|
|
if (!WCSToMB(lpUniName, -1, &lpAnsiName, -1, TRUE))
|
|
return NULL;
|
|
|
|
hRes = FINDRESOURCEEXA(hmod, lpAnsiName, (LPSTR)rt, LangId);
|
|
|
|
UserLocalFree(lpAnsiName);
|
|
|
|
return hRes;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* WOWLoadBitmapA
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HBITMAP WOWLoadBitmapA(
|
|
HINSTANCE hmod,
|
|
LPCSTR lpName,
|
|
LPBYTE pResData,
|
|
DWORD cbResData)
|
|
{
|
|
LPWSTR lpUniName;
|
|
HBITMAP hRet;
|
|
|
|
UNREFERENCED_PARAMETER(cbResData);
|
|
|
|
if (pResData == NULL) {
|
|
|
|
if (ID(lpName))
|
|
return LoadBmp(hmod, (LPCWSTR)lpName, 0, 0, 0);
|
|
|
|
if (!MBToWCS(lpName, -1, &lpUniName, -1, TRUE))
|
|
return NULL;
|
|
|
|
hRet = LoadBmp(hmod, lpUniName, 0, 0, 0);
|
|
|
|
UserLocalFree(lpUniName);
|
|
|
|
} else {
|
|
|
|
hRet = ConvertDIBBitmap((LPBITMAPINFOHEADER)pResData,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
return hRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* WOWServerLoadCreateCursorIcon
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HICON WowServerLoadCreateCursorIcon(
|
|
HANDLE hmod,
|
|
LPWSTR pszModName,
|
|
DWORD dwExpWinVer,
|
|
LPCWSTR lpName,
|
|
DWORD cb,
|
|
PVOID pResData,
|
|
LPWSTR type,
|
|
BOOL fClient)
|
|
{
|
|
HICON hRet;
|
|
BOOL fIcon = (type == RT_ICON);
|
|
UINT LR_Flags = LR_SHARED;
|
|
|
|
UNREFERENCED_PARAMETER(pszModName);
|
|
UNREFERENCED_PARAMETER(dwExpWinVer);
|
|
UNREFERENCED_PARAMETER(cb);
|
|
UNREFERENCED_PARAMETER(fClient);
|
|
|
|
if (!fIcon)
|
|
LR_Flags |= LR_MONOCHROME;
|
|
|
|
if (pResData == NULL) {
|
|
|
|
hRet = LoadIcoCur(hmod,
|
|
lpName,
|
|
type,
|
|
0,
|
|
0,
|
|
LR_Flags | LR_DEFAULTSIZE);
|
|
|
|
} else {
|
|
|
|
hRet = ConvertDIBIcon((LPBITMAPINFOHEADER)pResData,
|
|
hmod,
|
|
lpName,
|
|
fIcon,
|
|
GetIcoCurWidth(0 , fIcon, LR_DEFAULTSIZE, 0),
|
|
GetIcoCurHeight(0, fIcon, LR_DEFAULTSIZE, 0),
|
|
LR_Flags);
|
|
}
|
|
|
|
return hRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* WOWServerLoadCreateMenu
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
HMENU WowServerLoadCreateMenu(
|
|
HANDLE hMod,
|
|
LPCSTR lpName,
|
|
CONST LPMENUTEMPLATE pmt,
|
|
DWORD cb,
|
|
BOOL fCallClient)
|
|
{
|
|
UNREFERENCED_PARAMETER(cb);
|
|
UNREFERENCED_PARAMETER(fCallClient);
|
|
|
|
if (pmt == NULL) {
|
|
return LoadMenuA(hMod, lpName);
|
|
} else
|
|
return CreateMenuFromResource(pmt);
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* DIBFromBitmap()
|
|
*
|
|
* Creates a memory block with DIB information from a physical bitmap tagged
|
|
* to a specific DC.
|
|
*
|
|
* A DIB block consists of a BITMAPINFOHEADER + RGB colors + DIB bits.
|
|
*
|
|
* Returns: UserLocalAlloc pointer to DIB info.
|
|
*
|
|
* 03-Nov-1995 SanfordS Created.
|
|
\***********************************************************************/
|
|
|
|
PVOID DIBFromBitmap(
|
|
HBITMAP hbmp,
|
|
HDC hdc)
|
|
{
|
|
BITMAP bmp;
|
|
LPBITMAPINFOHEADER lpbi;
|
|
DWORD cbBits;
|
|
DWORD cbPalette;
|
|
DWORD cbTotal;
|
|
WORD cBits;
|
|
|
|
UserAssert(hbmp);
|
|
UserAssert(hdc);
|
|
|
|
if (GetObject(hbmp, sizeof(BITMAP), &bmp) == 0)
|
|
return NULL;
|
|
|
|
cBits = ((WORD)bmp.bmPlanes * (WORD)bmp.bmBitsPixel);
|
|
|
|
TrySmallerDIB:
|
|
|
|
cbBits = (DWORD)WIDTHBYTES((WORD)bmp.bmWidth * cBits) * (DWORD)bmp.bmHeight;
|
|
|
|
cbPalette = 0;
|
|
if (cBits <= 8)
|
|
cbPalette = (1 << cBits) * sizeof(RGBQUAD);
|
|
else
|
|
cbPalette = 3 * sizeof(RGBQUAD);
|
|
|
|
cbTotal = sizeof(BITMAPINFOHEADER) + cbPalette + cbBits;
|
|
lpbi = (LPBITMAPINFOHEADER)UserLocalAlloc(HEAP_ZERO_MEMORY, cbTotal);
|
|
if (lpbi == NULL) {
|
|
|
|
/*
|
|
* Try a smaller DIB, if we can. We can't if the DIB is mono.
|
|
*/
|
|
switch (cBits) {
|
|
case 4:
|
|
cBits = 1;
|
|
break;
|
|
|
|
case 8:
|
|
cBits = 4;
|
|
break;
|
|
|
|
case 16:
|
|
cBits = 8;
|
|
break;
|
|
|
|
case 24:
|
|
cBits = 16;
|
|
break;
|
|
|
|
case 32:
|
|
cBits = 24;
|
|
break;
|
|
|
|
default:
|
|
return NULL; // 1 or wierd.
|
|
}
|
|
|
|
RIPMSG1(RIP_WARNING, "Not enough memory to create large color DIB, trying %d bpp.", cBits);
|
|
goto TrySmallerDIB;
|
|
}
|
|
|
|
RtlZeroMemory(lpbi, sizeof(BITMAPINFOHEADER));
|
|
lpbi->biSize = sizeof(BITMAPINFOHEADER);
|
|
lpbi->biWidth = bmp.bmWidth;
|
|
lpbi->biHeight = bmp.bmHeight;
|
|
lpbi->biPlanes = 1;
|
|
lpbi->biBitCount = cBits;
|
|
|
|
/*
|
|
* Get old bitmap's DIB bits, using the current DC.
|
|
*/
|
|
GetDIBits(hdc,
|
|
hbmp,
|
|
0,
|
|
lpbi->biHeight,
|
|
((LPSTR)lpbi) + lpbi->biSize + cbPalette,
|
|
(LPBITMAPINFO)lpbi,
|
|
DIB_RGB_COLORS);
|
|
|
|
lpbi->biClrUsed = cbPalette / sizeof(RGBQUAD);
|
|
lpbi->biSizeImage = cbBits;
|
|
|
|
return lpbi;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CopyBmp
|
|
*
|
|
* Creates a new bitmap and copies the given bitmap to the new one,
|
|
* stretching and color-converting the bits if desired.
|
|
*
|
|
* 03-Nov-1995 SanfordS Created.
|
|
\***************************************************************************/
|
|
|
|
HBITMAP CopyBmp(
|
|
HBITMAP hbmpOrg,
|
|
int cxNew,
|
|
int cyNew,
|
|
UINT LR_flags)
|
|
{
|
|
HBITMAP hbmNew = NULL;
|
|
LPBITMAPINFOHEADER pdib;
|
|
|
|
RtlEnterCriticalSection(&gcsHdc);
|
|
|
|
if (pdib = DIBFromBitmap(hbmpOrg, ghdcBits2)) {
|
|
|
|
#if 0 // Win-9x comments this code out
|
|
if (LR_flags & LR_COPYRETURNORG) {
|
|
|
|
DWORD bpp = GetIcoCurBpp(LR_flags);
|
|
|
|
if ((cxNew == 0 || cxNew == pdib->biWidth) &&
|
|
(cyNew == 0 || cyNew == pdib->biHeight) &&
|
|
(bpp == 0 || bpp == pdib->biBitCount)) {
|
|
|
|
hbmNew = hbmpOrg;
|
|
}
|
|
}
|
|
|
|
if (hbmNew == NULL)
|
|
hbmNew = ConvertDIBBitmap(pdib, cxNew, cyNew, LR_flags, NULL, NULL);
|
|
#endif
|
|
|
|
hbmNew = ConvertDIBBitmap(pdib, cxNew, cyNew, LR_flags, NULL, NULL);
|
|
|
|
UserLocalFree(pdib);
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&gcsHdc);
|
|
|
|
if ((LR_flags & LR_COPYDELETEORG) && hbmNew && (hbmNew != hbmpOrg))
|
|
DeleteObject(hbmpOrg);
|
|
|
|
return hbmNew;
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* CopyImageFromRes
|
|
*
|
|
* This is used by the LR_COPYFROMRESOURCE option. We assume that the
|
|
* icon/cursor passed in is among the process list of loaded shared
|
|
* icons. If we find it there, we can attempt to load the icon from
|
|
* the resource to get an image that looks better than a stretched or
|
|
* compressed one.
|
|
*
|
|
* That way we will not stretch a 32x32 icon to 16x16 if someone added
|
|
* a 16x16 image to their class icon--a simple way for apps to jazz up
|
|
* their appearance.
|
|
*
|
|
* 12-Mar-1996 ChrisWil Created.
|
|
\***********************************************************************/
|
|
|
|
HICON CopyImageFromRes(
|
|
LPWSTR pszModName,
|
|
LPWSTR pszResName,
|
|
PCURSORFIND pcfSearch,
|
|
UINT LR_flags)
|
|
{
|
|
HINSTANCE hmod;
|
|
HICON hicoDst = NULL;
|
|
|
|
/*
|
|
* Override the search-criteria if this is the user-module. By
|
|
* setting these to zero, we are basically saying "don't care" for
|
|
* these attributes.
|
|
*/
|
|
hmod = (pszModName ? WowGetModuleHandle(pszModName) : hmodUser);
|
|
|
|
if (hmod == hmodUser) {
|
|
|
|
pcfSearch->cx = 0;
|
|
pcfSearch->cy = 0;
|
|
pcfSearch->bpp = 0;
|
|
|
|
pszModName = szUSER32;
|
|
}
|
|
|
|
/*
|
|
* If a resource has been found with this name/bpp, then attempt
|
|
* to load the resource with the desired dimensions.
|
|
*/
|
|
if (FindExistingCursorIcon(pszModName, pszResName, pcfSearch)) {
|
|
|
|
hicoDst = LoadIcoCur(hmod,
|
|
pszResName,
|
|
(LPWSTR)ULongToPtr( pcfSearch->rt ),
|
|
pcfSearch->cx,
|
|
pcfSearch->cy,
|
|
LR_flags);
|
|
}
|
|
|
|
return hicoDst;
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* CopyIcoCur()
|
|
*
|
|
* Allocates a new icon resource and transmogrifies the old icon into the
|
|
* newly desired format.
|
|
*
|
|
* Note that if we have to stretch the icon, the hotspot area changes. For
|
|
* icons, the hotspot is set to be the middle of the icon.
|
|
*
|
|
* Returns:
|
|
*
|
|
* 01-Nov-1995 SanfordS Created.
|
|
* 12-Mar-1996 ChrisWil Added lookup for existing icon/cursor.
|
|
\***********************************************************************/
|
|
|
|
HICON CopyIcoCur(
|
|
HICON hicoSrc,
|
|
BOOL fIcon,
|
|
int cxNew,
|
|
int cyNew,
|
|
UINT LR_flags)
|
|
{
|
|
HBITMAP hbmMaskNew;
|
|
HBITMAP hbmColorNew;
|
|
int cx;
|
|
int cy;
|
|
DWORD bpp;
|
|
DWORD bppDesired;
|
|
HICON hicoDst = NULL;
|
|
ICONINFO ii;
|
|
CURSORDATA cur;
|
|
UNICODE_STRING strModName;
|
|
UNICODE_STRING strResName;
|
|
WCHAR awszModName[MAX_PATH];
|
|
WCHAR awszResName[MAX_PATH];
|
|
|
|
/*
|
|
* Extract needed info from existing icon/cursor from the kernel
|
|
*/
|
|
if (!NtUserGetIconSize(hicoSrc, 0, &cx, &cy))
|
|
return NULL;
|
|
|
|
cy >>= 1;
|
|
|
|
if (LR_flags & LR_CREATEDIBSECTION)
|
|
LR_flags = (LR_flags & ~LR_CREATEDIBSECTION) | LR_CREATEREALDIB;
|
|
|
|
/*
|
|
* Setup unicode-strings for calls to kernel-side.
|
|
*/
|
|
strModName.Length = 0;
|
|
strModName.MaximumLength = MAX_PATH;
|
|
strModName.Buffer = awszModName;
|
|
|
|
strResName.Length = 0;
|
|
strResName.MaximumLength = MAX_PATH;
|
|
strResName.Buffer = awszResName;
|
|
|
|
/*
|
|
* Note: this creates copies of hbmMask and hbmColor that need to be
|
|
* freed before we leave.
|
|
*/
|
|
if (!NtUserGetIconInfo(hicoSrc,
|
|
&ii,
|
|
&strModName,
|
|
&strResName,
|
|
&bpp,
|
|
TRUE)) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
cxNew = GetIcoCurWidth(cxNew, fIcon, LR_flags, cx);
|
|
cyNew = GetIcoCurHeight(cyNew, fIcon, LR_flags, cy);
|
|
|
|
if (LR_flags & LR_COPYFROMRESOURCE) {
|
|
|
|
CURSORFIND cfSearch;
|
|
LPWSTR pszModName;
|
|
|
|
/*
|
|
* Setup the search criteria.
|
|
*/
|
|
cfSearch.hcur = hicoSrc;
|
|
cfSearch.rt = PtrToUlong((fIcon ? RT_ICON : RT_CURSOR));
|
|
cfSearch.cx = cxNew;
|
|
cfSearch.cy = cyNew;
|
|
cfSearch.bpp = bpp;
|
|
|
|
/*
|
|
* Copy the image. This performs a lookup for the hicoSrc. If
|
|
* it is not found in the process and shared caches, then we
|
|
* will proceed with copying the hicoSrc. If an icon is found
|
|
* in the cache, then we will attempt to reload the image for
|
|
* the best resolution possible.
|
|
*/
|
|
pszModName = (strModName.Length ? strModName.Buffer : NULL);
|
|
|
|
hicoDst = CopyImageFromRes(pszModName,
|
|
strResName.Buffer,
|
|
&cfSearch,
|
|
LR_flags);
|
|
|
|
if (hicoDst)
|
|
goto CleanupExit;
|
|
}
|
|
|
|
bppDesired = GetIcoCurBpp(LR_flags);
|
|
|
|
if ((cxNew != cx) ||
|
|
(cyNew != cy) ||
|
|
((bpp != 1) && (bppDesired != 0) && (bppDesired != bpp))) {
|
|
|
|
/*
|
|
* Since we have to stretch or maybe fixup the colors just get
|
|
* the DIB bits and let ConverDIBBitmap do all the magic.
|
|
*/
|
|
hbmMaskNew = CopyBmp(ii.hbmMask, cxNew, cyNew * 2, LR_MONOCHROME);
|
|
|
|
if (hbmMaskNew == NULL)
|
|
goto CleanupExit;
|
|
|
|
hbmColorNew = NULL;
|
|
|
|
if (ii.hbmColor) {
|
|
|
|
hbmColorNew = CopyBmp(ii.hbmColor, cxNew, cyNew, LR_flags);
|
|
|
|
if (hbmColorNew == NULL) {
|
|
DeleteObject(hbmMaskNew);
|
|
goto CleanupExit;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Replace ii.hbmxxx guys with our fixed up copies and delete the old.
|
|
*/
|
|
DeleteObject(ii.hbmMask);
|
|
ii.hbmMask = hbmMaskNew;
|
|
|
|
if (ii.hbmColor && (ii.hbmColor != hbmColorNew)) {
|
|
DeleteObject(ii.hbmColor);
|
|
ii.hbmColor = hbmColorNew;
|
|
}
|
|
|
|
/*
|
|
* tweak the hotspots for changes in size.
|
|
*/
|
|
if (cxNew != cx)
|
|
ii.xHotspot = MultDiv(ii.xHotspot, cxNew, cx);
|
|
|
|
if (cyNew != cy)
|
|
ii.yHotspot = MultDiv(ii.yHotspot, cyNew, cy);
|
|
|
|
} else if (LR_flags & LR_COPYRETURNORG) {
|
|
|
|
hicoDst = hicoSrc;
|
|
|
|
CleanupExit:
|
|
|
|
/*
|
|
* Free up the bitmaps which were created by GetIconInfo().
|
|
*/
|
|
DeleteObject(ii.hbmMask);
|
|
|
|
if (ii.hbmColor)
|
|
DeleteObject(ii.hbmColor);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Build the icon/cursor object from the info. The bitmaps
|
|
* are not freed in this case.
|
|
*/
|
|
hicoDst = (HICON)NtUserCallOneParam(0, SFI__CREATEEMPTYCURSOROBJECT);
|
|
|
|
if (hicoDst == NULL)
|
|
goto CleanupExit;
|
|
|
|
RtlZeroMemory(&cur, sizeof(cur));
|
|
cur.lpName = strResName.Length ? strResName.Buffer : NULL;
|
|
cur.lpModName = strModName.Length ? strModName.Buffer : NULL;
|
|
cur.rt = ii.fIcon ? PTR_TO_ID(RT_ICON) : PTR_TO_ID(RT_CURSOR);
|
|
cur.bpp = bpp;
|
|
cur.cx = cxNew;
|
|
cur.cy = cyNew * 2;
|
|
cur.xHotspot = (short)ii.xHotspot;
|
|
cur.yHotspot = (short)ii.yHotspot;
|
|
cur.hbmMask = ii.hbmMask;
|
|
cur.hbmColor = ii.hbmColor;
|
|
|
|
if (!_SetCursorIconData(hicoDst, &cur)) {
|
|
NtUserDestroyCursor(hicoDst, CURSOR_ALWAYSDESTROY);
|
|
return NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
/*
|
|
* destroy the original if asked to.
|
|
*/
|
|
if (hicoDst != hicoSrc && (LR_flags & LR_COPYDELETEORG))
|
|
DestroyCursor(hicoSrc);
|
|
|
|
return hicoDst;
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* CopyImage
|
|
*
|
|
* Allocates a new icon resource and copies the attributes of the old icon
|
|
* to the new icon.
|
|
*
|
|
* Returns: hIconNew
|
|
*
|
|
* 01-Nov-1995 SanfordS Created.
|
|
\***********************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, HANDLE, WINAPI, CopyImage, HANDLE, hImage, UINT, IMAGE_flag, int, cxNew, int, cyNew, UINT, LR_flags)
|
|
HANDLE WINAPI CopyImage(
|
|
HANDLE hImage,
|
|
UINT IMAGE_flag,
|
|
int cxNew,
|
|
int cyNew,
|
|
UINT LR_flags)
|
|
{
|
|
if (LR_flags & ~LR_VALID) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "CopyImage: bad LR_flags.");
|
|
return NULL;
|
|
}
|
|
|
|
return InternalCopyImage(hImage, IMAGE_flag, cxNew, cyNew, LR_flags);
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* InternalCopyImage
|
|
*
|
|
* Performs the copyimage work. This is called from the callback-thunk.
|
|
*
|
|
\***********************************************************************/
|
|
|
|
HANDLE InternalCopyImage(
|
|
HANDLE hImage,
|
|
UINT IMAGE_flag,
|
|
int cxNew,
|
|
int cyNew,
|
|
UINT LR_flags)
|
|
{
|
|
switch (IMAGE_flag) {
|
|
|
|
case IMAGE_BITMAP:
|
|
if (GetObjectType(hImage) != OBJ_BITMAP) {
|
|
RIPERR0(ERROR_INVALID_HANDLE, RIP_WARNING, "CopyImage: invalid bitmap");
|
|
return NULL;
|
|
}
|
|
|
|
return (HICON)CopyBmp(hImage, cxNew, cyNew, LR_flags);
|
|
|
|
case IMAGE_CURSOR:
|
|
case IMAGE_ICON:
|
|
|
|
return CopyIcoCur(hImage,
|
|
(IMAGE_flag == IMAGE_ICON),
|
|
cxNew,
|
|
cyNew,
|
|
LR_flags);
|
|
}
|
|
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "CopyImage: bad IMAGE_flag.");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* RtlGetIdFromDirectory
|
|
*
|
|
* History:
|
|
* 06-Apr-1991 ScottLu Cleaned up, make work with client/server.
|
|
* 16-Nov-1995 SanfordS Now uses LookupIconIdFromDirectoryEx
|
|
\***************************************************************************/
|
|
|
|
int RtlGetIdFromDirectory(
|
|
PBYTE presbits,
|
|
BOOL fIcon,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
DWORD LR_flags,
|
|
PDWORD pdwResSize)
|
|
{
|
|
LPNEWHEADER lpnh;
|
|
LPRESDIR lprsd;
|
|
UINT iImage;
|
|
UINT cImage;
|
|
UINT bpp;
|
|
|
|
/*
|
|
* Make sure this is pointing to valid resource bits.
|
|
*/
|
|
if (presbits == NULL)
|
|
return 0;
|
|
|
|
lpnh = (LPNEWHEADER)presbits;
|
|
|
|
/*
|
|
* Fill in defaults.
|
|
*/
|
|
cxDesired = GetIcoCurWidth(cxDesired, fIcon, LR_flags, 0);
|
|
cyDesired = GetIcoCurHeight(cyDesired, fIcon, LR_flags, 0);
|
|
|
|
bpp = GetIcoCurBpp(LR_flags);
|
|
|
|
/*
|
|
* We'll use the first image in the directory if we can't find one
|
|
* that's appropriate.
|
|
*/
|
|
cImage = lpnh->ResCount;
|
|
lprsd = (LPRESDIR)(lpnh + 1);
|
|
|
|
iImage = GetBestImage(lprsd, cImage, cxDesired, cyDesired, bpp, fIcon);
|
|
|
|
if (iImage == cImage)
|
|
iImage = 0;
|
|
|
|
if (pdwResSize != NULL)
|
|
*pdwResSize = (lprsd + iImage)->BytesInRes;
|
|
|
|
return ((LPRESDIR)(lprsd + iImage))->idIcon;
|
|
}
|