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.
533 lines
16 KiB
533 lines
16 KiB
/****************************** Module Header ******************************\
|
|
*
|
|
* Module Name: rtlres.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Resource Loading Routines
|
|
*
|
|
* History:
|
|
* 05-Apr-1991 ScottLu Fixed up, resource code is now shared between client
|
|
* and server, added a few new resource loading routines.
|
|
* 24-Sep-1990 MikeKe From win30
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
HICON IconFromBestImage(
|
|
ICONFILEHEADER *pifh,
|
|
LPNEWHEADER lpnhSrc,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT LR_flags);
|
|
|
|
/***************************************************************************\
|
|
* LoadStringOrError
|
|
*
|
|
* NOTE: Passing a NULL value for lpch returns the string length. (WRONG!)
|
|
*
|
|
* Warning: The return count does not include the terminating NULL WCHAR;
|
|
*
|
|
* History:
|
|
* 05-Apr-1991 ScottLu Fixed - code is now shared between client and server
|
|
* 24-Sep-1990 MikeKe From Win30
|
|
\***************************************************************************/
|
|
|
|
int LoadStringOrError(
|
|
HANDLE hModule,
|
|
UINT wID,
|
|
LPWSTR lpBuffer, // Unicode buffer
|
|
int cchBufferMax, // cch in Unicode buffer
|
|
WORD wLangId)
|
|
{
|
|
HANDLE hResInfo;
|
|
HANDLE hStringSeg;
|
|
LPTSTR lpsz;
|
|
int cch;
|
|
|
|
/*
|
|
* Make sure the parms are valid.
|
|
*/
|
|
if (lpBuffer == NULL) {
|
|
RIPMSG0(RIP_WARNING, "LoadStringOrError: lpBuffer == NULL");
|
|
return 0;
|
|
}
|
|
|
|
|
|
cch = 0;
|
|
|
|
/*
|
|
* String Tables are broken up into 16 string segments. Find the segment
|
|
* containing the string we are interested in.
|
|
*/
|
|
if (hResInfo = FINDRESOURCEEXW(hModule, (LPTSTR)ULongToPtr( ((LONG)(((USHORT)wID >> 4) + 1)) ), RT_STRING, wLangId)) {
|
|
|
|
/*
|
|
* Load that segment.
|
|
*/
|
|
hStringSeg = LOADRESOURCE(hModule, hResInfo);
|
|
|
|
/*
|
|
* Lock the resource.
|
|
*/
|
|
if (lpsz = (LPTSTR)LOCKRESOURCE(hStringSeg, hModule)) {
|
|
|
|
/*
|
|
* Move past the other strings in this segment.
|
|
* (16 strings in a segment -> & 0x0F)
|
|
*/
|
|
wID &= 0x0F;
|
|
while (TRUE) {
|
|
cch = *((UTCHAR *)lpsz++); // PASCAL like string count
|
|
// first UTCHAR is count if TCHARs
|
|
if (wID-- == 0) break;
|
|
lpsz += cch; // Step to start if next string
|
|
}
|
|
|
|
/*
|
|
* chhBufferMax == 0 means return a pointer to the read-only resource buffer.
|
|
*/
|
|
if (cchBufferMax == 0) {
|
|
*(LPTSTR *)lpBuffer = lpsz;
|
|
} else {
|
|
|
|
/*
|
|
* Account for the NULL
|
|
*/
|
|
cchBufferMax--;
|
|
|
|
/*
|
|
* Don't copy more than the max allowed.
|
|
*/
|
|
if (cch > cchBufferMax)
|
|
cch = cchBufferMax;
|
|
|
|
/*
|
|
* Copy the string into the buffer.
|
|
*/
|
|
RtlCopyMemory(lpBuffer, lpsz, cch*sizeof(WCHAR));
|
|
}
|
|
|
|
/*
|
|
* Unlock resource, but don't free it - better performance this
|
|
* way.
|
|
*/
|
|
UNLOCKRESOURCE(hStringSeg, hModule);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Append a NULL.
|
|
*/
|
|
if (cchBufferMax != 0) {
|
|
lpBuffer[cch] = 0;
|
|
}
|
|
|
|
return cch;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* RtlLoadObjectFromDIBFile
|
|
*
|
|
* Loads a resource object from file.
|
|
*
|
|
* 05-Sep-1995 ChrisWil Created.
|
|
\***************************************************************************/
|
|
|
|
#define BITMAPFILEHEADER_SIZE 14
|
|
#define MINHEADERS_SIZE (BITMAPFILEHEADER_SIZE + sizeof(BITMAPCOREHEADER))
|
|
|
|
HANDLE RtlLoadObjectFromDIBFile(
|
|
LPCWSTR lpszName,
|
|
LPWSTR type,
|
|
DWORD cxDesired,
|
|
DWORD cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
FILEINFO fi = { NULL, NULL, NULL };
|
|
HANDLE hFile;
|
|
HANDLE hFileMap = NULL;
|
|
HANDLE hObj = NULL;
|
|
TCHAR szFile[MAX_PATH];
|
|
TCHAR szFile2[MAX_PATH];
|
|
LPWSTR pszFileDummy;
|
|
|
|
if (LR_flags & LR_ENVSUBST) {
|
|
|
|
/*
|
|
* Do any %% string substitutions. We need this feature to handle
|
|
* loading custom cursors and icons from the registry which uses
|
|
* %SystemRoot% in the paths. It also makes the shell's job
|
|
* easier.
|
|
*/
|
|
ExpandEnvironmentStrings(lpszName, szFile2, MAX_PATH);
|
|
|
|
} else {
|
|
|
|
lstrcpyn(szFile2, lpszName, MAX_PATH);
|
|
}
|
|
|
|
if (SearchPath(NULL, // use default search locations
|
|
szFile2, // file name to search for
|
|
NULL, // already have file name extension
|
|
MAX_PATH, // how big is that buffer, anyway?
|
|
szFile, // stick fully qualified path name here
|
|
&pszFileDummy) == 0) {
|
|
RIPERR0(ERROR_FILE_NOT_FOUND, RIP_VERBOSE, "");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Open File for reading.
|
|
*/
|
|
hFile = CreateFileW(szFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
goto Done;
|
|
|
|
/*
|
|
* Create file-mapping for the file in question.
|
|
*/
|
|
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
if (hFileMap == NULL)
|
|
goto CloseDone;
|
|
|
|
/*
|
|
* Map the file into view.
|
|
*/
|
|
fi.pFileMap = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
if (fi.pFileMap == NULL)
|
|
goto CloseDone;
|
|
|
|
fi.pFileEnd = fi.pFileMap + GetFileSize(hFile, NULL);
|
|
fi.pFilePtr = fi.pFileMap;
|
|
fi.pszName = szFile;
|
|
|
|
try {
|
|
switch(PTR_TO_ID(type)) {
|
|
case PTR_TO_ID(RT_BITMAP): {
|
|
|
|
LPBITMAPFILEHEADER pBFH;
|
|
UPBITMAPINFOHEADER upBIH;
|
|
LPBYTE lpBits;
|
|
DWORD cx;
|
|
DWORD cy;
|
|
WORD planes;
|
|
WORD bpp;
|
|
DWORD cbSizeImage = 0;
|
|
DWORD cbSizeFile;
|
|
DWORD cbSizeBits;
|
|
|
|
/*
|
|
* Set the BitmapFileHeader and BitmapInfoHeader pointers.
|
|
*/
|
|
pBFH = (LPBITMAPFILEHEADER)fi.pFileMap;
|
|
upBIH = (UPBITMAPINFOHEADER)(fi.pFileMap + BITMAPFILEHEADER_SIZE);
|
|
|
|
/*
|
|
* Are we dealing with a bitmap file.
|
|
*/
|
|
if (pBFH->bfType != BFT_BITMAP)
|
|
break;
|
|
|
|
/*
|
|
* We need to check the filesize against the potential size of
|
|
* the image. Bad-Bitmaps would otherwise be able to slam us
|
|
* if they lied about the size (and/or) the file is truncated.
|
|
*/
|
|
if (upBIH->biSize == sizeof(BITMAPCOREHEADER)) {
|
|
|
|
cx = ((UPBITMAPCOREHEADER)upBIH)->bcWidth;
|
|
cy = ((UPBITMAPCOREHEADER)upBIH)->bcHeight;
|
|
bpp = ((UPBITMAPCOREHEADER)upBIH)->bcBitCount;
|
|
planes = ((UPBITMAPCOREHEADER)upBIH)->bcPlanes;
|
|
|
|
} else {
|
|
|
|
cx = upBIH->biWidth;
|
|
cy = upBIH->biHeight;
|
|
bpp = upBIH->biBitCount;
|
|
planes = upBIH->biPlanes;
|
|
|
|
if (upBIH->biSizeImage >= sizeof(BITMAPINFOHEADER)) {
|
|
cbSizeImage = upBIH->biSizeImage;
|
|
}
|
|
}
|
|
|
|
cbSizeFile = (DWORD)(fi.pFileEnd - fi.pFileMap);
|
|
cbSizeBits = BitmapSize(cx, cy, planes, bpp);
|
|
|
|
if ((!cbSizeImage && ((cbSizeFile - MINHEADERS_SIZE) < cbSizeBits)) ||
|
|
(cbSizeImage && ((cbSizeFile - MINHEADERS_SIZE) < cbSizeImage))) {
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Get the bits-offset in the file.
|
|
*/
|
|
if ((pBFH->bfOffBits >= (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPCOREHEADER))) &&
|
|
(pBFH->bfOffBits <= (cbSizeFile - cbSizeImage))) {
|
|
|
|
lpBits = ((LPBYTE)upBIH) + pBFH->bfOffBits - sizeof(BITMAPFILEHEADER);
|
|
|
|
} else {
|
|
|
|
lpBits = NULL;
|
|
}
|
|
|
|
/*
|
|
* Convert the dib-on-file to a bitmap-handle. This can
|
|
* convert both CORE and INFO formats.
|
|
*/
|
|
hObj = ConvertDIBBitmap(upBIH,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags,
|
|
NULL,
|
|
&lpBits); // use these bits!
|
|
}
|
|
break;
|
|
|
|
case PTR_TO_ID(RT_CURSOR):
|
|
case PTR_TO_ID(RT_ICON):
|
|
{
|
|
RTAG *prtag;
|
|
ICONFILEHEADER *pifh;
|
|
|
|
/*
|
|
* Is this a RIFF file?
|
|
*/
|
|
prtag = (RTAG *)fi.pFileMap;
|
|
|
|
if (prtag->ckID != FOURCC_RIFF) {
|
|
|
|
NEWHEADER nh;
|
|
|
|
pifh = (ICONFILEHEADER *)fi.pFileMap;
|
|
|
|
/*
|
|
* BUG?: looks like we can load icons as cursors and cursors
|
|
* as icons. Does this work? Is this desired? (SAS)
|
|
*/
|
|
if ((pifh->iReserved != 0) ||
|
|
((pifh->iResourceType != IMAGE_ICON) &&
|
|
(pifh->iResourceType != IMAGE_CURSOR)) ||
|
|
(pifh->cresIcons < 1))
|
|
|
|
break;
|
|
|
|
nh.ResType = ((type == RT_ICON) ? IMAGE_ICON : IMAGE_CURSOR);
|
|
nh.ResCount = pifh->cresIcons;
|
|
nh.Reserved = 0;
|
|
|
|
/*
|
|
* Get the size of the it and meanwhile seek the file pointer
|
|
* to point at the DIB we want. Files that have more than one
|
|
* icon/cursor are treated like a group. In other words,
|
|
* each image is treated like an individual element in the res
|
|
* dir. So we need to pick the best fit one...
|
|
*/
|
|
hObj = IconFromBestImage(pifh,
|
|
&nh,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
} else {
|
|
|
|
BOOL fAni;
|
|
|
|
hObj = LoadCursorIconFromFileMap(&fi,
|
|
&type,
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags,
|
|
&fAni);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
UserAssert(FALSE);
|
|
break;
|
|
} // switch
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
hObj = NULL;
|
|
}
|
|
CloseDone:
|
|
|
|
if (fi.pFileMap != NULL)
|
|
UnmapViewOfFile(fi.pFileMap);
|
|
|
|
if (hFileMap)
|
|
CloseHandle(hFileMap);
|
|
|
|
if (hFile && (hFile != INVALID_HANDLE_VALUE))
|
|
CloseHandle(hFile);
|
|
|
|
Done:
|
|
#if DBG
|
|
if (hObj == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"RtlLoadObjectFromDIBFile: Couldn't read resource from %ws",
|
|
lpszName);
|
|
}
|
|
#endif
|
|
|
|
return hObj;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* IconFromBestImage
|
|
*
|
|
* Creates HICON from best fitting image in the given file.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HICON IconFromBestImage(
|
|
ICONFILEHEADER *pifh,
|
|
LPNEWHEADER lpnhSrc,
|
|
int cxDesired,
|
|
int cyDesired,
|
|
UINT LR_flags)
|
|
{
|
|
UINT iImage;
|
|
UINT iImageBest;
|
|
LPNEWHEADER lpnhDst;
|
|
LPRESDIR lprd;
|
|
LPBYTE lpRes;
|
|
DWORD cbDIB;
|
|
HICON hIcon = NULL;
|
|
IMAGEFILEHEADER *pimh;
|
|
|
|
if (lpnhSrc->ResCount > 1) {
|
|
|
|
/*
|
|
* First, alloc dummy group resource.
|
|
*/
|
|
lpnhDst = (LPNEWHEADER)UserLocalAlloc(0,
|
|
sizeof(NEWHEADER) + (lpnhSrc->ResCount * sizeof(RESDIR)));
|
|
|
|
if (lpnhDst == NULL)
|
|
goto Done;
|
|
|
|
*lpnhDst = *lpnhSrc;
|
|
lprd = (LPRESDIR)(lpnhDst + 1);
|
|
|
|
/*
|
|
* Build up an image directory from the file's image header info.
|
|
*/
|
|
|
|
for (pimh = pifh->imh, iImage=0;
|
|
iImage < lpnhDst->ResCount;
|
|
iImage++, lprd++, pimh++) {
|
|
|
|
/*
|
|
* Fill in RESDIR
|
|
*/
|
|
lprd->Icon.Width = pimh->cx;
|
|
lprd->Icon.Height = pimh->cy;
|
|
lprd->Icon.reserved = 0;
|
|
lprd->BytesInRes = pimh->cbDIB;
|
|
lprd->idIcon = (WORD)iImage; // Make fake ID: the index of the image.
|
|
|
|
if (lpnhDst->ResType == IMAGE_ICON) {
|
|
/*
|
|
* 10/18/2000 - dwaynen
|
|
*
|
|
* For icons, this is really an ICONDIRENTRY (which has
|
|
* wPlanes and wBitCount fields that overlap xHotSpot and
|
|
* yHotSpot!
|
|
*/
|
|
lprd->Icon.ColorCount = pimh->nColors;
|
|
lprd->Planes = pimh->xHotSpot;
|
|
lprd->BitCount = pimh->yHotSpot;
|
|
} else {
|
|
/*
|
|
* 10/18/2000 - dwaynen
|
|
*
|
|
* Hopefully, cursors will only have one image. Otherwise,
|
|
* our selection logic is gonna be screwed up because we don't
|
|
* store the color bit depth! I suppose we could dig out the
|
|
* actual bitmap header and find the info there. Consider doing
|
|
* this if we ever want to support multi-resource cursors.
|
|
*/
|
|
lprd->Icon.ColorCount = 0;
|
|
lprd->Planes = 0;
|
|
lprd->BitCount = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Find the best image in the group
|
|
*/
|
|
iImageBest = LookupIconIdFromDirectoryEx((PBYTE)lpnhDst,
|
|
(lpnhDst->ResType == IMAGE_ICON),
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
/*
|
|
* Get rid of fake group resource
|
|
*/
|
|
UserLocalFree(lpnhDst);
|
|
|
|
} else {
|
|
iImageBest = 0;
|
|
}
|
|
|
|
/*
|
|
* Point to selected image.
|
|
*/
|
|
pimh = &pifh->imh[iImageBest];
|
|
cbDIB = pimh->cbDIB;
|
|
|
|
/*
|
|
* If we're creating a cursor, we have to whack in HOTSPOT in front
|
|
* Regardless of which type we are making, we need to make sure
|
|
* the resource is aligned. Thus we always copy.
|
|
*/
|
|
if (lpnhSrc->ResType == IMAGE_CURSOR)
|
|
cbDIB += sizeof(POINTS);
|
|
|
|
lpRes = (LPBYTE)UserLocalAlloc(0, cbDIB);
|
|
if (lpRes == NULL)
|
|
goto Done;
|
|
|
|
if (lpnhSrc->ResType == IMAGE_CURSOR)
|
|
lpRes += sizeof(POINTS);
|
|
|
|
RtlCopyMemory(lpRes,
|
|
((LPBYTE)pifh) + pimh->offsetDIB,
|
|
pimh->cbDIB);
|
|
|
|
if (lpnhSrc->ResType == IMAGE_CURSOR) {
|
|
|
|
lpRes -= sizeof(POINTS);
|
|
((LPPOINTS)lpRes)->x = pimh->xHotSpot;
|
|
((LPPOINTS)lpRes)->y = pimh->yHotSpot;
|
|
}
|
|
|
|
hIcon = CreateIconFromResourceEx(lpRes,
|
|
cbDIB,
|
|
(lpnhSrc->ResType == IMAGE_ICON),
|
|
0x00030000, // was WIN32VER40
|
|
cxDesired,
|
|
cyDesired,
|
|
LR_flags);
|
|
|
|
UserLocalFree(lpRes);
|
|
|
|
Done:
|
|
|
|
return hIcon;
|
|
}
|