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]

Reply via email to