|
|
/****************************** 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; }
|