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.
665 lines
16 KiB
665 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
winres.c
|
|
|
|
Abstract:
|
|
|
|
Functions used to read Windows .EXE/.DRV files to obtain the
|
|
information contained within their resources.
|
|
|
|
Environment:
|
|
|
|
Windows NT Unidrv driver
|
|
|
|
Revision History:
|
|
|
|
dd-mm-yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
HANDLE
|
|
HLoadResourceDLL(
|
|
WINRESDATA *pWinResData,
|
|
PWSTR pwstrResDLL
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This routine loads the resource DLL.
|
|
|
|
Arguments:
|
|
pWinResData Info about Resources
|
|
pwstrResDLL Unqualified resource DLL name
|
|
|
|
|
|
|
|
Return Value:
|
|
Handle to the loaded DLL or NULL for failure
|
|
|
|
Note:
|
|
|
|
10/26/1998 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
|
|
{
|
|
HANDLE hModule = 0;
|
|
PWSTR pwstrQualResDllName = (pWinResData->wchDriverDir);
|
|
PWSTR pwstr;
|
|
|
|
//
|
|
// Make sure that resource DLL name is not qualified.
|
|
//
|
|
if (pwstr = wcsrchr( pwstrResDLL, TEXT('\\')))
|
|
pwstrResDLL = pwstr + 1;
|
|
|
|
//
|
|
// Create the fully qualified Name for resource DLL name. We use
|
|
// wchDriverDir buffer to create the fully qualified name and reset it.
|
|
// Make sure we have enough space.
|
|
//
|
|
if ( (wcslen(pWinResData->wchDriverDir) + wcslen(pwstrResDLL) + 1) > MAX_PATH )
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("HLoadResourceDLL:Length of wchDriverDir + pwstrResDLL longer than MAX_PATH.\n"));
|
|
goto ErrorExit;
|
|
|
|
}
|
|
StringCchCatW(pwstrQualResDllName, CCHOF(pWinResData->wchDriverDir), pwstrResDLL);
|
|
|
|
//
|
|
// Now load the resource.
|
|
//
|
|
#if defined(KERNEL_MODE) && !defined(USERMODE_DRIVER)
|
|
|
|
//
|
|
// For Kernel mode drivers
|
|
//
|
|
hModule = EngLoadModule(pwstrQualResDllName);
|
|
|
|
#else
|
|
|
|
//
|
|
// For user mode drivers and UI module.
|
|
//
|
|
#ifdef WINNT_40 //NT 4.0
|
|
hModule = LoadLibraryEx( pwstrQualResDllName, NULL,
|
|
DONT_RESOLVE_DLL_REFERENCES );
|
|
#else //NT 5.0
|
|
hModule = LoadLibrary(pwstrQualResDllName);
|
|
#endif
|
|
|
|
#endif //defined(KERNEL_MODE) && !defined(USERMODE_DRIVER)
|
|
|
|
if (hModule == NULL)
|
|
{
|
|
ERR(("HLoadResourceDLL:Failed to load resource DLL '%ws': Error = %d\n",
|
|
pwstrQualResDllName,
|
|
GetLastError()));
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
|
|
ErrorExit:
|
|
//
|
|
// Reset the pWinResData->wchDriverDir. Save a '\0' after last backslash.
|
|
//
|
|
*(pWinResData->pwstrLastBackSlash + 1) = NUL;
|
|
return hModule;
|
|
|
|
}
|
|
|
|
BOOL
|
|
BInitWinResData(
|
|
WINRESDATA *pWinResData,
|
|
PWSTR pwstrDriverName,
|
|
PUIINFO pUIInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens the resource file name and init the resource table
|
|
information and initialize the hModule in WINRESDATA
|
|
|
|
Arguments:
|
|
pWinResData - Pointer to WINRESDATA struct
|
|
pwstrDriverName - Fully qualified name of the driver.
|
|
pUIInfo - Pointer to UI info.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
Note:
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR pstr = NULL;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwLen;
|
|
PWSTR pRootResDLLName;
|
|
|
|
//
|
|
// Always assume we are dealing with NT minidrivers
|
|
//
|
|
|
|
ZeroMemory(pWinResData, sizeof( WINRESDATA ));
|
|
|
|
//
|
|
// Check for fully qualified name. If the driver name is not fully qualified
|
|
// then this function will fail.
|
|
//
|
|
|
|
if (pstr = wcsrchr( pwstrDriverName, TEXT('\\')) )
|
|
{
|
|
//
|
|
// wcschr returns pointer to \. We need to add +1 include \ in the
|
|
// driver name to be stored.
|
|
//
|
|
dwLen = (DWORD)((pstr - pwstrDriverName) + 1);
|
|
|
|
//
|
|
// Check if the Length of the driver name is less that MAX_PATH.
|
|
//
|
|
if ((dwLen + 1) > MAX_PATH)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("BInitWinResData:Invalid pwstrDriverName,longer than MAX_PATH.\n"));
|
|
goto ErrorExit;
|
|
}
|
|
//
|
|
// Copy the driver dir name in winresdata. No need to save NULL as
|
|
// winresdata is zero initialised.
|
|
//
|
|
wcsncpy(pWinResData->wchDriverDir,pwstrDriverName, dwLen);
|
|
|
|
//
|
|
// Save the position of the last backslash.
|
|
//
|
|
pWinResData->pwstrLastBackSlash = pWinResData->wchDriverDir +
|
|
wcslen(pWinResData->wchDriverDir) - 1;
|
|
}
|
|
else // Driver name is not qualified. Error.
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("BInitWinResData:Invalid pwstrDriverName,Not qualified.\n"));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Load the root resource DLL
|
|
//
|
|
pRootResDLLName = OFFSET_TO_POINTER(pUIInfo->pubResourceData,
|
|
pUIInfo->loResourceName);
|
|
|
|
if (pRootResDLLName == NULL)
|
|
{
|
|
//
|
|
// This is OK since the GPD is not required to have the *ResourceDLL entry
|
|
//
|
|
// Already did ZeroMemory(pWinResData), no need to set hResDLLModule NULL here.
|
|
//
|
|
VERBOSE(("BInitWinResData: pRootResDLLName is NULL.\n"));
|
|
goto OKExit;
|
|
}
|
|
|
|
pWinResData->hResDLLModule = HLoadResourceDLL(pWinResData, pRootResDLLName);
|
|
|
|
//
|
|
// Check for success
|
|
//
|
|
if (!pWinResData->hResDLLModule)
|
|
{
|
|
//
|
|
// If GPD does specify *ResourceDLL but we can't load it, we will fail.
|
|
//
|
|
ERR(("BInitWinResData:Failed to load root resource DLL '%ws': Error = %d\n",
|
|
pRootResDLLName,
|
|
GetLastError()));
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
OKExit:
|
|
|
|
//
|
|
// Success so save the UI info in Winresdata.
|
|
//
|
|
bRet = TRUE;
|
|
pWinResData->pUIInfo = pUIInfo;
|
|
|
|
ErrorExit:
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
PGetResourceDLL(
|
|
PUIINFO pUIInfo,
|
|
PQUALNAMEEX pResQual
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This routine gets the resouce handle from the handle array. If the DLL is
|
|
not loaded then it loads it.
|
|
|
|
Arguments:
|
|
pResQual UI Info pointer
|
|
pResQual Pointer to qualified ID structure. It contains the info
|
|
about resource dll name and resource ID.
|
|
|
|
|
|
|
|
Return Value:
|
|
Name of the resource DLL or NULL for failure
|
|
|
|
Note:
|
|
|
|
10/26/1998 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
{
|
|
PFEATURE pResFeature;
|
|
POPTION pResOption;
|
|
PTSTR ptstrResDllName = NULL;
|
|
|
|
if (pUIInfo)
|
|
{
|
|
//
|
|
// Go to the start of the feature list.
|
|
//
|
|
pResFeature = PGetIndexedFeature(pUIInfo, 0);
|
|
|
|
if (pResFeature)
|
|
{
|
|
//
|
|
// Add the feature ID to featuer pointer to get Resource feature.
|
|
//
|
|
pResFeature += pResQual->bFeatureID;
|
|
|
|
if (pResOption = (PGetIndexedOption(pUIInfo, pResFeature, pResQual->bOptionID & 0x7f)))
|
|
{
|
|
ptstrResDllName = OFFSET_TO_POINTER(pUIInfo->pubResourceData,
|
|
pResOption->loDisplayName);
|
|
|
|
if (ptstrResDllName == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("PGetResourceDLL:Resource DLL name is not specified\n"));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("PGetResourceDLL:NULL resource option.\n"));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("PGetResourceDLL:NULL resource Feature.\n"));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("PGetResourceDLL:NULL pUIInfo.\n"));
|
|
|
|
}
|
|
return ptstrResDllName;
|
|
}
|
|
|
|
HANDLE
|
|
HGetModuleHandle(
|
|
WINRESDATA *pWinResData,
|
|
PQUALNAMEEX pQualifiedID
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This routine gets the resouce handle from the handle array. If the DLL is
|
|
not loaded then it loads it.
|
|
|
|
Arguments:
|
|
pWinResData Info about Resources
|
|
pQualifiedID Pointer to qualified ID structure. It contains the info
|
|
about resource dll name and resource ID.
|
|
|
|
|
|
|
|
Return Value:
|
|
Handle to the loaded DLL or NULL for failure
|
|
|
|
Note:
|
|
|
|
10/26/1998 -ganeshp-
|
|
Created it.
|
|
--*/
|
|
{
|
|
HANDLE hModule = 0 ;
|
|
PWSTR pResDLLName;
|
|
INT iResDLLID;
|
|
|
|
//
|
|
// Only the low 7 bits of bOptionID are valid. So mask them.
|
|
//
|
|
iResDLLID = (pQualifiedID->bOptionID & 0x7f);
|
|
|
|
if (iResDLLID >= MAX_RESOURCE)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("HGetModuleHandle:Res DLL ID (%d) larger than MAX_RESOURCE (%d).\n",
|
|
iResDLLID, MAX_RESOURCE));
|
|
return 0 ;
|
|
}
|
|
|
|
//
|
|
// Check for predefined system paper names.
|
|
//
|
|
if ((*((PDWORD)pQualifiedID) & 0x7FFFFFFF) == RCID_DMPAPER_SYSTEM_NAME)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("RCID_DMPAPER_SYSTEM_NAME is not a valid qualified resource name.\n"));
|
|
return 0 ;
|
|
}
|
|
|
|
//
|
|
// Check for the root resource DLL.
|
|
//
|
|
if (pQualifiedID->bFeatureID == 0 && iResDLLID == 0)
|
|
{
|
|
hModule = pWinResData->hResDLLModule;
|
|
}
|
|
else
|
|
{
|
|
hModule = pWinResData->ahModule[iResDLLID];
|
|
|
|
//
|
|
// The module is not loaded so load it.
|
|
//
|
|
if (!hModule)
|
|
{
|
|
//
|
|
// Get the resource DLL name form Qualified ID.
|
|
//
|
|
if (pResDLLName = PGetResourceDLL(pWinResData->pUIInfo,pQualifiedID) )
|
|
{
|
|
hModule = HLoadResourceDLL(pWinResData,pResDLLName);
|
|
|
|
//
|
|
// If successful loading then save the values in handle array
|
|
// and increament the counter.
|
|
//
|
|
if (hModule)
|
|
{
|
|
pWinResData->ahModule[iResDLLID] = hModule;
|
|
pWinResData->cLoadedEntries++;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
ERR(("HGetModuleHandle:Can't find Resource DLL name in UIINFO.\n"));
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hModule;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BGetWinRes(
|
|
WINRESDATA *pWinResData,
|
|
PQUALNAMEEX pQualifiedID,
|
|
INT iType,
|
|
RES_ELEM *pRInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get Windows Resource Data for the caller
|
|
|
|
Arguments:
|
|
pWinResData - Pointer to WINRESDATA struct
|
|
iQualifiedName - The fully qualified entry name
|
|
iType - Type of resource
|
|
pRInfo - Results info
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
INT iName;
|
|
HANDLE hModule;
|
|
|
|
iName = (INT)pQualifiedID->wResourceID;
|
|
|
|
if (hModule = HGetModuleHandle(pWinResData, pQualifiedID))
|
|
{
|
|
//
|
|
// Now Find the resource.
|
|
//
|
|
#if defined(KERNEL_MODE) && !defined(USERMODE_DRIVER)
|
|
|
|
//
|
|
// For Kernel mode drivers
|
|
//
|
|
pRInfo->pvResData = EngFindResource(
|
|
hModule,
|
|
iName,
|
|
iType,
|
|
&pRInfo->iResLen);
|
|
|
|
|
|
#else
|
|
|
|
//
|
|
// For user mode drivers and UI module.
|
|
//
|
|
{
|
|
HRSRC hRes;
|
|
HGLOBAL hLoadRes;
|
|
|
|
if( !(hRes = FindResource( hModule, (LPCTSTR)IntToPtr(iName), (LPCTSTR)IntToPtr(iType))) ||
|
|
!(hLoadRes = LoadResource( hModule, hRes )) ||
|
|
!(pRInfo->pvResData = LockResource(hLoadRes)) )
|
|
return FALSE;
|
|
|
|
pRInfo->iResLen = SizeofResource( hModule, hRes );
|
|
}
|
|
|
|
#endif //defined(KERNEL_MODE) && !defined(USERMODE_DRIVER)
|
|
|
|
return(pRInfo->pvResData != NULL);
|
|
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
VWinResClose(
|
|
WINRESDATA *pWinResData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function frees the resources allocated with this module. This
|
|
includes any memory allocated and the file handle to the driver.
|
|
|
|
Arguments:
|
|
pWinResData - Pointer to WINRESDATA struct
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Free used resources. Which resources are used has been recorded
|
|
// in the Handle array field of the WINRESDATA structure passed in to us.
|
|
// First free the root resource DLL and other DLLs.
|
|
|
|
INT iI;
|
|
|
|
#if defined(KERNEL_MODE) && !defined(USERMODE_DRIVER)
|
|
|
|
//
|
|
// For Kernel mode drivers
|
|
//
|
|
if (pWinResData->hResDLLModule)
|
|
{
|
|
EngFreeModule(pWinResData->hResDLLModule);
|
|
}
|
|
|
|
for (iI = 0; iI < MAX_RESOURCE; iI++)
|
|
{
|
|
if(pWinResData->ahModule[iI])
|
|
EngFreeModule(pWinResData->ahModule[iI]);
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
//
|
|
// For user mode drivers and UI module.
|
|
//
|
|
|
|
if (pWinResData->hResDLLModule)
|
|
{
|
|
FreeLibrary(pWinResData->hResDLLModule);
|
|
}
|
|
|
|
for (iI = 0; iI < MAX_RESOURCE; iI++)
|
|
{
|
|
if(pWinResData->ahModule[iI])
|
|
FreeLibrary(pWinResData->ahModule[iI]);
|
|
}
|
|
|
|
#endif //defined(KERNEL_MODE) && !defined(USERMODE_DRIVER)
|
|
|
|
//
|
|
// Reinitialize with ZeroFill.
|
|
//
|
|
ZeroMemory(pWinResData, sizeof( WINRESDATA ));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
INT
|
|
ILoadStringW (
|
|
WINRESDATA *pWinResData,
|
|
INT iID,
|
|
PWSTR wstrBuf,
|
|
WORD wBuf
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies the requested resource name into the buffer provided
|
|
and return the size of the resource string copied.
|
|
|
|
Arguments:
|
|
|
|
pWinResData - Pointer to WINRESDATA struct
|
|
iID - Resource ID
|
|
wstrBuf - Buffer to receive name
|
|
wBuf - Size of the buffer in number of characters
|
|
|
|
Return Value:
|
|
|
|
The number of characters of the resource string copied into wstrBuf
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// The string resources are stored in groups of 16. SO, the
|
|
// 4 LSBs of iID select which of the 16(entry name), 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.
|
|
//
|
|
|
|
INT iSize,iResID;
|
|
BYTE *pb;
|
|
WCHAR *pwch;
|
|
RES_ELEM RInfo;
|
|
PQUALNAMEEX pQualifiedID;
|
|
|
|
pQualifiedID = (PQUALNAMEEX)&iID;
|
|
|
|
iResID = pQualifiedID->wResourceID;
|
|
pQualifiedID->wResourceID = (pQualifiedID->wResourceID >> 4) + 1;
|
|
|
|
//
|
|
// Get entry name for resource
|
|
//
|
|
|
|
if( !BGetWinRes( pWinResData, (PQUALNAMEEX)&iID, WINRT_STRING, &RInfo ) ||
|
|
wBuf < sizeof( WCHAR ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Get the group ID
|
|
//
|
|
iResID &= 0xf;
|
|
|
|
//
|
|
// wBuf 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.
|
|
//
|
|
|
|
wBuf-- ;
|
|
|
|
pwch = RInfo.pvResData;
|
|
|
|
while( --iResID >= 0 )
|
|
pwch += 1 + *pwch;
|
|
|
|
if( iSize = *pwch )
|
|
{
|
|
if( iSize > wBuf )
|
|
iSize = wBuf;
|
|
|
|
wstrBuf[ iSize ] = (WCHAR)0;
|
|
iSize *= sizeof( WCHAR );
|
|
memcpy( wstrBuf, ++pwch, iSize );
|
|
|
|
}
|
|
return (iSize/sizeof( WCHAR ) ); // number of characters written
|
|
}
|
|
|
|
|