Upgrade Win32 from CPAN (from 0.39 to 0.40)
authorJan Dubois <jand@activestate.com>
Wed, 8 Dec 2010 22:07:18 +0000 (14:07 -0800)
committerJan Dubois <jand@activestate.com>
Wed, 8 Dec 2010 23:36:22 +0000 (15:36 -0800)
Yes, still has CR/LF line endings; I'll fix it in a CPAN
release with no changes but the line-endings fix first.

Porting/Maintainers.pl
cpan/Win32/Changes [changed mode: 0644->0755]
cpan/Win32/Win32.pm
cpan/Win32/Win32.xs
cpan/Win32/t/CreateFile.t [changed mode: 0644->0755]
cpan/Win32/t/GetOSName.t

index 4a96b5c..08f7e2b 100755 (executable)
@@ -1556,7 +1556,7 @@ use File::Glob qw(:case);
     'Win32' =>
        {
        'MAINTAINER'    => 'jand',
-       'DISTRIBUTION'  => "JDB/Win32-0.39.tar.gz",
+       'DISTRIBUTION'  => "JDB/Win32-0.40.tar.gz",
        'FILES'         => q[cpan/Win32],
        'UPSTREAM'      => 'cpan',
        },
old mode 100644 (file)
new mode 100755 (executable)
index b707793..7dd8986
@@ -1,5 +1,18 @@
 Revision history for the Perl extension Win32.\r
 \r
+0.40   [2010-12-08]\r
+       - Add Win32::GetSystemMetrics function.\r
+       - Add Win32::GetProductInfo() function.\r
+       - Add Win32::GetOSDisplayName() function.\r
+       - Detect "Windows Server 2008 R2" as "Win2008" in Win32::GetOSName()\r
+         (used to return "Win7" before).\r
+       - Detect "Windows Home Server" as "WinHomeSvr" in Win32::GetOSName()\r
+         (used to return "Win2003" before).\r
+       - Added "R2", "Media Center", "Tablet PC", "Starter Edition" etc.\r
+         tags to the description returned by Win32::GetOSName() in\r
+         list context.\r
+       - Rewrote the t/GetOSName.t tests\r
+\r
 0.39   [2009-01-19]\r
        - Add support for Windows 2008 Server and Windows 7 in\r
          Win32::GetOSName() and in the documentation for\r
index bc231ba..cef6271 100644 (file)
@@ -1,6 +1,6 @@
 package Win32;\r
 \r
-BEGIN {\r
+BEGIN {\r
     use strict;\r
     use vars qw|$VERSION $XS_VERSION @ISA @EXPORT @EXPORT_OK|;\r
 \r
@@ -8,7 +8,7 @@ BEGIN {
     require DynaLoader;\r
 \r
     @ISA = qw|Exporter DynaLoader|;\r
-    $VERSION = '0.39';\r
+    $VERSION = '0.40';\r
     $XS_VERSION = $VERSION;\r
     $VERSION = eval $VERSION;\r
 \r
@@ -79,7 +79,7 @@ BEGIN {
         CSIDL_RESOURCES_LOCALIZED\r
         CSIDL_CDBURN_AREA\r
     );\r
-}\r
+}\r
 \r
 # We won't bother with the constant stuff, too much of a hassle.  Just hard\r
 # code it here.\r
@@ -154,6 +154,106 @@ sub CSIDL_RESOURCES            ()       { 0x0038 }     # %windir%\Resources\, Fo
 sub CSIDL_RESOURCES_LOCALIZED  ()       { 0x0039 }     # %windir%\Resources\<LangID>, for theme and other windows specific resources.\r
 sub CSIDL_CDBURN_AREA          ()       { 0x003B }     # <user name>\Local Settings\Application Data\Microsoft\CD Burning\r
 \r
+sub VER_NT_DOMAIN_CONTROLLER () { 0x0000002 } # The system is a domain controller and the operating system is Windows Server 2008, Windows Server 2003, or Windows 2000 Server.\r
+sub VER_NT_SERVER () { 0x0000003 } # The operating system is Windows Server 2008, Windows Server 2003, or Windows 2000 Server.\r
+# Note that a server that is also a domain controller is reported as VER_NT_DOMAIN_CONTROLLER, not VER_NT_SERVER.\r
+sub VER_NT_WORKSTATION () { 0x0000001 } # The operating system is Windows Vista, Windows XP Professional, Windows XP Home Edition, or Windows 2000 Professional.\r
+\r
+\r
+sub VER_SUITE_BACKOFFICE               () { 0x00000004 } # Microsoft BackOffice components are installed.\r
+sub VER_SUITE_BLADE                    () { 0x00000400 } # Windows Server 2003, Web Edition is installed.\r
+sub VER_SUITE_COMPUTE_SERVER           () { 0x00004000 } # Windows Server 2003, Compute Cluster Edition is installed.\r
+sub VER_SUITE_DATACENTER               () { 0x00000080 } # Windows Server 2008 Datacenter, Windows Server 2003, Datacenter Edition, or Windows 2000 Datacenter Server is installed.\r
+sub VER_SUITE_ENTERPRISE               () { 0x00000002 } # Windows Server 2008 Enterprise, Windows Server 2003, Enterprise Edition, or Windows 2000 Advanced Server is installed. Refer to the Remarks section for more information about this bit flag.\r
+sub VER_SUITE_EMBEDDEDNT               () { 0x00000040 } # Windows XP Embedded is installed.\r
+sub VER_SUITE_PERSONAL                 () { 0x00000200 } # Windows Vista Home Premium, Windows Vista Home Basic, or Windows XP Home Edition is installed.\r
+sub VER_SUITE_SINGLEUSERTS             () { 0x00000100 } # Remote Desktop is supported, but only one interactive session is supported. This value is set unless the system is running in application server mode.\r
+sub VER_SUITE_SMALLBUSINESS            () { 0x00000001 } # Microsoft Small Business Server was once installed on the system, but may have been upgraded to another version of Windows. Refer to the Remarks section for more information about this bit flag.\r
+sub VER_SUITE_SMALLBUSINESS_RESTRICTED () { 0x00000020 } # Microsoft Small Business Server is installed with the restrictive client license in force. Refer to the Remarks section for more information about this bit flag.\r
+sub VER_SUITE_STORAGE_SERVER           () { 0x00002000 } # Windows Storage Server 2003 R2 or Windows Storage Server 2003 is installed.\r
+sub VER_SUITE_TERMINAL                 () { 0x00000010 } # Terminal Services is installed. This value is always set.\r
+# If VER_SUITE_TERMINAL is set but VER_SUITE_SINGLEUSERTS is not set, the system is running in application server mode.\r
+sub VER_SUITE_WH_SERVER                () { 0x00008000 } # Windows Home Server is installed.\r
+\r
+\r
+sub SM_TABLETPC                ()       { 86 }\r
+sub SM_MEDIACENTER             ()       { 87 }\r
+sub SM_STARTER                 ()       { 88 }\r
+sub SM_SERVERR2                ()       { 89 }\r
+\r
+sub PRODUCT_UNDEFINED                        () { 0x000 } # An unknown product\r
+sub PRODUCT_ULTIMATE                         () { 0x001 } # Ultimate\r
+sub PRODUCT_HOME_BASIC                       () { 0x002 } # Home Basic\r
+sub PRODUCT_HOME_PREMIUM                     () { 0x003 } # Home Premium\r
+sub PRODUCT_ENTERPRISE                       () { 0x004 } # Enterprise\r
+sub PRODUCT_HOME_BASIC_N                     () { 0x005 } # Home Basic N\r
+sub PRODUCT_BUSINESS                         () { 0x006 } # Business\r
+sub PRODUCT_STANDARD_SERVER                  () { 0x007 } # Server Standard (full installation)\r
+sub PRODUCT_DATACENTER_SERVER                () { 0x008 } # Server Datacenter (full installation)\r
+sub PRODUCT_SMALLBUSINESS_SERVER             () { 0x009 } # Windows Small Business Server\r
+sub PRODUCT_ENTERPRISE_SERVER                () { 0x00A } # Server Enterprise (full installation)\r
+sub PRODUCT_STARTER                          () { 0x00B } # Starter\r
+sub PRODUCT_DATACENTER_SERVER_CORE           () { 0x00C } # Server Datacenter (core installation)\r
+sub PRODUCT_STANDARD_SERVER_CORE             () { 0x00D } # Server Standard (core installation)\r
+sub PRODUCT_ENTERPRISE_SERVER_CORE           () { 0x00E } # Server Enterprise (core installation)\r
+sub PRODUCT_ENTERPRISE_SERVER_IA64           () { 0x00F } # Server Enterprise for Itanium-based Systems\r
+sub PRODUCT_BUSINESS_N                       () { 0x010 } # Business N\r
+sub PRODUCT_WEB_SERVER                       () { 0x011 } # Web Server (full installation)\r
+sub PRODUCT_CLUSTER_SERVER                   () { 0x012 } # HPC Edition\r
+sub PRODUCT_HOME_SERVER                      () { 0x013 } # Home Server Edition\r
+sub PRODUCT_STORAGE_EXPRESS_SERVER           () { 0x014 } # Storage Server Express\r
+sub PRODUCT_STORAGE_STANDARD_SERVER          () { 0x015 } # Storage Server Standard\r
+sub PRODUCT_STORAGE_WORKGROUP_SERVER         () { 0x016 } # Storage Server Workgroup\r
+sub PRODUCT_STORAGE_ENTERPRISE_SERVER        () { 0x017 } # Storage Server Enterprise\r
+sub PRODUCT_SERVER_FOR_SMALLBUSINESS         () { 0x018 } # Windows Server 2008 for Windows Essential Server Solutions\r
+sub PRODUCT_SMALLBUSINESS_SERVER_PREMIUM     () { 0x019 } # Windows Small Business Server Premium\r
+sub PRODUCT_HOME_PREMIUM_N                   () { 0x01A } # Home Premium N\r
+sub PRODUCT_ENTERPRISE_N                     () { 0x01B } # Enterprise N\r
+sub PRODUCT_ULTIMATE_N                       () { 0x01C } # Ultimate N\r
+sub PRODUCT_WEB_SERVER_CORE                  () { 0x01D } # Web Server (core installation)\r
+sub PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT () { 0x01E } # Windows Essential Business Server Management Server\r
+sub PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY   () { 0x01F } # Windows Essential Business Server Security Server\r
+sub PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING  () { 0x020 } # Windows Essential Business Server Messaging Server\r
+sub PRODUCT_SERVER_FOUNDATION                () { 0x021 } # Server Foundation\r
+\r
+sub PRODUCT_SERVER_FOR_SMALLBUSINESS_V       () { 0x023 } # Windows Server 2008 without Hyper-V for Windows Essential Server Solutions\r
+sub PRODUCT_STANDARD_SERVER_V                () { 0x024 } # Server Standard without Hyper-V (full installation)\r
+sub PRODUCT_DATACENTER_SERVER_V              () { 0x025 } # Server Datacenter without Hyper-V (full installation)\r
+sub PRODUCT_ENTERPRISE_SERVER_V              () { 0x026 } # Server Enterprise without Hyper-V (full installation)\r
+sub PRODUCT_DATACENTER_SERVER_CORE_V         () { 0x027 } # Server Datacenter without Hyper-V (core installation)\r
+sub PRODUCT_STANDARD_SERVER_CORE_V           () { 0x028 } # Server Standard without Hyper-V (core installation)\r
+sub PRODUCT_ENTERPRISE_SERVER_CORE_V         () { 0x029 } # Server Enterprise without Hyper-V (core installation)\r
+sub PRODUCT_HYPERV                           () { 0x02A } # Microsoft Hyper-V Server\r
+\r
+sub PRODUCT_STARTER_N                        () { 0x02F } # Starter N\r
+sub PRODUCT_PROFESSIONAL                     () { 0x030 } # Professional\r
+sub PRODUCT_PROFESSIONAL_N                   () { 0x031 } # Professional N\r
+\r
+sub PRODUCT_STARTER_E                        () { 0x042 } # Starter E\r
+sub PRODUCT_HOME_BASIC_E                     () { 0x043 } # Home Basic E\r
+sub PRODUCT_HOME_PREMIUM_E                   () { 0x044 } # Home Premium E\r
+sub PRODUCT_PROFESSIONAL_E                   () { 0x045 } # Professional E\r
+sub PRODUCT_ENTERPRISE_E                     () { 0x046 } # Enterprise E\r
+sub PRODUCT_ULTIMATE_E                       () { 0x047 } # Ultimate E\r
+\r
+sub PRODUCT_UNLICENSED                       () { 0xABCDABCD } # product has not been activated and is no longer in the grace period\r
+\r
+sub PROCESSOR_ARCHITECTURE_AMD64   ()   { 9 }      # x64 (AMD or Intel)\r
+sub PROCESSOR_ARCHITECTURE_IA64    ()   { 6 }      # Intel Itanium Processor Family (IPF)\r
+sub PROCESSOR_ARCHITECTURE_INTEL   ()   { 0 }      # x86\r
+sub PROCESSOR_ARCHITECTURE_UNKNOWN ()   { 0xffff } # Unknown architecture.\r
+\r
+sub _GetProcessorArchitecture {\r
+    my $arch = {\r
+        386 => PROCESSOR_ARCHITECTURE_INTEL,\r
+        486 => PROCESSOR_ARCHITECTURE_INTEL,\r
+        586 => PROCESSOR_ARCHITECTURE_INTEL,\r
+       2200 => PROCESSOR_ARCHITECTURE_IA64,\r
+       8664 => PROCESSOR_ARCHITECTURE_AMD64,\r
+    }->{Win32::GetChipName()};\r
+    return defined($arch) ? $arch : PROCESSOR_ARCHITECTURE_UNKNOWN;\r
+}\r
+\r
 ### This method is just a simple interface into GetOSVersion().  More\r
 ### specific or demanding situations should use that instead.\r
 \r
@@ -161,22 +261,69 @@ my ($cached_os, $cached_desc);
 \r
 sub GetOSName {\r
     unless (defined $cached_os) {\r
-       my($desc, $major, $minor, $build, $id, undef, undef, undef, $producttype)\r
+       my($desc, $major, $minor, $build, $id, undef, undef, $suitemask, $producttype)\r
            = Win32::GetOSVersion();\r
-       ($cached_os, $cached_desc) = _GetOSName($desc, $major, $minor, $build, $id, $producttype);\r
+       my $arch = _GetProcessorArchitecture();\r
+       my $productinfo = Win32::GetProductInfo(6, 0, 0, 0);\r
+       ($cached_os, $cached_desc) = _GetOSName($desc, $major, $minor, $build, $id,\r
+                                               $suitemask, $producttype, $productinfo, $arch);\r
     }\r
     return wantarray ? ($cached_os, $cached_desc) : $cached_os;\r
 }\r
 \r
+sub GetOSDisplayName {\r
+    # Calling GetOSDisplayName() with arguments is for the test suite only!\r
+    my($name,$desc) = @_ ? @_ : GetOSName();\r
+    $name =~ s/^Win//;\r
+    if ($desc eq "Windows Home Server" || $desc eq "Windows XP Professional x64 Edition") {\r
+       ($name, $desc) = ($desc, "");\r
+    }\r
+    elsif ($desc =~ s/\s*(Windows (.*) Server( \d+)?)$//) {\r
+       ($name, $desc) = ("$1 $name", $desc);\r
+    }\r
+    else {\r
+       for ($name) {\r
+           s/^/Windows / unless /^Win32s$/;\r
+           s/\/.Net//;\r
+           s/NT(\d)/NT $1/;\r
+           if ($desc =~ s/\s*(HPC|Small Business|Web) Server//) {\r
+               my $name = $1;\r
+               $desc =~ s/^\s*//;\r
+               s/(200.)/$name Server $1/;\r
+           }\r
+           s/^Windows (200[38])/Windows Server $1/;\r
+       }\r
+    }\r
+    $name .= " $desc" if length $desc;\r
+    return $name;\r
+}\r
+\r
+sub _GetSystemMetrics {\r
+    my($index,$metrics) = @_;\r
+    return $metrics->{$index} if ref $metrics eq "HASH" && defined $metrics->{$index};\r
+    return 1 if ref $metrics eq "ARRAY" && grep $_ == $index, @$metrics;\r
+    return Win32::GetSystemMetrics($index);\r
+}\r
+\r
 sub _GetOSName {\r
-    my($desc, $major, $minor, $build, $id, $producttype) = @_;\r
+    # The $metrics argument only exists for the benefit of t/GetOSName.t\r
+    my($csd, $major, $minor, $build, $id, $suitemask, $producttype, $productinfo, $arch, $metrics) = @_;\r
 \r
-    my($os,$tag);\r
+    my($os,@tags);\r
+    my $desc = "";\r
     if ($id == 0) {\r
        $os = "Win32s";\r
     }\r
     elsif ($id == 1) {\r
-       $os = { 0 => "95", 10 => "98", 90 => "Me" }->{$minor};\r
+       if ($minor == 0) {\r
+           $os = "95";\r
+       }\r
+       elsif ($minor == 10) {\r
+           $os = "98";\r
+       }\r
+       elsif ($minor == 90) {\r
+           $os = "Me";\r
+       }\r
     }\r
     elsif ($id == 2) {\r
        if ($major == 3) {\r
@@ -186,12 +333,193 @@ sub _GetOSName {
            $os = "NT4";\r
        }\r
        elsif ($major == 5) {\r
-           $os = { 0 => "2000", 1 => "XP/.Net", 2 => "2003" }->{$minor};\r
+           if ($minor == 0) {\r
+               $os = "2000";\r
+               if ($producttype == VER_NT_WORKSTATION) {\r
+                   $desc = "Professional";\r
+               }\r
+               else {\r
+                   if ($suitemask & VER_SUITE_DATACENTER) {\r
+                       $desc = "Datacenter Server";\r
+                   }\r
+                   elsif ($suitemask & VER_SUITE_ENTERPRISE) {\r
+                       $desc = "Advanced Server";\r
+                   }\r
+                   elsif ($suitemask & VER_SUITE_SMALLBUSINESS_RESTRICTED) {\r
+                       $desc = "Small Business Server";\r
+                   }\r
+                   else {\r
+                       $desc = "Server";\r
+                   }\r
+               }\r
+               # XXX ignoring "Windows 2000 Advanced Server Limited Edition" for Itanium\r
+               # XXX and "Windows 2000 Datacenter Server Limited Edition" for Itanium\r
+           }\r
+           elsif ($minor == 1) {\r
+               $os = "XP/.Net";\r
+               if (_GetSystemMetrics(SM_MEDIACENTER, $metrics)) {\r
+                   $desc = "Media Center Edition";\r
+               }\r
+               elsif (_GetSystemMetrics(SM_TABLETPC, $metrics)) {\r
+                   # Tablet PC Edition is based on XP Pro\r
+                   $desc = "Tablet PC Edition";\r
+               }\r
+               elsif (_GetSystemMetrics(SM_STARTER, $metrics)) {\r
+                   $desc = "Starter Edition";\r
+               }\r
+               elsif ($suitemask & VER_SUITE_PERSONAL) {\r
+                   $desc = "Home Edition";\r
+               }\r
+               else {\r
+                   $desc = "Professional";\r
+               }\r
+               # XXX ignoring all Windows XP Embedded and Fundamentals versions\r
+           }\r
+           elsif ($minor == 2) {\r
+               $os = "2003";\r
+\r
+               if (_GetSystemMetrics(SM_SERVERR2, $metrics)) {\r
+                   # XXX R2 was released for all x86 and x64 versions,\r
+                   # XXX but only Enterprise Edition for Itanium.\r
+                   $desc = "R2";\r
+               }\r
+\r
+               if ($suitemask == VER_SUITE_STORAGE_SERVER) {\r
+                   $desc .= " Windows Storage Server";\r
+               }\r
+               elsif ($suitemask == VER_SUITE_WH_SERVER) {\r
+                   $desc .= " Windows Home Server";\r
+               }\r
+               elsif ($producttype == VER_NT_WORKSTATION && $arch == PROCESSOR_ARCHITECTURE_AMD64) {\r
+                   $desc .= " Windows XP Professional x64 Edition";\r
+               }\r
+\r
+               # Test for the server type.\r
+               if ($producttype != VER_NT_WORKSTATION) {\r
+                   if ($arch == PROCESSOR_ARCHITECTURE_IA64) {\r
+                       if ($suitemask & VER_SUITE_DATACENTER) {\r
+                           $desc .= " Datacenter Edition for Itanium-based Systems";\r
+                       }\r
+                       elsif ($suitemask & VER_SUITE_ENTERPRISE) {\r
+                           $desc .= " Enterprise Edition for Itanium-based Systems";\r
+                       }\r
+                   }\r
+                   elsif ($arch == PROCESSOR_ARCHITECTURE_AMD64) {\r
+                       if ($suitemask & VER_SUITE_DATACENTER) {\r
+                           $desc .= " Datacenter x64 Edition";\r
+                       }\r
+                       elsif ($suitemask & VER_SUITE_ENTERPRISE) {\r
+                           $desc .= " Enterprise x64 Edition";\r
+                       }\r
+                       else {\r
+                           $desc .= " Standard x64 Edition";\r
+                       }\r
+                   }\r
+                   else {\r
+                       if ($suitemask & VER_SUITE_COMPUTE_SERVER) {\r
+                           $desc .= " Windows Compute Cluster Server";\r
+                       }\r
+                       elsif ($suitemask & VER_SUITE_DATACENTER) {\r
+                           $desc .= " Datacenter Edition";\r
+                       }\r
+                       elsif ($suitemask & VER_SUITE_ENTERPRISE) {\r
+                           $desc .= " Enterprise Edition";\r
+                       }\r
+                       elsif ($suitemask & VER_SUITE_BLADE) {\r
+                           $desc .= " Web Edition";\r
+                       }\r
+                       elsif ($suitemask & VER_SUITE_SMALLBUSINESS_RESTRICTED) {\r
+                           $desc .= " Small Business Server";\r
+                       }\r
+                       else {\r
+                           if ($desc !~ /Windows (Home|Storage) Server/) {\r
+                               $desc .= " Standard Edition";\r
+                           }\r
+                       }\r
+                   }\r
+               }\r
+           }\r
        }\r
        elsif ($major == 6) {\r
-           $os = { 0 => "Vista", 1 => "7" }->{$minor};\r
-           # 2008 is same as Vista but has "Domaincontroller" or "Server" type\r
-           $os = "2008" if $os eq "Vista" && $producttype != 1;\r
+           if ($minor == 0) {\r
+               if ($producttype == VER_NT_WORKSTATION) {\r
+                   $os = "Vista";\r
+               }\r
+               else {\r
+                   $os = "2008";\r
+               }\r
+           }\r
+           elsif ($minor == 1) {\r
+               if ($producttype == VER_NT_WORKSTATION) {\r
+                   $os = "7";\r
+               }\r
+               else {\r
+                   $os = "2008";\r
+                   $desc = "R2";\r
+               }\r
+           }\r
+\r
+            if ($productinfo == PRODUCT_ULTIMATE) {\r
+               $desc .= " Ultimate";\r
+           }\r
+            elsif ($productinfo == PRODUCT_HOME_PREMIUM) {\r
+               $desc .= " Home Premium";\r
+            }\r
+            elsif ($productinfo == PRODUCT_HOME_BASIC) {\r
+               $desc .= " Home Basic";\r
+            }\r
+            elsif ($productinfo == PRODUCT_ENTERPRISE) {\r
+               $desc .= " Enterprise";\r
+            }\r
+            elsif ($productinfo == PRODUCT_BUSINESS) {\r
+               $desc .= " Business";\r
+            }\r
+            elsif ($productinfo == PRODUCT_STARTER) {\r
+               $desc .= " Starter";\r
+            }\r
+            elsif ($productinfo == PRODUCT_CLUSTER_SERVER) {\r
+               $desc .= " HPC Server";\r
+            }\r
+            elsif ($productinfo == PRODUCT_DATACENTER_SERVER) {\r
+               $desc .= " Datacenter";\r
+            }\r
+            elsif ($productinfo == PRODUCT_DATACENTER_SERVER_CORE) {\r
+               $desc .= " Datacenter Edition (core installation)";\r
+            }\r
+            elsif ($productinfo == PRODUCT_ENTERPRISE_SERVER) {\r
+               $desc .= " Enterprise";\r
+            }\r
+            elsif ($productinfo == PRODUCT_ENTERPRISE_SERVER_CORE) {\r
+               $desc .= " Enterprise Edition (core installation)";\r
+            }\r
+            elsif ($productinfo == PRODUCT_ENTERPRISE_SERVER_IA64) {\r
+               $desc .= " Enterprise Edition for Itanium-based Systems";\r
+            }\r
+            elsif ($productinfo == PRODUCT_SMALLBUSINESS_SERVER) {\r
+               $desc .= " Small Business Server";\r
+            }\r
+            elsif ($productinfo == PRODUCT_SMALLBUSINESS_SERVER_PREMIUM) {\r
+               $desc .= " Small Business Server Premium Edition";\r
+            }\r
+            elsif ($productinfo == PRODUCT_STANDARD_SERVER) {\r
+               $desc .= " Standard";\r
+            }\r
+            elsif ($productinfo == PRODUCT_STANDARD_SERVER_CORE) {\r
+               $desc .= " Standard Edition (core installation)";\r
+            }\r
+            elsif ($productinfo == PRODUCT_WEB_SERVER) {\r
+               $desc .= " Web Server";\r
+            }\r
+            elsif ($productinfo == PRODUCT_PROFESSIONAL) {\r
+               $desc .= " Professional";\r
+            }\r
+\r
+           if ($arch == PROCESSOR_ARCHITECTURE_INTEL) {\r
+               $desc .= " (32-bit)";\r
+           }\r
+           elsif ($arch == PROCESSOR_ARCHITECTURE_AMD64) {\r
+               $desc .= " (64-bit)";\r
+           }\r
        }\r
     }\r
 \r
@@ -200,19 +528,29 @@ sub _GetOSName {
        return;\r
     }\r
 \r
-    # Take a look at the build numbers and try to deduce\r
-    # the exact release name, but we put that in the $desc\r
-    if ($os eq "95") {\r
-       $tag = { 67109814 => "(a)", 67306684 => "(b1)", "67109975" => "(b2)" }->{$build};\r
+    for ($desc) {\r
+       s/\s\s+/ /g;\r
+       s/^\s//;\r
+       s/\s$//;\r
     }\r
-    elsif ($os eq "98" && $build eq "67766446") {\r
-       $tag = "(2nd ed)";\r
+\r
+    # XXX What about "Small Business Server"? NT, 200, 2003, 2008 editions...\r
+\r
+    if ($major >= 5) {\r
+       # XXX XP, Vista, 7 all have starter editions\r
+       #push(@tags, "Starter Edition") if _GetSystemMetrics(SM_STARTER, $metrics);\r
     }\r
-    if ($tag) {\r
-       $desc = length($desc) ? "$tag $desc" : $tag;\r
+\r
+    if (@tags) {\r
+       unshift(@tags, $desc) if length $desc;\r
+       $desc = join(" ", @tags);\r
     }\r
 \r
-     return ("Win$os", $desc);\r
+    if (length $csd) {\r
+       $desc .= " " if length $desc;\r
+       $desc .= $csd;\r
+    }\r
+    return ("Win$os", $desc);\r
 }\r
 \r
 # "no warnings 'redefine';" doesn't work for 5.8.7 and earlier\r
@@ -366,8 +704,8 @@ $ENV{PROCESSOR_ARCHITECTURE}.  This might not work on Win9X.
 \r
 =item Win32::GetChipName()\r
 \r
-Returns the processor type: 386, 486 or 586 for Intel processors,\r
-21064 for the Alpha chip.\r
+Returns the processor type: 386, 486 or 586 for x86 processors,\r
+8664 for the x64 processor and 2200 for the Itanium.\r
 \r
 =item Win32::GetCwd()\r
 \r
@@ -505,6 +843,68 @@ before passing the path to a system call or another program.
 [CORE] Returns a string in the form of "<d>:" where <d> is the first\r
 available drive letter.\r
 \r
+=item Win32::GetOSDisplayName()\r
+\r
+Returns the "marketing" name of the Windows operating system version\r
+being used.  It returns names like these (random samples):\r
+\r
+   Windows 2000 Datacenter Server\r
+   Windows XP Professional\r
+   Windows XP Tablet PC Edition\r
+   Windows Home Server\r
+   Windows Server 2003 Enterprise Edition for Itanium-based Systems\r
+   Windows Vista Ultimate (32-bit)\r
+   Windows Small Business Server 2008 R2 (64-bit)\r
+\r
+This function should only be used to display the actual OS name to the\r
+user; it should not be used to determine the class of operating systems\r
+this system belongs to.  The Win32::GetOSName(), Win32::GetOSVersion,\r
+Win32::GetProductInfo() and Win32::GetSystemMetrics() functions provide\r
+the base information to check for certain capabilities, or for families\r
+of OS releases.\r
+\r
+=item Win32::GetOSName()\r
+\r
+In scalar context returns the name of the Win32 operating system\r
+being used.  In list context returns a two element list of the OS name\r
+and whatever edition information is known about the particular build\r
+(for Win9X boxes) and whatever service packs have been installed.\r
+The latter is roughly equivalent to the first item returned by\r
+GetOSVersion() in list context.\r
+\r
+The description will also include tags for other special editions,\r
+like "R2", "Media Center", "Tablet PC", or "Starter Edition".\r
+\r
+Currently the possible values for the OS name are\r
+\r
+    WinWin32s\r
+    Win95\r
+    Win98\r
+    WinMe\r
+    WinNT3.51\r
+    WinNT4\r
+    Win2000\r
+    WinXP/.Net\r
+    Win2003\r
+    WinHomeSvr\r
+    WinVista\r
+    Win2008\r
+    Win7\r
+\r
+This routine is just a simple interface into GetOSVersion().  More\r
+specific or demanding situations should use that instead.  Another\r
+option would be to use POSIX::uname(), however the latter appears to\r
+report only the OS family name and not the specific OS.  In scalar\r
+context it returns just the ID.\r
+\r
+The name "WinXP/.Net" is used for historical reasons only, to maintain\r
+backwards compatibility of the Win32 module.  Windows .NET Server has\r
+been renamed as Windows 2003 Server before final release and uses a\r
+different major/minor version number than Windows XP.\r
+\r
+Similarly the name "WinWin32s" should have been "Win32s" but has been\r
+kept as-is for backwards compatibility reasons too.\r
+\r
 =item Win32::GetOSVersion()\r
 \r
 [CORE] Returns the list (STRING, MAJOR, MINOR, BUILD, ID), where the\r
@@ -517,26 +917,40 @@ the ID.
 \r
 Currently known values for ID MAJOR and MINOR are as follows:\r
 \r
-    OS                    ID    MAJOR   MINOR\r
-    Win32s                 0      -       -\r
-    Windows 95             1      4       0\r
-    Windows 98             1      4      10\r
-    Windows Me             1      4      90\r
-    Windows NT 3.51        2      3      51\r
-    Windows NT 4           2      4       0\r
-    Windows 2000           2      5       0\r
-    Windows XP             2      5       1\r
-    Windows Server 2003    2      5       2\r
-    Windows Vista          2      6       0\r
-    Windows Server 2008    2      6       0\r
-    Windows 7              2      6       1\r
+    OS                      ID    MAJOR   MINOR\r
+    Win32s                   0      -       -\r
+    Windows 95               1      4       0\r
+    Windows 98               1      4      10\r
+    Windows Me               1      4      90\r
+\r
+    Windows NT 3.51          2      3      51\r
+    Windows NT 4             2      4       0\r
+\r
+    Windows 2000             2      5       0\r
+    Windows XP               2      5       1\r
+    Windows Server 2003      2      5       2\r
+    Windows Server 2003 R2   2      5       2\r
+    Windows Home Server      2      5       2\r
+\r
+    Windows Vista            2      6       0\r
+    Windows Server 2008      2      6       0\r
+    Windows 7                2      6       1\r
+    Windows Server 2008 R2   2      6       1\r
 \r
 On Windows NT 4 SP6 and later this function returns the following\r
 additional values: SPMAJOR, SPMINOR, SUITEMASK, PRODUCTTYPE.\r
 \r
+The version numbers for Windows 2003 and Windows Home Server are\r
+identical; the SUITEMASK field must be used to differentiate between\\r
+them.\r
+\r
 The version numbers for Windows Vista and Windows Server 2008 are\r
-identical; the PRODUCTTYPE field must be used to differentiate\r
-between them.\r
+identical; the PRODUCTTYPE field must be used to differentiate between\r
+them.\r
+\r
+The version numbers for Windows 7 and Windows Server 2008 R2 are\r
+identical; the PRODUCTTYPE field must be used to differentiate between\r
+them.\r
 \r
 SPMAJOR and SPMINOR are are the version numbers of the latest\r
 installed service pack.\r
@@ -557,6 +971,9 @@ the system.  Known bits are:
     VER_SUITE_BLADE                     0x00000400\r
     VER_SUITE_EMBEDDED_RESTRICTED       0x00000800\r
     VER_SUITE_SECURITY_APPLIANCE        0x00001000\r
+    VER_SUITE_STORAGE_SERVER            0x00002000\r
+    VER_SUITE_COMPUTE_SERVER            0x00004000\r
+    VER_SUITE_WH_SERVER                 0x00008000\r
 \r
 The VER_SUITE_xxx names are listed here to crossreference the Microsoft\r
 documentation.  The Win32 module does not provide symbolic names for these\r
@@ -572,44 +989,6 @@ be one of the following integer values:
 Note that a server that is also a domain controller is reported as\r
 PRODUCTTYPE 2 (Domaincontroller) and not PRODUCTTYPE 3 (Server).\r
 \r
-=item Win32::GetOSName()\r
-\r
-In scalar context returns the name of the Win32 operating system\r
-being used.  In list context returns a two element list of the OS name\r
-and whatever edition information is known about the particular build\r
-(for Win9X boxes) and whatever service packs have been installed.\r
-The latter is roughly equivalent to the first item returned by\r
-GetOSVersion() in list context.\r
-\r
-Currently the possible values for the OS name are\r
-\r
-    WinWin32s\r
-    Win95\r
-    Win98\r
-    WinMe\r
-    WinNT3.51\r
-    WinNT4\r
-    Win2000\r
-    WinXP/.Net\r
-    Win2003\r
-    WinVista\r
-    Win2008\r
-    Win7\r
-\r
-This routine is just a simple interface into GetOSVersion().  More\r
-specific or demanding situations should use that instead.  Another\r
-option would be to use POSIX::uname(), however the latter appears to\r
-report only the OS family name and not the specific OS.  In scalar\r
-context it returns just the ID.\r
-\r
-The name "WinXP/.Net" is used for historical reasons only, to maintain\r
-backwards compatibility of the Win32 module.  Windows .NET Server has\r
-been renamed as Windows 2003 Server before final release and uses a\r
-different major/minor version number than Windows XP.\r
-\r
-Similarly the name "WinWin32s" should have been "Win32s" but has been\r
-kept as-is for backwards compatibility reasons too.\r
-\r
 =item Win32::GetShortPathName(PATHNAME)\r
 \r
 [CORE] Returns a representation of PATHNAME that is composed of short\r
@@ -620,6 +999,13 @@ path containing spaces.  Returns C<undef> when the PATHNAME does not
 exist. Compare with Win32::GetFullPathName() and\r
 Win32::GetLongPathName().\r
 \r
+=item Win32::GetSystemMetrics(INDEX)\r
+\r
+Retrieves the specified system metric or system configuration setting.\r
+Please refer to the Microsoft documentation of the GetSystemMetrics()\r
+function for a reference of available INDEX values.  All system\r
+metrics return integer values.\r
+\r
 =item Win32::GetProcAddress(INSTANCE, PROCNAME)\r
 \r
 Returns the address of a function inside a loaded library.  The\r
@@ -627,6 +1013,19 @@ information about what you can do with this address has been lost in
 the mist of time.  Use the Win32::API module instead of this deprecated\r
 function.\r
 \r
+=item Win32::GetProductInfo(OSMAJOR, OSMINOR, SPMAJOR, SPMINOR)\r
+\r
+Retrieves the product type for the operating system on the local\r
+computer, and maps the type to the product types supported by the\r
+specified operating system.  Please refer to the Microsoft\r
+documentation of the GetProductInfo() function for more information\r
+about the parameters and return value.  This function requires Windows\r
+Vista or later.\r
+\r
+See also the Win32::GetOSName() and Win32::GetOSDisplayName()\r
+functions which provide a higher level abstraction of the data\r
+returned by this function.\r
+\r
 =item Win32::GetTickCount()\r
 \r
 [CORE] Returns the number of milliseconds elapsed since the last\r
@@ -645,7 +1044,7 @@ The return value is formatted according to OLE conventions, as groups
 of hex digits with surrounding braces.  For example:\r
 \r
     {09531CF1-D0C7-4860-840C-1C8C8735E2AD}\r
\r
+\r
 =item Win32::InitiateSystemShutdown\r
 \r
 (MACHINE, MESSAGE, TIMEOUT, FORCECLOSE, REBOOT)\r
index 1ccdcc3..2799290 100644 (file)
@@ -38,6 +38,7 @@ typedef BOOL (__stdcall *PFNAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,
 typedef BOOL (__stdcall *PFNEqualSid)(PSID, PSID);\r
 typedef void* (__stdcall *PFNFreeSid)(PSID);\r
 typedef BOOL (__stdcall *PFNIsUserAnAdmin)(void);\r
+typedef BOOL (WINAPI *PFNGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD*);\r
 \r
 #ifndef CSIDL_MYMUSIC\r
 #   define CSIDL_MYMUSIC              0x000D\r
@@ -1651,6 +1652,39 @@ XS(w32_CreateFile)
     XSRETURN(1);\r
 }\r
 \r
+XS(w32_GetSystemMetrics)\r
+{\r
+    dXSARGS;\r
+\r
+    if (items != 1)\r
+       Perl_croak(aTHX_ "usage: Win32::GetSystemMetrics($index)");\r
+\r
+    XSRETURN_IV(GetSystemMetrics(SvIV(ST(0))));\r
+}\r
+\r
+XS(w32_GetProductInfo)\r
+{\r
+    dXSARGS;\r
+    DWORD type;\r
+    HMODULE module;\r
+    PFNGetProductInfo pfnGetProductInfo;\r
+\r
+    if (items != 4)\r
+       Perl_croak(aTHX_ "usage: Win32::GetProductInfo($major,$minor,$spmajor,$spminor)");\r
+\r
+    module = GetModuleHandle("kernel32.dll");\r
+    GETPROC(GetProductInfo);\r
+    if (pfnGetProductInfo &&\r
+        pfnGetProductInfo((DWORD)SvIV(ST(0)), (DWORD)SvIV(ST(1)),\r
+                          (DWORD)SvIV(ST(2)), (DWORD)SvIV(ST(3)), &type))\r
+    {\r
+        XSRETURN_IV(type);\r
+    }\r
+\r
+    /* PRODUCT_UNDEFINED */\r
+    XSRETURN_IV(0);\r
+}\r
+\r
 MODULE = Win32            PACKAGE = Win32\r
 \r
 PROTOTYPES: DISABLE\r
@@ -1712,6 +1746,8 @@ BOOT:
     newXS("Win32::GetCurrentThreadId", w32_GetCurrentThreadId, file);\r
     newXS("Win32::CreateDirectory", w32_CreateDirectory, file);\r
     newXS("Win32::CreateFile", w32_CreateFile, file);\r
+    newXS("Win32::GetSystemMetrics", w32_GetSystemMetrics, file);\r
+    newXS("Win32::GetProductInfo", w32_GetProductInfo, file);\r
 #ifdef __CYGWIN__\r
     newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);\r
 #endif\r
old mode 100644 (file)
new mode 100755 (executable)
index a7ed9d5..8c29d30 100644 (file)
 use strict;\r
-use Test;\r
+use Test::More;\r
 use Win32;\r
 \r
-my @tests = (\r
-    #              $id, $major, $minor, $pt, $build, $tag\r
-    [ "WinWin32s",   0                                  ],\r
-    [ "Win95",       1, 4,  0                           ],\r
-    [ "Win95",       1, 4,  0,  0, 67109814, "(a)"      ],\r
-    [ "Win95",       1, 4,  0,  0, 67306684, "(b1)"     ],\r
-    [ "Win95",       1, 4,  0,  0, 67109975, "(b2)"     ],\r
-    [ "Win98",       1, 4, 10                           ],\r
-    [ "Win98",       1, 4, 10,  0, 67766446, "(2nd ed)" ],\r
-    [ "WinMe",       1, 4, 90                           ],\r
-    [ "WinNT3.51",   2, 3, 51                           ],\r
-    [ "WinNT4",      2, 4,  0                           ],\r
-    [ "Win2000",     2, 5,  0                           ],\r
-    [ "WinXP/.Net",  2, 5,  1                           ],\r
-    [ "Win2003",     2, 5,  2                           ],\r
-    [ "WinVista",    2, 6,  0,  1                       ],\r
-    [ "Win2008",     2, 6,  0,  2                       ],\r
-    [ "Win7",        2, 6,  1                           ],\r
+# The "description" value is extracted from the $pretty field:\r
+#\r
+#     "2000 [Server]" => "Server"\r
+#     "{Home Server}" => "Windows Home Server" (prefixed with "Windows ")\r
+#     "Anything R2"   => "R2 Anything"         (R2 moved to front)\r
+#\r
+# The "display name" value is the same as the $pretty field,\r
+# prefixed by "Windows ", with all "[]{}" characters removed.\r
+\r
+# $pretty, $os $id, $major, $minor, $sm, $pt, $metric, $tag\r
+\r
+my @intel_tests = (\r
+["Win32s",                          "Win32s",  0                     ],\r
+\r
+["95",                              "95",      1, 4, 0               ],\r
+["98",                              "98",      1, 4, 10              ],\r
+["Me",                              "Me",      1, 4, 90              ],\r
+\r
+["NT 3.51",                         "NT3.51",  2, 3, 51              ],\r
+["NT 4",                            "NT4",     2, 4, 0               ],\r
+\r
+["2000 [Professional]",             "2000",    2, 5, 0, 0x0000, 1,  0],\r
+["2000 [Server]",                   "2000",    2, 5, 0, 0x0000, 2,  0],\r
+["[Small Business Server] 2000",    "2000",    2, 5, 0, 0x0020, 2,  0],\r
+["2000 [Advanced Server]",          "2000",    2, 5, 0, 0x0002, 2,  0],\r
+["2000 [Datacenter Server]",        "2000",    2, 5, 0, 0x0080, 2,  0],\r
+\r
+["XP [Home Edition]",               "XP/.Net", 2, 5, 1, 0x0200, 1,  0],\r
+["XP [Professional]",               "XP/.Net", 2, 5, 1, 0x0000, 1,  0],\r
+["XP [Tablet PC Edition]",          "XP/.Net", 2, 5, 1, 0x0000, 1, 86],\r
+["XP [Media Center Edition]",       "XP/.Net", 2, 5, 1, 0x0000, 1, 87],\r
+["XP [Starter Edition]",            "XP/.Net", 2, 5, 1, 0x0000, 1, 88],\r
+\r
+["2003 [Standard Edition]",         "2003",    2, 5, 2, 0x0000, 2,  0],\r
+["[Small Business Server] 2003",    "2003",    2, 5, 2, 0x0020, 2,  0],\r
+["{Storage Server} 2003",           "2003",    2, 5, 2, 0x2000, 2,  0],\r
+["{Home Server}",                   "2003",    2, 5, 2, 0x8000, 2,  0],\r
+\r
+["{Compute Cluster Server} 2003",   "2003",    2, 5, 2, 0x4000, 2,  0],\r
+["2003 [Datacenter Edition]",       "2003",    2, 5, 2, 0x0080, 2,  0],\r
+["2003 [Enterprise Edition]",       "2003",    2, 5, 2, 0x0002, 2,  0],\r
+["2003 [Web Edition]",              "2003",    2, 5, 2, 0x0400, 2,  0],\r
+\r
+["2003 [R2 Standard Edition]",      "2003",    2, 5, 2, 0x0000, 2, 89],\r
+["[Small Business Server] 2003 R2", "2003",    2, 5, 2, 0x0020, 2, 89],\r
+["{Storage Server} 2003 R2",        "2003",    2, 5, 2, 0x2000, 2, 89],\r
+# ??? test for more R2 versions?\r
+);\r
+\r
+my @amd64_tests = (\r
+["{XP Professional x64 Edition}",   "2003",    2, 5, 2, 0x0000, 1,  0],\r
+["2003 [Datacenter x64 Edition]",   "2003",    2, 5, 2, 0x0080, 2,  0],\r
+["2003 [Enterprise x64 Edition]",   "2003",    2, 5, 2, 0x0002, 2,  0],\r
+["2003 [Standard x64 Edition]",     "2003",    2, 5, 2, 0x0000, 2,  0],\r
 );\r
 \r
-plan tests => 2*scalar(@tests) + 1;\r
+my @dual_tests = (\r
+["Vista",                           "Vista",   2, 6, 0               ],\r
+\r
+["Vista [Starter]",                 "Vista",   2, 6, 0, 0x0b         ],\r
+["Vista [Home Basic]",              "Vista",   2, 6, 0, 0x02         ],\r
+["Vista [Home Premium]",            "Vista",   2, 6, 0, 0x03         ],\r
+["Vista [Business]",                "Vista",   2, 6, 0, 0x06         ],\r
+["Vista [Enterprise]",              "Vista",   2, 6, 0, 0x04         ],\r
+["Vista [Ultimate]",                "Vista",   2, 6, 0, 0x01         ],\r
+\r
+#["Vista Business for Embedded Systems", "Vista",   2, 6, 0           ],\r
+#["Vista Ultimate for Embedded Systems", "Vista",   2, 6, 0           ],\r
+\r
+["2008 [Standard]",                 "2008",    2, 6, 0, 0x07, 2      ],\r
+["2008 [Enterprise]",               "2008",    2, 6, 0, 0x04, 2      ],\r
+["[HPC Server] 2008",               "2008",    2, 6, 0, 0x12, 2      ],\r
+["[Web Server] 2008",               "2008",    2, 6, 0, 0x11, 2      ],\r
+#["[Storage Server] 2008",           "2008",    2, 6, 0, ????, 2      ],\r
+["[Small Business Server] 2008",    "2008",    2, 6, 0, 0x09, 2,  0  ],\r
+\r
+#    * Windows Server 2008 Standard (x86 and x86-64)\r
+#    * Windows Server 2008 Enterprise (x86 and x86-64)\r
+#    * Windows HPC Server 2008 (replacing Windows Compute Cluster Server 2003)\r
+#    * Windows Web Server 2008 (x86 and x86-64)\r
+#    * Windows Storage Server 2008 (x86 and x86-64)\r
+#    * Windows Small Business Server 2008 (Codenamed "Cougar") (x86-64) for small businesses\r
+#    * Windows Essential Business Server 2008 (Codenamed "Centro") (x86-64) for medium-sized businesses [25]\r
+#    * Windows Server 2008 for Itanium-based Systems\r
+#    * Windows Server 2008 Foundation\r
+#\r
+# Server Core is available in the Web, Standard, Enterprise and Datacenter editions.\r
+\r
+["7",                               "7",       2, 6, 1               ],\r
+["7 [Starter]",                     "7",       2, 6, 1, 0x0b         ],\r
+["7 [Home Basic]",                  "7",       2, 6, 1, 0x02         ],\r
+["7 [Home Premium]",                "7",       2, 6, 1, 0x03         ],\r
+["7 [Professional]",                "7",       2, 6, 1, 0x30         ],\r
+["7 [Enterprise]",                  "7",       2, 6, 1, 0x04         ],\r
+["7 [Ultimate]",                    "7",       2, 6, 1, 0x01         ],\r
+\r
+\r
+["2008 [R2]",                       "2008",    2, 6, 1, 0x00, 2, 89  ],\r
+["[Small Business Server] 2008 R2", "2008",    2, 6, 1, 0x09, 2, 89  ],\r
+\r
+);\r
+\r
+my @ia64_tests = (\r
+["2003 [Datacenter Edition for Itanium-based Systems]", "2003", 2, 5, 2, 0x0080, 2, 0],\r
+["2003 [Enterprise Edition for Itanium-based Systems]", "2003", 2, 5, 2, 0x0002, 2, 0],\r
+);\r
+\r
+plan tests => 3 * (@intel_tests + @amd64_tests + 2*@dual_tests + @ia64_tests);\r
 \r
 # Test internal implementation function\r
-for my $test (@tests) {\r
-    my($expect, $id, $major, $minor, $pt, $build, $tag) = @$test;\r
-    my($os, $desc) = Win32::_GetOSName("", $major, $minor, $build||0, $id, $pt);\r
-    ok($os, $expect);\r
-    ok($desc, $tag||"");\r
+sub check {\r
+    my($test, $arch) = @_;\r
+    my($pretty, $expect, $id, $major, $minor, $sm, $pt, $metrics, $tag) = @$test;\r
+    $metrics = [$metrics] if defined($metrics) && not ref $metrics;\r
+    $tag ||= "";\r
+\r
+    unless ($tag) {\r
+       ($pretty, $tag) = ("$1$2$3", "$2") if $pretty =~ /^(.*)\[(.*)\](.*)$/;\r
+       ($pretty, $tag) = ("$1$2$3", "Windows $2") if $pretty =~ /^(.*)\{(.*)\}(.*)$/;\r
+       $tag = "R2 $tag" if $tag !~ /R2/ && $pretty =~ /R2$/;\r
+    }\r
+\r
+    # All display names start with "Windows";\r
+    # and 2003/2008 start with "Windows Server"\r
+    unless ($pretty eq "Win32s") {\r
+       my $prefix = "Windows";\r
+       $prefix .= " Server" if $pretty =~ /^200[38]/;\r
+       $pretty = "$prefix $pretty";\r
+    }\r
+\r
+    # @dual_tests: Vista and later all come in both 32-bit and 64-bit versions\r
+    if ($id == 2 && $major >= 6) {\r
+       my $suffix = "";\r
+       $suffix = " (32-bit)" if $arch == Win32::PROCESSOR_ARCHITECTURE_INTEL;\r
+       $suffix = " (64-bit)" if $arch == Win32::PROCESSOR_ARCHITECTURE_AMD64;\r
+       $_ .= $suffix for $pretty, $tag;\r
+       $tag =~ s/^\s*//;\r
+    }\r
+\r
+    # We pass the same value for $suitemask and $productinfo.  The former is\r
+    # used for Windows up to 2003, the latter is used for Vista and later.\r
+    my($os, $desc) = Win32::_GetOSName("", $major||0, $minor||0, 0,\r
+                                      $id, $sm||0, $pt||1, $sm||0, $arch, $metrics);\r
+    my $display = Win32::GetOSDisplayName($os, $desc);\r
+\r
+    note($pretty);\r
+    is($display, $pretty);\r
+    is($os, "Win$expect", "os:   $os");\r
+    is($desc, $tag,       "desc: $desc");\r
 }\r
 \r
-# Does Win32::GetOSName() return the correct value for the current OS?\r
-my(undef, $major, $minor, $build, $id, undef, undef, undef, $pt)\r
-    = Win32::GetOSVersion();\r
-my($os, $desc) = Win32::_GetOSName("", $major, $minor, $build, $id, $pt);\r
-ok(scalar Win32::GetOSName(), $os);\r
+check($_, Win32::PROCESSOR_ARCHITECTURE_INTEL) for @intel_tests, @dual_tests;\r
+check($_, Win32::PROCESSOR_ARCHITECTURE_AMD64) for @amd64_tests, @dual_tests;\r
+check($_, Win32::PROCESSOR_ARCHITECTURE_IA64)  for @ia64_tests;\r
+\r