2 * Implementation of VER.DLL
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
23 #define LZREAD(what) \
24 if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
25 #define LZTELL(lzfd) LZSeek32(lzfd, 0, SEEK_CUR);
27 /******************************************************************************
30 * char const * prologue,
31 * char const * teststring,
32 * char const * epilogue )
34 * This function will print via dprintf[_]ver to stddeb the prologue string,
35 * followed by the address of teststring and the string it contains if
36 * teststring is non-null or "(null)" otherwise, and then the epilogue
37 * string followed by a new line.
40 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
41 * Original implementation as dprintf[_]ver_string
42 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
43 * Fixed problem that caused bug with tools/make_debug -- renaming
44 * this function should fix the problem.
45 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
46 * Modified it to make it print the message using only one
49 *****************************************************************************/
51 static void ver_dstring(
52 char const * prologue
,
53 char const * teststring
,
54 char const * epilogue
)
56 TRACE(ver
, "%s %p (\"%s\") %s\n", prologue
,
57 (void const *) teststring
,
58 teststring
? teststring
: "(null)",
62 /******************************************************************************
64 * This function will print via dprintf[_]ver to stddeb debug info regarding
65 * the file info structure vffi.
66 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
67 * Added this function to clean up the code.
69 *****************************************************************************/
70 static void print_vffi_debug(VS_FIXEDFILEINFO
*vffi
)
72 dbg_decl_str(ver
, 1024);
74 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",
75 (vffi
->dwStrucVersion
>>16),vffi
->dwStrucVersion
&0xFFFF,
76 vffi
->dwFileVersionMS
,vffi
->dwFileVersionLS
,
77 vffi
->dwProductVersionMS
,vffi
->dwProductVersionLS
,
78 vffi
->dwFileFlagsMask
,
79 (vffi
->dwFileFlags
& VS_FF_DEBUG
) ? "DEBUG," : "",
80 (vffi
->dwFileFlags
& VS_FF_PRERELEASE
) ? "PRERELEASE," : "",
81 (vffi
->dwFileFlags
& VS_FF_PATCHED
) ? "PATCHED," : "",
82 (vffi
->dwFileFlags
& VS_FF_PRIVATEBUILD
) ? "PRIVATEBUILD," : "",
83 (vffi
->dwFileFlags
& VS_FF_INFOINFERRED
) ? "INFOINFERRED," : "",
84 (vffi
->dwFileFlags
& VS_FF_SPECIALBUILD
) ? "SPECIALBUILD," : ""
87 dsprintf(ver
," OS=0x%lx.0x%lx ",
88 (vffi
->dwFileOS
&0xFFFF0000)>>16,
89 vffi
->dwFileOS
&0x0000FFFF
91 switch (vffi
->dwFileOS
&0xFFFF0000) {
92 case VOS_DOS
:dsprintf(ver
,"DOS,");break;
93 case VOS_OS216
:dsprintf(ver
,"OS/2-16,");break;
94 case VOS_OS232
:dsprintf(ver
,"OS/2-32,");break;
95 case VOS_NT
:dsprintf(ver
,"NT,");break;
98 dsprintf(ver
,"UNKNOWN(0x%lx),",vffi
->dwFileOS
&0xFFFF0000);break;
100 switch (vffi
->dwFileOS
& 0xFFFF) {
101 case VOS__BASE
:dsprintf(ver
,"BASE");break;
102 case VOS__WINDOWS16
:dsprintf(ver
,"WIN16");break;
103 case VOS__WINDOWS32
:dsprintf(ver
,"WIN32");break;
104 case VOS__PM16
:dsprintf(ver
,"PM16");break;
105 case VOS__PM32
:dsprintf(ver
,"PM32");break;
106 default:dsprintf(ver
,"UNKNOWN(0x%lx)",vffi
->dwFileOS
&0xFFFF);break;
108 TRACE(ver
, "(%s)\n", dbg_str(ver
));
111 switch (vffi
->dwFileType
) {
114 dsprintf(ver
,"filetype=Unknown(0x%lx)",vffi
->dwFileType
);
116 case VFT_APP
:dsprintf(ver
,"filetype=APP,");break;
117 case VFT_DLL
:dsprintf(ver
,"filetype=DLL,");break;
119 dsprintf(ver
,"filetype=DRV,");
120 switch(vffi
->dwFileSubtype
) {
123 dsprintf(ver
,"UNKNOWN(0x%lx)",vffi
->dwFileSubtype
);
125 case VFT2_DRV_PRINTER
:
126 dsprintf(ver
,"PRINTER");
128 case VFT2_DRV_KEYBOARD
:
129 dsprintf(ver
,"KEYBOARD");
131 case VFT2_DRV_LANGUAGE
:
132 dsprintf(ver
,"LANGUAGE");
134 case VFT2_DRV_DISPLAY
:
135 dsprintf(ver
,"DISPLAY");
138 dsprintf(ver
,"MOUSE");
140 case VFT2_DRV_NETWORK
:
141 dsprintf(ver
,"NETWORK");
143 case VFT2_DRV_SYSTEM
:
144 dsprintf(ver
,"SYSTEM");
146 case VFT2_DRV_INSTALLABLE
:
147 dsprintf(ver
,"INSTALLABLE");
150 dsprintf(ver
,"SOUND");
153 dsprintf(ver
,"COMM");
155 case VFT2_DRV_INPUTMETHOD
:
156 dsprintf(ver
,"INPUTMETHOD");
161 dsprintf(ver
,"filetype=FONT.");
162 switch (vffi
->dwFileSubtype
) {
164 dsprintf(ver
,"UNKNOWN(0x%lx)",vffi
->dwFileSubtype
);
166 case VFT2_FONT_RASTER
:dsprintf(ver
,"RASTER");break;
167 case VFT2_FONT_VECTOR
:dsprintf(ver
,"VECTOR");break;
168 case VFT2_FONT_TRUETYPE
:dsprintf(ver
,"TRUETYPE");break;
171 case VFT_VXD
:dsprintf(ver
,"filetype=VXD");break;
172 case VFT_STATIC_LIB
:dsprintf(ver
,"filetype=STATIC_LIB");break;
174 TRACE(ver
, "%s\n", dbg_str(ver
));
176 TRACE(ver
, " filedata=0x%lx.0x%lx\n",
177 vffi
->dwFileDateMS
,vffi
->dwFileDateLS
);
180 /******************************************************************************
182 * int testFileExistence(
184 * char const * file )
186 * Tests whether a given path/file combination exists. If the file does
187 * not exist, the return value is zero. If it does exist, the return
191 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
192 * Original implementation
194 *****************************************************************************/
196 static int testFileExistence(
205 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
207 strcpy(filename
, path
);
208 filenamelen
= strlen(filename
);
210 /* Add a trailing \ if necessary */
212 if(filename
[filenamelen
- 1] != '\\')
213 strcat(filename
, "\\");
215 else /* specify the current directory */
216 strcpy(filename
, ".\\");
218 /* Create the full pathname */
219 strcat(filename
, file
);
221 if(OpenFile32(filename
, &fileinfo
, OF_EXIST
) == HFILE_ERROR32
)
229 /******************************************************************************
231 * int testFileExclusiveExistence(
233 * char const * file )
235 * Tests whether a given path/file combination exists and ensures that no
236 * other programs have handles to the given file. If the file does not
237 * exist or is open, the return value is zero. If it does exist, the
238 * return value is non-zero.
241 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
242 * Original implementation
244 *****************************************************************************/
246 static int testFileExclusiveExistence(
255 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
257 strcpy(filename
, path
);
258 filenamelen
= strlen(filename
);
260 /* Add a trailing \ if necessary */
262 if(filename
[filenamelen
- 1] != '\\')
263 strcat(filename
, "\\");
265 else /* specify the current directory */
266 strcpy(filename
, ".\\");
268 /* Create the full pathname */
269 strcat(filename
, file
);
271 if(OpenFile32(filename
, &fileinfo
, OF_EXIST
| OF_SHARE_EXCLUSIVE
) ==
281 static int read_xx_header(HFILE32 lzfd
) {
282 IMAGE_DOS_HEADER mzh
;
285 LZSeek32(lzfd
,0,SEEK_SET
);
286 if (sizeof(mzh
)!=LZRead32(lzfd
,&mzh
,sizeof(mzh
)))
288 if (mzh
.e_magic
!=IMAGE_DOS_SIGNATURE
)
290 LZSeek32(lzfd
,mzh
.e_lfanew
,SEEK_SET
);
291 if (2!=LZRead32(lzfd
,magic
,2))
293 LZSeek32(lzfd
,mzh
.e_lfanew
,SEEK_SET
);
294 if (magic
[0] == 'N' && magic
[1] == 'E')
295 return IMAGE_OS2_SIGNATURE
;
296 if (magic
[0] == 'P' && magic
[1] == 'E')
297 return IMAGE_NT_SIGNATURE
;
299 WARN(ver
,"Can't handle %s files.\n",magic
);
304 static int find_ne_resource(
305 HFILE32 lzfd
,SEGPTR
typeid,SEGPTR resid
,
306 BYTE
**resdata
,int *reslen
,DWORD
*off
308 IMAGE_OS2_HEADER nehd
;
315 nehdoffset
= LZTELL(lzfd
);
317 if (nehd
.resource_tab_offset
==nehd
.rname_tab_offset
) {
318 TRACE(ver
,"no resources in NE dll\n");
321 LZSeek32(lzfd
,nehd
.resource_tab_offset
+nehdoffset
,SEEK_SET
);
323 TRACE(ver
,"shiftcount is %d\n",shiftcount
);
324 TRACE(ver
,"reading resource typeinfo dir.\n");
326 if (!HIWORD(typeid)) typeid = (SEGPTR
)(LOWORD(typeid) | 0x8000);
327 if (!HIWORD(resid
)) resid
= (SEGPTR
)(LOWORD(resid
) | 0x8000);
334 TRACE(ver
," ti.typeid =%04x,count=%d\n",ti
.type_id
,ti
.count
);
337 if (!HIWORD(typeid)) {
338 if ((ti
.type_id
&0x8000)&&(typeid!=ti
.type_id
))
341 if (ti
.type_id
& 0x8000) {
348 whereleft
= LZTELL(lzfd
);
351 nehdoffset
+nehd
.resource_tab_offset
+ti
.type_id
,
356 if (len
!=LZRead32(lzfd
,str
,len
))
358 TRACE(ver
,"read %s to compare it with %s\n",
359 str
,(char*)PTR_SEG_TO_LIN(typeid)
361 if (lstrcmpi32A(str
,(char*)PTR_SEG_TO_LIN(typeid)))
364 LZSeek32(lzfd
,whereleft
,SEEK_SET
);
368 LZSeek32(lzfd
,ti
.count
*sizeof(ni
),SEEK_CUR
);
371 for (i
=0;i
<ti
.count
;i
++) {
376 TRACE(ver
," ni.id=%4x,offset=%d,length=%d\n",
377 ni
.id
,ni
.offset
,ni
.length
380 if (!HIWORD(resid
)) {
384 if (!(ni
.id
& 0x8000)) {
389 whereleft
= LZTELL(lzfd
);
392 nehdoffset
+nehd
.resource_tab_offset
+ni
.id
,
397 if (len
!=LZRead32(lzfd
,str
,len
))
399 TRACE(ver
,"read %s to compare it with %s\n",
400 str
,(char*)PTR_SEG_TO_LIN(typeid)
402 if (!lstrcmpi32A(str
,(char*)PTR_SEG_TO_LIN(typeid)))
405 LZSeek32(lzfd
,whereleft
,SEEK_SET
);
410 LZSeek32(lzfd
,((int)ni
.offset
<<shiftcount
),SEEK_SET
);
411 *off
= (int)ni
.offset
<<shiftcount
;
412 len
= ni
.length
<<shiftcount
;
413 rdata
=(WORD
*)xmalloc(len
);
414 if (len
!=LZRead32(lzfd
,rdata
,len
)) {
418 TRACE(ver
,"resource found.\n");
419 *resdata
= (BYTE
*)rdata
;
426 /* Loads the specified PE resource.
427 * FIXME: shouldn't load the whole image
431 HFILE32 lzfd
,LPWSTR
typeid,LPWSTR resid
,
432 BYTE
**resdata
,int *reslen
,DWORD
*off
434 IMAGE_NT_HEADERS pehd
;
437 DWORD imagesize
,pehdoffset
;
439 IMAGE_DATA_DIRECTORY resdir
;
440 LPIMAGE_RESOURCE_DIRECTORY resourcedir
,xresdir
;
441 LPIMAGE_RESOURCE_DATA_ENTRY xresdata
;
442 LPIMAGE_SECTION_HEADER sections
;
444 pehdoffset
= LZTELL(lzfd
);
446 resdir
= pehd
.OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
447 TRACE(ver
,"(.,%p,%p,....)\n",typeid,resid
);
449 WARN(ver
,"No resource directory found in PE file.\n");
452 imagesize
= pehd
.OptionalHeader
.SizeOfImage
;
453 image
= HeapAlloc(GetProcessHeap(),0,imagesize
);
454 nrofsections
= pehd
.FileHeader
.NumberOfSections
;
456 sections
= (LPIMAGE_SECTION_HEADER
)HeapAlloc(GetProcessHeap(),0,pehd
.FileHeader
.NumberOfSections
*sizeof(IMAGE_SECTION_HEADER
));
459 sizeof(DWORD
)+ /* Signature */
460 sizeof(IMAGE_FILE_HEADER
)+
461 pehd
.FileHeader
.SizeOfOptionalHeader
,
464 if ( nrofsections
*sizeof(IMAGE_SECTION_HEADER
)!=
465 LZRead32(lzfd
,sections
,nrofsections
*sizeof(IMAGE_SECTION_HEADER
))
467 HeapFree(GetProcessHeap(),0,image
);
470 for (i
=0;i
<nrofsections
;i
++) {
471 if (sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
473 LZSeek32(lzfd
,sections
[i
].PointerToRawData
,SEEK_SET
);
474 if ( sections
[i
].SizeOfRawData
!=
475 LZRead32(lzfd
,image
+sections
[i
].VirtualAddress
,sections
[i
].SizeOfRawData
)
477 HeapFree(GetProcessHeap(),0,image
);
481 resourcedir
= (LPIMAGE_RESOURCE_DIRECTORY
)(image
+resdir
.VirtualAddress
);
482 xresdir
= GetResDirEntryW(resourcedir
,typeid,(DWORD
)resourcedir
,FALSE
);
484 TRACE(ver
,"...no typeid entry found for %p\n",typeid);
485 HeapFree(GetProcessHeap(),0,image
);
488 xresdir
= GetResDirEntryW(xresdir
,resid
,(DWORD
)resourcedir
,FALSE
);
490 TRACE(ver
,"...no resid entry found for %p\n",resid
);
491 HeapFree(GetProcessHeap(),0,image
);
495 xresdir
= GetResDirEntryW(xresdir
,0,(DWORD
)resourcedir
,TRUE
);
497 TRACE(ver
,"...no 0 (default language) entry found for %p\n",resid
);
498 HeapFree(GetProcessHeap(),0,image
);
501 xresdata
= (LPIMAGE_RESOURCE_DATA_ENTRY
)xresdir
;
502 *reslen
= xresdata
->Size
;
503 *resdata
= (LPBYTE
)xmalloc(*reslen
);
504 memcpy(*resdata
,image
+xresdata
->OffsetToData
,*reslen
);
505 /* find physical address for virtual offset */
506 for (i
=0;i
<nrofsections
;i
++) {
507 if (sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
509 if ( (xresdata
->OffsetToData
>= sections
[i
].VirtualAddress
)&&
510 (xresdata
->OffsetToData
< sections
[i
].VirtualAddress
+sections
[i
].SizeOfRawData
)
512 *off
= (DWORD
)(xresdata
->OffsetToData
)-(DWORD
)(sections
[i
].VirtualAddress
)+(DWORD
)(sections
[i
].PointerToRawData
);
516 HeapFree(GetProcessHeap(),0,image
);
517 HeapFree(GetProcessHeap(),0,sections
);
521 /* GetFileResourceSize [VER.2] */
522 DWORD WINAPI
GetFileResourceSize(LPCSTR filename
,SEGPTR restype
,SEGPTR resid
,
527 BYTE
*resdata
= NULL
;
531 TRACE(ver
,"(%s,%lx,%lx,%p)\n",
532 filename
,(LONG
)restype
,(LONG
)resid
,off
534 lzfd
=LZOpenFile32A(filename
,&ofs
,OF_READ
);
537 switch (read_xx_header(lzfd
)) {
541 case IMAGE_OS2_SIGNATURE
:
542 res
=find_ne_resource(lzfd
,restype
,resid
,&resdata
,&reslen
,off
);
544 case IMAGE_NT_SIGNATURE
:
545 res
=find_pe_resource(lzfd
,(LPWSTR
)restype
,(LPWSTR
)resid
,&resdata
,&reslen
,off
);
558 /* GetFileResource [VER.3] */
559 DWORD WINAPI
GetFileResource(LPCSTR filename
,SEGPTR restype
,SEGPTR resid
,
560 DWORD off
,DWORD datalen
,LPVOID data
)
568 TRACE(ver
,"(%s,%lx,%lx,%ld,%ld,%p)\n",
569 filename
,(LONG
)restype
,(LONG
)resid
,off
,datalen
,data
572 lzfd
=LZOpenFile32A(filename
,&ofs
,OF_READ
);
576 switch (read_xx_header(lzfd
)) {
579 case IMAGE_OS2_SIGNATURE
:
580 res
= find_ne_resource(lzfd
,restype
,resid
,&resdata
,&reslen
,&off
);
582 case IMAGE_NT_SIGNATURE
:
583 res
= find_pe_resource(lzfd
,(LPWSTR
)restype
,(LPWSTR
)resid
,&resdata
,&reslen
,&off
);
589 if (reslen
>datalen
) reslen
= datalen
;
590 memcpy(data
,resdata
,reslen
);
594 LZSeek32(lzfd
,off
,SEEK_SET
);
595 reslen
= LZRead32(lzfd
,data
,datalen
);
600 /* GetFileVersionInfoSize [VER.6] */
601 DWORD WINAPI
GetFileVersionInfoSize16(LPCSTR filename
,LPDWORD handle
)
603 DWORD len
,ret
,isuni
=0;
605 VS_FIXEDFILEINFO
*vffi
;
607 TRACE(ver
,"(%s,%p)\n",filename
,handle
);
608 len
=GetFileResourceSize(filename
,VS_FILE_INFO
,VS_VERSION_INFO
,handle
);
612 filename
,VS_FILE_INFO
,VS_VERSION_INFO
,*handle
,sizeof(buf
),buf
617 vffi
=(VS_FIXEDFILEINFO
*)(buf
+0x14);
618 if (vffi
->dwSignature
!= VS_FFI_SIGNATURE
) {
619 /* unicode resource */
620 if (vffi
->dwSignature
== 0x004f0049) {
622 vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
624 WARN(ver
,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
625 vffi
->dwSignature
,VS_FFI_SIGNATURE
630 if (*(WORD
*)buf
< len
)
634 print_vffi_debug(vffi
);
639 /* GetFileVersionInfoSize32A [VERSION.1] */
640 DWORD WINAPI
GetFileVersionInfoSize32A(LPCSTR filename
,LPDWORD handle
)
642 TRACE(ver
,"(%s,%p)\n",filename
,handle
);
643 return GetFileVersionInfoSize16(filename
,handle
);
646 /* GetFileVersionInfoSize32W [VERSION.2] */
647 DWORD WINAPI
GetFileVersionInfoSize32W( LPCWSTR filename
, LPDWORD handle
)
649 LPSTR xfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
650 DWORD ret
= GetFileVersionInfoSize16( xfn
, handle
);
651 HeapFree( GetProcessHeap(), 0, xfn
);
655 /* GetFileVersionInfo [VER.7] */
656 DWORD WINAPI
GetFileVersionInfo16(LPCSTR filename
,DWORD handle
,DWORD datasize
,
659 TRACE(ver
,"(%s,%ld,%ld,%p)\n",
660 filename
,handle
,datasize
,data
662 return GetFileResource(
663 filename
,VS_FILE_INFO
,VS_VERSION_INFO
,handle
,datasize
,data
667 /* GetFileVersionInfoA [VERSION.0] */
668 DWORD WINAPI
GetFileVersionInfo32A(LPCSTR filename
,DWORD handle
,
669 DWORD datasize
,LPVOID data
)
671 return GetFileVersionInfo16(filename
,handle
,datasize
,data
);
674 /* GetFileVersionInfoW [VERSION.3] */
675 DWORD WINAPI
GetFileVersionInfo32W( LPCWSTR filename
, DWORD handle
,
676 DWORD datasize
, LPVOID data
)
678 LPSTR fn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
679 DWORD ret
= GetFileVersionInfo16( fn
, handle
, datasize
, data
);
680 HeapFree( GetProcessHeap(), 0, fn
);
684 /*****************************************************************************
686 * VerFindFile() [VER.8]
687 * Determines where to install a file based on whether it locates another
688 * version of the file in the system. The values VerFindFile returns are
689 * used in a subsequent call to the VerInstallFile function.
692 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
693 * Reimplementation of VerFindFile from original stub.
695 ****************************************************************************/
697 DWORD WINAPI
VerFindFile16(
703 UINT16
*lpuCurDirLen
,
705 UINT16
*lpuDestDirLen
)
710 unsigned int curDirSizeReq
;
711 unsigned int destDirSizeReq
;
715 /* Print out debugging information */
716 TRACE(ver
, "called with parameters:\n"
717 "\tflags = %x", flags
);
718 if(flags
& VFFF_ISSHAREDFILE
)
719 TRACE(ver
, " (VFFF_ISSHAREDFILE)\n");
723 ver_dstring("\tlpszFilename = ", lpszFilename
, "");
724 ver_dstring("\tlpszWinDir = ", lpszWinDir
, "");
725 ver_dstring("\tlpszAppDir = ", lpszAppDir
, "");
727 TRACE(ver
, "\tlpszCurDir = %p\n", lpszCurDir
);
729 TRACE(ver
, "\tlpuCurDirLen = %p (%u)\n",
730 lpuCurDirLen
, *lpuCurDirLen
);
732 TRACE(ver
, "\tlpuCurDirLen = (null)\n");
734 TRACE(ver
, "\tlpszDestDir = %p\n", lpszDestDir
);
736 TRACE(ver
, "\tlpuDestDirLen = %p (%u)\n",
737 lpuDestDirLen
, *lpuDestDirLen
);
739 /* Figure out where the file should go; shared files default to the
745 if(flags
& VFFF_ISSHAREDFILE
) {
746 GetSystemDirectory32A(destDir
, 256);
748 /* Were we given a filename? If so, try to find the file. */
750 if(testFileExistence(destDir
, lpszFilename
)) {
751 strcpy(curDir
, destDir
);
753 if(!testFileExclusiveExistence(destDir
, lpszFilename
))
754 retval
|= VFF_FILEINUSE
;
756 else if(lpszAppDir
&& testFileExistence(lpszAppDir
,
758 strcpy(curDir
, lpszAppDir
);
759 retval
|= VFF_CURNEDEST
;
761 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
762 retval
|= VFF_FILEINUSE
;
766 else if(!(flags
& VFFF_ISSHAREDFILE
)) { /* not a shared file */
769 GetSystemDirectory32A(systemDir
, 256);
771 strcpy(destDir
, lpszAppDir
);
774 if(testFileExistence(lpszAppDir
, lpszFilename
)) {
775 strcpy(curDir
, lpszAppDir
);
777 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
778 retval
|= VFF_FILEINUSE
;
780 else if(testFileExistence(systemDir
, lpszFilename
)) {
781 strcpy(curDir
, systemDir
);
782 retval
|= VFF_CURNEDEST
;
784 if(!testFileExclusiveExistence(systemDir
, lpszFilename
))
785 retval
|= VFF_FILEINUSE
;
791 curDirSizeReq
= strlen(curDir
) + 1;
792 destDirSizeReq
= strlen(destDir
) + 1;
796 /* Make sure that the pointers to the size of the buffers are
797 valid; if not, do NOTHING with that buffer. If that pointer
798 is valid, then make sure that the buffer pointer is valid, too! */
800 if(lpuDestDirLen
&& lpszDestDir
) {
801 if(*lpuDestDirLen
< destDirSizeReq
) {
802 retval
|= VFF_BUFFTOOSMALL
;
803 strncpy(lpszDestDir
, destDir
, *lpuDestDirLen
- 1);
804 lpszDestDir
[*lpuDestDirLen
- 1] = '\0';
807 strcpy(lpszDestDir
, destDir
);
809 *lpuDestDirLen
= destDirSizeReq
;
812 if(lpuCurDirLen
&& lpszCurDir
) {
813 if(*lpuCurDirLen
< curDirSizeReq
) {
814 retval
|= VFF_BUFFTOOSMALL
;
815 strncpy(lpszCurDir
, curDir
, *lpuCurDirLen
- 1);
816 lpszCurDir
[*lpuCurDirLen
- 1] = '\0';
819 strcpy(lpszCurDir
, curDir
);
821 *lpuCurDirLen
= curDirSizeReq
;
824 TRACE(ver
, "ret = %lu (%s%s%s)\n", retval
,
825 (retval
& VFF_CURNEDEST
) ? "VFF_CURNEDEST " : "",
826 (retval
& VFF_FILEINUSE
) ? "VFF_FILEINUSE " : "",
827 (retval
& VFF_BUFFTOOSMALL
) ? "VFF_BUFFTOOSMALL " : "");
829 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir
, "");
831 TRACE(ver
, "\t(Exit) lpuCurDirLen = %p (%u)\n",
832 lpuCurDirLen
, *lpuCurDirLen
);
834 TRACE(ver
, "\t(Exit) lpuCurDirLen = (null)\n");
836 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir
, "");
838 TRACE(ver
, "\t(Exit) lpuDestDirLen = %p (%u)\n",
839 lpuDestDirLen
, *lpuDestDirLen
);
844 /* VerFindFileA [VERSION.5] */
845 DWORD WINAPI
VerFindFile32A(
846 UINT32 flags
,LPCSTR filename
,LPCSTR windir
,LPCSTR appdir
,
847 LPSTR curdir
,UINT32
*pcurdirlen
,LPSTR destdir
,UINT32
*pdestdirlen
)
849 UINT16 curdirlen
, destdirlen
;
852 curdirlen
= (UINT16
)*pcurdirlen
;
853 destdirlen
= (UINT16
)*pdestdirlen
;
855 ret
= VerFindFile16(flags
,filename
,windir
,appdir
,
856 curdir
,&curdirlen
,destdir
,&destdirlen
);
857 *pcurdirlen
= curdirlen
;
858 *pdestdirlen
= destdirlen
;
862 /* VerFindFileW [VERSION.6] */
863 DWORD WINAPI
VerFindFile32W(
864 UINT32 flags
,LPCWSTR filename
,LPCWSTR windir
,LPCWSTR appdir
,
865 LPWSTR curdir
,UINT32
*pcurdirlen
,LPWSTR destdir
,UINT32
*pdestdirlen
)
867 UINT16 curdirlen
, destdirlen
;
868 LPSTR wfn
,wwd
,wad
,wdd
,wcd
;
871 wfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
872 wwd
= HEAP_strdupWtoA( GetProcessHeap(), 0, windir
);
873 wad
= HEAP_strdupWtoA( GetProcessHeap(), 0, appdir
);
874 wcd
= HeapAlloc( GetProcessHeap(), 0, *pcurdirlen
);
875 wdd
= HeapAlloc( GetProcessHeap(), 0, *pdestdirlen
);
876 ret
= VerFindFile16(flags
,wfn
,wwd
,wad
,wcd
,&curdirlen
,wdd
,&destdirlen
);
877 lstrcpynAtoW(curdir
,wcd
,*pcurdirlen
);
878 lstrcpynAtoW(destdir
,wdd
,*pdestdirlen
);
879 *pcurdirlen
= strlen(wcd
);
880 *pdestdirlen
= strlen(wdd
);
881 HeapFree( GetProcessHeap(), 0, wfn
);
882 HeapFree( GetProcessHeap(), 0, wwd
);
883 HeapFree( GetProcessHeap(), 0, wad
);
884 HeapFree( GetProcessHeap(), 0, wcd
);
885 HeapFree( GetProcessHeap(), 0, wdd
);
889 /* VerInstallFile [VER.9] */
890 DWORD WINAPI
VerInstallFile16(
891 UINT16 flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
892 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT16
*tmpfilelen
)
895 DWORD ret
= VerInstallFile32A(flags
,srcfilename
,destfilename
,srcdir
,
896 destdir
,curdir
,tmpfile
,&filelen
);
898 *tmpfilelen
= filelen
;
903 _fetch_versioninfo(LPSTR fn
,VS_FIXEDFILEINFO
**vffi
) {
909 buf
= xmalloc(alloclen
);
911 ret
= GetFileVersionInfo32A(fn
,0,alloclen
,buf
);
916 if (alloclen
<*(WORD
*)buf
) {
918 alloclen
= *(WORD
*)buf
;
919 buf
= xmalloc(alloclen
);
921 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x14);
922 if ((*vffi
)->dwSignature
== 0x004f0049) /* hack to detect unicode */
923 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
924 if ((*vffi
)->dwSignature
!= VS_FFI_SIGNATURE
)
925 WARN(ver
,"Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi
)->dwSignature
);
932 _error2vif(DWORD error
) {
934 case ERROR_ACCESS_DENIED
:
935 return VIF_ACCESSVIOLATION
;
936 case ERROR_SHARING_VIOLATION
:
937 return VIF_SHARINGVIOLATION
;
944 /******************************************************************************
945 * VerInstallFile32A [VERSION.7]
947 DWORD WINAPI
VerInstallFile32A(
948 UINT32 flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
949 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT32
*tmpfilelen
)
952 char destfn
[260],tmpfn
[260],srcfn
[260];
954 DWORD attr
,ret
,xret
,tmplast
;
958 TRACE(ver
,"(%x,%s,%s,%s,%s,%s,%p,%d)\n",
959 flags
,srcfilename
,destfilename
,srcdir
,destdir
,curdir
,tmpfile
,*tmpfilelen
962 sprintf(srcfn
,"%s\\%s",srcdir
,srcfilename
);
963 if (!destdir
|| !*destdir
) pdest
= srcdir
;
964 else pdest
= destdir
;
965 sprintf(destfn
,"%s\\%s",pdest
,destfilename
);
966 hfsrc
=LZOpenFile32A(srcfn
,&ofs
,OF_READ
);
967 if (hfsrc
==HFILE_ERROR32
)
968 return VIF_CANNOTREADSRC
;
969 sprintf(tmpfn
,"%s\\%s",pdest
,destfilename
);
970 tmplast
=strlen(pdest
)+1;
971 attr
= GetFileAttributes32A(tmpfn
);
973 if (attr
& FILE_ATTRIBUTE_READONLY
) {
975 return VIF_WRITEPROT
;
977 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
980 if (flags
& VIFF_FORCEINSTALL
) {
982 sprintf(tmpfn
,"%s\\%s",pdest
,tmpfile
);
983 tmplast
= strlen(pdest
)+1;
984 attr
= GetFileAttributes32A(tmpfn
);
985 /* if it exists, it has been copied by the call before.
986 * we jump over the copy part...
993 GetTempFileName32A(pdest
,"ver",0,tmpfn
); /* should not fail ... */
994 s
=strrchr(tmpfn
,'\\');
999 hfdst
= OpenFile32(tmpfn
,&ofs
,OF_CREATE
);
1000 if (hfdst
== HFILE_ERROR32
) {
1002 return VIF_CANNOTCREATE
; /* | translated dos error */
1004 ret
= LZCopy32(hfsrc
,hfdst
);
1006 if (((long) ret
) < 0) {
1007 /* translate LZ errors into VIF_xxx */
1009 case LZERROR_BADINHANDLE
:
1011 case LZERROR_BADVALUE
:
1012 case LZERROR_UNKNOWNALG
:
1013 ret
= VIF_CANNOTREADSRC
;
1015 case LZERROR_BADOUTHANDLE
:
1017 ret
= VIF_OUTOFMEMORY
; /* FIXME: correct? */
1019 case LZERROR_GLOBALLOC
:
1020 case LZERROR_GLOBLOCK
:
1021 ret
= VIF_OUTOFSPACE
;
1023 default: /* unknown error, should not happen */
1034 if (!(flags
& VIFF_FORCEINSTALL
)) {
1035 VS_FIXEDFILEINFO
*destvffi
,*tmpvffi
;
1036 buf1
= _fetch_versioninfo(destfn
,&destvffi
);
1038 buf2
= _fetch_versioninfo(tmpfn
,&tmpvffi
);
1045 /* compare file versions */
1046 if ((destvffi
->dwFileVersionMS
> tmpvffi
->dwFileVersionMS
)||
1047 ((destvffi
->dwFileVersionMS
==tmpvffi
->dwFileVersionMS
)&&
1048 (destvffi
->dwFileVersionLS
> tmpvffi
->dwFileVersionLS
)
1051 xret
|= VIF_MISMATCH
|VIF_SRCOLD
;
1052 /* compare filetypes and filesubtypes */
1053 if ((destvffi
->dwFileType
!=tmpvffi
->dwFileType
) ||
1054 (destvffi
->dwFileSubtype
!=tmpvffi
->dwFileSubtype
)
1056 xret
|= VIF_MISMATCH
|VIF_DIFFTYPE
;
1057 if (VerQueryValue32A(buf1
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf1
,&len1
) &&
1058 VerQueryValue32A(buf2
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf2
,&len2
)
1060 /* irgendwas mit tbuf1 und tbuf2 machen
1061 * generiert DIFFLANG|MISMATCH
1066 xret
=VIF_MISMATCH
|VIF_SRCOLD
;
1071 if (*tmpfilelen
<strlen(tmpfn
+tmplast
)) {
1072 xret
|=VIF_BUFFTOOSMALL
;
1073 DeleteFile32A(tmpfn
);
1075 strcpy(tmpfile
,tmpfn
+tmplast
);
1076 *tmpfilelen
= strlen(tmpfn
+tmplast
)+1;
1080 if (-1!=GetFileAttributes32A(destfn
))
1081 if (!DeleteFile32A(destfn
)) {
1082 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETE
;
1083 DeleteFile32A(tmpfn
);
1087 if ((!(flags
& VIFF_DONTDELETEOLD
)) &&
1090 lstrcmpi32A(curdir
,pdest
)
1094 sprintf(curfn
,"%s\\%s",curdir
,destfilename
);
1095 if (-1!=GetFileAttributes32A(curfn
)) {
1096 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
1097 if (!DeleteFile32A(curfn
))
1098 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR
;
1101 if (!MoveFile32A(tmpfn
,destfn
)) {
1102 xret
|=_error2vif(GetLastError())|VIF_CANNOTRENAME
;
1103 DeleteFile32A(tmpfn
);
1111 /* VerInstallFileW [VERSION.8] */
1112 DWORD WINAPI
VerInstallFile32W(
1113 UINT32 flags
,LPCWSTR srcfilename
,LPCWSTR destfilename
,LPCWSTR srcdir
,
1114 LPCWSTR destdir
,LPCWSTR curdir
,LPWSTR tmpfile
,UINT32
*tmpfilelen
)
1116 LPSTR wsrcf
,wsrcd
,wdestf
,wdestd
,wtmpf
,wcurd
;
1119 wsrcf
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename
);
1120 wsrcd
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir
);
1121 wdestf
= HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename
);
1122 wdestd
= HEAP_strdupWtoA( GetProcessHeap(), 0, destdir
);
1123 wtmpf
= HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile
);
1124 wcurd
= HEAP_strdupWtoA( GetProcessHeap(), 0, curdir
);
1125 ret
= VerInstallFile32A(flags
,wsrcf
,wdestf
,wsrcd
,wdestd
,wcurd
,wtmpf
,tmpfilelen
);
1127 lstrcpynAtoW(tmpfile
,wtmpf
,*tmpfilelen
);
1128 HeapFree( GetProcessHeap(), 0, wsrcf
);
1129 HeapFree( GetProcessHeap(), 0, wsrcd
);
1130 HeapFree( GetProcessHeap(), 0, wdestf
);
1131 HeapFree( GetProcessHeap(), 0, wdestd
);
1132 HeapFree( GetProcessHeap(), 0, wtmpf
);
1134 HeapFree( GetProcessHeap(), 0, wcurd
);
1142 /* in memory structure... */
1143 char name
[1]; /* padded to dword alignment */
1145 char data[datalen]; padded to dword alignment
1146 BYTE subdirdata[]; until nextoff
1150 #define DATA_OFFSET_A(db) ((4+(strlen((db)->name)+4))&~3)
1155 WORD btext
; /* type of data */
1156 /* in memory structure... */
1157 WCHAR name
[1]; /* padded to dword alignment */
1159 WCHAR data[datalen]; padded to dword alignment
1160 BYTE subdirdata[]; until nextoff
1167 * WCHAR szKey[]; (zero terminated)
1168 * PADDING (round up to nearest 32bit boundary)
1170 #define DATA_OFFSET_W(db) ((2+2+2+((lstrlen32W((db)->name)+1)*2+3))&~3)
1172 /* this one used for Win16 resources, which are always in ASCII format */
1174 _find_dataA(BYTE
*block
,LPCSTR str
, int buff_remain
) {
1176 int substrlen
, inc_size
;
1179 while (*str
&& *str
=='\\')
1181 if (NULL
!=(nextslash
=strchr(str
,'\\')))
1182 substrlen
=nextslash
-str
;
1184 substrlen
=strlen(str
);
1185 if (nextslash
!=NULL
) {
1186 while (*nextslash
&& *nextslash
=='\\')
1190 } else if (*str
== 0)
1195 db
=(struct dbA
*)block
;
1196 TRACE(ver
,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s\n",
1197 db
,db
->nextoff
,db
->datalen
,db
->name
1199 if ((!db
->nextoff
) || (buff_remain
<=0)) /* no more entries ? */
1202 TRACE(ver
,"comparing with %s\n",db
->name
);
1203 if (!lstrncmpi32A(db
->name
,str
,substrlen
)) {
1205 inc_size
=DATA_OFFSET_A(db
)+((db
->datalen
+3)&~3);
1206 return _find_dataA(block
+inc_size
,nextslash
,
1207 db
->nextoff
-inc_size
);
1211 inc_size
= ((db
->nextoff
+3)&~3);
1213 buff_remain
-= inc_size
;
1217 /* this one used for Win32 resources, which are always in UNICODE format */
1218 extern LPWSTR __cdecl
CRTDLL_wcschr(LPCWSTR str
,WCHAR xchar
);
1220 _find_dataW(BYTE
*block
,LPCWSTR str
, int buff_remain
) {
1222 int substrlen
, inc_size
;
1226 while (*str
&& *str
=='\\')
1228 if (NULL
!=(nextslash
=CRTDLL_wcschr(str
,'\\')))
1229 substrlen
=nextslash
-str
;
1231 substrlen
=lstrlen32W(str
);
1232 if (nextslash
!=NULL
) {
1233 while (*nextslash
&& *nextslash
=='\\')
1237 } else if (*str
== 0)
1243 db
=(struct dbW
*)block
;
1244 xs
= HEAP_strdupWtoA(GetProcessHeap(),0,db
->name
);
1247 vs
= HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR
*)((block
+DATA_OFFSET_W(db
))));
1249 vs
= HEAP_strdupA(GetProcessHeap(),0,"not a string");
1251 vs
= HEAP_strdupA(GetProcessHeap(),0,"no data");
1253 TRACE(ver
,"db->nextoff=%d,db->name=%s,db->data=\"%s\"\n",
1256 HeapFree(GetProcessHeap(),0,vs
);
1257 HeapFree(GetProcessHeap(),0,xs
);
1258 if ((!db
->nextoff
) || (buff_remain
<=0)) /* no more entries ? */
1261 if (!lstrncmpi32W(db
->name
,str
,substrlen
)) {
1263 /* DATA_OFFSET_W(db) (padded to 32bit already)
1265 * PADDING (round up to nearest 32bit boundary)
1266 * --> next level structs
1268 inc_size
=DATA_OFFSET_W(db
)+((db
->datalen
+3)&~3);
1269 return _find_dataW( block
+inc_size
,nextslash
,
1270 db
->nextoff
-inc_size
);
1274 /* skip over this block, round up to nearest 32bit boundary */
1275 inc_size
= ((db
->nextoff
+3)&~3);
1277 buff_remain
-= inc_size
;
1281 /* VerQueryValue [VER.11] */
1282 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
1283 DWORD WINAPI
VerQueryValue16(SEGPTR segblock
,LPCSTR subblock
,SEGPTR
*buffer
,
1287 BYTE
*block
=PTR_SEG_TO_LIN(segblock
),*b
;
1289 TRACE(ver
,"(%p,%s,%p,%d)\n",
1290 block
,subblock
,buffer
,*buflen
1293 s
=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock
)+1);
1294 strcpy(s
,"VS_VERSION_INFO\\");strcat(s
,subblock
);
1295 /* check for UNICODE version */
1296 if ( (*(DWORD
*)(block
+0x14) != VS_FFI_SIGNATURE
) &&
1297 (*(DWORD
*)(block
+0x28) == VS_FFI_SIGNATURE
)
1303 wstr
= HEAP_strdupAtoW(GetProcessHeap(),0,s
);
1304 b
=_find_dataW(block
,wstr
,*(WORD
*)block
);
1305 HeapFree(GetProcessHeap(),0,wstr
);
1307 WARN(ver
,"key %s not found in versionresource.\n",s
);
1313 b
= b
+DATA_OFFSET_W(db
);
1314 *buflen
= db
->datalen
;
1316 xs
= HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR
*)b
);
1317 TRACE(ver
,"->%s\n",xs
);
1318 HeapFree(GetProcessHeap(),0,xs
);
1320 TRACE(ver
,"->%p\n",b
);
1323 b
=_find_dataA(block
,s
,*(WORD
*)block
);
1325 WARN(ver
,"key %s not found in versionresource.\n",s
);
1331 b
= b
+DATA_OFFSET_A(db
);
1332 *buflen
= db
->datalen
;
1333 /* the string is only printable, if it is below \\StringFileInfo*/
1334 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s
,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1335 TRACE(ver
," -> %s=%s\n",subblock
,b
);
1337 TRACE(ver
," -> %s=%p\n",subblock
,b
);
1339 *buffer
= (b
-block
)+segblock
;
1344 DWORD WINAPI
VerQueryValue32A(LPVOID vblock
,LPCSTR subblock
,
1345 LPVOID
*vbuffer
,UINT32
*buflen
)
1347 BYTE
*b
,*block
=(LPBYTE
)vblock
,**buffer
=(LPBYTE
*)vbuffer
;
1350 TRACE(ver
,"(%p,%s,%p,%d)\n",
1351 block
,subblock
,buffer
,*buflen
1354 s
=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock
)+1);
1355 strcpy(s
,"VS_VERSION_INFO\\");strcat(s
,subblock
);
1357 /* check for UNICODE version */
1358 if ( (*(DWORD
*)(block
+0x14) != VS_FFI_SIGNATURE
) &&
1359 (*(DWORD
*)(block
+0x28) == VS_FFI_SIGNATURE
)
1365 wstr
= HEAP_strdupAtoW(GetProcessHeap(),0,s
);
1366 b
=_find_dataW(block
,wstr
,*(WORD
*)block
);
1367 HeapFree(GetProcessHeap(),0,wstr
);
1369 WARN(ver
,"key %s not found in versionresource.\n",s
);
1374 db
= (struct dbW
*)b
;
1375 *buflen
= db
->datalen
;
1376 b
= b
+DATA_OFFSET_W(db
);
1378 xs
= HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR
*)b
);
1379 TRACE(ver
,"->%s\n",xs
);
1380 HeapFree(GetProcessHeap(),0,xs
);
1382 TRACE(ver
,"->%p\n",b
);
1383 /* This is a leak. */
1384 b
= HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR
*)b
);
1387 b
=_find_dataA(block
,s
,*(WORD
*)block
);
1389 WARN(ver
,"key %s not found in versionresource.\n",subblock
);
1395 *buflen
= db
->datalen
;
1396 b
= b
+DATA_OFFSET_A(db
);
1398 /* the string is only printable, if it is below \\StringFileInfo*/
1399 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s
,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1400 TRACE(ver
," -> %s=%s\n",subblock
,b
);
1402 TRACE(ver
," -> %s=%p\n",subblock
,b
);
1409 DWORD WINAPI
VerQueryValue32W(LPVOID vblock
,LPCWSTR subblock
,LPVOID
*vbuffer
,
1415 sb
= HEAP_strdupWtoA( GetProcessHeap(), 0, subblock
);
1416 ret
= VerQueryValue32A(vblock
,sb
,vbuffer
,buflen
);
1417 HeapFree( GetProcessHeap(), 0, sb
);
1420 /* 20 GETFILEVERSIONINFORAW */