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