2 * Implementation of VER.DLL
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
24 #define LZREAD(what) \
25 if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
26 #define LZTELL(lzfd) LZSeek32(lzfd, 0, SEEK_CUR);
28 /******************************************************************************
31 * char const * prologue,
32 * char const * teststring,
33 * char const * epilogue )
35 * This function will print via dprintf[_]ver to stddeb the prologue string,
36 * followed by the address of teststring and the string it contains if
37 * teststring is non-null or "(null)" otherwise, and then the epilogue
38 * string followed by a new line.
41 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
42 * Original implementation as dprintf[_]ver_string
43 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
44 * Fixed problem that caused bug with tools/make_debug -- renaming
45 * this function should fix the problem.
46 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
47 * Modified it to make it print the message using only one
50 *****************************************************************************/
52 static void ver_dstring(
53 char const * prologue,
54 char const * teststring,
55 char const * epilogue )
57 dprintf_info(ver, "%s %p (\"%s\") %s\n", prologue,
58 (void const *) teststring,
59 teststring ? teststring : "(null)",
63 /******************************************************************************
65 * This function will print via dprintf[_]ver to stddeb debug info regarding
66 * the file info structure vffi.
67 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
68 * Added this function to clean up the code.
70 *****************************************************************************/
71 static void print_vffi_debug(VS_FIXEDFILEINFO *vffi)
73 dbg_decl_str(ver, 1024);
75 dprintf_info(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",
76 (vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF,
77 vffi->dwFileVersionMS,vffi->dwFileVersionLS,
78 vffi->dwProductVersionMS,vffi->dwProductVersionLS,
79 vffi->dwFileFlagsMask,
80 (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "",
81 (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "",
82 (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "",
83 (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "",
84 (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "",
85 (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : ""
88 dsprintf(ver," OS=0x%lx.0x%lx ",
89 (vffi->dwFileOS&0xFFFF0000)>>16,
90 vffi->dwFileOS&0x0000FFFF
92 switch (vffi->dwFileOS&0xFFFF0000) {
93 case VOS_DOS:dsprintf(ver,"DOS,");break;
94 case VOS_OS216:dsprintf(ver,"OS/2-16,");break;
95 case VOS_OS232:dsprintf(ver,"OS/2-32,");break;
96 case VOS_NT:dsprintf(ver,"NT,");break;
99 dsprintf(ver,"UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break;
101 switch (vffi->dwFileOS & 0xFFFF) {
102 case VOS__BASE:dsprintf(ver,"BASE");break;
103 case VOS__WINDOWS16:dsprintf(ver,"WIN16");break;
104 case VOS__WINDOWS32:dsprintf(ver,"WIN32");break;
105 case VOS__PM16:dsprintf(ver,"PM16");break;
106 case VOS__PM32:dsprintf(ver,"PM32");break;
107 default:dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileOS&0xFFFF);break;
109 dprintf_info(ver, "(%s)\n", dbg_str(ver));
112 switch (vffi->dwFileType) {
115 dsprintf(ver,"filetype=Unknown(0x%lx)",vffi->dwFileType);
117 case VFT_APP:dsprintf(ver,"filetype=APP,");break;
118 case VFT_DLL:dsprintf(ver,"filetype=DLL,");break;
120 dsprintf(ver,"filetype=DRV,");
121 switch(vffi->dwFileSubtype) {
124 dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype);
126 case VFT2_DRV_PRINTER:
127 dsprintf(ver,"PRINTER");
129 case VFT2_DRV_KEYBOARD:
130 dsprintf(ver,"KEYBOARD");
132 case VFT2_DRV_LANGUAGE:
133 dsprintf(ver,"LANGUAGE");
135 case VFT2_DRV_DISPLAY:
136 dsprintf(ver,"DISPLAY");
139 dsprintf(ver,"MOUSE");
141 case VFT2_DRV_NETWORK:
142 dsprintf(ver,"NETWORK");
144 case VFT2_DRV_SYSTEM:
145 dsprintf(ver,"SYSTEM");
147 case VFT2_DRV_INSTALLABLE:
148 dsprintf(ver,"INSTALLABLE");
151 dsprintf(ver,"SOUND");
154 dsprintf(ver,"COMM");
156 case VFT2_DRV_INPUTMETHOD:
157 dsprintf(ver,"INPUTMETHOD");
162 dsprintf(ver,"filetype=FONT.");
163 switch (vffi->dwFileSubtype) {
165 dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype);
167 case VFT2_FONT_RASTER:dsprintf(ver,"RASTER");break;
168 case VFT2_FONT_VECTOR:dsprintf(ver,"VECTOR");break;
169 case VFT2_FONT_TRUETYPE:dsprintf(ver,"TRUETYPE");break;
172 case VFT_VXD:dsprintf(ver,"filetype=VXD");break;
173 case VFT_STATIC_LIB:dsprintf(ver,"filetype=STATIC_LIB");break;
175 dprintf_info(ver, "%s\n", dbg_str(ver));
177 dprintf_info(ver, " filedata=0x%lx.0x%lx\n",
178 vffi->dwFileDateMS,vffi->dwFileDateLS);
181 /******************************************************************************
183 * int testFileExistence(
185 * char const * file )
187 * Tests whether a given path/file combination exists. If the file does
188 * not exist, the return value is zero. If it does exist, the return
192 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
193 * Original implementation
195 *****************************************************************************/
197 static int testFileExistence(
206 fileinfo.cBytes = sizeof(OFSTRUCT);
208 strcpy(filename, path);
209 filenamelen = strlen(filename);
211 /* Add a trailing \ if necessary */
213 if(filename[filenamelen - 1] != '\\')
214 strcat(filename, "\\");
216 else /* specify the current directory */
217 strcpy(filename, ".\\");
219 /* Create the full pathname */
220 strcat(filename, file);
222 if(OpenFile32(filename, &fileinfo, OF_EXIST) == HFILE_ERROR32)
230 /******************************************************************************
232 * int testFileExclusiveExistence(
234 * char const * file )
236 * Tests whether a given path/file combination exists and ensures that no
237 * other programs have handles to the given file. If the file does not
238 * exist or is open, the return value is zero. If it does exist, the
239 * return value is non-zero.
242 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
243 * Original implementation
245 *****************************************************************************/
247 static int testFileExclusiveExistence(
256 fileinfo.cBytes = sizeof(OFSTRUCT);
258 strcpy(filename, path);
259 filenamelen = strlen(filename);
261 /* Add a trailing \ if necessary */
263 if(filename[filenamelen - 1] != '\\')
264 strcat(filename, "\\");
266 else /* specify the current directory */
267 strcpy(filename, ".\\");
269 /* Create the full pathname */
270 strcat(filename, file);
272 if(OpenFile32(filename, &fileinfo, OF_EXIST | OF_SHARE_EXCLUSIVE) ==
282 static int read_xx_header(HFILE32 lzfd) {
283 IMAGE_DOS_HEADER mzh;
286 LZSeek32(lzfd,0,SEEK_SET);
287 if (sizeof(mzh)!=LZRead32(lzfd,&mzh,sizeof(mzh)))
289 if (mzh.e_magic!=IMAGE_DOS_SIGNATURE)
291 LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
292 if (2!=LZRead32(lzfd,magic,2))
294 LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET);
295 if (magic[0] == 'N' && magic[1] == 'E')
296 return IMAGE_OS2_SIGNATURE;
297 if (magic[0] == 'P' && magic[1] == 'E')
298 return IMAGE_NT_SIGNATURE;
300 fprintf(stderr,"misc/ver.c:read_ne_header:can't handle %s files.\n",magic);
305 static int find_ne_resource(
306 HFILE32 lzfd,SEGPTR typeid,SEGPTR resid,
307 BYTE **resdata,int *reslen,DWORD *off
309 IMAGE_OS2_HEADER nehd;
316 nehdoffset = LZTELL(lzfd);
318 if (nehd.resource_tab_offset==nehd.rname_tab_offset) {
319 dprintf_info(ver,"no resources in NE dll\n");
322 LZSeek32(lzfd,nehd.resource_tab_offset+nehdoffset,SEEK_SET);
324 dprintf_info(ver,"shiftcount is %d\n",shiftcount);
325 dprintf_info(ver,"reading resource typeinfo dir.\n");
327 if (!HIWORD(typeid)) typeid = (SEGPTR)(LOWORD(typeid) | 0x8000);
328 if (!HIWORD(resid)) resid = (SEGPTR)(LOWORD(resid) | 0x8000);
335 dprintf_info(ver," ti.typeid =%04x,count=%d\n",ti.type_id,ti.count);
338 if (!HIWORD(typeid)) {
339 if ((ti.type_id&0x8000)&&(typeid!=ti.type_id))
342 if (ti.type_id & 0x8000) {
349 whereleft = LZTELL(lzfd);
352 nehdoffset+nehd.resource_tab_offset+ti.type_id,
357 if (len!=LZRead32(lzfd,str,len))
359 dprintf_info(ver,"read %s to compare it with %s\n",
360 str,(char*)PTR_SEG_TO_LIN(typeid)
362 if (lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
365 LZSeek32(lzfd,whereleft,SEEK_SET);
369 LZSeek32(lzfd,ti.count*sizeof(ni),SEEK_CUR);
372 for (i=0;i<ti.count;i++) {
377 dprintf_info(ver," ni.id=%4x,offset=%d,length=%d\n",
378 ni.id,ni.offset,ni.length
381 if (!HIWORD(resid)) {
385 if (!(ni.id & 0x8000)) {
390 whereleft = LZTELL(lzfd);
393 nehdoffset+nehd.resource_tab_offset+ni.id,
398 if (len!=LZRead32(lzfd,str,len))
400 dprintf_info(ver,"read %s to compare it with %s\n",
401 str,(char*)PTR_SEG_TO_LIN(typeid)
403 if (!lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
406 LZSeek32(lzfd,whereleft,SEEK_SET);
411 LZSeek32(lzfd,((int)ni.offset<<shiftcount),SEEK_SET);
412 *off = (int)ni.offset<<shiftcount;
413 len = ni.length<<shiftcount;
414 rdata=(WORD*)xmalloc(len);
415 if (len!=LZRead32(lzfd,rdata,len)) {
419 dprintf_info(ver,"resource found.\n");
420 *resdata= (BYTE*)rdata;
427 /* Loads the specified PE resource.
428 * FIXME: shouldn't load the whole image
432 HFILE32 lzfd,LPWSTR typeid,LPWSTR resid,
433 BYTE **resdata,int *reslen,DWORD *off
435 IMAGE_NT_HEADERS pehd;
438 DWORD imagesize,pehdoffset;
440 IMAGE_DATA_DIRECTORY resdir;
441 LPIMAGE_RESOURCE_DIRECTORY resourcedir,xresdir;
442 LPIMAGE_RESOURCE_DATA_ENTRY xresdata;
443 LPIMAGE_SECTION_HEADER sections;
445 pehdoffset = LZTELL(lzfd);
447 resdir = pehd.OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
448 dprintf_info(ver,"find_pe_resource(.,%p,%p,....)\n",typeid,resid);
450 fprintf(stderr,"misc/ver.c:find_pe_resource() no resource directory found in PE file.\n");
453 imagesize = pehd.OptionalHeader.SizeOfImage;
454 image = HeapAlloc(GetProcessHeap(),0,imagesize);
455 nrofsections = pehd.FileHeader.NumberOfSections;
457 sections = (LPIMAGE_SECTION_HEADER)HeapAlloc(GetProcessHeap(),0,pehd.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
460 sizeof(DWORD)+ /* Signature */
461 sizeof(IMAGE_FILE_HEADER)+
462 pehd.FileHeader.SizeOfOptionalHeader,
465 if ( nrofsections*sizeof(IMAGE_SECTION_HEADER)!=
466 LZRead32(lzfd,sections,nrofsections*sizeof(IMAGE_SECTION_HEADER))
468 HeapFree(GetProcessHeap(),0,image);
471 for (i=0;i<nrofsections;i++) {
472 if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
474 LZSeek32(lzfd,sections[i].PointerToRawData,SEEK_SET);
475 if ( sections[i].SizeOfRawData!=
476 LZRead32(lzfd,image+sections[i].VirtualAddress,sections[i].SizeOfRawData)
480 resourcedir = (LPIMAGE_RESOURCE_DIRECTORY)(image+resdir.VirtualAddress);
481 xresdir = GetResDirEntryW(resourcedir,typeid,(DWORD)resourcedir,FALSE);
483 dprintf_info(ver,"...no typeid entry found for %p\n",typeid);
484 HeapFree(GetProcessHeap(),0,image);
487 xresdir = GetResDirEntryW(xresdir,resid,(DWORD)resourcedir,FALSE);
489 dprintf_info(ver,"...no resid entry found for %p\n",resid);
490 HeapFree(GetProcessHeap(),0,image);
494 xresdir = GetResDirEntryW(xresdir,0,(DWORD)resourcedir,TRUE);
496 dprintf_info(ver,"...no 0 (default language) entry found for %p\n",resid);
497 HeapFree(GetProcessHeap(),0,image);
500 xresdata = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir;
501 *reslen = xresdata->Size;
502 *resdata= (LPBYTE)xmalloc(*reslen);
503 memcpy(*resdata,image+xresdata->OffsetToData,*reslen);
504 /* find physical address for virtual offset */
505 for (i=0;i<nrofsections;i++) {
506 if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
508 if ( (xresdata->OffsetToData >= sections[i].VirtualAddress)&&
509 (xresdata->OffsetToData < sections[i].VirtualAddress+sections[i].SizeOfRawData)
511 *off = (DWORD)(xresdata->OffsetToData)-(DWORD)(sections[i].VirtualAddress)+(DWORD)(sections[i].PointerToRawData);
515 HeapFree(GetProcessHeap(),0,image);
516 HeapFree(GetProcessHeap(),0,sections);
520 /* GetFileResourceSize [VER.2] */
521 DWORD WINAPI GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,
526 BYTE *resdata = NULL;
530 dprintf_info(ver,"GetFileResourceSize(%s,%lx,%lx,%p)\n",
531 filename,(LONG)restype,(LONG)resid,off
533 lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
536 switch (read_xx_header(lzfd)) {
540 case IMAGE_OS2_SIGNATURE:
541 res=find_ne_resource(lzfd,restype,resid,&resdata,&reslen,off);
543 case IMAGE_NT_SIGNATURE:
544 res=find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,off);
557 /* GetFileResource [VER.3] */
558 DWORD WINAPI GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
559 DWORD off,DWORD datalen,LPVOID data )
567 dprintf_info(ver,"GetFileResource(%s,%lx,%lx,%ld,%ld,%p)\n",
568 filename,(LONG)restype,(LONG)resid,off,datalen,data
571 lzfd=LZOpenFile32A(filename,&ofs,OF_READ);
575 switch (read_xx_header(lzfd)) {
578 case IMAGE_OS2_SIGNATURE:
579 res= find_ne_resource(lzfd,restype,resid,&resdata,&reslen,&off);
581 case IMAGE_NT_SIGNATURE:
582 res= find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,&off);
588 if (reslen>datalen) reslen = datalen;
589 memcpy(data,resdata,reslen);
593 LZSeek32(lzfd,off,SEEK_SET);
594 reslen = LZRead32(lzfd,data,datalen);
599 /* GetFileVersionInfoSize [VER.6] */
600 DWORD WINAPI GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle)
602 DWORD len,ret,isuni=0;
604 VS_FIXEDFILEINFO *vffi;
606 dprintf_info(ver,"GetFileVersionInfoSize16(%s,%p)\n",filename,handle);
607 len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle);
611 filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf
616 vffi=(VS_FIXEDFILEINFO*)(buf+0x14);
617 if (vffi->dwSignature != VS_FFI_SIGNATURE) {
618 /* unicode resource */
619 if (vffi->dwSignature == 0x004f0049) {
621 vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
623 fprintf(stderr,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n",
624 vffi->dwSignature,VS_FFI_SIGNATURE
629 if (*(WORD*)buf < len)
632 if(debugging_info(ver))
633 print_vffi_debug(vffi);
638 /* GetFileVersionInfoSize32A [VERSION.1] */
639 DWORD WINAPI GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle)
641 dprintf_info(ver,"GetFileVersionInfoSize32A(%s,%p)\n",filename,handle);
642 return GetFileVersionInfoSize16(filename,handle);
645 /* GetFileVersionInfoSize32W [VERSION.2] */
646 DWORD WINAPI GetFileVersionInfoSize32W( LPCWSTR filename, LPDWORD handle )
648 LPSTR xfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
649 DWORD ret = GetFileVersionInfoSize16( xfn, handle );
650 HeapFree( GetProcessHeap(), 0, xfn );
654 /* GetFileVersionInfo [VER.7] */
655 DWORD WINAPI GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize,
658 dprintf_info(ver,"GetFileVersionInfo16(%s,%ld,%ld,%p)\n",
659 filename,handle,datasize,data
661 return GetFileResource(
662 filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data
666 /* GetFileVersionInfoA [VERSION.0] */
667 DWORD WINAPI GetFileVersionInfo32A(LPCSTR filename,DWORD handle,
668 DWORD datasize,LPVOID data)
670 return GetFileVersionInfo16(filename,handle,datasize,data);
673 /* GetFileVersionInfoW [VERSION.3] */
674 DWORD WINAPI GetFileVersionInfo32W( LPCWSTR filename, DWORD handle,
675 DWORD datasize, LPVOID data)
677 LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
678 DWORD ret = GetFileVersionInfo16( fn, handle, datasize, data );
679 HeapFree( GetProcessHeap(), 0, fn );
683 /*****************************************************************************
685 * VerFindFile() [VER.8]
686 * Determines where to install a file based on whether it locates another
687 * version of the file in the system. The values VerFindFile returns are
688 * used in a subsequent call to the VerInstallFile function.
691 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
692 * Reimplementation of VerFindFile from original stub.
694 ****************************************************************************/
696 DWORD WINAPI VerFindFile16(
702 UINT16 *lpuCurDirLen,
704 UINT16 *lpuDestDirLen )
709 unsigned int curDirSizeReq;
710 unsigned int destDirSizeReq;
714 /* Print out debugging information */
715 dprintf_info(ver, "VerFindFile() called with parameters:\n"
716 "\tflags = %x", flags);
717 if(flags & VFFF_ISSHAREDFILE)
718 dprintf_info(ver, " (VFFF_ISSHAREDFILE)\n");
720 dprintf_info(ver, "\n");
722 ver_dstring("\tlpszFilename = ", lpszFilename, "");
723 ver_dstring("\tlpszWinDir = ", lpszWinDir, "");
724 ver_dstring("\tlpszAppDir = ", lpszAppDir, "");
726 dprintf_info(ver, "\tlpszCurDir = %p\n", lpszCurDir);
728 dprintf_info(ver, "\tlpuCurDirLen = %p (%u)\n",
729 lpuCurDirLen, *lpuCurDirLen);
731 dprintf_info(ver, "\tlpuCurDirLen = (null)\n");
733 dprintf_info(ver, "\tlpszDestDir = %p\n", lpszDestDir);
735 dprintf_info(ver, "\tlpuDestDirLen = %p (%u)\n",
736 lpuDestDirLen, *lpuDestDirLen);
738 /* Figure out where the file should go; shared files default to the
744 if(flags & VFFF_ISSHAREDFILE) {
745 GetSystemDirectory32A(destDir, 256);
747 /* Were we given a filename? If so, try to find the file. */
749 if(testFileExistence(destDir, lpszFilename)) {
750 strcpy(curDir, destDir);
752 if(!testFileExclusiveExistence(destDir, lpszFilename))
753 retval |= VFF_FILEINUSE;
755 else if(lpszAppDir && testFileExistence(lpszAppDir,
757 strcpy(curDir, lpszAppDir);
758 retval |= VFF_CURNEDEST;
760 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
761 retval |= VFF_FILEINUSE;
765 else if(!(flags & VFFF_ISSHAREDFILE)) { /* not a shared file */
768 GetSystemDirectory32A(systemDir, 256);
770 strcpy(destDir, lpszAppDir);
773 if(testFileExistence(lpszAppDir, lpszFilename)) {
774 strcpy(curDir, lpszAppDir);
776 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
777 retval |= VFF_FILEINUSE;
779 else if(testFileExistence(systemDir, lpszFilename)) {
780 strcpy(curDir, systemDir);
781 retval |= VFF_CURNEDEST;
783 if(!testFileExclusiveExistence(systemDir, lpszFilename))
784 retval |= VFF_FILEINUSE;
790 curDirSizeReq = strlen(curDir) + 1;
791 destDirSizeReq = strlen(destDir) + 1;
795 /* Make sure that the pointers to the size of the buffers are
796 valid; if not, do NOTHING with that buffer. If that pointer
797 is valid, then make sure that the buffer pointer is valid, too! */
799 if(lpuDestDirLen && lpszDestDir) {
800 if(*lpuDestDirLen < destDirSizeReq) {
801 retval |= VFF_BUFFTOOSMALL;
802 strncpy(lpszDestDir, destDir, *lpuDestDirLen - 1);
803 lpszDestDir[*lpuDestDirLen - 1] = '\0';
806 strcpy(lpszDestDir, destDir);
808 *lpuDestDirLen = destDirSizeReq;
811 if(lpuCurDirLen && lpszCurDir) {
812 if(*lpuCurDirLen < curDirSizeReq) {
813 retval |= VFF_BUFFTOOSMALL;
814 strncpy(lpszCurDir, curDir, *lpuCurDirLen - 1);
815 lpszCurDir[*lpuCurDirLen - 1] = '\0';
818 strcpy(lpszCurDir, curDir);
820 *lpuCurDirLen = curDirSizeReq;
823 dprintf_info(ver, "VerFindFile() ret = %lu (%s%s%s)\n", retval,
824 (retval & VFF_CURNEDEST) ? "VFF_CURNEDEST " : "",
825 (retval & VFF_FILEINUSE) ? "VFF_FILEINUSE " : "",
826 (retval & VFF_BUFFTOOSMALL) ? "VFF_BUFFTOOSMALL " : "");
828 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir, "");
830 dprintf_info(ver, "\t(Exit) lpuCurDirLen = %p (%u)\n",
831 lpuCurDirLen, *lpuCurDirLen);
833 dprintf_info(ver, "\t(Exit) lpuCurDirLen = (null)\n");
835 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir, "");
837 dprintf_info(ver, "\t(Exit) lpuDestDirLen = %p (%u)\n",
838 lpuDestDirLen, *lpuDestDirLen);
843 /* VerFindFileA [VERSION.5] */
844 DWORD WINAPI VerFindFile32A(
845 UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
846 LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen )
848 UINT16 curdirlen, destdirlen;
851 curdirlen = (UINT16)*pcurdirlen;
852 destdirlen= (UINT16)*pdestdirlen;
854 ret = VerFindFile16(flags,filename,windir,appdir,
855 curdir,&curdirlen,destdir,&destdirlen);
856 *pcurdirlen = curdirlen;
857 *pdestdirlen = destdirlen;
861 /* VerFindFileW [VERSION.6] */
862 DWORD WINAPI VerFindFile32W(
863 UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir,
864 LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen )
866 UINT16 curdirlen, destdirlen;
867 LPSTR wfn,wwd,wad,wdd,wcd;
870 wfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
871 wwd = HEAP_strdupWtoA( GetProcessHeap(), 0, windir );
872 wad = HEAP_strdupWtoA( GetProcessHeap(), 0, appdir );
873 wcd = HeapAlloc( GetProcessHeap(), 0, *pcurdirlen );
874 wdd = HeapAlloc( GetProcessHeap(), 0, *pdestdirlen );
875 ret = VerFindFile16(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen);
876 lstrcpynAtoW(curdir,wcd,*pcurdirlen);
877 lstrcpynAtoW(destdir,wdd,*pdestdirlen);
878 *pcurdirlen = strlen(wcd);
879 *pdestdirlen = strlen(wdd);
880 HeapFree( GetProcessHeap(), 0, wfn );
881 HeapFree( GetProcessHeap(), 0, wwd );
882 HeapFree( GetProcessHeap(), 0, wad );
883 HeapFree( GetProcessHeap(), 0, wcd );
884 HeapFree( GetProcessHeap(), 0, wdd );
888 /* VerInstallFile [VER.9] */
889 DWORD WINAPI VerInstallFile16(
890 UINT16 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
891 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT16 *tmpfilelen )
894 DWORD ret= VerInstallFile32A(flags,srcfilename,destfilename,srcdir,
895 destdir,curdir,tmpfile,&filelen);
897 *tmpfilelen = filelen;
901 /* VerInstallFileA [VERSION.7] */
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 fprintf(stderr,"_fetch_versioninfo: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;
946 DWORD WINAPI VerInstallFile32A(
947 UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
948 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen )
951 char destfn[260],tmpfn[260],srcfn[260];
953 DWORD attr,ret,xret,tmplast;
957 fprintf(stddeb,"VerInstallFile(%x,%s,%s,%s,%s,%s,%p,%d)\n",
958 flags,srcfilename,destfilename,srcdir,destdir,curdir,tmpfile,*tmpfilelen
961 sprintf(srcfn,"%s\\%s",srcdir,srcfilename);
962 if (!destdir || !*destdir) pdest = srcdir;
963 else pdest = destdir;
964 sprintf(destfn,"%s\\%s",pdest,destfilename);
965 hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ);
966 if (hfsrc==HFILE_ERROR32)
967 return VIF_CANNOTREADSRC;
968 sprintf(tmpfn,"%s\\%s",pdest,destfilename);
969 tmplast=strlen(pdest)+1;
970 attr = GetFileAttributes32A(tmpfn);
972 if (attr & FILE_ATTRIBUTE_READONLY) {
974 return VIF_WRITEPROT;
976 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
979 if (flags & VIFF_FORCEINSTALL) {
981 sprintf(tmpfn,"%s\\%s",pdest,tmpfile);
982 tmplast = strlen(pdest)+1;
983 attr = GetFileAttributes32A(tmpfn);
984 /* if it exists, it has been copied by the call before.
985 * we jump over the copy part...
992 GetTempFileName32A(pdest,"ver",0,tmpfn); /* should not fail ... */
993 s=strrchr(tmpfn,'\\');
998 hfdst = OpenFile32(tmpfn,&ofs,OF_CREATE);
999 if (hfdst == HFILE_ERROR32) {
1001 return VIF_CANNOTCREATE; /* | translated dos error */
1003 ret = LZCopy32(hfsrc,hfdst);
1005 if (((long) ret) < 0) {
1006 /* translate LZ errors into VIF_xxx */
1008 case LZERROR_BADINHANDLE:
1010 case LZERROR_BADVALUE:
1011 case LZERROR_UNKNOWNALG:
1012 ret = VIF_CANNOTREADSRC;
1014 case LZERROR_BADOUTHANDLE:
1016 ret = VIF_OUTOFMEMORY; /* FIXME: correct? */
1018 case LZERROR_GLOBALLOC:
1019 case LZERROR_GLOBLOCK:
1020 ret = VIF_OUTOFSPACE;
1022 default: /* unknown error, should not happen */
1033 if (!(flags & VIFF_FORCEINSTALL)) {
1034 VS_FIXEDFILEINFO *destvffi,*tmpvffi;
1035 buf1 = _fetch_versioninfo(destfn,&destvffi);
1037 buf2 = _fetch_versioninfo(tmpfn,&tmpvffi);
1044 /* compare file versions */
1045 if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)||
1046 ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&&
1047 (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS)
1050 xret |= VIF_MISMATCH|VIF_SRCOLD;
1051 /* compare filetypes and filesubtypes */
1052 if ((destvffi->dwFileType!=tmpvffi->dwFileType) ||
1053 (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype)
1055 xret |= VIF_MISMATCH|VIF_DIFFTYPE;
1056 if (VerQueryValue32A(buf1,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf1,&len1) &&
1057 VerQueryValue32A(buf2,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf2,&len2)
1059 /* irgendwas mit tbuf1 und tbuf2 machen
1060 * generiert DIFFLANG|MISMATCH
1065 xret=VIF_MISMATCH|VIF_SRCOLD;
1070 if (*tmpfilelen<strlen(tmpfn+tmplast)) {
1071 xret|=VIF_BUFTOSMALL;
1072 DeleteFile32A(tmpfn);
1074 strcpy(tmpfile,tmpfn+tmplast);
1075 *tmpfilelen = strlen(tmpfn+tmplast)+1;
1079 if (-1!=GetFileAttributes32A(destfn))
1080 if (!DeleteFile32A(destfn)) {
1081 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE;
1082 DeleteFile32A(tmpfn);
1086 if ((!(flags & VIFF_DONTDELETEOLD)) &&
1089 lstrcmpi32A(curdir,pdest)
1093 sprintf(curfn,"%s\\%s",curdir,destfilename);
1094 if (-1!=GetFileAttributes32A(curfn)) {
1095 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
1096 if (!DeleteFile32A(curfn))
1097 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR;
1100 if (!MoveFile32A(tmpfn,destfn)) {
1101 xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME;
1102 DeleteFile32A(tmpfn);
1109 /* VerInstallFileW [VERSION.8] */
1110 DWORD WINAPI VerInstallFile32W(
1111 UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
1112 LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,UINT32 *tmpfilelen )
1114 LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf,wcurd;
1117 wsrcf = HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename );
1118 wsrcd = HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir );
1119 wdestf = HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename );
1120 wdestd = HEAP_strdupWtoA( GetProcessHeap(), 0, destdir );
1121 wtmpf = HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile );
1122 wcurd = HEAP_strdupWtoA( GetProcessHeap(), 0, curdir );
1123 ret = VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,tmpfilelen);
1125 lstrcpynAtoW(tmpfile,wtmpf,*tmpfilelen);
1126 HeapFree( GetProcessHeap(), 0, wsrcf );
1127 HeapFree( GetProcessHeap(), 0, wsrcd );
1128 HeapFree( GetProcessHeap(), 0, wdestf );
1129 HeapFree( GetProcessHeap(), 0, wdestd );
1130 HeapFree( GetProcessHeap(), 0, wtmpf );
1132 HeapFree( GetProcessHeap(), 0, wcurd );
1140 /* in memory structure... */
1141 char name[1]; /* padded to dword alignment */
1143 char data[datalen]; padded to dword alignment
1144 BYTE subdirdata[]; until nextoff
1148 #define DATA_OFFSET_A(db) ((4+(strlen((db)->name)+4))&~3)
1153 WORD btext; /* type of data */
1154 /* in memory structure... */
1155 WCHAR name[1]; /* padded to dword alignment */
1157 WCHAR data[datalen]; padded to dword alignment
1158 BYTE subdirdata[]; until nextoff
1165 * WCHAR szKey[]; (zero terminated)
1166 * PADDING (round up to nearest 32bit boundary)
1168 #define DATA_OFFSET_W(db) ((2+2+2+((lstrlen32W((db)->name)+1)*2+3))&~3)
1170 /* this one used for Win16 resources, which are always in ASCII format */
1172 _find_dataA(BYTE *block,LPCSTR str, int buff_remain) {
1174 int substrlen, inc_size;
1177 while (*str && *str=='\\')
1179 if (NULL!=(nextslash=strchr(str,'\\')))
1180 substrlen=nextslash-str;
1182 substrlen=strlen(str);
1183 if (nextslash!=NULL) {
1184 while (*nextslash && *nextslash=='\\')
1188 } else if (*str == 0)
1193 db=(struct dbA*)block;
1194 dprintf_info(ver,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s\n",
1195 db,db->nextoff,db->datalen,db->name
1197 if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
1200 dprintf_info(ver,"comparing with %s\n",db->name);
1201 if (!lstrncmpi32A(db->name,str,substrlen)) {
1203 inc_size=DATA_OFFSET_A(db)+((db->datalen+3)&~3);
1204 return _find_dataA(block+inc_size,nextslash,
1205 db->nextoff-inc_size);
1209 inc_size = ((db->nextoff+3)&~3);
1211 buff_remain -= inc_size;
1215 /* this one used for Win32 resources, which are always in UNICODE format */
1216 extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar);
1218 _find_dataW(BYTE *block,LPCWSTR str, int buff_remain) {
1220 int substrlen, inc_size;
1224 while (*str && *str=='\\')
1226 if (NULL!=(nextslash=CRTDLL_wcschr(str,'\\')))
1227 substrlen=nextslash-str;
1229 substrlen=lstrlen32W(str);
1230 if (nextslash!=NULL) {
1231 while (*nextslash && *nextslash=='\\')
1235 } else if (*str == 0)
1241 db=(struct dbW*)block;
1242 xs= HEAP_strdupWtoA(GetProcessHeap(),0,db->name);
1245 vs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)((block+DATA_OFFSET_W(db))));
1247 vs = HEAP_strdupA(GetProcessHeap(),0,"not a string");
1249 vs = HEAP_strdupA(GetProcessHeap(),0,"no data");
1251 dprintf_info(ver,"db->nextoff=%d,db->name=%s,db->data=\"%s\"\n",
1254 HeapFree(GetProcessHeap(),0,vs);
1255 HeapFree(GetProcessHeap(),0,xs);
1256 if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */
1259 if (!lstrncmpi32W(db->name,str,substrlen)) {
1261 /* DATA_OFFSET_W(db) (padded to 32bit already)
1263 * PADDING (round up to nearest 32bit boundary)
1264 * --> next level structs
1266 inc_size=DATA_OFFSET_W(db)+((db->datalen+3)&~3);
1267 return _find_dataW( block+inc_size ,nextslash,
1268 db->nextoff-inc_size);
1272 /* skip over this block, round up to nearest 32bit boundary */
1273 inc_size = ((db->nextoff+3)&~3);
1275 buff_remain -= inc_size;
1279 /* VerQueryValue [VER.11] */
1280 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
1281 DWORD WINAPI VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,
1285 BYTE *block=PTR_SEG_TO_LIN(segblock),*b;
1287 dprintf_info(ver,"VerQueryValue16(%p,%s,%p,%d)\n",
1288 block,subblock,buffer,*buflen
1291 s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
1292 strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
1293 /* check for UNICODE version */
1294 if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
1295 (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
1301 wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
1302 b=_find_dataW(block,wstr,*(WORD*)block);
1303 HeapFree(GetProcessHeap(),0,wstr);
1305 fprintf(stderr,"key %s not found in versionresource.\n",s);
1311 b = b+DATA_OFFSET_W(db);
1312 *buflen = db->datalen;
1314 xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1315 dprintf_info(ver,"->%s\n",xs);
1316 HeapFree(GetProcessHeap(),0,xs);
1318 dprintf_info(ver,"->%p\n",b);
1321 b=_find_dataA(block,s,*(WORD*)block);
1323 fprintf(stderr,"key %s not found in versionresource.\n",s);
1329 b = b+DATA_OFFSET_A(db);
1330 *buflen = db->datalen;
1331 /* the string is only printable, if it is below \\StringFileInfo*/
1332 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1333 dprintf_info(ver," -> %s=%s\n",subblock,b);
1335 dprintf_info(ver," -> %s=%p\n",subblock,b);
1337 *buffer = (b-block)+segblock;
1342 DWORD WINAPI VerQueryValue32A(LPVOID vblock,LPCSTR subblock,
1343 LPVOID *vbuffer,UINT32 *buflen)
1345 BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer;
1348 dprintf_info(ver,"VerQueryValue32A(%p,%s,%p,%d)\n",
1349 block,subblock,buffer,*buflen
1352 s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1);
1353 strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock);
1355 /* check for UNICODE version */
1356 if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) &&
1357 (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE)
1363 wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s);
1364 b=_find_dataW(block,wstr,*(WORD*)block);
1365 HeapFree(GetProcessHeap(),0,wstr);
1367 fprintf(stderr,"key %s not found in versionresource.\n",s);
1372 db = (struct dbW*)b;
1373 *buflen = db->datalen;
1374 b = b+DATA_OFFSET_W(db);
1376 xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1377 dprintf_info(ver,"->%s\n",xs);
1378 HeapFree(GetProcessHeap(),0,xs);
1380 dprintf_info(ver,"->%p\n",b);
1381 /* This is a leak. */
1382 b = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b);
1385 b=_find_dataA(block,s,*(WORD*)block);
1387 fprintf(stderr,"key %s not found in versionresource.\n",subblock);
1393 *buflen = db->datalen;
1394 b = b+DATA_OFFSET_A(db);
1396 /* the string is only printable, if it is below \\StringFileInfo*/
1397 if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\")))
1398 dprintf_info(ver," -> %s=%s\n",subblock,b);
1400 dprintf_info(ver," -> %s=%p\n",subblock,b);
1407 DWORD WINAPI VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer,
1413 sb = HEAP_strdupWtoA( GetProcessHeap(), 0, subblock );
1414 ret = VerQueryValue32A(vblock,sb,vbuffer,buflen);
1415 HeapFree( GetProcessHeap(), 0, sb );
1418 /* 20 GETFILEVERSIONINFORAW */