如何从 VB 6 应用程序中确定 Windows 版本?

20
我想检测95到Win 7中的任何Windows版本。
我也想显示操作系统是32位还是64位。
就是这样,很简单。 :) 我能用什么代码在VB 6应用程序内部实现这个功能?
7个回答

29
以下代码将返回一个字符串值,指示当前Windows的版本。基本上,它所做的就是使用GetVersionEx API函数从Windows获取系统版本号,然后将其与已知的Windows版本匹配。

(请注意,有些东西无法完全检测出来。例如,Windows XP的64位版本可能会被报告为Server 2003。例如,用于确定用户是否运行Windows Vista或Server 2008的代码也没有编写。但您可以根据需要对其进行微调。)

更新: 有关正确检测Windows 8.1和Windows 10的代码,请参见此答案

下面的代码仍然适用于旧版本的Windows,但它将把任何新于Windows 8的东西报告为Windows 8。

底部显示的“比特率”测试代码(查看操作系统是32位还是64位仍然有效,即使在Windows 10上也是如此。

Option Explicit

Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" _
    (lpVersionInformation As OSVERSIONINFO) As Long

Private Type OSVERSIONINFO
  OSVSize         As Long
  dwVerMajor      As Long
  dwVerMinor      As Long
  dwBuildNumber   As Long
  PlatformID      As Long
  szCSDVersion    As String * 128
End Type

Private Const VER_PLATFORM_WIN32s = 0
Private Const VER_PLATFORM_WIN32_WINDOWS = 1
Private Const VER_PLATFORM_WIN32_NT = 2

' Returns the version of Windows that the user is running
Public Function GetWindowsVersion() As String
    Dim osv As OSVERSIONINFO
    osv.OSVSize = Len(osv)

    If GetVersionEx(osv) = 1 Then
        Select Case osv.PlatformID
            Case VER_PLATFORM_WIN32s
                GetWindowsVersion = "Win32s on Windows 3.1"
            Case VER_PLATFORM_WIN32_NT
                GetWindowsVersion = "Windows NT"
                
                Select Case osv.dwVerMajor
                    Case 3
                        GetWindowsVersion = "Windows NT 3.5"
                    Case 4
                        GetWindowsVersion = "Windows NT 4.0"
                    Case 5
                        Select Case osv.dwVerMinor
                            Case 0
                                GetWindowsVersion = "Windows 2000"
                            Case 1
                                GetWindowsVersion = "Windows XP"
                            Case 2
                                GetWindowsVersion = "Windows Server 2003"
                        End Select
                    Case 6
                        Select Case osv.dwVerMinor
                            Case 0
                                GetWindowsVersion = "Windows Vista/Server 2008"
                            Case 1
                                GetWindowsVersion = "Windows 7/Server 2008 R2"
                            Case 2
                                GetWindowsVersion = "Windows 8/Server 2012"
                            Case 3
                                GetWindowsVersion = "Windows 8.1/Server 2012 R2"
                        End Select
                End Select
        
            Case VER_PLATFORM_WIN32_WINDOWS:
                Select Case osv.dwVerMinor
                    Case 0
                        GetWindowsVersion = "Windows 95"
                    Case 90
                        GetWindowsVersion = "Windows Me"
                    Case Else
                        GetWindowsVersion = "Windows 98"
                End Select
        End Select
    Else
        GetWindowsVersion = "Unable to identify your version of Windows."
    End If
End Function

此外,如果您不需要针对最早版本的Windows进行目标定位,则可以通过传递OSVERSIONINFOEX结构来获得更多信息。我刚刚用C ++编写了该代码,并且文档非常易于理解。
确定VB 6可执行文件的主机操作系统是32位还是64位有些棘手。原因是VB 6无法编译64位应用程序。在VB 6中编写的所有内容都将作为32位应用程序运行。而32位应用程序在Windows-on-Windows(WOW64)子系统中运行于64位Windows版本上。它们始终报告当前版本的Windows为32位,因为这就是它们看到的。
我们可以通过最初假设主机操作系统为32位,并尝试证明这个假设错误来解决此问题。以下是一些示例代码:
Private Declare Function GetProcAddress Lib "kernel32" _
    (ByVal hModule As Long, ByVal lpProcName As String) As Long
    
Private Declare Function GetModuleHandle Lib "kernel32" _
    Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
    
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long

Private Declare Function IsWow64Process Lib "kernel32" _
    (ByVal hProc As Long, ByRef bWow64Process As Boolean) As Long

Public Function IsHost64Bit() As Boolean
    Dim handle As Long
    Dim is64Bit As Boolean

    ' Assume initially that this is not a WOW64 process
    is64Bit = False

    ' Then try to prove that wrong by attempting to load the
    ' IsWow64Process function dynamically
    handle = GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process")

    ' The function exists, so call it
    If handle <> 0 Then
        IsWow64Process GetCurrentProcess(), is64Bit
    End If

    ' Return the value
    IsHost64Bit = is64Bit
End Function

@RemusRigo:你无法修复这个错误,你需要编写完全不同的代码。两种语言都包含“VB”这个名字是它们之间唯一的相似之处。如果你想在Visual Basic 2010中编程,你需要购买一本关于VB.NET或Visual Basic 2008/2010的书籍来学习该语言。询问如何将VB 6代码转换为VB.NET代码就像询问将C++或Java转换为VB.NET一样。这是可能的,但是这需要大量的努力,而且不是一个好主意。对于初学者来说,我也不建议这样做:非常容易出错。 - Cody Gray
1
除了买一本学习VB.NET的书之外,没有其他更好的方法。或者,如果你非常必须编写VB 6代码,那么切换回VB 6 IDE(如果你没有MSDN订阅,你就得在eBay上找到它)。最好的方法是获取一本关于VB.NET编程的书籍。无论SO上的答案有多好,都不足以教你一门语言。我肯定不能通过电子邮件来教你。是的,你已经知道的一些东西会转移过来,但并不是所有的东西都会。这会使学习变得更容易,但并不意味着它是不必要的。但是请随意发布新问题——在这里没有太基础的问题。 - Cody Gray
1
对于Windows 8,dwVerMajor = 6,dwVerMinor = 2。 - Martin
只是想指出一下,因为我的前几次编辑被接受了,但显然我的先前的编辑并没有被接受。在Windows 10中,GetVersionEx已经完全过时,它显示内核版本6.2或者有时是6.3,并显示为Windows 8或Windows 8.1。这意味着使用GetVersionEx永远不会收到6.4或10作为版本号(尽管这对我的第一个编辑来说似乎是可以接受的,即使它是错误的)。从GetVersionEx报告6.2或6.3(Windows 8)现在是可疑的,因为API已经过时,需要使用不同的解决方案。 - Brogan
@brogan 我终于有足够的灵感更新答案了。我将其编写为a new question,以便我可以解释所有复杂的细节,包括现在的工作方式(我在这里评论中开始讨论的内容)。我认为这样可以使答案更清晰,信息更易于查找。我已经交叉链接了两篇文章,以防万一! - Cody Gray
显示剩余8条评论

4

还有操作系统的WMI任务

strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")
For Each objOperatingSystem in colOperatingSystems
    Wscript.Echo objOperatingSystem.Caption & "  " & objOperatingSystem.Version
Next

您可以像Cody Gray上面提供的案例语句一样做类似的事情来解析Version值,或者解析纯文本Caption值,该值具有像Microsoft(R) Windows(R) Server 2003,标准版Microsoft Windows 7 Professional这样的列表。

2
您可以尝试使用 VB6 自带的 Microsoft Sysinfo 控件,并检查 OSPlatform、OSBuild 和 OSVersion 属性,以与适当的操作系统版本号匹配。

1
这个被接受的答案在我的应用程序上有效,直到我在Windows 10上尝试它。即使更新了代码以获取版本号细节(如此列出),它仍然报告错误的Windows版本。原来是因为:

未针对Windows 8.1或Windows 10发表表态的应用程序将返回Windows 8操作系统版本值(6.2)。一旦针对特定操作系统版本表达应用程序的表态,GetVersionEx在未来发布中将始终返回该应用程序表达的版本。若要使您的应用程序适用于Windows 8.1或Windows 10,请参阅为Windows定位您的应用程序

为了获得正确的Windows版本显示,需要添加一个应用程序清单部分。
   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
       <application> 
           <!-- Windows 10 --> 
           <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
           <!-- Windows 8.1 -->
           <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
           <!-- Windows Vista -->
           <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
           <!-- Windows 7 -->
           <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
           <!-- Windows 8 -->
           <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
       </application> 
   </compatibility>

然后,GetVersionInfo API按预期工作。我认为这个清单部分是Windows 7的新功能。

然而,一个非常重要的警告是,您必须实际上在列出与之兼容的每个操作系统版本上测试您的应用程序。这些设置影响某些Windows功能,不仅影响Windows版本信息的报告方式。


很好,欲了解更多信息,请参阅Cody Gray在上方更新的链接。虽然这里的第一个答案适合我的目的,因为我不关心W10版本(尽管正在运行它):P。 - Laurie Stearn

1

这里是我用来确定32位还是64位操作系统的非常简单的方法:

OSBits = IIf(Len(Environ$("PROGRAMFILES(X86)")) > 0, 64, 32)

在64位Windows中,操作系统设置了环境变量“PROGRAMFILES(X86)”,但在32位系统上没有设置。迄今为止它从未让我失望过...

0

适用于Windows 10 VB6 - 在调试模式下无法工作 - 仅在运行时工作

Private Declare Function RtlGetVersion Lib "ntdll" (ByRef lpVersionInformation As RTL_OSVERSIONINFOEX) As Long

Private Type RTL_OSVERSIONINFOEX
        dwOSVersionInfoSize As Long
        dwMajorVersion As Long
        dwMinorVersion As Long
        dwBuildNumber As Long
        dwPlatformId As Long
        szCSDVersion As String * 128
End Type

调用

Dim lpVersionInformation As RTL_OSVERSIONINFOEX
lpVersionInformation.dwOSVersionInfoSize = Len(lpVersionInformation)
RtlGetVersion(lpVersionInformation)

0

啊,找到了!我个人不使用这个类,因为对于我的需求来说它有些过度,但它绝对是我遇到的最全面的操作系统版本示例。这个功劳归功于 Kenneth Ives。

*我猜 StackOverflow 不喜欢巨大的代码块,所以这个类(clsOperSystem.cls)位于KiCrypt Demo中,这是一个出色的哈希和加密算法的编译。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接