2 * Implementation of VER.DLL
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
25 #define LZREAD(what) \
26 if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
27 #define LZTELL(lzfd) LZSeek32(lzfd, 0, SEEK_CUR);
29 /******************************************************************************
32 * char const * prologue,
33 * char const * teststring,
34 * char const * epilogue )
36 * This function will print via dprintf_ver to stddeb the prologue string,
37 * followed by the address of teststring and the string it contains if
38 * teststring is non-null or "(null)" otherwise, and then the epilogue
42 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
43 * Original implementation as dprintf[_]ver_string
44 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
45 * Fixed problem that caused bug with tools/make_debug -- renaming
46 * this function should fix the problem.
48 *****************************************************************************/
50 static void ver_dstring(
51 char const * prologue
,
52 char const * teststring
,
53 char const * epilogue
)
55 dprintf_ver(stddeb
, "%s", prologue
);
58 dprintf_ver(stddeb
, "%p (\"%s\")", (void const *) teststring
,
61 dprintf_ver(stddeb
, "(null)");
63 dprintf_ver(stddeb
, "%s", epilogue
);
68 /******************************************************************************
70 * int testFileExistence(
74 * Tests whether a given path/file combination exists. If the file does
75 * not exist, the return value is zero. If it does exist, the return
79 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
80 * Original implementation
82 *****************************************************************************/
84 static int testFileExistence(
93 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
95 strcpy(filename
, path
);
96 filenamelen
= strlen(filename
);
98 /* Add a trailing \ if necessary */
100 if(filename
[filenamelen
- 1] != '\\')
101 strcat(filename
, "\\");
103 else /* specify the current directory */
104 strcpy(filename
, ".\\");
106 /* Create the full pathname */
107 strcat(filename
, file
);
109 if(OpenFile32(filename
, &fileinfo
, OF_EXIST
) == HFILE_ERROR32
)
117 /******************************************************************************
119 * int testFileExclusiveExistence(
121 * char const * file )
123 * Tests whether a given path/file combination exists and ensures that no
124 * other programs have handles to the given file. If the file does not
125 * exist or is open, the return value is zero. If it does exist, the
126 * return value is non-zero.
129 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
130 * Original implementation
132 *****************************************************************************/
134 static int testFileExclusiveExistence(
143 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
145 strcpy(filename
, path
);
146 filenamelen
= strlen(filename
);
148 /* Add a trailing \ if necessary */
150 if(filename
[filenamelen
- 1] != '\\')
151 strcat(filename
, "\\");
153 else /* specify the current directory */
154 strcpy(filename
, ".\\");
156 /* Create the full pathname */
157 strcat(filename
, file
);
159 if(OpenFile32(filename
, &fileinfo
, OF_EXIST
| OF_SHARE_EXCLUSIVE
) ==
170 read_xx_header(HFILE32 lzfd
) {
171 IMAGE_DOS_HEADER mzh
;
174 LZSeek32(lzfd
,0,SEEK_SET
);
175 if (sizeof(mzh
)!=LZRead32(lzfd
,&mzh
,sizeof(mzh
)))
177 if (mzh
.e_magic
!=IMAGE_DOS_SIGNATURE
)
179 LZSeek32(lzfd
,mzh
.e_lfanew
,SEEK_SET
);
180 if (2!=LZRead32(lzfd
,magic
,2))
182 LZSeek32(lzfd
,mzh
.e_lfanew
,SEEK_SET
);
183 if (magic
[0] == 'N' && magic
[1] == 'E')
184 return IMAGE_OS2_SIGNATURE
;
185 if (magic
[0] == 'P' && magic
[1] == 'E')
186 return IMAGE_NT_SIGNATURE
;
187 fprintf(stderr
,"misc/ver.c:read_ne_header:can't handle %*s files.\n",2,magic
);
194 HFILE32 lzfd
,SEGPTR
typeid,SEGPTR resid
,
195 BYTE
**resdata
,int *reslen
,DWORD
*off
197 IMAGE_OS2_HEADER nehd
;
204 nehdoffset
= LZTELL(lzfd
);
206 if (nehd
.resource_tab_offset
==nehd
.rname_tab_offset
) {
207 dprintf_ver(stddeb
,"no resources in NE dll\n");
210 LZSeek32(lzfd
,nehd
.resource_tab_offset
+nehdoffset
,SEEK_SET
);
212 dprintf_ver(stddeb
,"shiftcount is %d\n",shiftcount
);
213 dprintf_ver(stddeb
,"reading resource typeinfo dir.\n");
215 if (!HIWORD(typeid)) typeid = (SEGPTR
)(LOWORD(typeid) | 0x8000);
216 if (!HIWORD(resid
)) resid
= (SEGPTR
)(LOWORD(resid
) | 0x8000);
223 dprintf_ver(stddeb
," ti.typeid =%04x,count=%d\n",ti
.type_id
,ti
.count
);
226 if (!HIWORD(typeid)) {
227 if ((ti
.type_id
&0x8000)&&(typeid!=ti
.type_id
))
230 if (ti
.type_id
& 0x8000) {
237 whereleft
= LZTELL(lzfd
);
240 nehdoffset
+nehd
.resource_tab_offset
+ti
.type_id
,
245 if (len
!=LZRead32(lzfd
,str
,len
))
247 dprintf_ver(stddeb
,"read %s to compare it with %s\n",
248 str
,(char*)PTR_SEG_TO_LIN(typeid)
250 if (lstrcmpi32A(str
,(char*)PTR_SEG_TO_LIN(typeid)))
253 LZSeek32(lzfd
,whereleft
,SEEK_SET
);
257 LZSeek32(lzfd
,ti
.count
*sizeof(ni
),SEEK_CUR
);
260 for (i
=0;i
<ti
.count
;i
++) {
265 dprintf_ver(stddeb
," ni.id=%4x,offset=%d,length=%d\n",
266 ni
.id
,ni
.offset
,ni
.length
269 if (!HIWORD(resid
)) {
273 if (!(ni
.id
& 0x8000)) {
278 whereleft
= LZTELL(lzfd
);
281 nehdoffset
+nehd
.resource_tab_offset
+ni
.id
,
286 if (len
!=LZRead32(lzfd
,str
,len
))
288 dprintf_ver(stddeb
,"read %s to compare it with %s\n",
289 str
,(char*)PTR_SEG_TO_LIN(typeid)
291 if (!lstrcmpi32A(str
,(char*)PTR_SEG_TO_LIN(typeid)))
294 LZSeek32(lzfd
,whereleft
,SEEK_SET
);
299 LZSeek32(lzfd
,((int)ni
.offset
<<shiftcount
),SEEK_SET
);
300 *off
= (int)ni
.offset
<<shiftcount
;
301 len
= ni
.length
<<shiftcount
;
302 rdata
=(WORD
*)xmalloc(len
);
303 if (len
!=LZRead32(lzfd
,rdata
,len
)) {
307 dprintf_ver(stddeb
,"resource found.\n");
308 *resdata
= (BYTE
*)rdata
;
315 extern LPIMAGE_RESOURCE_DIRECTORY
GetResDirEntryW(
316 LPIMAGE_RESOURCE_DIRECTORY resdirptr
,LPCWSTR name
,DWORD root
319 /* Loads the specified PE resource.
320 * FIXME: shouldn't load the whole image
324 HFILE32 lzfd
,LPWSTR
typeid,LPWSTR resid
,
325 BYTE
**resdata
,int *reslen
,DWORD
*off
327 IMAGE_NT_HEADERS pehd
;
330 DWORD imagesize
,pehdoffset
;
332 IMAGE_DATA_DIRECTORY resdir
;
333 LPIMAGE_RESOURCE_DIRECTORY resourcedir
,xresdir
;
334 LPIMAGE_RESOURCE_DATA_ENTRY xresdata
;
335 LPIMAGE_SECTION_HEADER sections
;
337 pehdoffset
= LZTELL(lzfd
);
339 resdir
= pehd
.OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
340 dprintf_ver(stddeb
,"find_pe_resource(.,%p,%p,....)\n",typeid,resid
);
342 fprintf(stderr
,"misc/ver.c:find_pe_resource() no resource directory found in PE file.\n");
345 imagesize
= pehd
.OptionalHeader
.SizeOfImage
;
346 image
= HeapAlloc(GetProcessHeap(),0,imagesize
);
347 nrofsections
= pehd
.FileHeader
.NumberOfSections
;
349 sections
= (LPIMAGE_SECTION_HEADER
)HeapAlloc(GetProcessHeap(),0,pehd
.FileHeader
.NumberOfSections
*sizeof(IMAGE_SECTION_HEADER
));
352 sizeof(DWORD
)+ /* Signature */
353 sizeof(IMAGE_FILE_HEADER
)+
354 pehd
.FileHeader
.SizeOfOptionalHeader
,
357 if ( nrofsections
*sizeof(IMAGE_SECTION_HEADER
)!=
358 LZRead32(lzfd
,sections
,nrofsections
*sizeof(IMAGE_SECTION_HEADER
))
360 HeapFree(GetProcessHeap(),0,image
);
363 for (i
=0;i
<nrofsections
;i
++) {
364 if (sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
366 LZSeek32(lzfd
,sections
[i
].PointerToRawData
,SEEK_SET
);
367 if ( sections
[i
].SizeOfRawData
!=
368 LZRead32(lzfd
,image
+sections
[i
].VirtualAddress
,sections
[i
].SizeOfRawData
)
372 resourcedir
= (LPIMAGE_RESOURCE_DIRECTORY
)(image
+resdir
.VirtualAddress
);
373 xresdir
= GetResDirEntryW(resourcedir
,typeid,(DWORD
)resourcedir
);
375 dprintf_ver(stddeb
,"...no typeid entry found for %p\n",typeid);
376 HeapFree(GetProcessHeap(),0,image
);
379 xresdir
= GetResDirEntryW(xresdir
,resid
,(DWORD
)resourcedir
);
381 dprintf_ver(stddeb
,"...no resid entry found for %p\n",resid
);
382 HeapFree(GetProcessHeap(),0,image
);
386 xresdir
= GetResDirEntryW(xresdir
,0,(DWORD
)resourcedir
);
388 dprintf_ver(stddeb
,"...no 0 (default language) entry found for %p\n",resid
);
389 HeapFree(GetProcessHeap(),0,image
);
392 xresdata
= (LPIMAGE_RESOURCE_DATA_ENTRY
)xresdir
;
393 *reslen
= xresdata
->Size
;
394 *resdata
= (LPBYTE
)xmalloc(*reslen
);
395 memcpy(*resdata
,image
+xresdata
->OffsetToData
,*reslen
);
396 /* find physical address for virtual offset */
397 for (i
=0;i
<nrofsections
;i
++) {
398 if (sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
400 if ( (xresdata
->OffsetToData
>= sections
[i
].VirtualAddress
)&&
401 (xresdata
->OffsetToData
< sections
[i
].VirtualAddress
+sections
[i
].SizeOfRawData
)
403 *off
= (DWORD
)(xresdata
->OffsetToData
)-(DWORD
)(sections
[i
].VirtualAddress
)+(DWORD
)(sections
[i
].PointerToRawData
);
407 HeapFree(GetProcessHeap(),0,image
);
408 HeapFree(GetProcessHeap(),0,sections
);
412 /* GetFileResourceSize [VER.2] */
413 DWORD WINAPI
GetFileResourceSize(LPCSTR filename
,SEGPTR restype
,SEGPTR resid
,
418 BYTE
*resdata
= NULL
;
422 dprintf_ver(stddeb
,"GetFileResourceSize(%s,%lx,%lx,%p)\n",
423 filename
,(LONG
)restype
,(LONG
)resid
,off
425 lzfd
=LZOpenFile32A(filename
,&ofs
,OF_READ
);
428 switch (read_xx_header(lzfd
)) {
432 case IMAGE_OS2_SIGNATURE
:
433 res
=find_ne_resource(lzfd
,restype
,resid
,&resdata
,&reslen
,off
);
435 case IMAGE_NT_SIGNATURE
:
436 res
=find_pe_resource(lzfd
,(LPWSTR
)restype
,(LPWSTR
)resid
,&resdata
,&reslen
,off
);
449 /* GetFileResource [VER.3] */
450 DWORD WINAPI
GetFileResource(LPCSTR filename
,SEGPTR restype
,SEGPTR resid
,
451 DWORD off
,DWORD datalen
,LPVOID data
)
459 dprintf_ver(stddeb
,"GetFileResource(%s,%lx,%lx,%ld,%ld,%p)\n",
460 filename
,(LONG
)restype
,(LONG
)resid
,off
,datalen
,data
463 lzfd
=LZOpenFile32A(filename
,&ofs
,OF_READ
);
467 switch (read_xx_header(lzfd
)) {
470 case IMAGE_OS2_SIGNATURE
:
471 res
= find_ne_resource(lzfd
,restype
,resid
,&resdata
,&reslen
,&off
);
473 case IMAGE_NT_SIGNATURE
:
474 res
= find_pe_resource(lzfd
,restype
,resid
,&resdata
,&reslen
,&off
);
480 if (reslen
>datalen
) reslen
= datalen
;
481 memcpy(data
,resdata
,reslen
);
485 LZSeek32(lzfd
,off
,SEEK_SET
);
486 reslen
= LZRead32(lzfd
,data
,datalen
);
491 /* GetFileVersionInfoSize [VER.6] */
492 DWORD WINAPI
GetFileVersionInfoSize16(LPCSTR filename
,LPDWORD handle
)
494 DWORD len
,ret
,isuni
=0;
496 VS_FIXEDFILEINFO
*vffi
;
498 dprintf_ver(stddeb
,"GetFileVersionInfoSize16(%s,%p)\n",filename
,handle
);
499 len
=GetFileResourceSize(filename
,VS_FILE_INFO
,VS_VERSION_INFO
,handle
);
503 filename
,VS_FILE_INFO
,VS_VERSION_INFO
,*handle
,sizeof(buf
),buf
508 vffi
=(VS_FIXEDFILEINFO
*)(buf
+0x14);
509 if (vffi
->dwSignature
!= VS_FFI_SIGNATURE
) {
510 /* unicode resource */
511 if (vffi
->dwSignature
== 0x004f0049) {
513 vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
515 fprintf(stderr
,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
516 vffi
->dwSignature
,VS_FFI_SIGNATURE
521 if (*(WORD
*)buf
< len
)
523 dprintf_ver(stddeb
," structversion=0x%lx.0x%lx,\n fileversion=0x%lx.0x%lx,\n productversion=0x%lx.0x%lx,\n flagmask=0x%lx,\n flags=",
524 (vffi
->dwStrucVersion
>>16),vffi
->dwStrucVersion
&0xFFFF,
525 vffi
->dwFileVersionMS
,vffi
->dwFileVersionLS
,
526 vffi
->dwProductVersionMS
,vffi
->dwProductVersionLS
,
527 vffi
->dwFileFlagsMask
529 if (vffi
->dwFileFlags
& VS_FF_DEBUG
)
530 dprintf_ver(stddeb
,"DEBUG,");
531 if (vffi
->dwFileFlags
& VS_FF_PRERELEASE
)
532 dprintf_ver(stddeb
,"PRERELEASE,");
533 if (vffi
->dwFileFlags
& VS_FF_PATCHED
)
534 dprintf_ver(stddeb
,"PATCHED,");
535 if (vffi
->dwFileFlags
& VS_FF_PRIVATEBUILD
)
536 dprintf_ver(stddeb
,"PRIVATEBUILD,");
537 if (vffi
->dwFileFlags
& VS_FF_INFOINFERRED
)
538 dprintf_ver(stddeb
,"INFOINFERRED,");
539 if (vffi
->dwFileFlags
& VS_FF_SPECIALBUILD
)
540 dprintf_ver(stddeb
,"SPECIALBUILD,");
541 dprintf_ver(stddeb
,"\n OS=0x%lx.0x%lx (",
542 (vffi
->dwFileOS
&0xFFFF0000)>>16,
543 vffi
->dwFileOS
&0x0000FFFF
545 switch (vffi
->dwFileOS
&0xFFFF0000) {
546 case VOS_DOS
:dprintf_ver(stddeb
,"DOS,");break;
547 case VOS_OS216
:dprintf_ver(stddeb
,"OS/2-16,");break;
548 case VOS_OS232
:dprintf_ver(stddeb
,"OS/2-32,");break;
549 case VOS_NT
:dprintf_ver(stddeb
,"NT,");break;
552 dprintf_ver(stddeb
,"UNKNOWN(0x%lx),",vffi
->dwFileOS
&0xFFFF0000);break;
554 switch (vffi
->dwFileOS
& 0xFFFF) {
555 case VOS__BASE
:dprintf_ver(stddeb
,"BASE");break;
556 case VOS__WINDOWS16
:dprintf_ver(stddeb
,"WIN16");break;
557 case VOS__WINDOWS32
:dprintf_ver(stddeb
,"WIN32");break;
558 case VOS__PM16
:dprintf_ver(stddeb
,"PM16");break;
559 case VOS__PM32
:dprintf_ver(stddeb
,"PM32");break;
560 default:dprintf_ver(stddeb
,"UNKNOWN(0x%lx)",vffi
->dwFileOS
&0xFFFF);break;
562 dprintf_ver(stddeb
,")\n ");
563 switch (vffi
->dwFileType
) {
566 dprintf_ver(stddeb
,"filetype=Unknown(0x%lx)",vffi
->dwFileType
);
568 case VFT_APP
:dprintf_ver(stddeb
,"filetype=APP,");break;
569 case VFT_DLL
:dprintf_ver(stddeb
,"filetype=DLL,");break;
571 dprintf_ver(stddeb
,"filetype=DRV,");
572 switch(vffi
->dwFileSubtype
) {
575 dprintf_ver(stddeb
,"UNKNOWN(0x%lx)",vffi
->dwFileSubtype
);
577 case VFT2_DRV_PRINTER
:
578 dprintf_ver(stddeb
,"PRINTER");
580 case VFT2_DRV_KEYBOARD
:
581 dprintf_ver(stddeb
,"KEYBOARD");
583 case VFT2_DRV_LANGUAGE
:
584 dprintf_ver(stddeb
,"LANGUAGE");
586 case VFT2_DRV_DISPLAY
:
587 dprintf_ver(stddeb
,"DISPLAY");
590 dprintf_ver(stddeb
,"MOUSE");
592 case VFT2_DRV_NETWORK
:
593 dprintf_ver(stddeb
,"NETWORK");
595 case VFT2_DRV_SYSTEM
:
596 dprintf_ver(stddeb
,"SYSTEM");
598 case VFT2_DRV_INSTALLABLE
:
599 dprintf_ver(stddeb
,"INSTALLABLE");
602 dprintf_ver(stddeb
,"SOUND");
605 dprintf_ver(stddeb
,"COMM");
607 case VFT2_DRV_INPUTMETHOD
:
608 dprintf_ver(stddeb
,"INPUTMETHOD");
613 dprintf_ver(stddeb
,"filetype=FONT.");
614 switch (vffi
->dwFileSubtype
) {
616 dprintf_ver(stddeb
,"UNKNOWN(0x%lx)",vffi
->dwFileSubtype
);
618 case VFT2_FONT_RASTER
:dprintf_ver(stddeb
,"RASTER");break;
619 case VFT2_FONT_VECTOR
:dprintf_ver(stddeb
,"VECTOR");break;
620 case VFT2_FONT_TRUETYPE
:dprintf_ver(stddeb
,"TRUETYPE");break;
623 case VFT_VXD
:dprintf_ver(stddeb
,"filetype=VXD");break;
624 case VFT_STATIC_LIB
:dprintf_ver(stddeb
,"filetype=STATIC_LIB");break;
626 dprintf_ver(stddeb
,"\n filedata=0x%lx.0x%lx\n",vffi
->dwFileDateMS
,vffi
->dwFileDateLS
);
630 /* GetFileVersionInfoSize32A [VERSION.1] */
631 DWORD WINAPI
GetFileVersionInfoSize32A(LPCSTR filename
,LPDWORD handle
)
633 dprintf_ver(stddeb
,"GetFileVersionInfoSize32A(%s,%p)\n",filename
,handle
);
634 return GetFileVersionInfoSize16(filename
,handle
);
637 /* GetFileVersionInfoSize32W [VERSION.2] */
638 DWORD WINAPI
GetFileVersionInfoSize32W( LPCWSTR filename
, LPDWORD handle
)
640 LPSTR xfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
641 DWORD ret
= GetFileVersionInfoSize16( xfn
, handle
);
642 HeapFree( GetProcessHeap(), 0, xfn
);
646 /* GetFileVersionInfo [VER.7] */
647 DWORD WINAPI
GetFileVersionInfo16(LPCSTR filename
,DWORD handle
,DWORD datasize
,
650 dprintf_ver(stddeb
,"GetFileVersionInfo16(%s,%ld,%ld,%p)\n->",
651 filename
,handle
,datasize
,data
653 return GetFileResource(
654 filename
,VS_FILE_INFO
,VS_VERSION_INFO
,handle
,datasize
,data
658 /* GetFileVersionInfoA [VERSION.0] */
659 DWORD WINAPI
GetFileVersionInfo32A(LPCSTR filename
,DWORD handle
,
660 DWORD datasize
,LPVOID data
)
662 return GetFileVersionInfo16(filename
,handle
,datasize
,data
);
665 /* GetFileVersionInfoW [VERSION.3] */
666 DWORD WINAPI
GetFileVersionInfo32W( LPCWSTR filename
, DWORD handle
,
667 DWORD datasize
, LPVOID data
)
669 LPSTR fn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
670 DWORD ret
= GetFileVersionInfo16( fn
, handle
, datasize
, data
);
671 HeapFree( GetProcessHeap(), 0, fn
);
675 /*****************************************************************************
677 * VerFindFile() [VER.8]
678 * Determines where to install a file based on whether it locates another
679 * version of the file in the system. The values VerFindFile returns are
680 * used in a subsequent call to the VerInstallFile function.
683 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
684 * Reimplementation of VerFindFile from original stub.
686 ****************************************************************************/
688 DWORD WINAPI
VerFindFile16(
694 UINT16
*lpuCurDirLen
,
696 UINT16
*lpuDestDirLen
)
701 unsigned int curDirSizeReq
;
702 unsigned int destDirSizeReq
;
706 /* Print out debugging information */
707 dprintf_ver(stddeb
, "VerFindFile() called with parameters:\n"
708 "\tflags = %x", flags
);
709 if(flags
& VFFF_ISSHAREDFILE
)
710 dprintf_ver(stddeb
, " (VFFF_ISSHAREDFILE)\n");
712 dprintf_ver(stddeb
, "\n");
714 ver_dstring("\tlpszFilename = ", lpszFilename
, "\n");
715 ver_dstring("\tlpszWinDir = ", lpszWinDir
, "\n");
716 ver_dstring("\tlpszAppDir = ", lpszAppDir
, "\n");
718 dprintf_ver(stddeb
, "\tlpszCurDir = %p\n", lpszCurDir
);
720 dprintf_ver(stddeb
, "\tlpuCurDirLen = %p (%u)\n",
721 lpuCurDirLen
, *lpuCurDirLen
);
723 dprintf_ver(stddeb
, "\tlpuCurDirLen = (null)\n");
725 dprintf_ver(stddeb
, "\tlpszDestDir = %p\n", lpszDestDir
);
727 dprintf_ver(stddeb
, "\tlpuDestDirLen = %p (%u)\n",
728 lpuDestDirLen
, *lpuDestDirLen
);
730 /* Figure out where the file should go; shared files default to the
736 if(flags
& VFFF_ISSHAREDFILE
&& !getuid()) {
737 GetSystemDirectory32A(destDir
, 256);
739 /* Were we given a filename? If so, try to find the file. */
741 if(testFileExistence(destDir
, lpszFilename
)) {
742 strcpy(curDir
, destDir
);
744 if(!testFileExclusiveExistence(destDir
, lpszFilename
))
745 retval
|= VFF_FILEINUSE
;
747 else if(lpszAppDir
&& testFileExistence(lpszAppDir
,
749 strcpy(curDir
, lpszAppDir
);
750 retval
|= VFF_CURNEDEST
;
752 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
753 retval
|= VFF_FILEINUSE
;
757 else if(!(flags
& VFFF_ISSHAREDFILE
)) { /* not a shared file */
760 GetSystemDirectory32A(systemDir
, 256);
762 strcpy(destDir
, lpszAppDir
);
765 if(testFileExistence(lpszAppDir
, lpszFilename
)) {
766 strcpy(curDir
, lpszAppDir
);
768 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
769 retval
|= VFF_FILEINUSE
;
771 else if(testFileExistence(systemDir
, lpszFilename
)) {
772 strcpy(curDir
, systemDir
);
773 retval
|= VFF_CURNEDEST
;
775 if(!testFileExclusiveExistence(systemDir
, lpszFilename
))
776 retval
|= VFF_FILEINUSE
;
782 curDirSizeReq
= strlen(curDir
) + 1;
783 destDirSizeReq
= strlen(destDir
) + 1;
787 /* Make sure that the pointers to the size of the buffers are
788 valid; if not, do NOTHING with that buffer. If that pointer
789 is valid, then make sure that the buffer pointer is valid, too! */
791 if(lpuDestDirLen
&& lpszDestDir
) {
792 if(*lpuDestDirLen
< destDirSizeReq
) {
793 retval
|= VFF_BUFFTOOSMALL
;
794 strncpy(lpszDestDir
, destDir
, *lpuDestDirLen
- 1);
795 lpszDestDir
[*lpuDestDirLen
- 1] = '\0';
798 strcpy(lpszDestDir
, destDir
);
800 *lpuDestDirLen
= destDirSizeReq
;
803 if(lpuCurDirLen
&& lpszCurDir
) {
804 if(*lpuCurDirLen
< curDirSizeReq
) {
805 retval
|= VFF_BUFFTOOSMALL
;
806 strncpy(lpszCurDir
, curDir
, *lpuCurDirLen
- 1);
807 lpszCurDir
[*lpuCurDirLen
- 1] = '\0';
810 strcpy(lpszCurDir
, curDir
);
812 *lpuCurDirLen
= curDirSizeReq
;
815 dprintf_ver(stddeb
, "VerFindFile() ret = %lu ",
819 dprintf_ver(stddeb
, "( ");
821 if(retval
& VFF_CURNEDEST
)
822 dprintf_ver(stddeb
, "VFF_CURNEDEST ");
823 if(retval
& VFF_FILEINUSE
)
824 dprintf_ver(stddeb
, "VFF_FILEINUSE ");
825 if(retval
& VFF_BUFFTOOSMALL
)
826 dprintf_ver(stddeb
, "VFF_BUFFTOOSMALL ");
828 dprintf_ver(stddeb
, ")");
831 ver_dstring("\n\t(Exit) lpszCurDir = ", lpszCurDir
, "\n");
833 dprintf_ver(stddeb
, "\t(Exit) lpuCurDirLen = %p (%u)\n",
834 lpuCurDirLen
, *lpuCurDirLen
);
836 dprintf_ver(stddeb
, "\t(Exit) lpuCurDirLen = (null)\n");
838 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir
, "\n");
840 dprintf_ver(stddeb
, "\t(Exit) lpuDestDirLen = %p (%u)\n",
841 lpuDestDirLen
, *lpuDestDirLen
);
846 /* VerFindFileA [VERSION.5] */
847 DWORD WINAPI
VerFindFile32A(
848 UINT32 flags
,LPCSTR filename
,LPCSTR windir
,LPCSTR appdir
,
849 LPSTR curdir
,UINT32
*pcurdirlen
,LPSTR destdir
,UINT32
*pdestdirlen
)
851 UINT16 curdirlen
, destdirlen
;
852 DWORD ret
= VerFindFile16(flags
,filename
,windir
,appdir
,
853 curdir
,&curdirlen
,destdir
,&destdirlen
);
854 *pcurdirlen
= curdirlen
;
855 *pdestdirlen
= destdirlen
;
859 /* VerFindFileW [VERSION.6] */
860 DWORD WINAPI
VerFindFile32W(
861 UINT32 flags
,LPCWSTR filename
,LPCWSTR windir
,LPCWSTR appdir
,
862 LPWSTR curdir
,UINT32
*pcurdirlen
,LPWSTR destdir
,UINT32
*pdestdirlen
)
864 UINT16 curdirlen
, destdirlen
;
865 LPSTR wfn
,wwd
,wad
,wdd
,wcd
;
868 wfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
869 wwd
= HEAP_strdupWtoA( GetProcessHeap(), 0, windir
);
870 wad
= HEAP_strdupWtoA( GetProcessHeap(), 0, appdir
);
871 wcd
= HeapAlloc( GetProcessHeap(), 0, *pcurdirlen
);
872 wdd
= HeapAlloc( GetProcessHeap(), 0, *pdestdirlen
);
873 ret
= VerFindFile16(flags
,wfn
,wwd
,wad
,wcd
,&curdirlen
,wdd
,&destdirlen
);
874 lstrcpynAtoW(curdir
,wcd
,*pcurdirlen
);
875 lstrcpynAtoW(destdir
,wdd
,*pdestdirlen
);
876 *pcurdirlen
= strlen(wcd
);
877 *pdestdirlen
= strlen(wdd
);
878 HeapFree( GetProcessHeap(), 0, wfn
);
879 HeapFree( GetProcessHeap(), 0, wwd
);
880 HeapFree( GetProcessHeap(), 0, wad
);
881 HeapFree( GetProcessHeap(), 0, wcd
);
882 HeapFree( GetProcessHeap(), 0, wdd
);
886 /* VerInstallFile [VER.9] */
887 DWORD WINAPI
VerInstallFile16(
888 UINT16 flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
889 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT16
*tmpfilelen
)
892 DWORD ret
= VerInstallFile32A(flags
,srcfilename
,destfilename
,srcdir
,
893 destdir
,curdir
,tmpfile
,&filelen
);
895 *tmpfilelen
= filelen
;
899 /* VerInstallFileA [VERSION.7] */
901 _fetch_versioninfo(LPSTR fn
,VS_FIXEDFILEINFO
**vffi
) {
907 buf
= xmalloc(alloclen
);
909 ret
= GetFileVersionInfo32A(fn
,0,alloclen
,buf
);
914 if (alloclen
<*(WORD
*)buf
) {
916 alloclen
= *(WORD
*)buf
;
917 buf
= xmalloc(alloclen
);
919 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x14);
920 if ((*vffi
)->dwSignature
== 0x004f0049) /* hack to detect unicode */
921 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
922 if ((*vffi
)->dwSignature
!= VS_FFI_SIGNATURE
)
923 fprintf(stderr
,"_fetch_versioninfo:bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi
)->dwSignature
);
930 _error2vif(DWORD error
) {
932 case ERROR_ACCESS_DENIED
:
933 return VIF_ACCESSVIOLATION
;
934 case ERROR_SHARING_VIOLATION
:
935 return VIF_SHARINGVIOLATION
;
941 DWORD WINAPI
VerInstallFile32A(
942 UINT32 flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
943 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT32
*tmpfilelen
)
945 char destfn
[260],tmpfn
[260],srcfn
[260];
947 DWORD attr
,ret
,xret
,tmplast
;
951 fprintf(stddeb
,"VerInstallFile(%x,%s,%s,%s,%s,%s,%p,%d)\n",
952 flags
,srcfilename
,destfilename
,srcdir
,destdir
,curdir
,tmpfile
,*tmpfilelen
955 sprintf(srcfn
,"%s\\%s",srcdir
,srcfilename
);
956 sprintf(destfn
,"%s\\%s",destdir
,destfilename
);
957 hfsrc
=LZOpenFile32A(srcfn
,&ofs
,OF_READ
);
958 if (hfsrc
==HFILE_ERROR32
)
959 return VIF_CANNOTREADSRC
;
960 sprintf(tmpfn
,"%s\\%s",destdir
,destfilename
);
961 tmplast
=strlen(destdir
)+1;
962 attr
= GetFileAttributes32A(tmpfn
);
964 if (attr
& FILE_ATTRIBUTE_READONLY
) {
966 return VIF_WRITEPROT
;
968 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
971 if (flags
& VIFF_FORCEINSTALL
) {
973 sprintf(tmpfn
,"%s\\%s",destdir
,tmpfile
);
974 tmplast
= strlen(destdir
)+1;
975 attr
= GetFileAttributes32A(tmpfn
);
976 /* if it exists, it has been copied by the call before.
977 * we jump over the copy part...
984 GetTempFileName32A(destdir
,"ver",0,tmpfn
); /* should not fail ... */
985 s
=strrchr(tmpfn
,'\\');
990 hfdst
= OpenFile32(tmpfn
,&ofs
,OF_CREATE
);
991 if (hfdst
== HFILE_ERROR32
) {
993 return VIF_CANNOTCREATE
; /* | translated dos error */
995 ret
= LZCopy32(hfsrc
,hfdst
);
997 if (((long) ret
) < 0) {
998 /* translate LZ errors into VIF_xxx */
1000 case LZERROR_BADINHANDLE
:
1002 case LZERROR_BADVALUE
:
1003 case LZERROR_UNKNOWNALG
:
1004 ret
= VIF_CANNOTREADSRC
;
1006 case LZERROR_BADOUTHANDLE
:
1008 ret
= VIF_OUTOFMEMORY
; /* FIXME: correct? */
1010 case LZERROR_GLOBALLOC
:
1011 case LZERROR_GLOBLOCK
:
1012 ret
= VIF_OUTOFSPACE
;
1014 default: /* unknown error, should not happen */
1025 if (!(flags
& VIFF_FORCEINSTALL
)) {
1026 VS_FIXEDFILEINFO
*destvffi
,*tmpvffi
;
1027 buf1
= _fetch_versioninfo(destfn
,&destvffi
);
1029 buf2
= _fetch_versioninfo(tmpfn
,&tmpvffi
);
1036 /* compare file versions */
1037 if ((destvffi
->dwFileVersionMS
> tmpvffi
->dwFileVersionMS
)||
1038 ((destvffi
->dwFileVersionMS
==tmpvffi
->dwFileVersionMS
)&&
1039 (destvffi
->dwFileVersionLS
> tmpvffi
->dwFileVersionLS
)
1042 xret
|= VIF_MISMATCH
|VIF_SRCOLD
;
1043 /* compare filetypes and filesubtypes */
1044 if ((destvffi
->dwFileType
!=tmpvffi
->dwFileType
) ||
1045 (destvffi
->dwFileSubtype
!=tmpvffi
->dwFileSubtype
)
1047 xret
|= VIF_MISMATCH
|VIF_DIFFTYPE
;
1048 if (VerQueryValue32A(buf1
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf1
,&len1
) &&
1049 VerQueryValue32A(buf2
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf2
,&len2
)
1051 /* irgendwas mit tbuf1 und tbuf2 machen
1052 * generiert DIFFLANG|MISMATCH
1057 xret
=VIF_MISMATCH
|VIF_SRCOLD
;
1062 if (*tmpfilelen
<strlen(tmpfn
+tmplast
)) {
1063 xret
|=VIF_BUFTOSMALL
;
1064 DeleteFile32A(tmpfn
);
1066 strcpy(tmpfile
,tmpfn
+tmplast
);
1067 *tmpfilelen
= strlen(tmpfn
+tmplast
)+1;
1071 if (-1!=GetFileAttributes32A(destfn
))
1072 if (!DeleteFile32A(destfn
)) {
1073 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETE
;
1074 DeleteFile32A(tmpfn
);
1078 if ((!(flags
& VIFF_DONTDELETEOLD
)) &&
1081 lstrcmpi32A(curdir
,destdir
)
1085 sprintf(curfn
,"%s\\%s",curdir
,destfilename
);
1086 if (-1!=GetFileAttributes32A(curfn
)) {
1087 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
1088 if (!DeleteFile32A(curfn
))
1089 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR
;
1092 if (!MoveFile32A(tmpfn
,destfn
)) {
1093 xret
|=_error2vif(GetLastError())|VIF_CANNOTRENAME
;
1094 DeleteFile32A(tmpfn
);
1101 /* VerInstallFileW [VERSION.8] */
1102 DWORD WINAPI
VerInstallFile32W(
1103 UINT32 flags
,LPCWSTR srcfilename
,LPCWSTR destfilename
,LPCWSTR srcdir
,
1104 LPCWSTR destdir
,LPCWSTR curdir
,LPWSTR tmpfile
,UINT32
*tmpfilelen
)
1106 LPSTR wsrcf
,wsrcd
,wdestf
,wdestd
,wtmpf
,wcurd
;
1109 wsrcf
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename
);
1110 wsrcd
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir
);
1111 wdestf
= HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename
);
1112 wdestd
= HEAP_strdupWtoA( GetProcessHeap(), 0, destdir
);
1113 wtmpf
= HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile
);
1114 wcurd
= HEAP_strdupWtoA( GetProcessHeap(), 0, curdir
);
1115 ret
= VerInstallFile32A(flags
,wsrcf
,wdestf
,wsrcd
,wdestd
,wcurd
,wtmpf
,tmpfilelen
);
1117 lstrcpynAtoW(tmpfile
,wtmpf
,*tmpfilelen
);
1118 HeapFree( GetProcessHeap(), 0, wsrcf
);
1119 HeapFree( GetProcessHeap(), 0, wsrcd
);
1120 HeapFree( GetProcessHeap(), 0, wdestf
);
1121 HeapFree( GetProcessHeap(), 0, wdestd
);
1122 HeapFree( GetProcessHeap(), 0, wtmpf
);
1124 HeapFree( GetProcessHeap(), 0, wcurd
);
1129 /* FIXME: UNICODE? */
1133 /* in memory structure... */
1134 char name
[1]; /* padded to dword alignment */
1136 char data[datalen]; padded to dword alignment
1137 BYTE subdirdata[]; until nextoff
1141 /* FIXME: UNICODE? */
1145 WORD btext
; /* type of data */
1146 /* in memory structure... */
1147 WCHAR name
[1]; /* padded to dword alignment */
1149 WCHAR data[datalen]; padded to dword alignment
1150 BYTE subdirdata[]; until nextoff
1154 /* this one used for Win16 resources, which are always in ASCII format */
1156 _find_dataA(BYTE
*block
,LPCSTR str
, WORD buff_remain
) {
1158 int substrlen
, inc_size
;
1161 while (*str
&& *str
=='\\')
1163 if (NULL
!=(nextslash
=strchr(str
,'\\')))
1164 substrlen
=nextslash
-str
;
1166 substrlen
=strlen(str
);
1167 if (nextslash
!=NULL
) {
1168 while (*nextslash
&& *nextslash
=='\\')
1176 db
=(struct dbA
*)block
;
1177 dprintf_ver(stddeb
,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s,db->data=%s\n",
1178 db
,db
->nextoff
,db
->datalen
,db
->name
,(char*)((char*)db
+4+((strlen(db
->name
)+4)&~3))
1180 if ((!db
->nextoff
) || (!buff_remain
)) /* no more entries ? */
1183 dprintf_ver(stddeb
,"comparing with %s\n",db
->name
);
1184 if (!strncmp(db
->name
,str
,substrlen
)) {
1186 inc_size
= 4+((strlen(db
->name
)+4)&~3)+((db
->datalen
+3)&~3);
1188 return _find_dataA( block
+inc_size
,nextslash
,
1189 buff_remain
- inc_size
);
1194 inc_size
=((db
->nextoff
+3)&~3);
1195 block
=block
+inc_size
;
1196 buff_remain
=buff_remain
-inc_size
;
1200 /* this one used for Win32 resources, which are always in UNICODE format */
1201 extern LPWSTR
CRTDLL_wcschr(LPCWSTR str
,WCHAR xchar
);
1203 _find_dataW(BYTE
*block
,LPCWSTR str
, WORD buff_remain
) {
1205 int substrlen
, inc_size
;
1208 while (*str
&& *str
=='\\')
1210 if (NULL
!=(nextslash
=CRTDLL_wcschr(str
,'\\')))
1211 substrlen
=nextslash
-str
;
1213 substrlen
=lstrlen32W(str
);
1214 if (nextslash
!=NULL
) {
1215 while (*nextslash
&& *nextslash
=='\\')
1223 db
=(struct dbW
*)block
;
1224 if ((!db
->nextoff
) || (!buff_remain
)) /* no more entries ? */
1227 if (!lstrncmp32W(db
->name
,str
,substrlen
)) {
1229 inc_size
= 8+((lstrlen32W(db
->name
)*sizeof(WCHAR
)+4)&~3)+((db
->datalen
+3)&~3);
1231 return _find_dataW( block
+inc_size
,nextslash
,
1232 buff_remain
- inc_size
);
1236 inc_size
=((db
->nextoff
+3)&~3);
1237 block
=block
+inc_size
;
1238 buff_remain
=buff_remain
-inc_size
;
1242 /* VerQueryValue [VER.11] */
1243 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
1244 DWORD WINAPI
VerQueryValue16(SEGPTR segblock
,LPCSTR subblock
,SEGPTR
*buffer
,
1247 BYTE
*block
=PTR_SEG_TO_LIN(segblock
),*b
;
1250 dprintf_ver(stddeb
,"VerQueryValue16(%p,%s,%p,%d)\n",
1251 block
,subblock
,buffer
,*buflen
1253 s
=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock
)+1);
1254 strcpy(s
,"VS_VERSION_INFO\\");strcat(s
,subblock
);
1256 /* check for UNICODE version */
1257 if ( (*(DWORD
*)(block
+0x14) != VS_FFI_SIGNATURE
) &&
1258 (*(DWORD
*)(block
+0x28) == VS_FFI_SIGNATURE
)
1262 wstr
= HEAP_strdupAtoW(GetProcessHeap(),0,s
);
1263 b
=_find_dataW(block
, wstr
, *(WORD
*)block
);
1264 HeapFree(GetProcessHeap(),0,wstr
);
1266 fprintf(stderr
,"key %s not found in versionresource.\n",subblock
);
1271 b
= b
+8+((lstrlen32W(db
->name
)*sizeof(WCHAR
)+4)&~3);
1272 *buflen
= db
->datalen
;
1275 b
=_find_dataA(block
, s
, *(WORD
*)block
);
1277 fprintf(stderr
,"key %s not found in versionresource.\n",subblock
);
1282 b
= b
+4+((lstrlen32A(db
->name
)+4)&~3);
1283 *buflen
= db
->datalen
;
1285 *buffer
= (b
-block
)+segblock
;
1286 dprintf_ver(stddeb
," -> %s=%s\n",subblock
,b
);
1290 DWORD WINAPI
VerQueryValue32A(LPVOID vblock
,LPCSTR subblock
,
1291 LPVOID
*vbuffer
,UINT32
*buflen
)
1293 BYTE
*b
,*block
=(LPBYTE
)vblock
,**buffer
=(LPBYTE
*)vbuffer
;
1296 dprintf_ver(stddeb
,"VerQueryValue32A(%p,%s,%p,%d)\n",
1297 block
,subblock
,buffer
,*buflen
1299 s
=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock
)+1);
1300 strcpy(s
,"VS_VERSION_INFO\\");strcat(s
,subblock
);
1301 /* check for UNICODE version */
1302 if ( (*(DWORD
*)(block
+0x14) != VS_FFI_SIGNATURE
) &&
1303 (*(DWORD
*)(block
+0x28) == VS_FFI_SIGNATURE
)
1307 wstr
= HEAP_strdupAtoW(GetProcessHeap(),0,s
);
1308 b
=_find_dataW(block
, wstr
, *(WORD
*)block
);
1309 HeapFree(GetProcessHeap(),0,wstr
);
1311 fprintf(stderr
,"key %s not found in versionresource.\n",subblock
);
1316 *buflen
= db
->datalen
;
1317 b
= b
+8+((lstrlen32W(db
->name
)*sizeof(WCHAR
)+4)&~3);
1320 b
=_find_dataA(block
, s
, *(WORD
*)block
);
1322 fprintf(stderr
,"key %s not found in versionresource.\n",subblock
);
1327 *buflen
= db
->datalen
;
1328 b
= b
+4+((lstrlen32A(db
->name
)+4)&~3);
1331 dprintf_ver(stddeb
," -> %s=%s\n",subblock
,b
);
1335 DWORD WINAPI
VerQueryValue32W(LPVOID vblock
,LPCWSTR subblock
,LPVOID
*vbuffer
,
1341 sb
= HEAP_strdupWtoA( GetProcessHeap(), 0, subblock
);
1342 ret
= VerQueryValue32A(vblock
,sb
,vbuffer
,buflen
);
1343 HeapFree( GetProcessHeap(), 0, sb
);
1346 /* 20 GETFILEVERSIONINFORAW */