From ce8217734e83a1a0ebc21adb9fd8cb6d726cb09a Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Sun, 31 Jan 1999 10:11:54 +0000 Subject: [PATCH] Implementation of VERSION.DLL. Based on old misc/ver.c. - Accessing PE version info resources should work correctly now. - Fixed memory leaks. - Clean separation of 16- and 32-bit parts. - Minor bugfixes. --- dlls/version/.cvsignore | 1 + dlls/version/Makefile.in | 17 ++ dlls/version/info.c | 577 ++++++++++++++++++++++++++++++++++++++ dlls/version/install.c | 578 +++++++++++++++++++++++++++++++++++++++ dlls/version/resource.c | 329 ++++++++++++++++++++++ 5 files changed, 1502 insertions(+) create mode 100644 dlls/version/.cvsignore create mode 100644 dlls/version/Makefile.in create mode 100644 dlls/version/info.c create mode 100644 dlls/version/install.c create mode 100644 dlls/version/resource.c diff --git a/dlls/version/.cvsignore b/dlls/version/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/dlls/version/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/dlls/version/Makefile.in b/dlls/version/Makefile.in new file mode 100644 index 00000000000..663760324f2 --- /dev/null +++ b/dlls/version/Makefile.in @@ -0,0 +1,17 @@ +DEFS = @DLLFLAGS@ -D__WINE__ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = version + +C_SRCS = \ + info.c \ + install.c \ + resource.c + +all: $(MODULE).o + +@MAKE_RULES@ + +### Dependencies: diff --git a/dlls/version/info.c b/dlls/version/info.c new file mode 100644 index 00000000000..146eead288a --- /dev/null +++ b/dlls/version/info.c @@ -0,0 +1,577 @@ +/* + * Implementation of VERSION.DLL - Version Info access + * + * Copyright 1996,1997 Marcus Meissner + * Copyright 1997 David Cuthbert + * Copyright 1999 Ulrich Weigand + */ + +#include +#include + +#include "windows.h" +#include "winerror.h" +#include "heap.h" +#include "ver.h" +#include "winreg.h" +#include "debug.h" + + +/****************************************************************************** + * + * This function will print via dprintf[_]ver to stddeb debug info regarding + * the file info structure vffi. + * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu) + * Added this function to clean up the code. + * + *****************************************************************************/ +static void print_vffi_debug(VS_FIXEDFILEINFO *vffi) +{ + dbg_decl_str(ver, 1024); + + TRACE(ver," structversion=%u.%u, fileversion=%u.%u.%u.%u, productversion=%u.%u.%u.%u, flagmask=0x%lx, flags=%s%s%s%s%s%s\n", + HIWORD(vffi->dwStrucVersion),LOWORD(vffi->dwStrucVersion), + HIWORD(vffi->dwFileVersionMS),LOWORD(vffi->dwFileVersionMS), + HIWORD(vffi->dwFileVersionLS),LOWORD(vffi->dwFileVersionLS), + HIWORD(vffi->dwProductVersionMS),LOWORD(vffi->dwProductVersionMS), + HIWORD(vffi->dwProductVersionLS),LOWORD(vffi->dwProductVersionLS), + vffi->dwFileFlagsMask, + (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "", + (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "", + (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "", + (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "", + (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "", + (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : "" + ); + + dsprintf(ver," OS=0x%x.0x%x ", + HIWORD(vffi->dwFileOS), + LOWORD(vffi->dwFileOS) + ); + switch (vffi->dwFileOS&0xFFFF0000) { + case VOS_DOS:dsprintf(ver,"DOS,");break; + case VOS_OS216:dsprintf(ver,"OS/2-16,");break; + case VOS_OS232:dsprintf(ver,"OS/2-32,");break; + case VOS_NT:dsprintf(ver,"NT,");break; + case VOS_UNKNOWN: + default: + dsprintf(ver,"UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break; + } + switch (LOWORD(vffi->dwFileOS)) { + case VOS__BASE:dsprintf(ver,"BASE");break; + case VOS__WINDOWS16:dsprintf(ver,"WIN16");break; + case VOS__WINDOWS32:dsprintf(ver,"WIN32");break; + case VOS__PM16:dsprintf(ver,"PM16");break; + case VOS__PM32:dsprintf(ver,"PM32");break; + default:dsprintf(ver,"UNKNOWN(0x%x)",LOWORD(vffi->dwFileOS));break; + } + TRACE(ver, "(%s)\n", dbg_str(ver)); + + dbg_reset_str(ver); + switch (vffi->dwFileType) { + default: + case VFT_UNKNOWN: + dsprintf(ver,"filetype=Unknown(0x%lx)",vffi->dwFileType); + break; + case VFT_APP:dsprintf(ver,"filetype=APP,");break; + case VFT_DLL:dsprintf(ver,"filetype=DLL,");break; + case VFT_DRV: + dsprintf(ver,"filetype=DRV,"); + switch(vffi->dwFileSubtype) { + default: + case VFT2_UNKNOWN: + dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype); + break; + case VFT2_DRV_PRINTER: + dsprintf(ver,"PRINTER"); + break; + case VFT2_DRV_KEYBOARD: + dsprintf(ver,"KEYBOARD"); + break; + case VFT2_DRV_LANGUAGE: + dsprintf(ver,"LANGUAGE"); + break; + case VFT2_DRV_DISPLAY: + dsprintf(ver,"DISPLAY"); + break; + case VFT2_DRV_MOUSE: + dsprintf(ver,"MOUSE"); + break; + case VFT2_DRV_NETWORK: + dsprintf(ver,"NETWORK"); + break; + case VFT2_DRV_SYSTEM: + dsprintf(ver,"SYSTEM"); + break; + case VFT2_DRV_INSTALLABLE: + dsprintf(ver,"INSTALLABLE"); + break; + case VFT2_DRV_SOUND: + dsprintf(ver,"SOUND"); + break; + case VFT2_DRV_COMM: + dsprintf(ver,"COMM"); + break; + case VFT2_DRV_INPUTMETHOD: + dsprintf(ver,"INPUTMETHOD"); + break; + } + break; + case VFT_FONT: + dsprintf(ver,"filetype=FONT."); + switch (vffi->dwFileSubtype) { + default: + dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype); + break; + case VFT2_FONT_RASTER:dsprintf(ver,"RASTER");break; + case VFT2_FONT_VECTOR:dsprintf(ver,"VECTOR");break; + case VFT2_FONT_TRUETYPE:dsprintf(ver,"TRUETYPE");break; + } + break; + case VFT_VXD:dsprintf(ver,"filetype=VXD");break; + case VFT_STATIC_LIB:dsprintf(ver,"filetype=STATIC_LIB");break; + } + TRACE(ver, "%s\n", dbg_str(ver)); + + TRACE(ver, " filedata=0x%lx.0x%lx\n", + vffi->dwFileDateMS,vffi->dwFileDateLS); +} + + +/*********************************************************************** + * Version Info Structure + */ + +typedef struct +{ + WORD wLength; + WORD wValueLength; + CHAR szKey[1]; +#if 0 /* variable length structure */ + /* DWORD aligned */ + BYTE Value[]; + /* DWORD aligned */ + VS_VERSION_INFO16 Children[]; +#endif +} VS_VERSION_INFO16; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD bText; + WCHAR szKey[1]; +#if 0 /* variable length structure */ + /* DWORD aligned */ + BYTE Value[]; + /* DWORD aligned */ + VS_VERSION_INFO32 Children[]; +#endif +} VS_VERSION_INFO32; + +#define VersionInfoIs16( ver ) \ + ( ((VS_VERSION_INFO16 *)ver)->szKey[0] >= ' ' ) + +#define VersionInfo16_Value( ver ) \ + (LPBYTE)( ((DWORD)((ver)->szKey) + (lstrlen32A((ver)->szKey)+1) + 3) & ~3 ) +#define VersionInfo32_Value( ver ) \ + (LPBYTE)( ((DWORD)((ver)->szKey) + 2*(lstrlen32W((ver)->szKey)+1) + 3) & ~3 ) + +#define VersionInfo16_Children( ver ) \ + (VS_VERSION_INFO16 *)( VersionInfo16_Value( ver ) + \ + ( ( (ver)->wValueLength + 3 ) & ~3 ) ) +#define VersionInfo32_Children( ver ) \ + (VS_VERSION_INFO32 *)( VersionInfo32_Value( ver ) + \ + ( ( (ver)->wValueLength * \ + ((ver)->bText? 2 : 1) + 3 ) & ~3 ) ) + +#define VersionInfo16_Next( ver ) \ + (VS_VERSION_INFO16 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) ) +#define VersionInfo32_Next( ver ) \ + (VS_VERSION_INFO32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) ) + +/*********************************************************************** + * ConvertVersionInfo32To16 [internal] + */ +void ConvertVersionInfo32To16( VS_VERSION_INFO32 *info32, + VS_VERSION_INFO16 *info16 ) +{ + /* Copy data onto local stack to prevent overwrites */ + WORD wLength = info32->wLength; + WORD wValueLength = info32->wValueLength; + WORD bText = info32->bText; + LPBYTE lpValue = VersionInfo32_Value( info32 ); + VS_VERSION_INFO32 *child32 = VersionInfo32_Children( info32 ); + VS_VERSION_INFO16 *child16; + + TRACE( ver, "Converting %p to %p\n", info32, info16 ); + TRACE( ver, "wLength %d, wValueLength %d, bText %d, value %p, child %p\n", + wLength, wValueLength, bText, lpValue, child32 ); + + /* Convert key */ + lstrcpyWtoA( info16->szKey, info32->szKey ); + + TRACE( ver, "Copied key from %p to %p: %s\n", info32->szKey, info16->szKey, + debugstr_a(info16->szKey) ); + + /* Convert value */ + if ( wValueLength == 0 ) + { + info16->wValueLength = 0; + TRACE( ver, "No value present\n" ); + } + else if ( bText ) + { + info16->wValueLength = lstrlen32W( (LPCWSTR)lpValue ) + 1; + lstrcpyWtoA( VersionInfo16_Value( info16 ), (LPCWSTR)lpValue ); + + TRACE( ver, "Copied value from %p to %p: %s\n", lpValue, + VersionInfo16_Value( info16 ), + debugstr_a(VersionInfo16_Value( info16 )) ); + } + else + { + info16->wValueLength = wValueLength; + memmove( VersionInfo16_Value( info16 ), lpValue, wValueLength ); + + TRACE( ver, "Copied value from %p to %p: %d bytes\n", lpValue, + VersionInfo16_Value( info16 ), wValueLength ); + } + + /* Convert children */ + child16 = VersionInfo16_Children( info16 ); + while ( (DWORD)child32 < (DWORD)info32 + wLength ) + { + VS_VERSION_INFO32 *nextChild = VersionInfo32_Next( child32 ); + + ConvertVersionInfo32To16( child32, child16 ); + + child16 = VersionInfo16_Next( child16 ); + child32 = nextChild; + } + + /* Fixup length */ + info16->wLength = (DWORD)child16 - (DWORD)info16; + + TRACE( ver, "Finished, length is %d (%p - %p)\n", + info16->wLength, info16, child16 ); +} + + +/*********************************************************************** + * GetFileVersionInfoSize32A [VERSION.2] + */ +DWORD WINAPI GetFileVersionInfoSize32A( LPCSTR filename, LPDWORD handle ) +{ + VS_FIXEDFILEINFO *vffi; + DWORD len, ret; + BYTE buf[144]; + + TRACE( ver, "(%s,%p)\n", debugstr_a(filename), handle ); + + len = GetFileResourceSize32( filename, + MAKEINTRESOURCE32A(VS_FILE_INFO), + MAKEINTRESOURCE32A(VS_VERSION_INFO), + handle ); + if (!len) return 0; + + ret = GetFileResource32( filename, + MAKEINTRESOURCE32A(VS_FILE_INFO), + MAKEINTRESOURCE32A(VS_VERSION_INFO), + *handle, sizeof( buf ), buf ); + if (!ret) return 0; + + + if ( VersionInfoIs16( buf ) ) + vffi = (VS_FIXEDFILEINFO *)VersionInfo16_Value( (VS_VERSION_INFO16 *)buf ); + else + vffi = (VS_FIXEDFILEINFO *)VersionInfo32_Value( (VS_VERSION_INFO32 *)buf ); + + if ( vffi->dwSignature != VS_FFI_SIGNATURE ) + { + WARN( ver, "vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n", + vffi->dwSignature, VS_FFI_SIGNATURE ); + return 0; + } + + if ( ((VS_VERSION_INFO16 *)buf)->wLength < len ) + len = ((VS_VERSION_INFO16 *)buf)->wLength; + + if ( TRACE_ON( ver ) ) + print_vffi_debug( vffi ); + + return len; +} + +/*********************************************************************** + * GetFileVersionInfoSize32W [VERSION.3] + */ +DWORD WINAPI GetFileVersionInfoSize32W( LPCWSTR filename, LPDWORD handle ) +{ + LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); + DWORD ret = GetFileVersionInfoSize32A( fn, handle ); + HeapFree( GetProcessHeap(), 0, fn ); + return ret; +} + +/*********************************************************************** + * GetFileVersionInfo32A [VERSION.1] + */ +DWORD WINAPI GetFileVersionInfo32A( LPCSTR filename, DWORD handle, + DWORD datasize, LPVOID data ) +{ + TRACE( ver, "(%s,%ld,size=%ld,data=%p)\n", + debugstr_a(filename), handle, datasize, data ); + + if ( !GetFileResource32( filename, MAKEINTRESOURCE32A(VS_FILE_INFO), + MAKEINTRESOURCE32A(VS_VERSION_INFO), + handle, datasize, data ) ) + return FALSE; + + if ( datasize >= sizeof(VS_VERSION_INFO16) + && datasize >= ((VS_VERSION_INFO16 *)data)->wLength + && !VersionInfoIs16( data ) ) + { + /* convert resource from PE format to NE format */ + ConvertVersionInfo32To16( (VS_VERSION_INFO32 *)data, + (VS_VERSION_INFO16 *)data ); + } + + return TRUE; +} + +/*********************************************************************** + * GetFileVersionInfo32W [VERSION.4] + */ +DWORD WINAPI GetFileVersionInfo32W( LPCWSTR filename, DWORD handle, + DWORD datasize, LPVOID data ) +{ + LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); + DWORD retv = TRUE; + + TRACE( ver, "(%s,%ld,size=%ld,data=%p)\n", + debugstr_a(fn), handle, datasize, data ); + + if ( !GetFileResource32( fn, MAKEINTRESOURCE32A(VS_FILE_INFO), + MAKEINTRESOURCE32A(VS_VERSION_INFO), + handle, datasize, data ) ) + retv = FALSE; + + else if ( datasize >= sizeof(VS_VERSION_INFO16) + && datasize >= ((VS_VERSION_INFO16 *)data)->wLength + && VersionInfoIs16( data ) ) + { + ERR( ver, "Cannot access NE resource in %s\n", debugstr_a(fn) ); + retv = FALSE; + } + + HeapFree( GetProcessHeap(), 0, fn ); + return retv; +} + + +/*********************************************************************** + * VersionInfo16_FindChild [internal] + */ +VS_VERSION_INFO16 *VersionInfo16_FindChild( VS_VERSION_INFO16 *info, + LPCSTR szKey, UINT32 cbKey ) +{ + VS_VERSION_INFO16 *child = VersionInfo16_Children( info ); + + while ( (DWORD)child < (DWORD)info + info->wLength ) + { + if ( !lstrncmpi32A( child->szKey, szKey, cbKey ) ) + return child; + + child = VersionInfo16_Next( child ); + } + + return NULL; +} + +/*********************************************************************** + * VersionInfo32_FindChild [internal] + */ +VS_VERSION_INFO32 *VersionInfo32_FindChild( VS_VERSION_INFO32 *info, + LPCWSTR szKey, UINT32 cbKey ) +{ + VS_VERSION_INFO32 *child = VersionInfo32_Children( info ); + + while ( (DWORD)child < (DWORD)info + info->wLength ) + { + if ( !lstrncmpi32W( child->szKey, szKey, cbKey ) ) + return child; + + child = VersionInfo32_Next( child ); + } + + return NULL; +} + +/*********************************************************************** + * VerQueryValue32A [VERSION.12] + */ +DWORD WINAPI VerQueryValue32A( LPVOID pBlock, LPCSTR lpSubBlock, + LPVOID *lplpBuffer, UINT32 *puLen ) +{ + VS_VERSION_INFO16 *info = (VS_VERSION_INFO16 *)pBlock; + if ( !VersionInfoIs16( info ) ) + { + ERR( ver, "called on PE resource!\n" ); + return FALSE; + } + + TRACE( ver, "(%p,%s,%p,%p)\n", + pBlock, debugstr_a(lpSubBlock), lplpBuffer, puLen ); + + while ( *lpSubBlock ) + { + /* Find next path component */ + LPCSTR lpNextSlash; + for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ ) + if ( *lpNextSlash == '\\' ) + break; + + /* Skip empty components */ + if ( lpNextSlash == lpSubBlock ) + { + lpSubBlock++; + continue; + } + + /* We have a non-empty component: search info for key */ + info = VersionInfo16_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock ); + if ( !info ) return FALSE; + + /* Skip path component */ + lpSubBlock = lpNextSlash; + } + + /* Return value */ + *lplpBuffer = VersionInfo16_Value( info ); + *puLen = info->wValueLength; + + return TRUE; +} + +/*********************************************************************** + * VerQueryValue32W [VERSION.13] + */ +DWORD WINAPI VerQueryValue32W( LPVOID pBlock, LPCWSTR lpSubBlock, + LPVOID *lplpBuffer, UINT32 *puLen ) +{ + VS_VERSION_INFO32 *info = (VS_VERSION_INFO32 *)pBlock; + if ( VersionInfoIs16( info ) ) + { + ERR( ver, "called on NE resource!\n" ); + return FALSE; + } + + TRACE( ver, "(%p,%s,%p,%p)\n", + pBlock, debugstr_w(lpSubBlock), lplpBuffer, puLen ); + + while ( *lpSubBlock ) + { + /* Find next path component */ + LPCWSTR lpNextSlash; + for ( lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++ ) + if ( *lpNextSlash == '\\' ) + break; + + /* Skip empty components */ + if ( lpNextSlash == lpSubBlock ) + { + lpSubBlock++; + continue; + } + + /* We have a non-empty component: search info for key */ + info = VersionInfo32_FindChild( info, lpSubBlock, lpNextSlash-lpSubBlock ); + if ( !info ) return FALSE; + + /* Skip path component */ + lpSubBlock = lpNextSlash; + } + + /* Return value */ + *lplpBuffer = VersionInfo32_Value( info ); + *puLen = info->wValueLength; + + return TRUE; +} + +extern LPCSTR WINE_GetLanguageName( UINT32 langid ); + +/*********************************************************************** + * VerLanguageName32A [VERSION.9] + */ +DWORD WINAPI VerLanguageName32A( UINT32 wLang, LPSTR szLang, UINT32 nSize ) +{ + char buffer[80]; + LPCSTR name; + DWORD result; + + TRACE( ver, "(%d,%p,%d)\n", wLang, szLang, nSize ); + + /* + * First, check \System\CurrentControlSet\control\Nls\Locale\ + * from the registry. + */ + + sprintf( buffer, + "\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x", + wLang ); + + result = RegQueryValue32A( HKEY_LOCAL_MACHINE, buffer, szLang, (LPDWORD)&nSize ); + if ( result == ERROR_SUCCESS || result == ERROR_MORE_DATA ) + return nSize; + + /* + * If that fails, use the internal table + * (actually, Windows stores the names in a string table resource ...) + */ + + name = WINE_GetLanguageName( wLang ); + lstrcpyn32A( szLang, name, nSize ); + return lstrlen32A( name ); +} + +/*********************************************************************** + * VerLanguageName32W [VERSION.10] + */ +DWORD WINAPI VerLanguageName32W( UINT32 wLang, LPWSTR szLang, UINT32 nSize ) +{ + char buffer[80]; + LPWSTR keyname; + LPCSTR name; + DWORD result; + + TRACE( ver, "(%d,%p,%d)\n", wLang, szLang, nSize ); + + /* + * First, check \System\CurrentControlSet\control\Nls\Locale\ + * from the registry. + */ + + sprintf( buffer, + "\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x", + wLang ); + + keyname = HEAP_strdupAtoW( GetProcessHeap(), 0, buffer ); + result = RegQueryValue32W( HKEY_LOCAL_MACHINE, keyname, szLang, (LPDWORD)&nSize ); + HeapFree( GetProcessHeap(), 0, keyname ); + + if ( result == ERROR_SUCCESS || result == ERROR_MORE_DATA ) + return nSize; + + /* + * If that fails, use the internal table + * (actually, Windows stores the names in a string table resource ...) + */ + + name = WINE_GetLanguageName( wLang ); + lstrcpynAtoW( szLang, name, nSize ); + return lstrlen32A( name ); +} + + diff --git a/dlls/version/install.c b/dlls/version/install.c new file mode 100644 index 00000000000..e921ecfb69a --- /dev/null +++ b/dlls/version/install.c @@ -0,0 +1,578 @@ +/* + * Implementation of VERSION.DLL - File Installer routines + * + * Copyright 1996,1997 Marcus Meissner + * Copyright 1997 David Cuthbert + */ + +#include +#include + +#include "windows.h" +#include "winerror.h" +#include "heap.h" +#include "ver.h" +#include "lzexpand.h" +#include "xmalloc.h" +#include "debug.h" + + +/****************************************************************************** + * + * void ver_dstring( + * char const * prologue, + * char const * teststring, + * char const * epilogue ) + * + * This function will print via dprintf[_]ver to stddeb the prologue string, + * followed by the address of teststring and the string it contains if + * teststring is non-null or "(null)" otherwise, and then the epilogue + * string followed by a new line. + * + * Revision history + * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation as dprintf[_]ver_string + * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Fixed problem that caused bug with tools/make_debug -- renaming + * this function should fix the problem. + * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu) + * Modified it to make it print the message using only one + * dprintf[_]ver call. + * + *****************************************************************************/ + +static void ver_dstring( + char const * prologue, + char const * teststring, + char const * epilogue ) +{ + TRACE(ver, "%s %p (\"%s\") %s\n", prologue, + (void const *) teststring, + teststring ? teststring : "(null)", + epilogue); +} + +/****************************************************************************** + * + * int testFileExistence( + * char const * path, + * char const * file ) + * + * Tests whether a given path/file combination exists. If the file does + * not exist, the return value is zero. If it does exist, the return + * value is non-zero. + * + * Revision history + * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation + * + *****************************************************************************/ + +static int testFileExistence( + char const * path, + char const * file ) +{ + char filename[1024]; + int filenamelen; + OFSTRUCT fileinfo; + int retval; + + fileinfo.cBytes = sizeof(OFSTRUCT); + + strcpy(filename, path); + filenamelen = strlen(filename); + + /* Add a trailing \ if necessary */ + if(filenamelen) { + if(filename[filenamelen - 1] != '\\') + strcat(filename, "\\"); + } + else /* specify the current directory */ + strcpy(filename, ".\\"); + + /* Create the full pathname */ + strcat(filename, file); + + if(OpenFile32(filename, &fileinfo, OF_EXIST) == HFILE_ERROR32) + retval = 0; + else + retval = 1; + + return retval; +} + +/****************************************************************************** + * + * int testFileExclusiveExistence( + * char const * path, + * char const * file ) + * + * Tests whether a given path/file combination exists and ensures that no + * other programs have handles to the given file. If the file does not + * exist or is open, the return value is zero. If it does exist, the + * return value is non-zero. + * + * Revision history + * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Original implementation + * + *****************************************************************************/ + +static int testFileExclusiveExistence( + char const * path, + char const * file ) +{ + char filename[1024]; + int filenamelen; + OFSTRUCT fileinfo; + int retval; + + fileinfo.cBytes = sizeof(OFSTRUCT); + + strcpy(filename, path); + filenamelen = strlen(filename); + + /* Add a trailing \ if necessary */ + if(filenamelen) { + if(filename[filenamelen - 1] != '\\') + strcat(filename, "\\"); + } + else /* specify the current directory */ + strcpy(filename, ".\\"); + + /* Create the full pathname */ + strcat(filename, file); + + if(OpenFile32(filename, &fileinfo, OF_EXIST | OF_SHARE_EXCLUSIVE) == + HFILE_ERROR32) + retval = 0; + else + retval = 1; + + return retval; +} + +/***************************************************************************** + * + * VerFindFile() [VER.8] + * Determines where to install a file based on whether it locates another + * version of the file in the system. The values VerFindFile returns are + * used in a subsequent call to the VerInstallFile function. + * + * Revision history: + * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) + * Reimplementation of VerFindFile from original stub. + * + ****************************************************************************/ + +/* VerFindFile32A [VERSION.5] */ +DWORD WINAPI VerFindFile32A( + UINT32 flags, + LPCSTR lpszFilename, + LPCSTR lpszWinDir, + LPCSTR lpszAppDir, + LPSTR lpszCurDir, + UINT32 *lpuCurDirLen, + LPSTR lpszDestDir, + UINT32 *lpuDestDirLen ) +{ + DWORD retval; + char curDir[256]; + char destDir[256]; + unsigned int curDirSizeReq; + unsigned int destDirSizeReq; + + retval = 0; + + /* Print out debugging information */ + TRACE(ver, "called with parameters:\n" + "\tflags = %x", flags); + if(flags & VFFF_ISSHAREDFILE) + TRACE(ver, " (VFFF_ISSHAREDFILE)\n"); + else + TRACE(ver, "\n"); + + ver_dstring("\tlpszFilename = ", lpszFilename, ""); + ver_dstring("\tlpszWinDir = ", lpszWinDir, ""); + ver_dstring("\tlpszAppDir = ", lpszAppDir, ""); + + TRACE(ver, "\tlpszCurDir = %p\n", lpszCurDir); + if(lpuCurDirLen) + TRACE(ver, "\tlpuCurDirLen = %p (%u)\n", + lpuCurDirLen, *lpuCurDirLen); + else + TRACE(ver, "\tlpuCurDirLen = (null)\n"); + + TRACE(ver, "\tlpszDestDir = %p\n", lpszDestDir); + if(lpuDestDirLen) + TRACE(ver, "\tlpuDestDirLen = %p (%u)\n", + lpuDestDirLen, *lpuDestDirLen); + + /* Figure out where the file should go; shared files default to the + system directory */ + + strcpy(curDir, ""); + strcpy(destDir, ""); + + if(flags & VFFF_ISSHAREDFILE) { + GetSystemDirectory32A(destDir, 256); + + /* Were we given a filename? If so, try to find the file. */ + if(lpszFilename) { + if(testFileExistence(destDir, lpszFilename)) { + strcpy(curDir, destDir); + + if(!testFileExclusiveExistence(destDir, lpszFilename)) + retval |= VFF_FILEINUSE; + } + else if(lpszAppDir && testFileExistence(lpszAppDir, + lpszFilename)) { + strcpy(curDir, lpszAppDir); + retval |= VFF_CURNEDEST; + + if(!testFileExclusiveExistence(lpszAppDir, lpszFilename)) + retval |= VFF_FILEINUSE; + } + } + } + else if(!(flags & VFFF_ISSHAREDFILE)) { /* not a shared file */ + if(lpszAppDir) { + char systemDir[256]; + GetSystemDirectory32A(systemDir, 256); + + strcpy(destDir, lpszAppDir); + + if(lpszFilename) { + if(testFileExistence(lpszAppDir, lpszFilename)) { + strcpy(curDir, lpszAppDir); + + if(!testFileExclusiveExistence(lpszAppDir, lpszFilename)) + retval |= VFF_FILEINUSE; + } + else if(testFileExistence(systemDir, lpszFilename)) { + strcpy(curDir, systemDir); + retval |= VFF_CURNEDEST; + + if(!testFileExclusiveExistence(systemDir, lpszFilename)) + retval |= VFF_FILEINUSE; + } + } + } + } + + curDirSizeReq = strlen(curDir) + 1; + destDirSizeReq = strlen(destDir) + 1; + + + + /* Make sure that the pointers to the size of the buffers are + valid; if not, do NOTHING with that buffer. If that pointer + is valid, then make sure that the buffer pointer is valid, too! */ + + if(lpuDestDirLen && lpszDestDir) { + if(*lpuDestDirLen < destDirSizeReq) { + retval |= VFF_BUFFTOOSMALL; + strncpy(lpszDestDir, destDir, *lpuDestDirLen - 1); + lpszDestDir[*lpuDestDirLen - 1] = '\0'; + } + else + strcpy(lpszDestDir, destDir); + + *lpuDestDirLen = destDirSizeReq; + } + + if(lpuCurDirLen && lpszCurDir) { + if(*lpuCurDirLen < curDirSizeReq) { + retval |= VFF_BUFFTOOSMALL; + strncpy(lpszCurDir, curDir, *lpuCurDirLen - 1); + lpszCurDir[*lpuCurDirLen - 1] = '\0'; + } + else + strcpy(lpszCurDir, curDir); + + *lpuCurDirLen = curDirSizeReq; + } + + TRACE(ver, "ret = %lu (%s%s%s)\n", retval, + (retval & VFF_CURNEDEST) ? "VFF_CURNEDEST " : "", + (retval & VFF_FILEINUSE) ? "VFF_FILEINUSE " : "", + (retval & VFF_BUFFTOOSMALL) ? "VFF_BUFFTOOSMALL " : ""); + + ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir, ""); + if(lpuCurDirLen) + TRACE(ver, "\t(Exit) lpuCurDirLen = %p (%u)\n", + lpuCurDirLen, *lpuCurDirLen); + else + TRACE(ver, "\t(Exit) lpuCurDirLen = (null)\n"); + + ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir, ""); + if(lpuDestDirLen) + TRACE(ver, "\t(Exit) lpuDestDirLen = %p (%u)\n", + lpuDestDirLen, *lpuDestDirLen); + + return retval; +} + +/* VerFindFile32W [VERSION.6] */ +DWORD WINAPI VerFindFile32W( + UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir, + LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen ) +{ + UINT32 curdirlen, destdirlen; + LPSTR wfn,wwd,wad,wdd,wcd; + DWORD ret; + + wfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); + wwd = HEAP_strdupWtoA( GetProcessHeap(), 0, windir ); + wad = HEAP_strdupWtoA( GetProcessHeap(), 0, appdir ); + wcd = HeapAlloc( GetProcessHeap(), 0, *pcurdirlen ); + wdd = HeapAlloc( GetProcessHeap(), 0, *pdestdirlen ); + ret = VerFindFile32A(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen); + lstrcpynAtoW(curdir,wcd,*pcurdirlen); + lstrcpynAtoW(destdir,wdd,*pdestdirlen); + *pcurdirlen = strlen(wcd); + *pdestdirlen = strlen(wdd); + HeapFree( GetProcessHeap(), 0, wfn ); + HeapFree( GetProcessHeap(), 0, wwd ); + HeapFree( GetProcessHeap(), 0, wad ); + HeapFree( GetProcessHeap(), 0, wcd ); + HeapFree( GetProcessHeap(), 0, wdd ); + return ret; +} + +static LPBYTE +_fetch_versioninfo(LPSTR fn,VS_FIXEDFILEINFO **vffi) { + DWORD alloclen; + LPBYTE buf; + DWORD ret; + + alloclen = 1000; + buf= xmalloc(alloclen); + while (1) { + ret = GetFileVersionInfo32A(fn,0,alloclen,buf); + if (!ret) { + free(buf); + return 0; + } + if (alloclen<*(WORD*)buf) { + free(buf); + alloclen = *(WORD*)buf; + buf = xmalloc(alloclen); + } else { + *vffi = (VS_FIXEDFILEINFO*)(buf+0x14); + if ((*vffi)->dwSignature == 0x004f0049) /* hack to detect unicode */ + *vffi = (VS_FIXEDFILEINFO*)(buf+0x28); + if ((*vffi)->dwSignature != VS_FFI_SIGNATURE) + WARN(ver,"Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi)->dwSignature); + return buf; + } + } +} + +static DWORD +_error2vif(DWORD error) { + switch (error) { + case ERROR_ACCESS_DENIED: + return VIF_ACCESSVIOLATION; + case ERROR_SHARING_VIOLATION: + return VIF_SHARINGVIOLATION; + default: + return 0; + } +} + + +/****************************************************************************** + * VerInstallFile32A [VERSION.7] + */ +DWORD WINAPI VerInstallFile32A( + UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir, + LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen ) +{ + LPCSTR pdest; + char destfn[260],tmpfn[260],srcfn[260]; + HFILE32 hfsrc,hfdst; + DWORD attr,ret,xret,tmplast; + LPBYTE buf1,buf2; + OFSTRUCT ofs; + + TRACE(ver,"(%x,%s,%s,%s,%s,%s,%p,%d)\n", + flags,srcfilename,destfilename,srcdir,destdir,curdir,tmpfile,*tmpfilelen + ); + xret = 0; + sprintf(srcfn,"%s\\%s",srcdir,srcfilename); + if (!destdir || !*destdir) pdest = srcdir; + else pdest = destdir; + sprintf(destfn,"%s\\%s",pdest,destfilename); + hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ); + if (hfsrc==HFILE_ERROR32) + return VIF_CANNOTREADSRC; + sprintf(tmpfn,"%s\\%s",pdest,destfilename); + tmplast=strlen(pdest)+1; + attr = GetFileAttributes32A(tmpfn); + if (attr!=-1) { + if (attr & FILE_ATTRIBUTE_READONLY) { + LZClose32(hfsrc); + return VIF_WRITEPROT; + } + /* FIXME: check if file currently in use and return VIF_FILEINUSE */ + } + attr = -1; + if (flags & VIFF_FORCEINSTALL) { + if (tmpfile[0]) { + sprintf(tmpfn,"%s\\%s",pdest,tmpfile); + tmplast = strlen(pdest)+1; + attr = GetFileAttributes32A(tmpfn); + /* if it exists, it has been copied by the call before. + * we jump over the copy part... + */ + } + } + if (attr == -1) { + char *s; + + GetTempFileName32A(pdest,"ver",0,tmpfn); /* should not fail ... */ + s=strrchr(tmpfn,'\\'); + if (s) + tmplast = s-tmpfn; + else + tmplast = 0; + hfdst = OpenFile32(tmpfn,&ofs,OF_CREATE); + if (hfdst == HFILE_ERROR32) { + LZClose32(hfsrc); + return VIF_CANNOTCREATE; /* | translated dos error */ + } + ret = LZCopy32(hfsrc,hfdst); + _lclose32(hfdst); + if (((long) ret) < 0) { + /* translate LZ errors into VIF_xxx */ + switch (ret) { + case LZERROR_BADINHANDLE: + case LZERROR_READ: + case LZERROR_BADVALUE: + case LZERROR_UNKNOWNALG: + ret = VIF_CANNOTREADSRC; + break; + case LZERROR_BADOUTHANDLE: + case LZERROR_WRITE: + ret = VIF_OUTOFMEMORY; /* FIXME: correct? */ + break; + case LZERROR_GLOBALLOC: + case LZERROR_GLOBLOCK: + ret = VIF_OUTOFSPACE; + break; + default: /* unknown error, should not happen */ + ret = 0; + break; + } + if (ret) { + LZClose32(hfsrc); + return ret; + } + } + } + xret = 0; + if (!(flags & VIFF_FORCEINSTALL)) { + VS_FIXEDFILEINFO *destvffi,*tmpvffi; + buf1 = _fetch_versioninfo(destfn,&destvffi); + if (buf1) { + buf2 = _fetch_versioninfo(tmpfn,&tmpvffi); + if (buf2) { + char *tbuf1,*tbuf2; + UINT32 len1,len2; + + len1=len2=40; + + /* compare file versions */ + if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)|| + ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&& + (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS) + ) + ) + xret |= VIF_MISMATCH|VIF_SRCOLD; + /* compare filetypes and filesubtypes */ + if ((destvffi->dwFileType!=tmpvffi->dwFileType) || + (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype) + ) + xret |= VIF_MISMATCH|VIF_DIFFTYPE; + if (VerQueryValue32A(buf1,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf1,&len1) && + VerQueryValue32A(buf2,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf2,&len2) + ) { + /* irgendwas mit tbuf1 und tbuf2 machen + * generiert DIFFLANG|MISMATCH + */ + } + free(buf2); + } else + xret=VIF_MISMATCH|VIF_SRCOLD; + free(buf1); + } + } + if (xret) { + if (*tmpfilelen +#include + +#include "windows.h" +#include "heap.h" +#include "ver.h" +#include "lzexpand.h" +#include "module.h" +#include "neexe.h" +#include "debug.h" + + +/*********************************************************************** + * read_xx_header [internal] + */ +static int read_xx_header( HFILE32 lzfd ) +{ + IMAGE_DOS_HEADER mzh; + char magic[3]; + + LZSeek32( lzfd, 0, SEEK_SET ); + if ( sizeof(mzh) != LZRead32( lzfd, &mzh, sizeof(mzh) ) ) + return 0; + if ( mzh.e_magic != IMAGE_DOS_SIGNATURE ) + return 0; + + LZSeek32( lzfd, mzh.e_lfanew, SEEK_SET ); + if ( 2 != LZRead32( lzfd, magic, 2 ) ) + return 0; + + LZSeek32( lzfd, mzh.e_lfanew, SEEK_SET ); + + if ( magic[0] == 'N' && magic[1] == 'E' ) + return IMAGE_OS2_SIGNATURE; + if ( magic[0] == 'P' && magic[1] == 'E' ) + return IMAGE_NT_SIGNATURE; + + magic[2] = '\0'; + WARN( ver, "Can't handle %s files.\n", magic ); + return 0; +} + +/*********************************************************************** + * load_ne_resource [internal] + */ +static BOOL32 find_ne_resource( HFILE32 lzfd, LPCSTR typeid, LPCSTR resid, + DWORD *resLen, DWORD *resOff ) +{ + IMAGE_OS2_HEADER nehd; + NE_TYPEINFO *typeInfo; + NE_NAMEINFO *nameInfo; + DWORD nehdoffset; + LPBYTE resTab; + DWORD resTabSize; + + /* Read in NE header */ + nehdoffset = LZSeek32( lzfd, 0, SEEK_CUR ); + if ( sizeof(nehd) != LZRead32( lzfd, &nehd, sizeof(nehd) ) ) return 0; + + resTabSize = nehd.rname_tab_offset - nehd.resource_tab_offset; + if ( !resTabSize ) + { + TRACE( ver, "No resources in NE dll\n" ); + return FALSE; + } + + /* Read in resource table */ + resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize ); + if ( !resTab ) return FALSE; + + LZSeek32( lzfd, nehd.resource_tab_offset + nehdoffset, SEEK_SET ); + if ( resTabSize != LZRead32( lzfd, resTab, resTabSize ) ) + { + HeapFree( GetProcessHeap(), 0, resTab ); + return FALSE; + } + + /* Find resource */ + typeInfo = (NE_TYPEINFO *)(resTab + 2); + typeInfo = NE_FindTypeSection( resTab, typeInfo, typeid ); + if ( !typeInfo ) + { + TRACE( ver, "No typeid entry found for %p\n", typeid ); + HeapFree( GetProcessHeap(), 0, resTab ); + return FALSE; + } + nameInfo = NE_FindResourceFromType( resTab, typeInfo, resid ); + if ( !nameInfo ) + { + TRACE( ver, "No resid entry found for %p\n", typeid ); + HeapFree( GetProcessHeap(), 0, resTab ); + return FALSE; + } + + /* Return resource data */ + *resLen = nameInfo->length << *(WORD *)resTab; + *resOff = nameInfo->offset << *(WORD *)resTab; + + HeapFree( GetProcessHeap(), 0, resTab ); + return TRUE; +} + +/*********************************************************************** + * load_pe_resource [internal] + */ +static BOOL32 find_pe_resource( HFILE32 lzfd, LPCSTR typeid, LPCSTR resid, + DWORD *resLen, DWORD *resOff ) +{ + IMAGE_NT_HEADERS pehd; + DWORD pehdoffset; + PIMAGE_DATA_DIRECTORY resDataDir; + PIMAGE_SECTION_HEADER sections; + LPBYTE resSection; + DWORD resSectionSize; + DWORD resDir; + PIMAGE_RESOURCE_DIRECTORY resPtr; + PIMAGE_RESOURCE_DATA_ENTRY resData; + int i, nSections; + + + /* Read in PE header */ + pehdoffset = LZSeek32( lzfd, 0, SEEK_CUR ); + if ( sizeof(pehd) != LZRead32( lzfd, &pehd, sizeof(pehd) ) ) return 0; + + resDataDir = pehd.OptionalHeader.DataDirectory+IMAGE_FILE_RESOURCE_DIRECTORY; + if ( !resDataDir->Size ) + { + TRACE( ver, "No resources in PE dll\n" ); + return FALSE; + } + + /* Read in section table */ + nSections = pehd.FileHeader.NumberOfSections; + sections = HeapAlloc( GetProcessHeap(), 0, + nSections * sizeof(IMAGE_SECTION_HEADER) ); + if ( !sections ) return FALSE; + + LZSeek32( lzfd, pehdoffset + + sizeof(DWORD) + /* Signature */ + sizeof(IMAGE_FILE_HEADER) + + pehd.FileHeader.SizeOfOptionalHeader, SEEK_SET ); + + if ( nSections * sizeof(IMAGE_SECTION_HEADER) != + LZRead32( lzfd, sections, nSections * sizeof(IMAGE_SECTION_HEADER) ) ) + { + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + + /* Find resource section */ + for ( i = 0; i < nSections; i++ ) + if ( resDataDir->VirtualAddress >= sections[i].VirtualAddress + && resDataDir->VirtualAddress < sections[i].VirtualAddress + + sections[i].SizeOfRawData ) + break; + + if ( i == nSections ) + { + HeapFree( GetProcessHeap(), 0, sections ); + TRACE( ver, "Couldn't find resource section\n" ); + return FALSE; + } + + /* Read in resource section */ + resSectionSize = sections[i].SizeOfRawData; + resSection = HeapAlloc( GetProcessHeap(), 0, resSectionSize ); + if ( !resSection ) + { + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + + LZSeek32( lzfd, sections[i].PointerToRawData, SEEK_SET ); + if ( resSectionSize != LZRead32( lzfd, resSection, resSectionSize ) ) + { + HeapFree( GetProcessHeap(), 0, resSection ); + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + + /* Find resource */ + resDir = (DWORD)resSection + + (resDataDir->VirtualAddress - sections[i].VirtualAddress); + + resPtr = (PIMAGE_RESOURCE_DIRECTORY)resDir; + resPtr = GetResDirEntryA( resPtr, typeid, resDir, FALSE ); + if ( !resPtr ) + { + TRACE( ver, "No typeid entry found for %p\n", typeid ); + HeapFree( GetProcessHeap(), 0, resSection ); + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + resPtr = GetResDirEntryA( resPtr, resid, resDir, FALSE ); + if ( !resPtr ) + { + TRACE( ver, "No resid entry found for %p\n", resid ); + HeapFree( GetProcessHeap(), 0, resSection ); + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + resPtr = GetResDirEntryA( resPtr, 0, resDir, TRUE ); + if ( !resPtr ) + { + TRACE( ver, "No default language entry found for %p\n", resid ); + HeapFree( GetProcessHeap(), 0, resSection ); + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + + /* Find resource data section */ + resData = (PIMAGE_RESOURCE_DATA_ENTRY)resPtr; + for ( i = 0; i < nSections; i++ ) + if ( resData->OffsetToData >= sections[i].VirtualAddress + && resData->OffsetToData < sections[i].VirtualAddress + + sections[i].SizeOfRawData ) + break; + + if ( i == nSections ) + { + TRACE( ver, "Couldn't find resource data section\n" ); + HeapFree( GetProcessHeap(), 0, resSection ); + HeapFree( GetProcessHeap(), 0, sections ); + return FALSE; + } + + /* Return resource data */ + *resLen = resData->Size; + *resOff = resData->OffsetToData - sections[i].VirtualAddress + + sections[i].PointerToRawData; + + HeapFree( GetProcessHeap(), 0, resSection ); + HeapFree( GetProcessHeap(), 0, sections ); + return TRUE; +} + +/*********************************************************************** + * GetFileResourceSize32 [internal] + */ +DWORD WINAPI GetFileResourceSize32( LPCSTR lpszFileName, + LPCSTR lpszResType, LPCSTR lpszResId, + LPDWORD lpdwFileOffset ) +{ + BOOL32 retv = FALSE; + HFILE32 lzfd; + OFSTRUCT ofs; + DWORD reslen; + + TRACE( ver, "(%s,type=0x%lx,id=0x%lx,off=%p)\n", + debugstr_a(lpszFileName), (LONG)lpszResType, (LONG)lpszResId, + lpszResId ); + + lzfd = LZOpenFile32A( lpszFileName, &ofs, OF_READ ); + if ( !lzfd ) return 0; + + switch ( read_xx_header( lzfd ) ) + { + case IMAGE_OS2_SIGNATURE: + retv = find_ne_resource( lzfd, lpszResType, lpszResId, + &reslen, lpdwFileOffset ); + break; + + case IMAGE_NT_SIGNATURE: + retv = find_pe_resource( lzfd, lpszResType, lpszResId, + &reslen, lpdwFileOffset ); + break; + } + + LZClose32( lzfd ); + return retv? reslen : 0; +} + +/*********************************************************************** + * GetFileResource32 [internal] + */ +DWORD WINAPI GetFileResource32( LPCSTR lpszFileName, + LPCSTR lpszResType, LPCSTR lpszResId, + DWORD dwFileOffset, + DWORD dwResLen, LPVOID lpvData ) +{ + BOOL32 retv = FALSE; + HFILE32 lzfd; + OFSTRUCT ofs; + DWORD reslen; + + TRACE( ver, "(%s,type=0x%lx,id=0x%lx,off=%ld,len=%ld,data=%p)\n", + debugstr_a(lpszFileName), (LONG)lpszResType, (LONG)lpszResId, + dwFileOffset, dwResLen, lpvData ); + + lzfd = LZOpenFile32A( lpszFileName, &ofs, OF_READ ); + if ( lzfd == 0 ) return 0; + + if ( !dwFileOffset ) + { + switch ( read_xx_header( lzfd ) ) + { + case IMAGE_OS2_SIGNATURE: + retv = find_ne_resource( lzfd, lpszResType, lpszResId, + &reslen, &dwFileOffset ); + break; + + case IMAGE_NT_SIGNATURE: + retv = find_pe_resource( lzfd, lpszResType, lpszResId, + &reslen, &dwFileOffset ); + break; + } + + if ( !retv ) + { + LZClose32( lzfd ); + return 0; + } + } + + LZSeek32( lzfd, dwFileOffset, SEEK_SET ); + reslen = LZRead32( lzfd, lpvData, min( reslen, dwResLen ) ); + LZClose32( lzfd ); + + return reslen; +} +