wine/misc/ver.c
Alexandre Julliard 767e6f6f9d Release 980809
Sat Aug  8 19:11:46 1998  Marcus Meissner <marcus@jet.franken.de>

 	* [*/*]
	Added some missing WINAPI and some missing prototypes for
	functions.

	* [controls/static.c]
	Got rid of the MODULE32_LookupHMODULE error showing up for every
	message box.

	* [windows/winproc.c]
	WM_NOTIFY 16->32 mapping (AOL Instant Messenger or however it is called).

	* [misc/winsock.c]
	hostent/servent/protoent should not use the same static buffers.
	(has broken nt3.15 finger.exe which does hp=gethostbyname(), then
	getservbyname("finger","tcp") and the references hp->h_addr_list[0]).

Sat Aug  8 13:21:24 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [include/server.h] [tools/make_requests] [server/request.c]
	  [server/trace.c]
	Automated part of the client/server request code generation.
	Added tracing of client/server communication.

	* [scheduler/*.c] [server/process.c]
	Added support for server-side handles.

	* [scheduler/thread.c]
	Added DLL_THREAD_ATTACH/DETACH notifications.

	* [configure.in]
	Added check for -lsocket.

	* [windows/winproc.c]
	Return the thunk address in WINPROC_GetProc if the function types
	don't match.

Sat Aug  8 02:44:04 1998  Douglas Ridgway  <ridgway@winehq.com>

	* [windows/winproc.c][windows/win.c][windows/message.c]  
	Documentation for CallWindowProc, SetWindowLong, DispatchMessage,
	WaitMessage, GetMessage, and PeekMessage.

Sat Aug  8 01:00:00 1998  Juergen Schmied <juergen.schmied@metronet.de>

	* [controls/commctrl.c][controls/widgets.c][include/builtin32.h]
	  [include/commctrl.h][relay32/builtin32.c][relay32/comctl32.spec]
	  [tools/build.c] [relay32/shell32.spec]
	Added the functionality of the LibMain function. The common 
	controls are properly initialized now.

	* [controls/treeview.c][memory/atom.c][scheduler/thread.c][windows/class.c]
	  [windows/msgbox.c][windows/win.c]
	Put TRACE in, put SetLastError() in.

	* [include/interfaces.h]
	Added IClassFactory::LockServer.

	* [include/ole2.h]
	Added struct for LPOLEMENUGROUPWIDTHS32, HOLEMENU32.

	* [include/shell.h][include/shlobj.h][misc/shell.c][ole/folders.c]
	Reorganized and many structs and classes (IShellBrowser,IShellView)
	added. shell32.dll should work in many cases now.
	Started SHGetFileInfoA implementeation, rewrote SHGetPathFromIDList32A.
	New Shell32LibMain started ShellIconCache Implementation.

	* [misc/shellord.c]
	Rewrote ILCombine, ILGetSize
	New stubs SHFind_InitMenuPopup, FileMenu_Create, ShellExecuteEx,
	SHSetInstanceExplorer, SHGetInstanceExplorer, SHFreeUnusedLibraries.

	* [include/winerror.h]
	Class and window related error codes added.

	* [memory/heap.c]
	Changed lstrlen32A to strlen to get rid of milions of TRACE lines.

	* [misc/ddeml.c]
	First lines for DdeCreateStringHandle32A / DdeFreeStringHandle32.

	* [misc/network.c][relay32/mpr.spec]
	Fixed some bugs, changed ordinals.

	* [windows/class.c]
	Workarounds for incorrect hInstance handling. Fixes parts of
	MSWord95/Excel95 and Money95.

Thu Aug  6 21:05:35 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [windows/nonclient.c][misc/tweak.c][include/tweak.h]
	  [documentation/win95look]
	Removed some tweak variables. They are no longer needed.

	* [files/dos_fs.c]
	Added check for null pointer in DOSFS_GetDevice().

	* [controls/tooltips.c][include/commctrl.h]
	Improved tooltips.

	* [controls/status.c][include/commctrl.h]
	Cleaned up code and added tooltip support.

	* [controls/toolbar.c][include/commctrl.h]
	Added tooltip support.

	* [documentation/common_controls]
	Updated.

Thu Aug  6 00:05:22 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [include/ver.h] [misc/ver.c]
	Write VIF_BUFFTOOSMALL, not VIF_BUFTOSMALL.

	* [debugger/hash.c] [debugger/stabs.c]
	Make debug output more friendly for posting.

	* [files/file.c]
	Partial implementation of OF_SHARE_EXCLUSIVE.
	Needed for Quicklogic/QuickChip (InstallShield).

	* [files/profile.c]
	When a cached-only entry is found, return it.

	* [graphics/x11drv/xfont.c]
	Accept a space as delimiter for a fontname and inhibit overrun
	(Make xplasim.ex from the Phillips Coolrunner CPLD suite proceed).

	* [miscemu/main.c]
	Delay setting IF1632_CallLargeStack after loading the executables.
	Stops fpgaexp.exe from the Viewlogic FPGA suite from crashing when
 	showing the Blinker error Message Box.

	* [misc/network.c]
	Make WNetGetConnection16 recognise a CDROM as a local drive.

	* [multimedia/mmsystem.c]
	Preliminary check for MCI_ALL_DEVICE_ID in MCI_Close by a FIXME.


Tue Aug 4 21:15:23 1998  James Juran <jrj120@psu.edu>

	* [ole/ole2nls.c]
	Fixed bug in CompareString32A.  strcmp() doesn't necessarily
	return -1, 0, or 1, which the previous code depended on.
	Changed name of is_punctuation to OLE2NLS_isPunctuation.
	Made NORM_IGNOREWIDTH not print a FIXME message in 
	LCMapString32A.
	Other debugging messages, documentation, and code cleanups.

	* [objects/font.c] [relay32/gdi32.spec] [include/winerror.h]
	Added stub for GetFontData32, and added GDI_ERROR constant 
	to winerror.h.

Tue Aug  4 07:44:43 1998  Ove Kaaven <ovek@arcticnet.no>

	* [multimedia/mmio.c]
	Implemented mmioSetBuffer, mmioAdvance, mmioAscend, and
	mmioCreateChunk to the best of my knowledge. But watch out,
	there's bound to be bugs in there...

	* [include/mmsystem.h] [multimedia/mmsystem.c]
	Hacked in support for 32-bit multimedia function callbacks.

	* [AUTHORS] [misc/shell.c]
	Selfishly credited my authorship. Hopefully I'm excused.

	* [include/dosexe.h] [include/module.h] [loader/dos/*]
	  [loader/module.c] [loader/task.c] [Makefile.in]
	  [configure.in] [Makefile.in]
	Added DOS EXE (MZ) loader and virtual machine. Task
	structure integration thanks to Ulrich Weigand.

	* [files/dos_fs.c]
	Work around a null pointer dereference if ioctlGetDeviceInfo-ing
	a FILE_DupUnixHandle'd file (i.e. GetStdHandle'd).

	* [include/miscemu.h] [include/winnt.h] [loader/main.c]
	  [memory/global.c] [msdos/dpmi.c] [msdos/dosmem.c]
	Added support for DOS memory images, and added
	DOSMEM_ResizeBlock() and DOSMEM_Available().

	* [msdos/int21.c]
	Added support for the DOS virtual machine, tweaked handle
	assignment to avoid stdio clashes, forced INT21_FindNext to exit
	wildcardless searches after finding one entry, added AH=7, 8, 9,
	C, 48, 49, 4A, and 7160 CL=1 (Get Short Filename), and made the
	long filename calls only respond if running with with -winver
	win95.

	* [objects/cursoricon.c]
	DestroyCursor32 and DestroyIcon32 should now free the objects
	(hopefully) correctly.

Sun Aug  2 21:42:09 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [graphics/psdrv/*] [include/psdrv.h]
	Added PPD file parsing - at the moment it reads a file called
	default.ppd from the directory in which you start Wine. Page sizes
	other than A4 should now work (landscape may not). All fonts that are
	present on your printer (according to the PPD) should be available,
	providing you have the AFM files. Fonts should now be the correct size.
	Graphics is still basically lines only. See graphics/psdrv/README .

	* [misc/printdrv.c]
	Yet more Drv[Get/Set]PrinterData fixes.

Fri Jul 31 21:33:22 1998  Per Lindström <pelinstr@algonet.se>

	* [relay32/crtdll.spec] [misc/crtdll.c]
	Added stub for freopen, _findfirst, _findnext, _fstat and _read.

	* [files/directory.c]
	Modified warning message.

Wed Jul 29 11:25:28 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [objects/font.c]
	Added stub for GetFontData.

	* [multimedia/msvideo.c]
	Created this file to hold the msvideo.dll calls (and maybe also
	msvfw32.dll). 

	* [objects/cursoricon.c]
	Added search in Global Heap for cursor when trying to destroy it
	with DestroyCursor16. This test should be done in many (all?)
	other functions that use FreeResource.

	* [controls/treeview.c] [include/commctrl.h]
	Minor correction in name and addition of many placeholders for TVM
	messages in TREEVIEW_WindowProc.

	* [msdos/dpmi.c]
	Fixed a bug in DPMI_xrealloc where in a copy of a memory region
	"A" of size "a" to a region "B" of size "b", "b" bytes were being
	copied, instead of "a", as the new version does. This both
	increases speed, as well as avoids segfaults.
1998-08-09 12:47:43 +00:00

1421 lines
38 KiB
C

/*
* Implementation of VER.DLL
*
* Copyright 1996,1997 Marcus Meissner
* Copyright 1997 David Cuthbert
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "windows.h"
#include "win.h"
#include "winerror.h"
#include "heap.h"
#include "ver.h"
#include "lzexpand.h"
#include "module.h"
#include "neexe.h"
#include "debug.h"
#include "xmalloc.h"
#include "winreg.h"
#define LZREAD(what) \
if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
#define LZTELL(lzfd) LZSeek32(lzfd, 0, SEEK_CUR);
/******************************************************************************
*
* 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);
}
/******************************************************************************
*
* 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=0x%lx.0x%lx, fileversion=0x%lx.0x%lx, productversion=0x%lx.0x%lx, flagmask=0x%lx, flags=%s%s%s%s%s%s\n",
(vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF,
vffi->dwFileVersionMS,vffi->dwFileVersionLS,
vffi->dwProductVersionMS,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%lx.0x%lx ",
(vffi->dwFileOS&0xFFFF0000)>>16,
vffi->dwFileOS&0x0000FFFF
);
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 (vffi->dwFileOS & 0xFFFF) {
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%lx)",vffi->dwFileOS&0xFFFF);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);
}
/******************************************************************************
*
* 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;
}
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;
}
static int find_ne_resource(
HFILE32 lzfd,SEGPTR typeid,SEGPTR resid,
BYTE **resdata,int *reslen,DWORD *off
) {
IMAGE_OS2_HEADER nehd;
NE_TYPEINFO ti;
NE_NAMEINFO ni;
int i;
WORD shiftcount;
DWORD nehdoffset;
nehdoffset = LZTELL(lzfd);
LZREAD(&nehd);
if (nehd.resource_tab_offset==nehd.rname_tab_offset) {
TRACE(ver,"no resources in NE dll\n");
return 0;
}
LZSeek32(lzfd,nehd.resource_tab_offset+nehdoffset,SEEK_SET);
LZREAD(&shiftcount);
TRACE(ver,"shiftcount is %d\n",shiftcount);
TRACE(ver,"reading resource typeinfo dir.\n");
if (!HIWORD(typeid)) typeid = (SEGPTR)(LOWORD(typeid) | 0x8000);
if (!HIWORD(resid)) resid = (SEGPTR)(LOWORD(resid) | 0x8000);
while (1) {
int skipflag;
LZREAD(&ti);
if (!ti.type_id)
return 0;
TRACE(ver," ti.typeid =%04x,count=%d\n",ti.type_id,ti.count);
skipflag=0;
if (!HIWORD(typeid)) {
if ((ti.type_id&0x8000)&&(typeid!=ti.type_id))
skipflag=1;
} else {
if (ti.type_id & 0x8000) {
skipflag=1;
} else {
BYTE len;
char *str;
DWORD whereleft;
whereleft = LZTELL(lzfd);
LZSeek32(
lzfd,
nehdoffset+nehd.resource_tab_offset+ti.type_id,
SEEK_SET
);
LZREAD(&len);
str=xmalloc(len);
if (len!=LZRead32(lzfd,str,len))
return 0;
TRACE(ver,"read %s to compare it with %s\n",
str,(char*)PTR_SEG_TO_LIN(typeid)
);
if (lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
skipflag=1;
free(str);
LZSeek32(lzfd,whereleft,SEEK_SET);
}
}
if (skipflag) {
LZSeek32(lzfd,ti.count*sizeof(ni),SEEK_CUR);
continue;
}
for (i=0;i<ti.count;i++) {
WORD *rdata;
int len;
LZREAD(&ni);
TRACE(ver," ni.id=%4x,offset=%d,length=%d\n",
ni.id,ni.offset,ni.length
);
skipflag=1;
if (!HIWORD(resid)) {
if (ni.id == resid)
skipflag=0;
} else {
if (!(ni.id & 0x8000)) {
BYTE len;
char *str;
DWORD whereleft;
whereleft = LZTELL(lzfd);
LZSeek32(
lzfd,
nehdoffset+nehd.resource_tab_offset+ni.id,
SEEK_SET
);
LZREAD(&len);
str=xmalloc(len);
if (len!=LZRead32(lzfd,str,len))
return 0;
TRACE(ver,"read %s to compare it with %s\n",
str,(char*)PTR_SEG_TO_LIN(typeid)
);
if (!lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
skipflag=0;
free(str);
LZSeek32(lzfd,whereleft,SEEK_SET);
}
}
if (skipflag)
continue;
LZSeek32(lzfd,((int)ni.offset<<shiftcount),SEEK_SET);
*off = (int)ni.offset<<shiftcount;
len = ni.length<<shiftcount;
rdata=(WORD*)xmalloc(len);
if (len!=LZRead32(lzfd,rdata,len)) {
free(rdata);
return 0;
}
TRACE(ver,"resource found.\n");
*resdata= (BYTE*)rdata;
*reslen = len;
return 1;
}
}
}
/* Loads the specified PE resource.
* FIXME: shouldn't load the whole image
*/
static int
find_pe_resource(
HFILE32 lzfd,LPWSTR typeid,LPWSTR resid,
BYTE **resdata,int *reslen,DWORD *off
) {
IMAGE_NT_HEADERS pehd;
int i;
UINT32 nrofsections;
DWORD imagesize,pehdoffset;
BYTE *image;
IMAGE_DATA_DIRECTORY resdir;
LPIMAGE_RESOURCE_DIRECTORY resourcedir,xresdir;
LPIMAGE_RESOURCE_DATA_ENTRY xresdata;
LPIMAGE_SECTION_HEADER sections;
pehdoffset = LZTELL(lzfd);
LZREAD(&pehd);
resdir = pehd.OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
TRACE(ver,"(.,%p,%p,....)\n",typeid,resid);
if (!resdir.Size) {
WARN(ver,"No resource directory found in PE file.\n");
return 0;
}
imagesize = pehd.OptionalHeader.SizeOfImage;
image = HeapAlloc(GetProcessHeap(),0,imagesize);
nrofsections = pehd.FileHeader.NumberOfSections;
sections = (LPIMAGE_SECTION_HEADER)HeapAlloc(GetProcessHeap(),0,pehd.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
LZSeek32(lzfd,
pehdoffset+
sizeof(DWORD)+ /* Signature */
sizeof(IMAGE_FILE_HEADER)+
pehd.FileHeader.SizeOfOptionalHeader,
SEEK_SET
);
if ( nrofsections*sizeof(IMAGE_SECTION_HEADER)!=
LZRead32(lzfd,sections,nrofsections*sizeof(IMAGE_SECTION_HEADER))
) {
HeapFree(GetProcessHeap(),0,image);
return 0;
}
for (i=0;i<nrofsections;i++) {
if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
continue;
LZSeek32(lzfd,sections[i].PointerToRawData,SEEK_SET);
if ( sections[i].SizeOfRawData!=
LZRead32(lzfd,image+sections[i].VirtualAddress,sections[i].SizeOfRawData)
) {
HeapFree(GetProcessHeap(),0,image);
return 0;
}
}
resourcedir = (LPIMAGE_RESOURCE_DIRECTORY)(image+resdir.VirtualAddress);
xresdir = GetResDirEntryW(resourcedir,typeid,(DWORD)resourcedir,FALSE);
if (!xresdir) {
TRACE(ver,"...no typeid entry found for %p\n",typeid);
HeapFree(GetProcessHeap(),0,image);
return 0;
}
xresdir = GetResDirEntryW(xresdir,resid,(DWORD)resourcedir,FALSE);
if (!xresdir) {
TRACE(ver,"...no resid entry found for %p\n",resid);
HeapFree(GetProcessHeap(),0,image);
return 0;
}
xresdir = GetResDirEntryW(xresdir,0,(DWORD)resourcedir,TRUE);
if (!xresdir) {
TRACE(ver,"...no 0 (default language) entry found for %p\n",resid);
HeapFree(GetProcessHeap(),0,image);
return 0;
}
xresdata = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir;
*reslen = xresdata->Size;
*resdata= (LPBYTE)xmalloc(*reslen);
memcpy(*resdata,image+xresdata->OffsetToData,*reslen);
/* find physical address for virtual offset */
for (i=0;i<nrofsections;i++) {
if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
continue;
if ( (xresdata->OffsetToData >= sections[i].VirtualAddress)&&
(xresdata->OffsetToData < sections[i].VirtualAddress+sections[i].SizeOfRawData)
) {
*off = (DWORD)(xresdata->OffsetToData)-(DWORD)(sections[i].VirtualAddress)+(DWORD)(sections[i].PointerToRawData);
break;
}
}
HeapFree(GetProcessHeap(),0,image);
HeapFree(GetProcessHeap(),0,sections);
return 1;
}
/* GetFileResourceSize [VER.2] */
DWORD WINAPI GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,
LPDWORD off)
{
HFILE32 lzfd;
OFSTRUCT ofs;
BYTE *resdata = NULL;
int reslen=0;
int res=0;
TRACE(ver,"(%s,%lx,%lx,%p)\n",
filename,(LONG)restype,(LONG)resid,off
);
lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
if (!lzfd)
return 0;
switch (read_xx_header(lzfd)) {
case 0:
res=0;
break;
case IMAGE_OS2_SIGNATURE:
res=find_ne_resource(lzfd,restype,resid,&resdata,&reslen,off);
break;
case IMAGE_NT_SIGNATURE:
res=find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,off);
break;
}
if (!res) {
LZClose32(lzfd);
return 0;
}
if (resdata)
free(resdata);
LZClose32(lzfd);
return reslen;
}
/* GetFileResource [VER.3] */
DWORD WINAPI GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
DWORD off,DWORD datalen,LPVOID data )
{
HFILE32 lzfd;
OFSTRUCT ofs;
BYTE *resdata=NULL;
int res=0;
int reslen=datalen;
TRACE(ver,"(%s,%lx,%lx,%ld,%ld,%p)\n",
filename,(LONG)restype,(LONG)resid,off,datalen,data
);
lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
if (lzfd==0)
return 0;
if (!off) {
switch (read_xx_header(lzfd)) {
case 0: res=0;
break;
case IMAGE_OS2_SIGNATURE:
res= find_ne_resource(lzfd,restype,resid,&resdata,&reslen,&off);
break;
case IMAGE_NT_SIGNATURE:
res= find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,&off);
break;
}
LZClose32(lzfd);
if (!res)
return 0;
if (reslen>datalen) reslen = datalen;
memcpy(data,resdata,reslen);
free(resdata);
return reslen;
}
LZSeek32(lzfd,off,SEEK_SET);
reslen = LZRead32(lzfd,data,datalen);
LZClose32(lzfd);
return reslen;
}
/* GetFileVersionInfoSize [VER.6] */
DWORD WINAPI GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle)
{
DWORD len,ret,isuni=0;
BYTE buf[144];
VS_FIXEDFILEINFO *vffi;
TRACE(ver,"(%s,%p)\n",filename,handle);
len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle);
if (!len)
return 0;
ret=GetFileResource(
filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf
);
if (!ret)
return 0;
vffi=(VS_FIXEDFILEINFO*)(buf+0x14);
if (vffi->dwSignature != VS_FFI_SIGNATURE) {
/* unicode resource */
if (vffi->dwSignature == 0x004f0049) {
isuni = 1;
vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
} else {
WARN(ver,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
vffi->dwSignature,VS_FFI_SIGNATURE
);
return 0;
}
}
if (*(WORD*)buf < len)
len = *(WORD*)buf;
if(TRACE_ON(ver))
print_vffi_debug(vffi);
return len;
}
/* GetFileVersionInfoSize32A [VERSION.1] */
DWORD WINAPI GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle)
{
TRACE(ver,"(%s,%p)\n",filename,handle);
return GetFileVersionInfoSize16(filename,handle);
}
/* GetFileVersionInfoSize32W [VERSION.2] */
DWORD WINAPI GetFileVersionInfoSize32W( LPCWSTR filename, LPDWORD handle )
{
LPSTR xfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
DWORD ret = GetFileVersionInfoSize16( xfn, handle );
HeapFree( GetProcessHeap(), 0, xfn );
return ret;
}
/* GetFileVersionInfo [VER.7] */
DWORD WINAPI GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize,
LPVOID data)
{
TRACE(ver,"(%s,%ld,%ld,%p)\n",
filename,handle,datasize,data
);
return GetFileResource(
filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data
);
}
/* GetFileVersionInfoA [VERSION.0] */
DWORD WINAPI GetFileVersionInfo32A(LPCSTR filename,DWORD handle,
DWORD datasize,LPVOID data)
{
return GetFileVersionInfo16(filename,handle,datasize,data);
}
/* GetFileVersionInfoW [VERSION.3] */
DWORD WINAPI GetFileVersionInfo32W( LPCWSTR filename, DWORD handle,
DWORD datasize, LPVOID data)
{
LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
DWORD ret = GetFileVersionInfo16( fn, handle, datasize, data );
HeapFree( GetProcessHeap(), 0, fn );
return ret;
}
/*****************************************************************************
*
* 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.
*
****************************************************************************/
DWORD WINAPI VerFindFile16(
UINT16 flags,
LPCSTR lpszFilename,
LPCSTR lpszWinDir,
LPCSTR lpszAppDir,
LPSTR lpszCurDir,
UINT16 *lpuCurDirLen,
LPSTR lpszDestDir,
UINT16 *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;
}
/* VerFindFileA [VERSION.5] */
DWORD WINAPI VerFindFile32A(
UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen )
{
UINT16 curdirlen, destdirlen;
DWORD ret;
curdirlen = (UINT16)*pcurdirlen;
destdirlen= (UINT16)*pdestdirlen;
ret = VerFindFile16(flags,filename,windir,appdir,
curdir,&curdirlen,destdir,&destdirlen);
*pcurdirlen = curdirlen;
*pdestdirlen = destdirlen;
return ret;
}
/* VerFindFileW [VERSION.6] */
DWORD WINAPI VerFindFile32W(
UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir,
LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen )
{
UINT16 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 = VerFindFile16(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;
}
/* VerInstallFile [VER.9] */
DWORD WINAPI VerInstallFile16(
UINT16 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT16 *tmpfilelen )
{
UINT32 filelen;
DWORD ret= VerInstallFile32A(flags,srcfilename,destfilename,srcdir,
destdir,curdir,tmpfile,&filelen);
*tmpfilelen = filelen;
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<strlen(tmpfn+tmplast)) {
xret|=VIF_BUFFTOOSMALL;
DeleteFile32A(tmpfn);
} else {
strcpy(tmpfile,tmpfn+tmplast);
*tmpfilelen = strlen(tmpfn+tmplast)+1;
xret|=VIF_TEMPFILE;
}
} else {
if (-1!=GetFileAttributes32A(destfn))
if (!DeleteFile32A(destfn)) {
xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE;
DeleteFile32A(tmpfn);
LZClose32(hfsrc);
return xret;
}
if ((!(flags & VIFF_DONTDELETEOLD)) &&
curdir &&
*curdir &&
lstrcmpi32A(curdir,pdest)
) {
char curfn[260];
sprintf(curfn,"%s\\%s",curdir,destfilename);
if (-1!=GetFileAttributes32A(curfn)) {
/* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
if (!DeleteFile32A(curfn))
xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR;
}
}
if (!MoveFile32A(tmpfn,destfn)) {
xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME;
DeleteFile32A(tmpfn);
}
}
LZClose32(hfsrc);
return xret;
}
/* VerInstallFileW [VERSION.8] */
DWORD WINAPI VerInstallFile32W(
UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,UINT32 *tmpfilelen )
{
LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf,wcurd;
DWORD ret;
wsrcf = HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename );
wsrcd = HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir );
wdestf = HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename );
wdestd = HEAP_strdupWtoA( GetProcessHeap(), 0, destdir );
wtmpf = HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile );
wcurd = HEAP_strdupWtoA( GetProcessHeap(), 0, curdir );
ret = VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,tmpfilelen);
if (!ret)
lstrcpynAtoW(tmpfile,wtmpf,*tmpfilelen);
HeapFree( GetProcessHeap(), 0, wsrcf );
HeapFree( GetProcessHeap(), 0, wsrcd );
HeapFree( GetProcessHeap(), 0, wdestf );
HeapFree( GetProcessHeap(), 0, wdestd );
HeapFree( GetProcessHeap(), 0, wtmpf );
if (wcurd)
HeapFree( GetProcessHeap(), 0, wcurd );
return ret;
}
struct dbA {
WORD nextoff;
WORD datalen;
/* in memory structure... */
char name[1]; /* padded to dword alignment */
/* ....
char data[datalen]; padded to dword alignment
BYTE subdirdata[]; until nextoff
*/
};
#define DATA_OFFSET_A(db) ((4+(strlen((db)->name)+4))&~3)
struct dbW {
WORD nextoff;
WORD datalen;
WORD btext; /* type of data */
/* in memory structure... */
WCHAR name[1]; /* padded to dword alignment */
/* ....
WCHAR data[datalen]; padded to dword alignment
BYTE subdirdata[]; until nextoff
*/
};
/* WORD nextoffset;
* WORD datalength;
* WORD btype;
* WCHAR szKey[]; (zero terminated)
* PADDING (round up to nearest 32bit boundary)
*/
#define DATA_OFFSET_W(db) ((2+2+2+((lstrlen32W((db)->name)+1)*2+3))&~3)
/* this one used for Win16 resources, which are always in ASCII format */
static BYTE*
_find_dataA(BYTE *block,LPCSTR str, int buff_remain) {
char *nextslash;
int substrlen, inc_size;
struct dbA *db;
while (*str && *str=='\\')
str++;
if (NULL!=(nextslash=strchr(str,'\\')))
substrlen=nextslash-str;
else
substrlen=strlen(str);
if (nextslash!=NULL) {
while (*nextslash && *nextslash=='\\')
nextslash++;
if (!*nextslash)
nextslash=NULL;
} else if (*str == 0)
return NULL;
while (1) {
db=(struct dbA*)block;
TRACE(ver,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s\n",
db,db->nextoff,db->datalen,db->name
);
if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
return NULL;
TRACE(ver,"comparing with %s\n",db->name);
if (!lstrncmpi32A(db->name,str,substrlen)) {
if (nextslash) {
inc_size=DATA_OFFSET_A(db)+((db->datalen+3)&~3);
return _find_dataA(block+inc_size,nextslash,
db->nextoff-inc_size);
} else
return block;
}
inc_size = ((db->nextoff+3)&~3);
block += inc_size;
buff_remain -= inc_size;
}
}
/* this one used for Win32 resources, which are always in UNICODE format */
extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar);
static BYTE*
_find_dataW(BYTE *block,LPCWSTR str, int buff_remain) {
LPWSTR nextslash;
int substrlen, inc_size;
struct dbW *db;
while (*str && *str=='\\')
str++;
if (NULL!=(nextslash=CRTDLL_wcschr(str,'\\')))
substrlen=nextslash-str;
else
substrlen=lstrlen32W(str);
if (nextslash!=NULL) {
while (*nextslash && *nextslash=='\\')
nextslash++;
if (!*nextslash)
nextslash=NULL;
} else if (*str == 0)
return NULL;
while (1) {
char *xs,*vs;
db=(struct dbW*)block;
xs= HEAP_strdupWtoA(GetProcessHeap(),0,db->name);
if (db->datalen) {
if (db->btext)
vs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)((block+DATA_OFFSET_W(db))));
else
vs = HEAP_strdupA(GetProcessHeap(),0,"not a string");
} else
vs = HEAP_strdupA(GetProcessHeap(),0,"no data");
TRACE(ver,"db->nextoff=%d,db->name=%s,db->data=\"%s\"\n",
db->nextoff,xs,vs
);
HeapFree(GetProcessHeap(),0,vs);
HeapFree(GetProcessHeap(),0,xs);
if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
return NULL;
if (!lstrncmpi32W(db->name,str,substrlen)) {
if (nextslash) {
/* DATA_OFFSET_W(db) (padded to 32bit already)
* DATA[datalength]
* PADDING (round up to nearest 32bit boundary)
* --> next level structs
*/
inc_size=DATA_OFFSET_W(db)+((db->datalen+3)&~3);
return _find_dataW( block+inc_size ,nextslash,
db->nextoff-inc_size);
} else
return block;
}
/* skip over this block, round up to nearest 32bit boundary */
inc_size = ((db->nextoff+3)&~3);
block += inc_size;
buff_remain -= inc_size;
}
}
/* VerQueryValue [VER.11] */
/* take care, 'buffer' is NOT a SEGPTR, it just points to one */
DWORD WINAPI VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,
UINT16 *buflen)
{
LPSTR s;
BYTE *block=PTR_SEG_TO_LIN(segblock),*b;
TRACE(ver,"(%p,%s,%p,%d)\n",
block,subblock,buffer,*buflen
);
s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
/* check for UNICODE version */
if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
(*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
) {
struct dbW *db;
LPWSTR wstr;
LPSTR xs;
wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
b=_find_dataW(block,wstr,*(WORD*)block);
HeapFree(GetProcessHeap(),0,wstr);
if (!b) {
WARN(ver,"key %s not found in versionresource.\n",s);
*buflen=0;
free (s);
return 0;
}
db=(struct dbW*)b;
b = b+DATA_OFFSET_W(db);
*buflen = db->datalen;
if (db->btext) {
xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
TRACE(ver,"->%s\n",xs);
HeapFree(GetProcessHeap(),0,xs);
} else
TRACE(ver,"->%p\n",b);
} else {
struct dbA *db;
b=_find_dataA(block,s,*(WORD*)block);
if (!b) {
WARN(ver,"key %s not found in versionresource.\n",s);
*buflen=0;
free (s);
return 0;
}
db=(struct dbA*)b;
b = b+DATA_OFFSET_A(db);
*buflen = db->datalen;
/* the string is only printable, if it is below \\StringFileInfo*/
if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
TRACE(ver," -> %s=%s\n",subblock,b);
else
TRACE(ver," -> %s=%p\n",subblock,b);
}
*buffer = (b-block)+segblock;
free(s);
return 1;
}
DWORD WINAPI VerQueryValue32A(LPVOID vblock,LPCSTR subblock,
LPVOID *vbuffer,UINT32 *buflen)
{
BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer;
LPSTR s;
TRACE(ver,"(%p,%s,%p,%d)\n",
block,subblock,buffer,*buflen
);
s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
/* check for UNICODE version */
if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
(*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
) {
LPWSTR wstr;
LPSTR xs;
struct dbW *db;
wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
b=_find_dataW(block,wstr,*(WORD*)block);
HeapFree(GetProcessHeap(),0,wstr);
if (!b) {
WARN(ver,"key %s not found in versionresource.\n",s);
*buflen=0;
free (s);
return 0;
}
db = (struct dbW*)b;
*buflen = db->datalen;
b = b+DATA_OFFSET_W(db);
if (db->btext) {
xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
TRACE(ver,"->%s\n",xs);
HeapFree(GetProcessHeap(),0,xs);
} else
TRACE(ver,"->%p\n",b);
/* This is a leak. */
b = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
} else {
struct dbA *db;
b=_find_dataA(block,s,*(WORD*)block);
if (!b) {
WARN(ver,"key %s not found in versionresource.\n",subblock);
*buflen=0;
free (s);
return 0;
}
db=(struct dbA*)b;
*buflen = db->datalen;
b = b+DATA_OFFSET_A(db);
/* the string is only printable, if it is below \\StringFileInfo*/
if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
TRACE(ver," -> %s=%s\n",subblock,b);
else
TRACE(ver," -> %s=%p\n",subblock,b);
}
*buffer = b;
free(s);
return 1;
}
DWORD WINAPI VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer,
UINT32 *buflen)
{
LPSTR sb;
DWORD ret;
sb = HEAP_strdupWtoA( GetProcessHeap(), 0, subblock );
ret = VerQueryValue32A(vblock,sb,vbuffer,buflen);
HeapFree( GetProcessHeap(), 0, sb );
return 1;
}
/* 20 GETFILEVERSIONINFORAW */