Leaked source code of windows server 2003
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

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