jlongino has asked for the wisdom of the Perl Monks concerning the following question:

I was wondering if anyone knows of a good Perl method/module for detecting what Windows platform/version a Perl program is running under (the program will be Perl2exe compiled). I've done several searches here and on The Perl CD Bookshelf without finding anything consistent for the Win32 platforms.

I started out looking at $^O, but it: "Contains the name of the operating system that the current Perl binary was compiled for." (from Perl in a Nutshell). Besides the value returned in my particular test program under Win98 was "MSWin32" which is not nearly specific enough.

Then I looked through Learning Perl on Win32 Systems at the Win32::Registry modules, but there are too many inconsistencies between OS registry structures.

After much frustration with Win NT 4.0, I typed the DOS VER command from a DOS shell and thought "Hmm ..., this might work". Then I tested VER on Win95/98/2k machines and discovered that I could use them as well. So far I have the following snippet:

my $ver_str = `ver`; # Test strings # my $ver_str = 'Windows 98 [Version 4.10.1998]'; # my $ver_str = 'Microsoft Windows 2000 [Version 5.00.2195]'; # my $ver_str = 'Microsoft Windows 95. [Version 4.00.1111]'; ## guessed on this one ## my $ver_str = 'Windows NT Version 3.51'; # my $ver_str = 'Windows NT Version 4.0'; print "VER: $ver_str\n"; $_ = $ver_str; my $os_ver = "N/A"; $os_ver = 'win95' if m/( 95 | 95. )/; $os_ver = 'win98' if m/ 98 /; $os_ver = 'nt351' if m/ NT / && m/ 3.51/; $os_ver = 'nt40' if m/ NT / && m/ 4.0/; $os_ver = 'win2k' if m/ 2000 /; print "\$os_ver: $os_ver\n\n";
Since I don't have access to an NT 3.51 machine, I guessed at that one. I also need an example for Win ME as well but I can get that later at work.

The problems that I see now are:

So if anyone here at the Monastery has any reasonable ideas or suggestions I love to ++ them for it. Thanks.

P.S., this is related to my node Small Project Definition.

"The reward of a thing well done, is to have to done it." -- Ralph Waldo Emerson

Replies are listed 'Best First'.
Re: Windows Version Detection
by John M. Dlugosz (Monsignor) on Oct 07, 2001 at 05:38 UTC
    And what does the console VER do to obtain its information?

    Call the Win32 function GetVersionEx.

    However, the docs for that advise, "Identifying the current operating system is usually not the best way to determine whether a particular operating system feature is present. This is because the operating system may have had new features added in a redistributable DLL. Rather than using GetVersionEx to determine the operating system platform or version number, test for the presence of the feature itself. For more information, see Operating System Version."

    —John
Re: Windows Version Detection
by demerphq (Chancellor) on Oct 07, 2001 at 06:21 UTC
    Well I think you should look into John M. Dlugosz suggestion. Using an API call to do this has got be better than calling ver through a backtick or system() call. On the subject of windows resources though I would strongly suggest you check out www.sysinternals.com probably the most useful set of windows power tools. (I exclude cygwin on purpose :-)

    But no matter what you do I cant help but saying that some of your regexen worry me a bit. Like for instance you are using dot unescaped. Personally I might try to come up with a regex that pulled apart the various version strings and then looked them up in a hash. Something like

    local $,="\t"; while (<DATA>) { /Windows\s(\w+)\W+Version\s((?:\d+\.?)+)/ && print $1,$2,"\n"; } #Outputs # 98 4.10.1998 # 2000 5.00.2195 # 95 4.00.1111 # NT 3.51 # NT 4.0 __DATA__ Windows 98 [Version 4.10.1998] Microsoft Windows 2000 [Version 5.00.2195] Microsoft Windows 95. [Version 4.00.1111] Windows NT Version 3.51 Windows NT Version 4.0
    Now you have WinType and WinVer as $1 and $2 respectively. Anyway just thought it needed to be said.

    :-)

    Yves
    --
    You are not ready to use symrefs unless you already know why they are bad. -- tadmc (CLPM)

      D'oh! You're absolutely right about the regexn (escaping periods). I've seen it several times from reading critiques of other nodes. Believe it or not I've been using Perl for 4.5 years and have never had to use regexen more than once or twice. Having complete control over your own input is nice and makes coding so much easier.

      Fortunately, there are patient souls around to remind me. I've been playing the piano for 35 years but am still taking lessons. It keeps me honest.

      I'll pursue both yours and John's leads before I make a decision. I might have to stick with the DOS VER backticks angle due to code size though. The majority of users that will be running this code won't have Perl (thus Perl2exe) and I know that each additional module requirement is going to cause a hit in areas of startup time and memory required.

      The goal is not to make a perfect assessment, but to offer the user a reasonable guess as to which platform they are using (like setting a default for an OS picklist). If they don't know what OS they have, they can't possibly have already installed the correct version of the software this program will be referencing.

      Thanks to both you and John for replying.

      "I have not failed. I've just found 10,000 ways that won't work." -- Thomas Alva Edison

Re: Windows Version Detection
by $code or die (Deacon) on Oct 07, 2001 at 22:34 UTC
    use Win32; print "$_\n" for Win32::GetOSVersion();
    Explanation of what is returned by Win32::GetOSVersion is of course in the docs:

    Win32::GetOSVersion() CORE Returns the array (STRING, MAJOR, MINOR, BUILD, ID), where the elements are, respectively: An arbitrary descriptive string, the major version number of the operating system, the minor version number, the build number, and a digit indicating the actual operating system. For ID, the values are 0 for Win32s, 1 for Windows 9X and 2 for Windows NT. In scalar context it returns just the ID.
    Simon Flack ($code or die)
    $,=reverse'"ro_';s,$,\$,;s,$,lc ref sub{},e;$,
    =~y'_"' ';eval"die";print $_,lc substr$@,0,3;


    update: pasted doc info for Win32::GetOSVersion()
    update2: Fixed miss-spell GetOSVersion() - I was doing it from memory and only later posted in from docs - should have double checked.
      For those that might try to cut/paste $code or dies' example:   print "$_\n" for Win32::GetOsVersion(); should read:   print "$_\n" for Win32::GetOSVersion(); Win32::GetOSVersion() showed up in the initial searches I made via The Perl CD Bookshelf. It was the first thing I tested but I forgot to mention it in the original post. Apologies for that.

      My primary objection to it was that I couldn't easily discern whether a system was using Windows 2000 or not. The software that I'm looking at must distinguish between win2k and nt. I'll confirm this at work Monday, since I don't have access to win2k at home. It also doesn't mention anything about Windows ME, although for my purposes it can be lumped together with win9x.

      Thanks for bringing it up though, as others will want to be aware of it as a alternative approach.

      "Make everything as simple as possible, but not simpler." -- Albert Einstein

        Untested, but you should get the jist:
        my @winver = Win32::GetOSVersion(); print "Windows 2000" if $winver[1] == 5 and $winver[4] == 2;
        To find out it it's Windows Me or Windows 98 or Windows 95, you'd need somthing like this:
        # I'm guessing at the major Windows versions for 9x here, but it shoul +d be easy to test: print "Windows 95" if $winver[1] == 1 and $winver[4] == 1; print "Windows 98" if $winver[1] == 2 and $winver[4] == 1; print "Windows Me" if $winver[1] == 3 and $winver[4] == 1;
        Alternatively, you could build a lookup:
        my $version_lookup = [ [], # Win32s (not sure what goes here) [ undef, "Windows95", "Windows98", "WindowsMe" ], [ undef, undef, undef, "NT 3", "NT 4", "Windows 2000"] ]; my @winver = Win32::GetOSVersion(); printf "Operating System is %s", $version_lookup->[$winver[4]]->[$winv +er[1]];
        My point is here, that there are loads of ways of doing this, but this way is much better than using the output of "ver" You get all the imformation that "ver" gives but in a way that makes it easy to use without a regex. Plus it's easily extendible - XP is out this month, I'd be willing to bet that you could detect XP like this: (or something very similar)

        print "I'm XP!!" if $winver[1] == 6 and $winver[4] == 2;
        Do you know what the output of ver will be for Windows XP?

        Simon Flack ($code or die)
        $,=reverse'"ro_';s,$,\$,;s,$,lc ref sub{},e;$,
        =~y'_"' ';eval"die";print $_,lc substr$@,0,3;