2 * Implementation of VER.DLL
4 * Copyright 1996 Marcus Meissner
24 #define LZREAD(what) if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
26 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
27 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
30 read_ne_header(HFILE lzfd
,struct ne_header_s
*nehd
) {
31 struct mz_header_s mzh
;
33 LZSeek(lzfd
,0,SEEK_SET
);
34 if (sizeof(mzh
)!=LZRead32(lzfd
,&mzh
,sizeof(mzh
)))
36 if (mzh
.mz_magic
!=MZ_SIGNATURE
)
38 LZSeek(lzfd
,mzh
.ne_offset
,SEEK_SET
);
40 if (nehd
->ne_magic
== NE_SIGNATURE
) {
41 LZSeek(lzfd
,mzh
.ne_offset
,SEEK_SET
);
44 /* must handle PE files too. Later. */
51 HFILE lzfd
,struct ne_header_s
*nehd
,SEGPTR
typeid,SEGPTR resid
,
52 BYTE
**resdata
,int *reslen
,DWORD
*off
60 nehdoffset
=LZSeek(lzfd
,nehd
->resource_tab_offset
,SEEK_CUR
);
62 dprintf_resource(stderr
,"shiftcount is %d\n",shiftcount
);
63 dprintf_resource(stderr
,"reading resource typeinfo dir.\n");
65 if (!HIWORD(typeid)) typeid = (SEGPTR
)(LOWORD(typeid) | 0x8000);
66 if (!HIWORD(resid
)) resid
= (SEGPTR
)(LOWORD(resid
) | 0x8000);
73 dprintf_resource(stderr
," ti.typeid =%04x,count=%d\n",ti
.type_id
,ti
.count
);
75 if (!HIWORD(typeid)) {
76 if ((ti
.type_id
&0x8000)&&(typeid!=ti
.type_id
))
79 if (ti
.type_id
& 0x8000) {
88 nehdoffset
+nehd
->resource_tab_offset
+ti
.type_id
,
93 if (len
!=LZRead32(lzfd
,str
,len
))
95 dprintf_resource(stderr
,"read %s to compare it with %s\n",
96 str
,(char*)PTR_SEG_TO_LIN(typeid)
98 if (lstrcmpi32A(str
,(char*)PTR_SEG_TO_LIN(typeid)))
101 LZSeek(lzfd
,whereleft
,SEEK_SET
);
105 LZSeek(lzfd
,ti
.count
*sizeof(ni
),SEEK_CUR
);
108 for (i
=0;i
<ti
.count
;i
++) {
113 dprintf_resource(stderr
," ni.id=%4x,offset=%d,length=%d\n",
114 ni
.id
,ni
.offset
,ni
.length
117 if (!HIWORD(resid
)) {
121 if (!(ni
.id
& 0x8000)) {
128 nehdoffset
+nehd
->resource_tab_offset
+ni
.id
,
133 if (len
!=LZRead32(lzfd
,str
,len
))
135 dprintf_resource(stderr
,"read %s to compare it with %s\n",
136 str
,(char*)PTR_SEG_TO_LIN(typeid)
138 if (!lstrcmpi32A(str
,(char*)PTR_SEG_TO_LIN(typeid)))
141 LZSeek(lzfd
,whereleft
,SEEK_SET
);
146 LZSeek(lzfd
,((int)ni
.offset
<<shiftcount
),SEEK_SET
);
147 *off
= (int)ni
.offset
<<shiftcount
;
148 len
= ni
.length
<<shiftcount
;
149 rdata
=(WORD
*)xmalloc(len
);
150 if (len
!=LZRead32(lzfd
,rdata
,len
)) {
154 dprintf_resource(stderr
,"resource found.\n");
155 *resdata
= (BYTE
*)rdata
;
162 /* GetFileResourceSize [VER.2] */
164 GetFileResourceSize(LPCSTR filename
,SEGPTR restype
,SEGPTR resid
,LPDWORD off
) {
169 struct ne_header_s nehd
;
171 fprintf(stderr
,"GetFileResourceSize(%s,%lx,%lx,%p)\n",
172 filename
,(LONG
)restype
,(LONG
)resid
,off
174 lzfd
=LZOpenFile16(filename
,&ofs
,OF_READ
);
177 if (!read_ne_header(lzfd
,&nehd
)) {
181 if (!find_ne_resource(lzfd
,&nehd
,restype
,resid
,&resdata
,&reslen
,off
)) {
190 /* GetFileResourceSize [VER.3] */
192 GetFileResource(LPCSTR filename
,SEGPTR restype
,SEGPTR resid
,
193 DWORD off
,DWORD datalen
,LPVOID data
199 struct ne_header_s nehd
;
200 fprintf(stderr
,"GetFileResource(%s,%lx,%lx,%ld,%ld,%p)\n",
201 filename
,(LONG
)restype
,(LONG
)resid
,off
,datalen
,data
204 lzfd
=LZOpenFile16(filename
,&ofs
,OF_READ
);
208 if (!read_ne_header(lzfd
,&nehd
)) {
212 if (!find_ne_resource(lzfd
,&nehd
,restype
,resid
,&resdata
,&reslen
,&off
)) {
218 LZSeek(lzfd
,off
,SEEK_SET
);
221 LZRead32(lzfd
,data
,reslen
);
226 /* GetFileVersionInfoSize [VER.6] */
228 GetFileVersionInfoSize16(LPCSTR filename
,LPDWORD handle
) {
231 VS_FIXEDFILEINFO
*vffi
;
233 dprintf_resource(stderr
,"GetFileVersionInfoSize16(%s,%p)\n",filename
,handle
);
234 len
=GetFileResourceSize(filename
,VS_FILE_INFO
,VS_VERSION_INFO
,handle
);
238 filename
,VS_FILE_INFO
,VS_VERSION_INFO
,*handle
,sizeof(buf
),buf
243 vffi
=(VS_FIXEDFILEINFO
*)(buf
+0x14);
244 if (vffi
->dwSignature
!= VS_FFI_SIGNATURE
)
246 if (*(WORD
*)buf
< len
)
248 fprintf(stderr
,"->strucver=%ld.%ld,filever=%ld.%ld,productver=%ld.%ld,flagmask=%lx,flags=%lx,OS=",
249 (vffi
->dwStrucVersion
>>16),vffi
->dwStrucVersion
&0xFFFF,
250 vffi
->dwFileVersionMS
,vffi
->dwFileVersionLS
,
251 vffi
->dwProductVersionMS
,vffi
->dwProductVersionLS
,
252 vffi
->dwFileFlagsMask
,vffi
->dwFileFlags
254 switch (vffi
->dwFileOS
&0xFFFF0000) {
255 case VOS_DOS
:fprintf(stderr
,"DOS,");break;
256 case VOS_OS216
:fprintf(stderr
,"OS/2-16,");break;
257 case VOS_OS232
:fprintf(stderr
,"OS/2-32,");break;
258 case VOS_NT
:fprintf(stderr
,"NT,");break;
261 fprintf(stderr
,"UNKNOWN(%ld),",vffi
->dwFileOS
&0xFFFF0000);break;
263 switch (vffi
->dwFileOS
& 0xFFFF) {
264 case VOS__BASE
:fprintf(stderr
,"BASE");break;
265 case VOS__WINDOWS16
:fprintf(stderr
,"WIN16");break;
266 case VOS__WINDOWS32
:fprintf(stderr
,"WIN32");break;
267 case VOS__PM16
:fprintf(stderr
,"PM16");break;
268 case VOS__PM32
:fprintf(stderr
,"PM32");break;
269 default:fprintf(stderr
,"UNKNOWN(%ld)",vffi
->dwFileOS
&0xFFFF);break;
271 switch (vffi
->dwFileType
) {
274 fprintf(stderr
,"filetype=Unknown(%ld)",vffi
->dwFileType
);
276 case VFT_APP
:fprintf(stderr
,"filetype=APP");break;
277 case VFT_DLL
:fprintf(stderr
,"filetype=DLL");break;
279 fprintf(stderr
,"filetype=DRV,");
280 switch(vffi
->dwFileSubtype
) {
283 fprintf(stderr
,"UNKNOWN(%ld)",vffi
->dwFileSubtype
);
285 case VFT2_DRV_PRINTER
:
286 fprintf(stderr
,"PRINTER");
288 case VFT2_DRV_KEYBOARD
:
289 fprintf(stderr
,"KEYBOARD");
291 case VFT2_DRV_LANGUAGE
:
292 fprintf(stderr
,"LANGUAGE");
294 case VFT2_DRV_DISPLAY
:
295 fprintf(stderr
,"DISPLAY");
298 fprintf(stderr
,"MOUSE");
300 case VFT2_DRV_NETWORK
:
301 fprintf(stderr
,"NETWORK");
303 case VFT2_DRV_SYSTEM
:
304 fprintf(stderr
,"SYSTEM");
306 case VFT2_DRV_INSTALLABLE
:
307 fprintf(stderr
,"INSTALLABLE");
310 fprintf(stderr
,"SOUND");
313 fprintf(stderr
,"COMM");
315 case VFT2_DRV_INPUTMETHOD
:
316 fprintf(stderr
,"INPUTMETHOD");
321 fprintf(stderr
,"filetype=FONT.");
322 switch (vffi
->dwFileSubtype
) {
324 fprintf(stderr
,"UNKNOWN(%ld)",vffi
->dwFileSubtype
);
326 case VFT2_FONT_RASTER
:fprintf(stderr
,"RASTER");break;
327 case VFT2_FONT_VECTOR
:fprintf(stderr
,"VECTOR");break;
328 case VFT2_FONT_TRUETYPE
:fprintf(stderr
,"TRUETYPE");break;
331 case VFT_VXD
:fprintf(stderr
,"filetype=VXD");break;
332 case VFT_STATIC_LIB
:fprintf(stderr
,"filetype=STATIC_LIB");break;
334 fprintf(stderr
,"filedata=%lx.%lx\n",vffi
->dwFileDateMS
,vffi
->dwFileDateLS
);
338 /* GetFileVersionInfoSize32A [VERSION.1] */
340 GetFileVersionInfoSize32A(LPCSTR filename
,LPDWORD handle
) {
341 dprintf_resource(stderr
,"GetFileVersionInfoSize32A(%s,%p)\n",filename
,handle
);
342 return GetFileVersionInfoSize16(filename
,handle
);
345 /* GetFileVersionInfoSize32W [VERSION.2] */
347 GetFileVersionInfoSize32W(LPCWSTR filename
,LPDWORD handle
) {
351 xfn
= strdupW2A(filename
);
352 ret
=GetFileVersionInfoSize16(xfn
,handle
);
357 /* GetFileVersionInfo [VER.7] */
359 GetFileVersionInfo16(LPCSTR filename
,DWORD handle
,DWORD datasize
,LPVOID data
) {
360 dprintf_resource(stderr
,"GetFileVersionInfo16(%s,%ld,%ld,%p)\n->",
361 filename
,handle
,datasize
,data
363 return GetFileResource(
364 filename
,VS_FILE_INFO
,VS_VERSION_INFO
,handle
,datasize
,data
368 /* GetFileVersionInfoA [VERSION.0] */
370 GetFileVersionInfo32A(LPCSTR filename
,DWORD handle
,DWORD datasize
,LPVOID data
) {
371 return GetFileVersionInfo16(filename
,handle
,datasize
,data
);
374 /* GetFileVersionInfoW [VERSION.3] */
376 GetFileVersionInfo32W(LPCWSTR filename
,DWORD handle
,DWORD datasize
,LPVOID data
){
380 fn
= strdupW2A(filename
);
381 ret
= GetFileVersionInfo16(fn
,handle
,datasize
,data
);
386 /* VerFindFile [VER.8] */
389 UINT16 flags
,LPCSTR filename
,LPCSTR windir
,LPCSTR appdir
,
390 LPSTR curdir
,UINT16
*curdirlen
,LPSTR destdir
,UINT16
*destdirlen
392 fprintf(stderr
,"VerFindFile(%x,%s,%s,%s,%p,%d,%p,%d)\n",
393 flags
,filename
,windir
,appdir
,curdir
,*curdirlen
,destdir
,*destdirlen
395 strcpy(curdir
,"Z:\\ROOT\\.WINE\\");/*FIXME*/
396 *curdirlen
=strlen(curdir
);
397 strcpy(destdir
,"Z:\\ROOT\\.WINE\\");/*FIXME*/
398 *destdirlen
=strlen(destdir
);
402 /* VerFindFileA [VERSION.5] */
405 UINT32 flags
,LPCSTR filename
,LPCSTR windir
,LPCSTR appdir
,
406 LPSTR curdir
,UINT32
*curdirlen
,LPSTR destdir
,UINT32
*destdirlen
408 return VerFindFile16(flags
,filename
,windir
,appdir
,curdir
,curdirlen
,destdir
,destdirlen
);
411 /* VerFindFileW [VERSION.6] */
414 UINT32 flags
,LPCWSTR filename
,LPCWSTR windir
,LPCWSTR appdir
,
415 LPWSTR curdir
,UINT32
*curdirlen
,LPWSTR destdir
,UINT32
*destdirlen
417 LPSTR wfn
,wwd
,wad
,wdd
,wcd
;
420 wfn
= strdupW2A(filename
);
421 wwd
= strdupW2A(windir
);
422 wad
= strdupW2A(appdir
);
423 wcd
= (LPSTR
)malloc(*curdirlen
);
424 wdd
= (LPSTR
)malloc(*destdirlen
);
425 ret
=VerFindFile16(flags
,wfn
,wwd
,wad
,wcd
,curdirlen
,wdd
,destdirlen
);
426 STRING32_AnsiToUni(curdir
,wcd
);
427 STRING32_AnsiToUni(destdir
,wdd
);
428 *curdirlen
= strlen(wcd
);
429 *destdirlen
= strlen(wdd
);
433 /* VerInstallFile [VER.9] */
436 UINT16 flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
437 LPCSTR destdir
,LPSTR tmpfile
,UINT16
*tmpfilelen
439 fprintf(stderr
,"VerInstallFile(%x,%s,%s,%s,%s,%p,%d)\n",
440 flags
,srcfilename
,destfilename
,srcdir
,destdir
,tmpfile
,*tmpfilelen
443 /* FIXME: Implementation still missing .... */
448 /* VerFindFileA [VERSION.5] */
451 UINT32 flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
452 LPCSTR destdir
,LPSTR tmpfile
,UINT32
*tmpfilelen
454 return VerInstallFile16(flags
,srcfilename
,destfilename
,srcdir
,destdir
,tmpfile
,tmpfilelen
);
457 /* VerFindFileW [VERSION.6] */
460 UINT32 flags
,LPCWSTR srcfilename
,LPCWSTR destfilename
,LPCWSTR srcdir
,
461 LPCWSTR destdir
,LPWSTR tmpfile
,UINT32
*tmpfilelen
463 LPSTR wsrcf
,wsrcd
,wdestf
,wdestd
,wtmpf
;
466 wsrcf
= strdupW2A(srcfilename
);
467 wsrcd
= strdupW2A(srcdir
);
468 wdestf
= strdupW2A(destfilename
);
469 wdestd
= strdupW2A(destdir
);
470 wtmpf
= strdupW2A(tmpfile
);
471 ret
=VerInstallFile32A(flags
,wsrcf
,wdestf
,wsrcd
,wdestd
,wtmpf
,tmpfilelen
);
480 /* FIXME: This table should, of course, be language dependend */
481 static const struct map_id2str
{
483 const char *langname
;
486 {0x0402,"Bulgarisch"},
487 {0x0403,"Katalanisch"},
488 {0x0404,"Traditionales Chinesisch"},
489 {0x0405,"Tschecisch"},
492 {0x0408,"Griechisch"},
493 {0x0409,"Amerikanisches Englisch"},
494 {0x040A,"Kastilisches Spanisch"},
496 {0x040C,"Französisch"},
497 {0x040D,"Hebräisch"},
498 {0x040E,"Ungarisch"},
499 {0x040F,"Isländisch"},
500 {0x0410,"Italienisch"},
501 {0x0411,"Japanisch"},
502 {0x0412,"Koreanisch"},
503 {0x0413,"Niederländisch"},
504 {0x0414,"Norwegisch-Bokmal"},
506 {0x0416,"Brasilianisches Portugiesisch"},
507 {0x0417,"Rätoromanisch"},
508 {0x0418,"Rumänisch"},
510 {0x041A,"Kroatoserbisch (lateinisch)"},
511 {0x041B,"Slowenisch"},
512 {0x041C,"Albanisch"},
513 {0x041D,"Schwedisch"},
518 {0x0804,"Vereinfachtes Chinesisch"},
519 {0x0807,"Schweizerdeutsch"},
520 {0x0809,"Britisches Englisch"},
521 {0x080A,"Mexikanisches Spanisch"},
522 {0x080C,"Belgisches Französisch"},
523 {0x0810,"Schweizerisches Italienisch"},
524 {0x0813,"Belgisches Niederländisch"},
525 {0x0814,"Norgwegisch-Nynorsk"},
526 {0x0816,"Portugiesisch"},
527 {0x081A,"Serbokratisch (kyrillisch)"},
528 {0x0C1C,"Kanadisches Französisch"},
529 {0x100C,"Schweizerisches Französisch"},
530 {0x0000,"Unbekannt"},
533 /* VerLanguageName [VER.10] */
535 VerLanguageName16(UINT16 langid
,LPSTR langname
,UINT16 langnamelen
) {
539 fprintf(stderr
,"VerLanguageName(%d,%p,%d)\n",langid
,langname
,langnamelen
);
540 /* First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
543 buf
=(char*)malloc(strlen("\\System\\CurrentControlSet\\control\\Nls\\Locale\\")+9);
544 sprintf(buf
,"\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",langid
);
545 if (ERROR_SUCCESS
==RegQueryValue16(HKEY_LOCAL_MACHINE
,buf
,langname
,(LPDWORD
)&langnamelen
)) {
546 langname
[langnamelen
-1]='\0';
549 /* if that fails, use the interal table */
550 for (i
=0;languages
[i
].langid
!=0;i
++)
551 if (langid
==languages
[i
].langid
)
553 strncpy(langname
,languages
[i
].langname
,langnamelen
);
554 langname
[langnamelen
-1]='\0';
555 return strlen(languages
[i
].langname
);
558 /* VerLanguageNameA [VERSION.9] */
560 VerLanguageName32A(UINT32 langid
,LPSTR langname
,UINT32 langnamelen
) {
561 return VerLanguageName16(langid
,langname
,langnamelen
);
564 /* VerLanguageNameW [VERSION.10] */
566 VerLanguageName32W(UINT32 langid
,LPWSTR langname
,UINT32 langnamelen
) {
569 LPWSTR keyname
,result
;
571 /* First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
574 buf
=(char*)malloc(strlen("\\System\\CurrentControlSet\\control\\Nls\\Locale\\")+9);
575 sprintf(buf
,"\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",langid
);
576 keyname
=strdupA2W(buf
);free(buf
);
577 if (ERROR_SUCCESS
==RegQueryValue32W(HKEY_LOCAL_MACHINE
,keyname
,langname
,(LPDWORD
)&langnamelen
)) {
582 /* if that fails, use the interal table */
583 for (i
=0;languages
[i
].langid
!=0;i
++)
584 if (langid
==languages
[i
].langid
)
586 result
=strdupA2W(languages
[i
].langname
);
587 i
=lstrlen32W(result
)*sizeof(WCHAR
);
590 memcpy(langname
,result
,i
);
591 langname
[langnamelen
-1]='\0';
593 return strlen(languages
[i
].langname
); /* same as strlenW(result); */
596 /* FIXME: UNICODE? */
600 /* in memory structure... */
601 char name
[1]; /* padded to dword alignment */
603 char data[datalen]; padded to dword alignemnt
604 BYTE subdirdata[]; until nextoff
609 _find_data(BYTE
*block
,LPCSTR str
) {
614 while (*str
&& *str
=='\\')
616 if (NULL
!=(nextslash
=strchr(str
,'\\')))
617 substrlen
=nextslash
-str
;
619 substrlen
=strlen(str
);
620 if (nextslash
!=NULL
) {
621 while (*nextslash
&& *nextslash
=='\\')
629 db
=(struct db
*)block
;
630 fprintf(stderr
,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s,db->data=%s\n",
631 db
,db
->nextoff
,db
->datalen
,db
->name
,(char*)((char*)db
+4+((strlen(db
->name
)+4)&~3))
636 fprintf(stderr
,"comparing with %s\n",db
->name
);
637 if (!strncmp(db
->name
,str
,substrlen
)) {
640 block
+4+((strlen(db
->name
)+4)&~3)+((db
->datalen
+3)&~3)
646 block
=block
+((db
->nextoff
+3)&~3);
650 /* VerQueryValue [VER.11] */
651 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
653 VerQueryValue16(SEGPTR segblock
,LPCSTR subblock
,SEGPTR
*buffer
,UINT16
*buflen
)
655 BYTE
*block
=PTR_SEG_TO_LIN(segblock
),*b
;
659 fprintf(stderr
,"VerQueryValue16(%p,%s,%p,%d)\n",
660 block
,subblock
,buffer
,*buflen
662 s
=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(subblock
)+1);
663 strcpy(s
,"VS_VERSION_INFO");strcat(s
,subblock
);
664 b
=_find_data(block
,s
);
670 *buflen
= db
->datalen
;
671 /* let b point to data area */
672 b
= b
+4+((strlen(db
->name
)+4)&3);
673 /* now look up what the resp. SEGPTR would be ...
674 * we could use MAKE_SEGPTR , but we don't need to
676 *buffer
= (b
-block
)+segblock
;
677 fprintf(stderr
," -> %s=%s\n",subblock
,b
);
682 VerQueryValue32A(LPVOID vblock
,LPCSTR subblock
,LPVOID
*vbuffer
,UINT32
*buflen
)
684 BYTE
*b
,*block
=(LPBYTE
)vblock
,**buffer
=(LPBYTE
*)vbuffer
;
688 fprintf(stderr
,"VerQueryValue32A(%p,%s,%p,%d)\n",
689 block
,subblock
,buffer
,*buflen
691 s
=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(subblock
)+1);
692 strcpy(s
,"VS_VERSION_INFO");strcat(s
,subblock
);
693 b
=_find_data(block
,s
);
699 *buflen
= db
->datalen
;
700 /* let b point to data area */
701 b
= b
+4+((strlen(db
->name
)+4)&3);
703 fprintf(stderr
," -> %s=%s\n",subblock
,b
);
708 VerQueryValue32W(LPVOID vblock
,LPCWSTR subblock
,LPVOID
*vbuffer
,UINT32
*buflen
)
710 /* FIXME: hmm, we not only need to convert subblock, but also
712 * And what about UNICODE version info?
713 * And the NAMES of the values?
715 BYTE
*b
,**buffer
=(LPBYTE
*)vbuffer
,*block
=(LPBYTE
)vblock
;
719 sb
=strdupW2A(subblock
);
720 s
=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(sb
)+1);
721 strcpy(s
,"VS_VERSION_INFO");strcat(s
,sb
);
722 b
=_find_data(block
,s
);
729 *buflen
= db
->datalen
;
730 /* let b point to data area */
731 b
= b
+4+((strlen(db
->name
)+4)&3);
733 fprintf(stderr
," -> %s=%s\n",sb
,b
);
737 /* 20 GETFILEVERSIONINFORAW */