mirror of https://github.com/lianthony/NT4.0
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.
740 lines
21 KiB
740 lines
21 KiB
/*************************** Module Header **********************************
|
|
* winres.c
|
|
* Functions used to read windows 3.0 .exe/.drv files and obtain
|
|
* the information contained within their resources. Also handles
|
|
* NT format files, and processes them transparently.
|
|
*
|
|
* HISTORY:
|
|
* 09:18 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Created it, after investigating Windows/DOS etc.
|
|
*
|
|
* Copyright (C) 1990 Microsoft Corporation
|
|
*
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
|
|
#include "winres.h"
|
|
#include "newexe.h"
|
|
#include "libproto.h"
|
|
|
|
/*
|
|
* Some defines to maintain old names used in the above structure.
|
|
*/
|
|
|
|
#define hFile uh.hFILE
|
|
#define hMod uh.hMOD
|
|
|
|
#define pResData ur.pRESDATA
|
|
#define hLoadRes ur.hLOAD
|
|
|
|
/*
|
|
* Private function prototypes.
|
|
*/
|
|
|
|
static int GetExeHeader( WINRESDATA *, NEW_EXE * );
|
|
static BOOL GetExeResTab( WINRESDATA * );
|
|
static long ResDataSum( WINRESDATA * );
|
|
static BOOL LoadWinResData( WINRESDATA * );
|
|
|
|
/* !!!LindsayH: quick & dirty unicode conversion */
|
|
#define AtoWc( x ) ((x) & 0xff)
|
|
|
|
|
|
/************************** Function Header ********************************
|
|
* iLoadStringW
|
|
* Function to return a copy of a null terminated string from a
|
|
* minidriver resource. Similiar to windows function of same name.
|
|
*
|
|
* RETURNS:
|
|
* Number of (wide) chars in string (NOT including null). 0 if missing.
|
|
*
|
|
* HISTORY:
|
|
* 10:03 on Mon 09 Mar 1992 -by- Lindsay Harris [lindsayh]
|
|
* Converted to use UNICODE NT resources & convert Win 3.X
|
|
*
|
|
* 15:17 on Thu 27 Jun 1991 -by- Lindsay Harris [lindsayh]
|
|
* Moved from specdata.c - prepare to split from rasdd in toto.
|
|
*
|
|
* 12:04 on Fri 30 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Created it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
int
|
|
iLoadStringW( pWRD, iID, wstrBuf, cBuf )
|
|
WINRESDATA *pWRD; /* Key to the data */
|
|
int iID; /* Resource "name" */
|
|
PWSTR wstrBuf; /* Place to put data */
|
|
UINT cBuf; /* Bytes in above */
|
|
{
|
|
/*
|
|
* The string resources are stored in groups of 16. SO, the
|
|
* 4 LSBs of iID select which of the 16, while the remainder
|
|
* select the group.
|
|
* Each string resource contains a count byte followed by that
|
|
* many bytes of data WITHOUT A NULL. Entries that are missing
|
|
* have a 0 count.
|
|
*/
|
|
|
|
UINT iSize;
|
|
BYTE *pb;
|
|
WCHAR *pwch; /* The wide version */
|
|
|
|
RES_ELEM RInfo; /* Resource information */
|
|
|
|
|
|
if( !GetWinRes( pWRD, (iID >> 4) + 1, WINRT_STRING, &RInfo ) ||
|
|
cBuf < sizeof( WCHAR ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
iID &= 0xf; /* The string within this resource element */
|
|
|
|
/*
|
|
* cBuf has some limit on sensible sizes. For one, it should be
|
|
* a multiple of sizeof( WCHAR ). Secondly, we want to put a 0
|
|
* to terminate the string, so add that in now.
|
|
*/
|
|
|
|
cBuf = (cBuf & ~(sizeof( WCHAR ) - 1)) - sizeof( WCHAR );
|
|
|
|
if( pWRD->fStatus & WRD_NT_DLL )
|
|
{
|
|
/*
|
|
* This means we are UNICODE to start with. It also means
|
|
* we have 16 bits widths too!
|
|
*/
|
|
|
|
pwch = RInfo.pvResData;
|
|
|
|
while( --iID >= 0 )
|
|
pwch += 1 + *pwch;
|
|
|
|
if( iSize = *pwch )
|
|
{
|
|
/* There is a string: so copy it across */
|
|
|
|
if( iSize > cBuf )
|
|
iSize = cBuf;
|
|
|
|
wstrBuf[ iSize ] = (WCHAR)0;
|
|
iSize *= sizeof( WCHAR ); /* Into bytes */
|
|
memcpy( wstrBuf, ++pwch, iSize );
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
/*
|
|
* Byte data: Scan looking for the desired element.
|
|
*/
|
|
|
|
pb = RInfo.pvResData; /* Start of data segment */
|
|
|
|
while( --iID >= 0 )
|
|
pb += 1 + *pb; /* Skip count and string (if any) */
|
|
|
|
if( iSize = *pb )
|
|
{
|
|
/* Got some data!! */
|
|
int iI;
|
|
|
|
|
|
iSize *= sizeof( WCHAR ); /* Into WCHARs */
|
|
|
|
if( iSize > cBuf )
|
|
iSize = cBuf;
|
|
|
|
for( pwch = wstrBuf, iI = iSize; iI > 0; iI -= sizeof( WCHAR ) )
|
|
*pwch++ = AtoWc( *++pb );
|
|
|
|
*pwch = (WCHAR)0;
|
|
}
|
|
|
|
}
|
|
|
|
return iSize;
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************ Function Header **********************************
|
|
* GetWinRes
|
|
* Returns a pointer to the selected resource from a windows minidriver.
|
|
* Note that the return value is only valid until the next call
|
|
* to this function.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE - TRUE for success.
|
|
*
|
|
* HISTORY:
|
|
* 09:50 on Fri 30 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Created it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL
|
|
GetWinRes( pWRD, iName, iType, pRInfo )
|
|
WINRESDATA *pWRD; /* All the info we need */
|
|
int iName; /* The specific entry */
|
|
int iType; /* Type (e.g. string, menu etc */
|
|
RES_ELEM *pRInfo; /* Full details of results */
|
|
{
|
|
/*
|
|
* The WinResData passed in contains all the information we need
|
|
* about the resource data, and so we can consulting the resource
|
|
* table it contains and so determine the location in the file/memory
|
|
* where the data is located.
|
|
*/
|
|
|
|
int iLoop;
|
|
WORD wID;
|
|
|
|
RSRC_TYPEINFO *pRSType;
|
|
RSRC_NAMEINFO *pRNType;
|
|
|
|
|
|
|
|
if( pWRD->fStatus & WRD_NT_DLL )
|
|
{
|
|
/* NT style DLL, so we can use the standard calls for this one. */
|
|
HANDLE hRes;
|
|
|
|
if( pWRD->hLoadRes )
|
|
{
|
|
/* Unlock any resource locked last time through */
|
|
|
|
UnlockResource( pWRD->hLoadRes );
|
|
FreeResource( pWRD->hLoadRes );
|
|
|
|
pWRD->hLoadRes = 0; /* Mark it as free */
|
|
}
|
|
|
|
if( !(hRes = FindResource( pWRD->hFile, (LPCTSTR)iName, (LPCTSTR)iType )) ||
|
|
!(pWRD->hLoadRes = LoadResource( pWRD->hFile, hRes )) ||
|
|
!(pRInfo->pvResData = LockResource( pWRD->hLoadRes )) )
|
|
return FALSE;
|
|
|
|
|
|
pRInfo->iResLen = SizeofResource( pWRD->hFile, hRes );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
wID = (WORD)(iType | RSORDID); /* Only type we can handle */
|
|
|
|
/*
|
|
* Scan the resource table data, looking for the desired type.
|
|
*/
|
|
|
|
pRSType = (RSRC_TYPEINFO *)pWRD->paResTab;
|
|
|
|
while( pRSType->rt_id && pRSType->rt_id != wID )
|
|
{
|
|
/*
|
|
* Find the next entry. The data layout is explained in the
|
|
* WinResSize() function.
|
|
*/
|
|
|
|
pRSType = (RSRC_TYPEINFO *)((char *)pRSType + pRSType->rt_nres * sizeof( RSRC_NAMEINFO ));
|
|
++pRSType;
|
|
|
|
}
|
|
|
|
if( pRSType->rt_id == 0 )
|
|
{
|
|
SetLastError( ERROR_BAD_FORMAT );
|
|
|
|
return FALSE; /* Nothing there */
|
|
}
|
|
|
|
/*
|
|
* Now have the resource type, we need to find the specific piece
|
|
* of data requested by the caller. This requires looping through the
|
|
* name structures following the type structure we are looking at.
|
|
*/
|
|
|
|
iLoop = pRSType->rt_nres;
|
|
pRNType = (RSRC_NAMEINFO *)++pRSType;
|
|
wID = (WORD)(iName | RSORDID);
|
|
|
|
while( --iLoop >= 0 && pRNType->rn_id != wID )
|
|
++pRNType;
|
|
|
|
if( iLoop < 0 )
|
|
{
|
|
/* Not available here, so skip report the bad news */
|
|
SetLastError( ERROR_BAD_FORMAT );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Now a little fiddling with addresses, and we have the data
|
|
* to return to our caller. pRNType contains an offset and length
|
|
* field - these need to be shifted to turn into real numbers.
|
|
*/
|
|
|
|
pRInfo->iResLen = pRNType->rn_length << pWRD->iShift;
|
|
pRInfo->pvResData = (char *)pWRD->pResData +
|
|
(pRNType->rn_offset << pWRD->iShift) - pWRD->lResOffset;
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/************************ Function Header **********************************
|
|
* InitWinResData
|
|
* Opens the named file and initialises the resource table information.
|
|
* Requires a partially filled in WINRESDATA structure. This needs
|
|
* to have the heap handle initialised. Then allocate storage and
|
|
* load the data from the file.
|
|
*
|
|
* RETURNS:
|
|
* TRUE - file opened, data read, structures initialised.
|
|
* FALSE - none of the above.
|
|
*
|
|
* HISTORY:
|
|
* 13:35 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
|
|
* Try NT format dll first, then Windows 16 if NT fails
|
|
*
|
|
* 13:08 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
|
|
* Changed name; called LoadWinResData to load resources
|
|
*
|
|
* 09:30 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* First version.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL
|
|
InitWinResData( pWinResData, hHeap, pwstrDllName )
|
|
register WINRESDATA *pWinResData; /* Data area to fill in */
|
|
HANDLE hHeap; /* For heap access */
|
|
PWSTR pwstrDllName; /* Name to try opening as a DLL */
|
|
{
|
|
|
|
/*
|
|
* We may have an NT or a Windows 16 minidriver to process!
|
|
* Assume that it is an NT minidriver - until proven wrong. So
|
|
* try LoadLibrary on it, then a GetProcAddr. If both of these
|
|
* succeed, it is presumed to be an NT module, and so all
|
|
* that is needed is to return the module handle in pWinResData,
|
|
* and set the flag saying it is an NT DLL!
|
|
*/
|
|
|
|
DWORD dwOldErrMode; /* Save it for later */
|
|
|
|
|
|
|
|
memset( pWinResData, 0, sizeof( WINRESDATA ) );
|
|
pWinResData->hHeap = hHeap; /* For later */
|
|
|
|
dwOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
pWinResData->hMod = LoadLibraryEx( pwstrDllName, NULL,
|
|
DONT_RESOLVE_DLL_REFERENCES );
|
|
|
|
SetErrorMode( dwOldErrMode ); /* Restore error mode */
|
|
|
|
if( pWinResData->hMod )
|
|
{
|
|
/* So far, so good! Look for the magic entry point */
|
|
|
|
if( GetProcAddress( pWinResData->hMod, "bInitProc" ) )
|
|
{
|
|
/* Assume it's good, so set the flag & return */
|
|
pWinResData->fStatus = WRD_NT_DLL;
|
|
|
|
return TRUE;
|
|
}
|
|
FreeLibrary( pWinResData->hMod ); /* No good! */
|
|
}
|
|
|
|
/*
|
|
* Next step is to open the file and read in the header info.
|
|
* The first header contains little information that is of use
|
|
* to us. Basically it contains the file address of the new header.
|
|
* The new header contains the location of the resource data.
|
|
*/
|
|
|
|
|
|
pWinResData->hFile = CreateFileW( pwstrDllName, GENERIC_READ,
|
|
FILE_SHARE_READ, 0, OPEN_EXISTING,
|
|
0, 0 );
|
|
|
|
if( pWinResData->hFile == (HANDLE)~0 )
|
|
return FALSE;
|
|
|
|
|
|
pWinResData->fStatus = WRD_FOPEN; /* Know that we need to close */
|
|
|
|
if( !GetExeResTab( pWinResData ) )
|
|
{
|
|
WinResClose( pWinResData );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Allocate memory and read the data in.
|
|
*/
|
|
|
|
if( !LoadWinResData( pWinResData ) )
|
|
{
|
|
WinResClose( pWinResData );
|
|
|
|
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/************************** Function Header *******************************
|
|
* LoadWinResData
|
|
* Retrieve the resource data from the minidriver file.
|
|
*
|
|
* RETURNS:
|
|
* TRUE for success, FALSE for failure.
|
|
*
|
|
* HISTORY
|
|
* 13:09 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
|
|
* Changed name from GetWinResData; made local function only
|
|
*
|
|
* 13:39 on Thu 29 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Time = 0
|
|
*
|
|
**************************************************************************/
|
|
|
|
static BOOL
|
|
LoadWinResData( pWRD )
|
|
WINRESDATA *pWRD;
|
|
{
|
|
DWORD lSize; /* Determine how big they are */
|
|
DWORD lSize2; /* 'Cos of silly ReadFile parameters */
|
|
|
|
/*
|
|
* Determine the length of the resource data in the file, then
|
|
* allocate storage and read it all in. Not that hard!
|
|
*/
|
|
|
|
if( (lSize = ResDataSum( pWRD )) == 0 )
|
|
{
|
|
/* Zero length is not a good sign! */
|
|
return FALSE;
|
|
}
|
|
|
|
if( !(pWRD->pResData = (void *)GlobalAlloc( GMEM_FIXED, lSize )) )
|
|
return FALSE;
|
|
|
|
|
|
/*
|
|
* Now read the data - ASSUME IT IS CONTIGUOUS!!!
|
|
*/
|
|
|
|
/* !!!LindsayH - as the resource data COULD be quite large, we should
|
|
* be careful here, and perhaps set a size limit, above which the
|
|
* the data is paged. For now, assume the data is small enough
|
|
* to handle in one chunk.
|
|
*/
|
|
|
|
if( SetFilePointer( pWRD->hFile, pWRD->lResOffset, NULL, FILE_BEGIN ) == -1)
|
|
return FALSE;
|
|
|
|
|
|
if( !ReadFile( pWRD->hFile, pWRD->pResData, lSize, &lSize2, NULL ) ||
|
|
lSize != lSize2 )
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************** Function Header *******************************
|
|
* ResDataSum
|
|
* Determine the size and starting location of the resource data
|
|
* in the minidriver file.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE, TRUE for success.
|
|
*
|
|
* HISTORY
|
|
* 14:52 on Thu 29 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Creation time
|
|
*
|
|
**************************************************************************/
|
|
|
|
static long
|
|
ResDataSum( pWRD )
|
|
WINRESDATA *pWRD;
|
|
{
|
|
/*
|
|
* The data consists of a RSRC_TYPEINFO structure, followed by
|
|
* an array of RSRC_NAMEINFO structures, which are then followed
|
|
* by a RSRC_TYPEINFO structure, again followed by an array of
|
|
* RSRC_NAMEINFO structures. This continues until an RSRC_TYPEINFO
|
|
* structure which has a 0 in the rt_id field.
|
|
*/
|
|
|
|
long lSize;
|
|
unsigned short usOffset; /* Find lowest offset of resources */
|
|
|
|
RSRC_TYPEINFO *pRSType;
|
|
RSRC_NAMEINFO *pRSName;
|
|
|
|
|
|
lSize = 0;
|
|
pRSType = (RSRC_TYPEINFO *)(pWRD->paResTab);
|
|
usOffset = (unsigned short)~0;
|
|
|
|
while( pRSType->rt_id )
|
|
{
|
|
int cNames;
|
|
|
|
/* Each TYPE contains a count of the number of NAMEs following */
|
|
cNames = pRSType->rt_nres;
|
|
++pRSType; /* Skip over that one */
|
|
|
|
for( pRSName = (RSRC_NAMEINFO *)pRSType; --cNames >= 0; ++pRSName )
|
|
{
|
|
lSize += pRSName->rn_length;
|
|
if( usOffset > pRSName->rn_offset )
|
|
usOffset = pRSName->rn_offset;
|
|
}
|
|
|
|
pRSType = (RSRC_TYPEINFO *)pRSName;
|
|
}
|
|
pWRD->lResOffset = (LONG)usOffset << pWRD->iShift;
|
|
pWRD->cbResData = lSize <<= pWRD->iShift;
|
|
|
|
return lSize;
|
|
}
|
|
|
|
/************************** Function Header *******************************
|
|
* WinResClose
|
|
* Free the resources associated with this module. This includes
|
|
* any memory allocated, and also the file handle to the driver.
|
|
*
|
|
* RETURNS:
|
|
* Nothing
|
|
*
|
|
* 13:36 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
|
|
* Disengage NT resource mechanism if that has been used.
|
|
*
|
|
* 14:22 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Creation
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
WinResClose( pWinResData )
|
|
WINRESDATA *pWinResData;
|
|
{
|
|
/*
|
|
* Free used resources. Which resources are used has been recorded
|
|
* in the fStatus field of the WINRESDATA structure passed in to us.
|
|
*/
|
|
|
|
|
|
if( pWinResData->fStatus & WRD_NT_DLL )
|
|
{
|
|
/* An NT DLL - so free it up! */
|
|
|
|
if( pWinResData->hLoadRes )
|
|
{
|
|
/* A resource is being used - free it */
|
|
UnlockResource( pWinResData->hLoadRes );
|
|
FreeResource( pWinResData->hLoadRes );
|
|
|
|
pWinResData->hLoadRes = 0; /* Mark it as free */
|
|
}
|
|
|
|
FreeLibrary( pWinResData->hMod );
|
|
}
|
|
|
|
if( pWinResData->fStatus & WRD_FOPEN )
|
|
{
|
|
/* File opened, so close it. */
|
|
CloseHandle( pWinResData->hFile );
|
|
}
|
|
|
|
if( pWinResData->pResTab )
|
|
{
|
|
/* Resource table is allocated - free it */
|
|
GlobalFree( pWinResData->pResTab );
|
|
pWinResData->pResTab = 0;
|
|
}
|
|
|
|
if( pWinResData->pResData )
|
|
{
|
|
/* Resource table is allocated - free it */
|
|
GlobalFree( pWinResData->pResData );
|
|
pWinResData->pResData = 0;
|
|
}
|
|
|
|
pWinResData->fStatus = WRD_NOTHING; /* Zero, actually */
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*************************** Function Header *******************************
|
|
* GetExeResTab
|
|
* Reads the .exe resource table from the file, and installs the
|
|
* relevant data in the WINRESDATA structure passed in.
|
|
*
|
|
* RETURNS:
|
|
* FALSE on error, TRUE on success.
|
|
*
|
|
* HISTORY:
|
|
* 15:15 on Mon 11 May 1992 -by- Lindsay Harris [lindsayh]
|
|
* Changed to delete NEW_RSRC structure x on stack
|
|
*
|
|
* 14:17 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
* Must be the initial version.
|
|
*
|
|
**************************************************************************/
|
|
|
|
static BOOL
|
|
GetExeResTab( pWRD )
|
|
WINRESDATA *pWRD;
|
|
{
|
|
|
|
|
|
DWORD dwSilly; /* For new, detiorated ReadFile call */
|
|
|
|
NEW_EXE NewExe; /* New header - for ease of manipulation */
|
|
|
|
|
|
|
|
if( !(pWRD->cbResTab = GetExeHeader( pWRD, &NewExe )) )
|
|
return FALSE;
|
|
|
|
if( !(pWRD->pResTab = (void *)GlobalAlloc( GMEM_FIXED, pWRD->cbResTab )) )
|
|
return FALSE; /* Caller cleans up */
|
|
|
|
/*
|
|
* Read the resource table data. This is all that's required to
|
|
* learn all that is of interest to us about the resources.
|
|
*/
|
|
if( SetFilePointer( pWRD->hFile,
|
|
NewExe.ne_rsrctab + pWRD->lNewExe,
|
|
NULL, FILE_BEGIN ) == -1 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if( !ReadFile( pWRD->hFile, pWRD->pResTab, pWRD->cbResTab, &dwSilly,NULL) ||
|
|
(DWORD)pWRD->cbResTab != dwSilly )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* IMPORTANT: record the shift information for size & offsets */
|
|
pWRD->iShift = ((NEW_RSRC *)(pWRD->pResTab))->rs_align;
|
|
|
|
/*
|
|
* ALSO ADD 2 TO THE ADDRESS. THIS IS MESSY, BUT THE COMPILER
|
|
* HAS ALIGNED THE ELEMENTS OF NEW_RSRC TYPE, SO THAT TAKING THE
|
|
* ADDRESS OF NEW_RSRC.rs_typeinfo PRODUCES A RESULT 2 BIGGER THAN
|
|
* EXPECTED. THE COMPILER DOES THE RIGHT THING HERE, BUT THE DATA
|
|
* ON THE DISK IS NOT LAID OUT HOW THE COMPILER DOES IT IN MEMORY
|
|
* WHEN GENERATING CODE FOR A 32 BIT ENVIRONMENT. SINCE THE DISK
|
|
* LAYOUT IS PREDETERMINED, WE NEED TO ADJUST THE POINTER.
|
|
*/
|
|
|
|
pWRD->paResTab = (BYTE *)(pWRD->pResTab) +
|
|
sizeof( ((NEW_RSRC *)0)->rs_align );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************ Function Header *********************************
|
|
* GetExeHeader
|
|
* Reads the new header associated with .exe files, and returns its
|
|
* size. A zero return indicates an error: either an explicit
|
|
* error (e.g. I/O error), or an absence of resources.
|
|
*
|
|
* RETURNS:
|
|
* Number of bytes in resourc table, else 0 on error.
|
|
*
|
|
* 14:13 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
|
|
*
|
|
**************************************************************************/
|
|
|
|
static int
|
|
GetExeHeader( pWRD, pNewExe )
|
|
WINRESDATA *pWRD; /* The magic data we need */
|
|
NEW_EXE *pNewExe; /* Where new header is placed */
|
|
{
|
|
/*
|
|
* Read the old header to get the location of the new header.
|
|
* Also check the old header's magic value, for verification.
|
|
*/
|
|
|
|
DWORD dwSilly;
|
|
|
|
EXE_HDR ExeHdr; /* Old format, at beginning of file */
|
|
|
|
if( !ReadFile( pWRD->hFile, &ExeHdr, sizeof( ExeHdr ), &dwSilly, NULL ) ||
|
|
dwSilly != sizeof( ExeHdr ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if( ExeHdr.e_magic != EMAGIC )
|
|
{
|
|
SetLastError( ERROR_BAD_FORMAT );
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
* The e_lfanew field in ExeHdr contains the file location of the
|
|
* new header, so we need to seek to that location.
|
|
*/
|
|
|
|
pWRD->lNewExe = ExeHdr.e_lfanew; /* Offsets are relative to here */
|
|
if( SetFilePointer( pWRD->hFile, ExeHdr.e_lfanew, NULL, FILE_BEGIN ) == -1 )
|
|
return 0;
|
|
|
|
|
|
if( !ReadFile( pWRD->hFile, pNewExe, sizeof( NEW_EXE ), &dwSilly, NULL ) ||
|
|
dwSilly != sizeof( NEW_EXE ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( pNewExe->ne_magic != NEMAGIC )
|
|
{
|
|
SetLastError( ERROR_BAD_FORMAT );
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
* The following test is applied by DOS, so I presume that it is
|
|
* legitimate. The assumption is that the resident name table
|
|
* FOLLOWS the resource table directly, and that if it points to
|
|
* the same location as the resource table, then there are no
|
|
* resources.
|
|
*/
|
|
|
|
if( pNewExe->ne_rsrctab == pNewExe->ne_restab )
|
|
SetLastError( ERROR_BAD_FORMAT );
|
|
|
|
|
|
return pNewExe->ne_restab - pNewExe->ne_rsrctab;
|
|
}
|