
Sat Jun 14 13:05:23 1997 Andreas Mohr <100.30936@germany.net> * [include/mmsystem.h] Avoided infinite loop in audio code when accessing WAVEOUTCAPS/WAVEINCAPS/MIDIOUTCAPS/AUXCAPS with rigid variable offsets (I applied WINE_PACKED). * [*/*] Added "WARNING:" and "ERROR:" to some printf's. Just grep for them with '-debugmsg +all'. * [multimedia/audio.c] [multimedia/mmsystem.c] Implemented wave callbacks: window and function callback. Fixed problem with WAVE_NotifyClient(). Misc fixes. * [windows/winhelp.c] Fixed problem with windows help telling "Help topic doesn't exist". But this problem still remains when using Winword. Wed Jun 11 09:14:20 1997 Alex Korobka <alex@trantor.pharm.sunysb.edu> * [wine.ini] New 'fonts' section format. Read documentation/fonts. * [controls/icontitle.c] [windows/winpos.c] [windows/nonclient.c] [windows/win.c] [include/win.h] Implemented icon titles. * [graphics/x11drv/xfont.c] [objects/font.c] [objects/dc.c] [include/x11drv.h] [include/x11font.h] [documentation/fonts] Rewrote font mapper from scratch. * [tools/fnt2bdf.c] Bug fixes. REPLACE FONTS CREATED BY THE PREVIOUS VERSIONS. * [windows/defwnd.c] [windows/nonclient.c] Word document window activation fix. * [windows/mdi.c] [windows/win.c] Replaced WCL lists with WIN_BuildWinArray(). Mon Jun 9 23:51:16 1997 Andrew Taylor <andrew@riscan.com> * [misc/error.c] [include/windows.h] [if1632/kernel.spec] Implemented LogParamError, LogError functions. Tue Jun 3 23:46:04 1997 Michiel van Loon <mfvl@xs4all.nl> * [include/mmsystem.h] [multimedia/audio.c] Constants for asynchronous play and record. * [multimedia/time.c] Filled in some empty functions. * [multimedia/mmsystem.c] Fixed bugs in waveOutOpen. * [multimedia/mmsystem.c] [multimedia/audio.c] Implemented Window Callback for wave output at least. * [files/file.c] Corrected bug in FileDosSetError. NULL pointer checking added. * [misc/spy.c] Added Multimedia messages to SPY_GetMsgName. Tue Jun 3 22:34:30 1997 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de> * [debugger/*.c][include/peexe.h][loader/*.c][tools/build.c] [tools/fnt2bdf.c][library/sup.c] IMAGE_* structs/defines changed fit better to SDK naming Don't load non-i386 PE executables. %fs should already be initialised for the FIRST loaded PE module. * [if1632/advapi.spec][win32/advapi.c] Some small stubs added to bring win32 setup.exe a bit farther. * [if1632/kernel32.spec][scheduler/process.c] Adapted to match win95 kernel32.dll ordinals (NT doesn't use ordinal import), some ordinal only exported functions added. * [if1632/relay.c] Added CallProc32W. * [misc/lzexpand.c] Fixed return values of GetExpandedName* (thanks to Andreas Mohr). * [objects/dib.c] Everything with more than 8 bit of color is a truecolor mode and doesn't have a colormap. Tue Jun 3 09:24:53 1997 John Harvey <john@division.co.uk> * [graphics/win16drv/font.c] [graphics/win16drv/init.c] [graphics/win16drv/prtdrv.c] [graphics/win16drv/text.c] [include/win16drv.h] Changed some structures that are passed to and from the 16 bit drivers to be allocated on the global heap. Implemented Escape(Control) 0x100 GetExtTextData properly to stop word from crashing. Postscript driver now prints on complete page instead of top left corner. Print spooling implemented. * [loader/module.c] MODULE_GetOrdinal changed char buffer to unsigned char to stop a loop that was happening when running the font control program from the control panel. Sun Jun 1 19:05:02 1997 Peter Schlaile <up9n@rz.uni-karlsruhe.de> * [include/miscemu.h] [loader/main.c] [msdos/ioports.c] Added support for direct io port access. Fri May 30 16:18:35 1997 David A. Cuthbert <dacut@dssc3353.ece.cmu.edu> * [misc/ver.c] Implemented VerFindFile16. Tue May 27 22:00:39 1997 Rick Richardson <rick@dgii.com> * [misc/comm.c] Fixed GetCommError and GetCommEventMask. Tue May 27 9:10:53 1997 Georg Beyerle <gbeyerle@awi-potsdam.de> * [scheduler/thread.c] Minor fix in thread database initialization. Mon May 26 19:46:34 1997 Philippe De Muyter <phdm@info.ucl.ac.be> * [objects/dc.c] In DC_SetupGCForPen, avoid to draw in GXxor mode with a 0 mask. Mon May 26 15:22:42 1997 Bruce Milner <Bruce.Milner@genetics.utah.edu> * [loader/pe_image.c] Add code for modules that co-reference each other. Photodex's agds.exe (cpic32) has two dll's that make calls into each other. Mon May 26 13:38:16 1997 Jody Goldberg <jodyg@idt.net> * [memory/virtual.c] Dont use stdio when reading /proc/self/maps. It causes problems with libc6. * [windows/dialog.c] Translate messages in IsDialogMessage when DLGC_WANTMESSAGE is used. Sun May 25 17:02:21 1997 Huw D M Davies <h.davies1@physics.oxford.ac.uk> * [objects/metafile.c] Resource cleanup in EnumMetaFile(). This was one reason Word was crashing after long periods of use. (Thanks to Chris Underhill for the logs) Sun May 25 14:59:33 1997 Jimen Ching <jching@flex.com> * [multimedia/mcistring.c] Initial support for compound MCI commands. Use case-insensitive compare for 'alias' and 'element' keywords. Fixed pointer copy of args keywords array.
1224 lines
32 KiB
C
1224 lines
32 KiB
C
/*
|
||
* Implementation of VER.DLL
|
||
*
|
||
* Copyright 1996 Marcus Meissner
|
||
*/
|
||
#include <stdlib.h>
|
||
#include <stdio.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 "stddebug.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 dprintf_ver_string(
|
||
* 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.
|
||
*
|
||
* Revision history
|
||
* 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
|
||
* Original implementation
|
||
*
|
||
*****************************************************************************/
|
||
|
||
static void dprintf_ver_string(
|
||
char const * prologue,
|
||
char const * teststring,
|
||
char const * epilogue )
|
||
{
|
||
dprintf_ver(stddeb, "%s", prologue);
|
||
|
||
if(teststring)
|
||
dprintf_ver(stddeb, "%p (\"%s\")", (void const *) teststring,
|
||
teststring);
|
||
else
|
||
dprintf_ver(stddeb, "(null)");
|
||
|
||
dprintf_ver(stddeb, "%s", epilogue);
|
||
|
||
return;
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* 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;
|
||
}
|
||
|
||
|
||
int
|
||
read_ne_header(HFILE32 lzfd,LPIMAGE_OS2_HEADER nehd) {
|
||
IMAGE_DOS_HEADER mzh;
|
||
|
||
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);
|
||
LZREAD(nehd);
|
||
if (nehd->ne_magic == IMAGE_OS2_SIGNATURE) {
|
||
LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
|
||
return 1;
|
||
}
|
||
fprintf(stderr,"misc/ver.c:read_ne_header:can't handle PE files yet.\n");
|
||
/* must handle PE files too. Later. */
|
||
return 0;
|
||
}
|
||
|
||
|
||
int
|
||
find_ne_resource(
|
||
HFILE32 lzfd,LPIMAGE_OS2_HEADER nehd,SEGPTR typeid,SEGPTR resid,
|
||
BYTE **resdata,int *reslen,DWORD *off
|
||
) {
|
||
NE_TYPEINFO ti;
|
||
NE_NAMEINFO ni;
|
||
int i;
|
||
WORD shiftcount;
|
||
DWORD nehdoffset;
|
||
|
||
nehdoffset = LZTELL(lzfd);
|
||
LZSeek32(lzfd,nehd->resource_tab_offset,SEEK_CUR);
|
||
LZREAD(&shiftcount);
|
||
dprintf_ver(stddeb,"shiftcount is %d\n",shiftcount);
|
||
dprintf_ver(stddeb,"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;
|
||
dprintf_ver(stddeb," 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;
|
||
dprintf_ver(stddeb,"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);
|
||
dprintf_ver(stddeb," 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;
|
||
dprintf_ver(stddeb,"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;
|
||
}
|
||
dprintf_ver(stddeb,"resource found.\n");
|
||
*resdata= (BYTE*)rdata;
|
||
*reslen = len;
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* GetFileResourceSize [VER.2] */
|
||
DWORD
|
||
GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,LPDWORD off) {
|
||
HFILE32 lzfd;
|
||
OFSTRUCT ofs;
|
||
BYTE *resdata;
|
||
int reslen;
|
||
IMAGE_OS2_HEADER nehd;
|
||
|
||
dprintf_ver(stddeb,"GetFileResourceSize(%s,%lx,%lx,%p)\n",
|
||
filename,(LONG)restype,(LONG)resid,off
|
||
);
|
||
lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
|
||
if (lzfd==0)
|
||
return 0;
|
||
if (!read_ne_header(lzfd,&nehd)) {
|
||
LZClose32(lzfd);
|
||
return 0;
|
||
}
|
||
if (!find_ne_resource(lzfd,&nehd,restype,resid,&resdata,&reslen,off)) {
|
||
LZClose32(lzfd);
|
||
return 0;
|
||
}
|
||
free(resdata);
|
||
LZClose32(lzfd);
|
||
return reslen;
|
||
}
|
||
|
||
/* GetFileResource [VER.3] */
|
||
DWORD
|
||
GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
|
||
DWORD off,DWORD datalen,LPVOID data
|
||
) {
|
||
HFILE32 lzfd;
|
||
OFSTRUCT ofs;
|
||
BYTE *resdata;
|
||
int reslen=datalen;
|
||
IMAGE_OS2_HEADER nehd;
|
||
dprintf_ver(stddeb,"GetFileResource(%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) {
|
||
if (!read_ne_header(lzfd,&nehd)) {
|
||
LZClose32(lzfd);
|
||
return 0;
|
||
}
|
||
if (!find_ne_resource(lzfd,&nehd,restype,resid,&resdata,&reslen,&off)) {
|
||
LZClose32(lzfd);
|
||
return 0;
|
||
}
|
||
free(resdata);
|
||
}
|
||
LZSeek32(lzfd,off,SEEK_SET);
|
||
if (reslen>datalen)
|
||
reslen=datalen;
|
||
LZRead32(lzfd,data,reslen);
|
||
LZClose32(lzfd);
|
||
return reslen;
|
||
}
|
||
|
||
/* GetFileVersionInfoSize [VER.6] */
|
||
DWORD
|
||
GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle) {
|
||
DWORD len,ret;
|
||
BYTE buf[72];
|
||
VS_FIXEDFILEINFO *vffi;
|
||
|
||
dprintf_ver(stddeb,"GetFileVersionInfoSize16(%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)
|
||
return 0;
|
||
if (*(WORD*)buf < len)
|
||
len = *(WORD*)buf;
|
||
dprintf_ver(stddeb,"->strucver=%ld.%ld,filever=%ld.%ld,productver=%ld.%ld,flagmask=%lx,flags=%lx,OS=",
|
||
(vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF,
|
||
vffi->dwFileVersionMS,vffi->dwFileVersionLS,
|
||
vffi->dwProductVersionMS,vffi->dwProductVersionLS,
|
||
vffi->dwFileFlagsMask,vffi->dwFileFlags
|
||
);
|
||
switch (vffi->dwFileOS&0xFFFF0000) {
|
||
case VOS_DOS:dprintf_ver(stddeb,"DOS,");break;
|
||
case VOS_OS216:dprintf_ver(stddeb,"OS/2-16,");break;
|
||
case VOS_OS232:dprintf_ver(stddeb,"OS/2-32,");break;
|
||
case VOS_NT:dprintf_ver(stddeb,"NT,");break;
|
||
case VOS_UNKNOWN:
|
||
default:
|
||
dprintf_ver(stddeb,"UNKNOWN(%ld),",vffi->dwFileOS&0xFFFF0000);break;
|
||
}
|
||
switch (vffi->dwFileOS & 0xFFFF) {
|
||
case VOS__BASE:dprintf_ver(stddeb,"BASE");break;
|
||
case VOS__WINDOWS16:dprintf_ver(stddeb,"WIN16");break;
|
||
case VOS__WINDOWS32:dprintf_ver(stddeb,"WIN32");break;
|
||
case VOS__PM16:dprintf_ver(stddeb,"PM16");break;
|
||
case VOS__PM32:dprintf_ver(stddeb,"PM32");break;
|
||
default:dprintf_ver(stddeb,"UNKNOWN(%ld)",vffi->dwFileOS&0xFFFF);break;
|
||
}
|
||
switch (vffi->dwFileType) {
|
||
default:
|
||
case VFT_UNKNOWN:
|
||
dprintf_ver(stddeb,"filetype=Unknown(%ld)",vffi->dwFileType);
|
||
break;
|
||
case VFT_APP:dprintf_ver(stddeb,"filetype=APP");break;
|
||
case VFT_DLL:dprintf_ver(stddeb,"filetype=DLL");break;
|
||
case VFT_DRV:
|
||
dprintf_ver(stddeb,"filetype=DRV,");
|
||
switch(vffi->dwFileSubtype) {
|
||
default:
|
||
case VFT2_UNKNOWN:
|
||
dprintf_ver(stddeb,"UNKNOWN(%ld)",vffi->dwFileSubtype);
|
||
break;
|
||
case VFT2_DRV_PRINTER:
|
||
dprintf_ver(stddeb,"PRINTER");
|
||
break;
|
||
case VFT2_DRV_KEYBOARD:
|
||
dprintf_ver(stddeb,"KEYBOARD");
|
||
break;
|
||
case VFT2_DRV_LANGUAGE:
|
||
dprintf_ver(stddeb,"LANGUAGE");
|
||
break;
|
||
case VFT2_DRV_DISPLAY:
|
||
dprintf_ver(stddeb,"DISPLAY");
|
||
break;
|
||
case VFT2_DRV_MOUSE:
|
||
dprintf_ver(stddeb,"MOUSE");
|
||
break;
|
||
case VFT2_DRV_NETWORK:
|
||
dprintf_ver(stddeb,"NETWORK");
|
||
break;
|
||
case VFT2_DRV_SYSTEM:
|
||
dprintf_ver(stddeb,"SYSTEM");
|
||
break;
|
||
case VFT2_DRV_INSTALLABLE:
|
||
dprintf_ver(stddeb,"INSTALLABLE");
|
||
break;
|
||
case VFT2_DRV_SOUND:
|
||
dprintf_ver(stddeb,"SOUND");
|
||
break;
|
||
case VFT2_DRV_COMM:
|
||
dprintf_ver(stddeb,"COMM");
|
||
break;
|
||
case VFT2_DRV_INPUTMETHOD:
|
||
dprintf_ver(stddeb,"INPUTMETHOD");
|
||
break;
|
||
}
|
||
break;
|
||
case VFT_FONT:
|
||
dprintf_ver(stddeb,"filetype=FONT.");
|
||
switch (vffi->dwFileSubtype) {
|
||
default:
|
||
dprintf_ver(stddeb,"UNKNOWN(%ld)",vffi->dwFileSubtype);
|
||
break;
|
||
case VFT2_FONT_RASTER:dprintf_ver(stddeb,"RASTER");break;
|
||
case VFT2_FONT_VECTOR:dprintf_ver(stddeb,"VECTOR");break;
|
||
case VFT2_FONT_TRUETYPE:dprintf_ver(stddeb,"TRUETYPE");break;
|
||
}
|
||
break;
|
||
case VFT_VXD:dprintf_ver(stddeb,"filetype=VXD");break;
|
||
case VFT_STATIC_LIB:dprintf_ver(stddeb,"filetype=STATIC_LIB");break;
|
||
}
|
||
dprintf_ver(stddeb,"filedata=%lx.%lx\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
|
||
return len;
|
||
}
|
||
|
||
/* GetFileVersionInfoSize32A [VERSION.1] */
|
||
DWORD
|
||
GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle) {
|
||
dprintf_ver(stddeb,"GetFileVersionInfoSize32A(%s,%p)\n",filename,handle);
|
||
return GetFileVersionInfoSize16(filename,handle);
|
||
}
|
||
|
||
/* GetFileVersionInfoSize32W [VERSION.2] */
|
||
DWORD 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
|
||
GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize,LPVOID data) {
|
||
dprintf_ver(stddeb,"GetFileVersionInfo16(%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
|
||
GetFileVersionInfo32A(LPCSTR filename,DWORD handle,DWORD datasize,LPVOID data) {
|
||
return GetFileVersionInfo16(filename,handle,datasize,data);
|
||
}
|
||
|
||
/* GetFileVersionInfoW [VERSION.3] */
|
||
DWORD 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 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 */
|
||
dprintf_ver(stddeb, "VerFindFile() called with parameters:\n"
|
||
"\tflags = %x", flags);
|
||
if(flags & VFFF_ISSHAREDFILE)
|
||
dprintf_ver(stddeb, " (VFFF_ISSHAREDFILE)\n");
|
||
else
|
||
dprintf_ver(stddeb, "\n");
|
||
|
||
dprintf_ver_string("\tlpszFilename = ", lpszFilename, "\n");
|
||
dprintf_ver_string("\tlpszWinDir = ", lpszWinDir, "\n");
|
||
dprintf_ver_string("\tlpszAppDir = ", lpszAppDir, "\n");
|
||
|
||
dprintf_ver(stddeb, "\tlpszCurDir = %p\n", lpszCurDir);
|
||
if(lpuCurDirLen)
|
||
dprintf_ver(stddeb, "\tlpuCurDirLen = %p (%u)\n",
|
||
lpuCurDirLen, *lpuCurDirLen);
|
||
else
|
||
dprintf_ver(stddeb, "\tlpuCurDirLen = (null)\n");
|
||
|
||
dprintf_ver(stddeb, "\tlpszDestDir = %p\n", lpszDestDir);
|
||
if(lpuDestDirLen)
|
||
dprintf_ver(stddeb, "\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 && !getuid()) {
|
||
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;
|
||
}
|
||
|
||
dprintf_ver(stddeb, "VerFindFile() ret = %lu ",
|
||
retval);
|
||
|
||
if(retval) {
|
||
dprintf_ver(stddeb, "( ");
|
||
|
||
if(retval & VFF_CURNEDEST)
|
||
dprintf_ver(stddeb, "VFF_CURNEDEST ");
|
||
if(retval & VFF_FILEINUSE)
|
||
dprintf_ver(stddeb, "VFF_FILEINUSE ");
|
||
if(retval & VFF_BUFFTOOSMALL)
|
||
dprintf_ver(stddeb, "VFF_BUFFTOOSMALL ");
|
||
|
||
dprintf_ver(stddeb, ")");
|
||
}
|
||
|
||
dprintf_ver_string("\n\t(Exit) lpszCurDir = ", lpszCurDir, "\n");
|
||
if(lpuCurDirLen)
|
||
dprintf_ver(stddeb, "\t(Exit) lpuCurDirLen = %p (%u)\n",
|
||
lpuCurDirLen, *lpuCurDirLen);
|
||
else
|
||
dprintf_ver(stddeb, "\t(Exit) lpuCurDirLen = (null)\n");
|
||
|
||
dprintf_ver_string("\t(Exit) lpszDestDir = ", lpszDestDir, "\n");
|
||
if(lpuDestDirLen)
|
||
dprintf_ver(stddeb, "\t(Exit) lpuDestDirLen = %p (%u)\n",
|
||
lpuDestDirLen, *lpuDestDirLen);
|
||
|
||
return retval;
|
||
}
|
||
|
||
/* VerFindFileA [VERSION.5] */
|
||
DWORD
|
||
VerFindFile32A(
|
||
UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
|
||
LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen )
|
||
{
|
||
UINT16 curdirlen, destdirlen;
|
||
DWORD ret = VerFindFile16(flags,filename,windir,appdir,
|
||
curdir,&curdirlen,destdir,&destdirlen);
|
||
*pcurdirlen = curdirlen;
|
||
*pdestdirlen = destdirlen;
|
||
return ret;
|
||
}
|
||
|
||
/* VerFindFileW [VERSION.6] */
|
||
DWORD
|
||
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
|
||
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;
|
||
}
|
||
|
||
/* VerInstallFileA [VERSION.7] */
|
||
static LPBYTE
|
||
_fetch_versioninfo(LPSTR fn) {
|
||
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
|
||
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;
|
||
}
|
||
}
|
||
|
||
DWORD
|
||
VerInstallFile32A(
|
||
UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
|
||
LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen )
|
||
{
|
||
char destfn[260],tmpfn[260],srcfn[260];
|
||
HFILE32 hfsrc,hfdst;
|
||
DWORD attr,ret,xret,tmplast;
|
||
LPBYTE buf1,buf2;
|
||
OFSTRUCT ofs;
|
||
|
||
fprintf(stddeb,"VerInstallFile(%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);
|
||
sprintf(destfn,"%s\\%s",destdir,destfilename);
|
||
hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ);
|
||
if (hfsrc==HFILE_ERROR32)
|
||
return VIF_CANNOTREADSRC;
|
||
sprintf(tmpfn,"%s\\%s",destdir,destfilename);
|
||
tmplast=strlen(destdir)+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",destdir,tmpfile);
|
||
tmplast = strlen(destdir)+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(destdir,"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)) {
|
||
buf1 = _fetch_versioninfo(destfn);
|
||
if (buf1) {
|
||
buf2 = _fetch_versioninfo(tmpfn);
|
||
if (buf2) {
|
||
char *tbuf1,*tbuf2;
|
||
VS_FIXEDFILEINFO *destvffi,*tmpvffi;
|
||
UINT32 len1,len2;
|
||
|
||
destvffi= (VS_FIXEDFILEINFO*)(buf1+0x14);
|
||
tmpvffi = (VS_FIXEDFILEINFO*)(buf2+0x14);
|
||
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_BUFTOSMALL;
|
||
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,destdir)
|
||
) {
|
||
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
|
||
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;
|
||
}
|
||
|
||
/* FIXME: This table should, of course, be language dependend */
|
||
static const struct map_id2str {
|
||
UINT16 langid;
|
||
const char *langname;
|
||
} languages[]={
|
||
{0x0401,"Arabisch"},
|
||
{0x0402,"Bulgarisch"},
|
||
{0x0403,"Katalanisch"},
|
||
{0x0404,"Traditionales Chinesisch"},
|
||
{0x0405,"Tschecisch"},
|
||
{0x0406,"D<EFBFBD>nisch"},
|
||
{0x0407,"Deutsch"},
|
||
{0x0408,"Griechisch"},
|
||
{0x0409,"Amerikanisches Englisch"},
|
||
{0x040A,"Kastilisches Spanisch"},
|
||
{0x040B,"Finnisch"},
|
||
{0x040C,"Franz<EFBFBD>sisch"},
|
||
{0x040D,"Hebr<EFBFBD>isch"},
|
||
{0x040E,"Ungarisch"},
|
||
{0x040F,"Isl<EFBFBD>ndisch"},
|
||
{0x0410,"Italienisch"},
|
||
{0x0411,"Japanisch"},
|
||
{0x0412,"Koreanisch"},
|
||
{0x0413,"Niederl<EFBFBD>ndisch"},
|
||
{0x0414,"Norwegisch-Bokmal"},
|
||
{0x0415,"Polnisch"},
|
||
{0x0416,"Brasilianisches Portugiesisch"},
|
||
{0x0417,"R<EFBFBD>toromanisch"},
|
||
{0x0418,"Rum<EFBFBD>nisch"},
|
||
{0x0419,"Russisch"},
|
||
{0x041A,"Kroatoserbisch (lateinisch)"},
|
||
{0x041B,"Slowenisch"},
|
||
{0x041C,"Albanisch"},
|
||
{0x041D,"Schwedisch"},
|
||
{0x041E,"Thai"},
|
||
{0x041F,"T<EFBFBD>rkisch"},
|
||
{0x0420,"Urdu"},
|
||
{0x0421,"Bahasa"},
|
||
{0x0804,"Vereinfachtes Chinesisch"},
|
||
{0x0807,"Schweizerdeutsch"},
|
||
{0x0809,"Britisches Englisch"},
|
||
{0x080A,"Mexikanisches Spanisch"},
|
||
{0x080C,"Belgisches Franz<6E>sisch"},
|
||
{0x0810,"Schweizerisches Italienisch"},
|
||
{0x0813,"Belgisches Niederl<72>ndisch"},
|
||
{0x0814,"Norgwegisch-Nynorsk"},
|
||
{0x0816,"Portugiesisch"},
|
||
{0x081A,"Serbokratisch (kyrillisch)"},
|
||
{0x0C1C,"Kanadisches Franz<6E>sisch"},
|
||
{0x100C,"Schweizerisches Franz<6E>sisch"},
|
||
{0x0000,"Unbekannt"},
|
||
};
|
||
|
||
/* VerLanguageName [VER.10] */
|
||
DWORD
|
||
VerLanguageName16(UINT16 langid,LPSTR langname,UINT16 langnamelen) {
|
||
int i;
|
||
char *buf;
|
||
|
||
dprintf_ver(stddeb,"VerLanguageName(%d,%p,%d)\n",langid,langname,langnamelen);
|
||
/* First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
|
||
* from the registry.
|
||
*/
|
||
buf=(char*)malloc(strlen("\\System\\CurrentControlSet\\control\\Nls\\Locale\\")+9);
|
||
sprintf(buf,"\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",langid);
|
||
if (ERROR_SUCCESS==RegQueryValue16(HKEY_LOCAL_MACHINE,buf,langname,(LPDWORD)&langnamelen)) {
|
||
langname[langnamelen-1]='\0';
|
||
return langnamelen;
|
||
}
|
||
/* if that fails, use the interal table */
|
||
for (i=0;languages[i].langid!=0;i++)
|
||
if (langid==languages[i].langid)
|
||
break;
|
||
strncpy(langname,languages[i].langname,langnamelen);
|
||
langname[langnamelen-1]='\0';
|
||
return strlen(languages[i].langname);
|
||
}
|
||
|
||
/* VerLanguageNameA [VERSION.9] */
|
||
DWORD
|
||
VerLanguageName32A(UINT32 langid,LPSTR langname,UINT32 langnamelen) {
|
||
return VerLanguageName16(langid,langname,langnamelen);
|
||
}
|
||
|
||
/* VerLanguageNameW [VERSION.10] */
|
||
DWORD
|
||
VerLanguageName32W(UINT32 langid,LPWSTR langname,UINT32 langnamelen) {
|
||
int i;
|
||
char buffer[80];
|
||
LPWSTR keyname;
|
||
|
||
/* First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
|
||
* from the registry.
|
||
*/
|
||
sprintf(buffer,"\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",langid);
|
||
keyname = HEAP_strdupAtoW( GetProcessHeap(), 0, buffer );
|
||
if (ERROR_SUCCESS==RegQueryValue32W(HKEY_LOCAL_MACHINE,keyname,langname,(LPDWORD)&langnamelen)) {
|
||
HeapFree( GetProcessHeap(), 0, keyname );
|
||
return langnamelen;
|
||
}
|
||
HeapFree( GetProcessHeap(), 0, keyname );
|
||
/* if that fails, use the interal table */
|
||
for (i=0;languages[i].langid!=0;i++)
|
||
if (langid==languages[i].langid)
|
||
break;
|
||
lstrcpyAtoW( langname, languages[i].langname );
|
||
return strlen(languages[i].langname); /* same as strlenW(langname); */
|
||
}
|
||
|
||
/* FIXME: UNICODE? */
|
||
struct db {
|
||
WORD nextoff;
|
||
WORD datalen;
|
||
/* in memory structure... */
|
||
char name[1]; /* padded to dword alignment */
|
||
/* ....
|
||
char data[datalen]; padded to dword alignemnt
|
||
BYTE subdirdata[]; until nextoff
|
||
*/
|
||
};
|
||
|
||
static BYTE*
|
||
_find_data(BYTE *block,LPCSTR str) {
|
||
char *nextslash;
|
||
int substrlen;
|
||
struct db *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;
|
||
}
|
||
|
||
|
||
while (1) {
|
||
db=(struct db*)block;
|
||
dprintf_ver(stddeb,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s,db->data=%s\n",
|
||
db,db->nextoff,db->datalen,db->name,(char*)((char*)db+4+((strlen(db->name)+4)&~3))
|
||
);
|
||
if (!db->nextoff)
|
||
return NULL;
|
||
|
||
dprintf_ver(stddeb,"comparing with %s\n",db->name);
|
||
if (!strncmp(db->name,str,substrlen)) {
|
||
if (nextslash)
|
||
return _find_data(
|
||
block+4+((strlen(db->name)+4)&~3)+((db->datalen+3)&~3)
|
||
,nextslash
|
||
);
|
||
else
|
||
return block;
|
||
}
|
||
block=block+((db->nextoff+3)&~3);
|
||
}
|
||
}
|
||
|
||
/* VerQueryValue [VER.11] */
|
||
/* take care, 'buffer' is NOT a SEGPTR, it just points to one */
|
||
DWORD
|
||
VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,UINT16 *buflen)
|
||
{
|
||
BYTE *block=PTR_SEG_TO_LIN(segblock),*b;
|
||
struct db *db;
|
||
char *s;
|
||
|
||
dprintf_ver(stddeb,"VerQueryValue16(%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);
|
||
b=_find_data(block,s);
|
||
if (b==NULL) {
|
||
*buflen=0;
|
||
return 0;
|
||
}
|
||
db=(struct db*)b;
|
||
*buflen = db->datalen;
|
||
/* let b point to data area */
|
||
b = b+4+((strlen(db->name)+4)&~3);
|
||
/* now look up what the resp. SEGPTR would be ... */
|
||
*buffer = (b-block)+segblock;
|
||
dprintf_ver(stddeb," -> %s=%s\n",subblock,b);
|
||
return 1;
|
||
}
|
||
|
||
DWORD
|
||
VerQueryValue32A(LPVOID vblock,LPCSTR subblock,LPVOID *vbuffer,UINT32 *buflen)
|
||
{
|
||
BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer;
|
||
struct db *db;
|
||
char *s;
|
||
|
||
dprintf_ver(stddeb,"VerQueryValue32A(%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);
|
||
b=_find_data(block,s);
|
||
if (b==NULL) {
|
||
*buflen=0;
|
||
return 0;
|
||
}
|
||
db=(struct db*)b;
|
||
*buflen = db->datalen;
|
||
/* let b point to data area */
|
||
b = b+4+((strlen(db->name)+4)&~3);
|
||
*buffer = b;
|
||
dprintf_ver(stddeb," -> %s=%s\n",subblock,b);
|
||
return 1;
|
||
}
|
||
|
||
DWORD
|
||
VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer,UINT32 *buflen)
|
||
{
|
||
/* FIXME: hmm, we not only need to convert subblock, but also
|
||
* the content...or?
|
||
* And what about UNICODE version info?
|
||
* And the NAMES of the values?
|
||
*/
|
||
BYTE *b,**buffer=(LPBYTE*)vbuffer,*block=(LPBYTE)vblock;
|
||
struct db *db;
|
||
char *s,*sb;
|
||
|
||
sb = HEAP_strdupWtoA( GetProcessHeap(), 0, subblock );
|
||
s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(sb)+1);
|
||
strcpy(s,"VS_VERSION_INFO\\");strcat(s,sb);
|
||
b=_find_data(block,s);
|
||
if (b==NULL) {
|
||
*buflen=0;
|
||
HeapFree( GetProcessHeap(), 0, sb );
|
||
return 0;
|
||
}
|
||
db=(struct db*)b;
|
||
*buflen = db->datalen;
|
||
/* let b point to data area */
|
||
b = b+4+((strlen(db->name)+4)&~3);
|
||
*buffer = b;
|
||
dprintf_ver(stddeb," -> %s=%s\n",sb,b);
|
||
HeapFree( GetProcessHeap(), 0, sb );
|
||
return 1;
|
||
}
|
||
/* 20 GETFILEVERSIONINFORAW */
|