This is an effort to write filever.exe in Perl. Filever extracts file version
information and is available in the later Windows resource kits I think, or maybe as
early as NT4. In verbose mode it prints info like this:
D:\>filever.exe /v c:\windows\system32\kernel32.dll
--a-- W32i DLL ENU 5.1.2600.0 shp 926,720 08-23-2001 kernel32.dll
Language 0x0409 (English (United States))
CharSet 0x04b0 Unicode
OleSelfRegister Disabled
CompanyName Microsoft Corporation
FileDescription Windows NT BASE API Client DLL
InternalName kernel32
OriginalFilenam kernel32
ProductName Microsoft« Windows« Operating System
ProductVersion 5.1.2600.0
FileVersion 5.1.2600.0 (xpclient.010817-1148)
LegalCopyright ⌐ Microsoft Corporation. All rights reserved.
VS_FIXEDFILEINFO:
Signature: feef04bd
Struc Ver: 00010000
FileVer: 00050001:0a280000 (5.1:2600.0)
ProdVer: 00050001:0a280000 (5.1:2600.0)
FlagMask: 0000003f
Flags: 00000000
OS: 00040004 NT Win32
FileType: 00000002 Dll
SubType: 00000000
FileDate: 00000000:00000000
I want to do the same thing with Perl so my script can use the information without
having to rely on an external exe, and I don't want to use AdminMisc (I forget why
right now, maybe pride or something even dummer).
The script below prints:
c:\windows\system32\kernel32.dll
î♥4 VS_VERSION_INFO ╜♦∩■
♣ (
♣ (
? ♦♦☻ Ω☻
StringFileInfo ╞☻
040904B0 L▬
CompanyName Microsoft Corporation f▼
FileDescription Windows NT BASE API Client DLL d"
FileVersion 5.1.2600.0 (xpclient.010817-1148) 2
InternalName kernel32 Ç.
LegalCopyright ⌐ Microsoft Corporation. All rights reserved. :
OriginalFilename kernel32 j%
ProductName Microsoft« Windows« Operating System :♂
ProductVersion 5.1.2600.0 D
VarFileInfo $♦ Translation ♦░♦FE2X
[Screen capture if that doesn't make any sense:
http://www.eskimo.com/~ghawk/images/filever.gif]
Now, most everything in there is relatively easy to clean up. The problem area is the
information between VS_VERSION_INFO and StringFileInfo that if translated to hex will
become the numbers shown by filever.exe in the VS_FIXEDFILEINFO section. So if you
do a match between the two bookends and then unpack("h*", $&), you get a hex string
with all of the data. In an ideal world. It works fine on some files. Drop the
first ten bytes and then from that point some of them need to be reversed but it is
accurate.
Here's the problem: With that particular dll the VS_VERSION_INFO contains
"00050001:0a280000". Somehow, when the pattern match sees 0a (really a0 because it
has to be reversed later, or possibly 000A (a Unicode linefeed, since the \000's are
still in there at that point), it interprets that as '\n', and the screen print does
too, as you can see above. I want it all on one line or least be able to match past
those.
I tried $/ = "", $/ = "xyz", and $* = 1 to no avail.
Is there someone out there, some Unicode guru or anybody who can help clear up what's
wrong here?
My Perl version is v5.6.1 built for MSWin32-x86-multi-thread.
Thanks!
Gary
#!perl.exe
use Win32::API;
#use utf8; # no effect
if (! $ARGV[0]) {
print "\n\tFilename arg needed.\n\n";
exit;
} else {
$filename = $ARGV[0];
}
if ($filename && $filename =~ /\*/) { # for *.* etc wildcards
$filenameprefix = $filename;
$filenameprefix =~ s/(.*)\\.*/$1\\/;
@filenames = `dir /b $filename`; # readdir later maybe
} else {
$filenames[0] = $filename;
}
chomp @filenames;
for (@filenames) {
s/^(.*)/$filenameprefix$1/; # reassemble full path
$pBlock = "";
print "\n\n$_\t\n\n";
$GetFileVersionInfoSize =
new Win32::API(
"version.dll",
"GetFileVersionInfoSizeA",
['P', 'P'],
'N'
);
if ( $GetFileVersionInfoSize->Call(
$_,
$lpHandle
)
) {
$lpBufferSize =
$GetFileVersionInfoSize->Call(
$_,
$lpHandle
);
} else {
print "Apparently 16-bit\n";
next;
}
$GetFileVersionInfo = new Win32::API(
"version.dll",
"GetFileVersionInfoA",
['P', 'N', 'N', 'P'],
'I'
);
$pBlock = "#" x $lpBufferSize;
if ( $GetFileVersionInfo->Call(
$_,
0,
$lpBufferSize,
$pBlock
)
) {
$one_or_zero_ignored =
$GetFileVersionInfo->Call(
$_,
0,
$lpBufferSize,
$pBlock
); # merely to get $pBlock
}
$lplpBuffer = "X" x 32;
$puLen = 16;
$VerQueryValue = new Win32::API(
"version.dll",
"VerQueryValueA",
['P', 'P' , 'P', 'P'],
'N'
);
if (! $VerQueryValue->Call(
$pBlock,
$lpSubBlock,
$lplpBuffer,
$puLen
)
) {
print Win32::FormatMessage(Win32::GetLastError);
}
#print "$pBlock\n"; next; # raw output, or...
$pBlock =~ s/\#*$//; # excess buffer erase
$pBlock =~ s/\001\000/\n/g; # 001 smiley face, \000 space
$pBlock =~ s/\000\000\000/\t/g; # mo pretty
$pBlock =~ s/\000//g; # human-readable
print "$pBlock\n";
}
__END__
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]