精通 Visual Basic .NET(收藏)

精通 Visual Basic .NET

发布日期: 7/12/2004 | 更新日期: 7/12/2004

在进行 Internet 或基于 Windows 的开发方面,您遇到过问题或难题吗?这时,您可以求助于 GUI 博士 (drgui@microsoft.com);他每个月两次在 MSDN 上在线回答您的问题。虽然博士忙碌的工作安排使他无法回复所有的问题,但他会尽可能地在这里回答更多的问题。如果恰好选中了您的问题,那么博士会送您一件 GUI 博士 T 恤衫!

摘要:GUI 博士为 Visual Basic .NET 开发人员讲述了如何确定运行程序的操作系统的准确版本。

如何确定操作系统版本?

嗨,GUI 博士!

我现在刚刚开始着手 Visual Basic .NET 下的开发,不过之前我已经使用了多年 Visual Basic 6.0。我并不是个专业开发人员,但是我很幸运能够得到这个机会在这里浑水摸鱼。

现在,我的一个朋友(他是个专业人士)和我都被一个问题难住了。我们在一个 MUD 服务器上工作,但仍在 Visual Basic 6.0 下开发。但是其中的某些组件(包括我正在负责的一个开发程序)基本上是依赖有关当前机器的返回信息来控制应用程序如何以依赖操作系统的方式运行。

例如,如果用户在 Windows 2000 Professional 或 Windows XP(Home 或 Professional)下运行一个叫做 DevTools? 的程序,则该程序将以客户端模式进行操作。但是如果它运行在任何 2000 或 .NET Server 版本上,则将以服务器模式操作。

基本上系统是自动工作的,但此时却不行,因为我们无法确定操作系统的准确版本。当然,我们可以直接通过编译来确定 Windows 版本号,但是我们缺少一种简单的方式来返回与 OsVersionInfoEx API 调用不同的套件掩码。如果您能提供任何帮助,我们将不胜感激!

谢谢,

Brandon Dobbie

GUI 博士的回复:

毫无疑问,GUI 博士可以为您的问题提供一个解决办法。您已经为 ol' Doc 提供了很多线索,这意味着他不必做多少工作却可以收取您的全额费用。

顺便说一下,虽然有许多好的理由可以知道您的程序到底运行在哪一种操作系统上,但我们的博士是不会这样仅根据操作系统而盲目地改变操作模式的。例如,有人可能在便携式电脑上运行服务器操作系统(据 GUI 博士所知,在 Microsoft 有许多人是这样的),但同时还想作为客户端运行您的 软件。我们的博士可以通过命令行参数来处理这个问题。(当然,可以像您建议的那样默认进行这种处理,但前提是您允许重写命令行参数。)

不过,您还是应该检查一下,以确保您是在服务器操作系统上运行服务器功能。那么,现在我们来谈谈该怎么做吧。

.NET 框架提供了一个名为 OperatingSystem 的类,该类会提供一些(但不是全部,如您所见)有关当前操作系统的信息。我们可以通过这个对象找出当前正在操作的平台以及该平台的版本,还可以用它来完成查找系统版本的工作。我们还可以使用现有的知识库 (KB) 文章来了解有关使用该对象的基本知识:HOW TO: Determine Windows Version by Using Visual Basic .NET

实际上,我们只要做一点代码的剪切和粘贴工作就可以开始了。(再次声明,博士非常愿意少劳多得。)不过,虽然这很有用,但它并不能提供我们需要的全部信息。为了获得您惯用的 OSVERSIONINFOEX 结构的所有信息,我们必须使用 OSVERSIONINFOEX 结构。这也意味着我们需要进行一些 Win32 API 调用。所以,您在 Microsoft Visual Basic 6.0 编程中掌握的所有 API 技巧仍然有用。

在 Visual Basic .NET 和 .NET 框架中,您可以使用相当透明的封送处理和 interop 机制从托管代码中调用 Microsoft Windows API。您需要做的就是使用与 API 声明相关联的结构定义来创建 API 声明,并确保通知 .NET 运行库预计如何处理这些结构。(请注意,正确地创建结构并不是无关紧要的;为了帮助进行调试和测试,您可能要编写 C 或 C++ 程序来显示所需结构中的数据;然后从 .NET 框架中调用该程序。这可以帮助您验证所有数据是否已正确传递。)

首先,我们要声明需要使用的 API 函数:GetVersionEx

有两种方法可以声明您的 API 调用:

1.

使用与 Visual Basic 6.0 中极为类似的声明语句。

2.

使用 DllImport 属性(它适用于任何语言)。

从简洁性来说,我愿意用 Declare 语句风格,因为大家都了解并喜欢这种方法。下面我们来看一下对 GetVersionEx 的声明:

Public Declare Auto Function GetVersionEx Lib "kernel32.dll" _ (<MarshalAs(UnmanagedType.Struct)> ByRef osinfo As OSVERSIONINFOEX) _ As Int32 

大部分内容应该很熟悉,但是我们应注意到有一些新东西。首先是声明中的 Auto 关键字。我们需要告诉运行库,该函数要调用 Unicode 版本还是 ANSI 版本的 API。我们可以显式声明要调用哪一种格式的 API,也可以使用 Auto 关键字让运行库自动选择。如果使用 Auto 关键字,则在 Windows NT、Windows 2000 和 Windows XP 平台上使用 Unicode 版本的 API,在 Windows 98 和 Windows Me 平台上使用 ANSI 版本的 API。

现在我们已经声明了 API,接下来需要定义 OSVERSIONINFOEX 结构:

 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _ Public Structure OSVERSIONINFOEX Public dwOSVersionInfoSize As Int32 Public dwMajorVersion As Int32 Public dwMinorVersion As Int32 Public dwBuildNumber As Int32 Public dwPlatformId As Int32 <VBFixedString(128), MarshalAs(UnmanagedType.ByValTStr, _ SizeConst:=128)> Public szCSDVersion As String Public wServicePackMajor As Int16 Public wServicePackMinor As Int16 Public wSuiteMask As Int16 Public wProductType As Byte Public wReserved As Byte End Structure 

我们还要让运行库知道我们要使用哪种字符集,以及如何使用 StructLayout 属性将该结构排放到内存中。在此例中,我们将告诉编译器按照次序一个接一个地将该结构排放到内存中。这个声明中最有意思的部分是结构中间包含的固定字符串:

<VBFixedString(128), MarshalAs(UnmanagedType.ByValTStr, _ SizeConst:=128)> Public szCSDVersion As String 

VBFixedString 属性会通知运行库:我们将使用 128 个字符长度的固定长度字符串。MarshalAs 属性则通知运行库在运行时处理该字符串的方式。我们还要告诉编译器该字符串的长度为 128 个字符 (SizeConst:=128),并且应根据平台将该字符串当作字符集处理 (ByValTStr)。

处理好这些声明后,我们就可以调用 GetVersionEx 来检索信息,然后查看我们需要的返回值。该结构包含多个成员,这些成员具有许多不同的可能值,因此我们需要参阅 OSVERSIONEX 的联机帮助来查看这些值的含义。

现在我们来看一下该代码的完整示例。要创建用来测试该代码的项目,请执行以下步骤:

1.

启动一个新的 Visual Basic .NET 控制台应用程序。

2.

将下列代码粘贴到默认模块的代码窗口中:

Option Strict On Imports System.Environment Imports System.Runtime.InteropServices Module Module1 ' API declarations Public Declare Auto Function GetVersionEx Lib "kernel32.dll" _ (<MarshalAs(UnmanagedType.Struct)> ByRef osinfo As _ OSVERSIONINFOEX) As Int32 ' Structure definition <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _ Public Structure OSVERSIONINFOEX Public dwOSVersionInfoSize As Int32 Public dwMajorVersion As Int32 Public dwMinorVersion As Int32 Public dwBuildNumber As Int32 Public dwPlatformId As Int32 <VBFixedString(128), MarshalAs( _ UnmanagedType.ByValTStr, SizeConst:=128)> _ Public szCSDVersion As String Public wServicePackMajor As Int16 Public wServicePackMinor As Int16 Public wSuiteMask As Int16 Public wProductType As Byte Public wReserved As Byte End Structure ' Useful constants Public Const VER_NT_WORKSTATION As Int32 = &H1 Public Const VER_NT_DOMAIN_CONTROLLER As Int32 = &H2 Public Const VER_NT_SERVER As Int32 = &H3 Public Const VER_WORKSTATION_NT As Int32 = &H40000000& ' Microsoft Small Business Server Public Const VER_SUITE_SMALLBUSINESS As Int32 = &H1& ' Win2k Adv Server or .Net Enterprise Server Public Const VER_SUITE_ENTERPRISE As Int32 = &H2& ' Terminal Services is installed. Public Const VER_SUITE_TERMINAL As Int32 = &H10& ' Win2k Datacenter Public Const VER_SUITE_DATACENTER As Int32 = &H80& ' Terminal server in remote admin mode Public Const VER_SUITE_SINGLEUSERTS As Int32 = &H100& Public Const VER_SUITE_PERSONAL As Int32 = &H200& ' Microsoft .Net webserver installed Public Const VER_SUITE_BLADE As Int32 = &H400 Sub Main() Console.WriteLine(getVersion()) End Sub Public Function getVersion() As String Dim osInfo As OperatingSystem osInfo = OSVersion With osInfo Select Case .Platform Case .Platform.Win32Windows Select Case (.Version.Minor) Case 0 getVersion = "Windows 95" Case 10 If .Version.Revision.ToString() = _ "2222A" Then getVersion = _ "Windows 98 Second Edition" Else getVersion = "Windows 98" End If Case 90 getVersion = "Windows Me" End Select Case .Platform.Win32NT Select Case (.Version.Major) Case 4 getVersion = "Windows NT 4.0" Case 5 If .Version.Minor = 0 Then getVersion = "Windows 2000" Else getVersion = "Windows XP" End If End Select ' Since this is an NT/2k/XP product, ' Check the product type getVersion += " " getVersion += getProductType(osInfo) Case Else getVersion = "Failed to get version information" End Select End With End Function Public Function getProductType(ByVal osinfo As OperatingSystem) _ As String Dim osverinfo As OSVERSIONINFOEX Dim result As Int32 osverinfo.dwOSVersionInfoSize = Marshal.SizeOf(osverinfo) result = GetVersionEx(osverinfo) If result = 0 Then ' There was a failure in the api call. ' There should be error handling here! Console.WriteLine("Error calling GetVersionEx!") Return "Failed" End If If osinfo.Version.Major = 4 Then ' Windows NT If osverinfo.wProductType = VER_NT_WORKSTATION Then Return "Workstation" ElseIf osverinfo.wProductType = VER_NT_SERVER Then Return "Server" Else Return "Unknown" End If ElseIf osinfo.Version.Major = 5 Then ' Windows 2000 or XP If osverinfo.wProductType = VER_NT_WORKSTATION Then ' This is a workstation verion If (osverinfo.wSuiteMask And VER_SUITE_PERSONAL) = _ VER_SUITE_PERSONAL Then Return "Personal" Else Return "Professional" End If ElseIf osverinfo.wProductType = VER_NT_SERVER Then If osinfo.Version.Minor = 0 Then ' This is Win2k If (osverinfo.wSuiteMask And _ VER_SUITE_DATACENTER) = _ VER_SUITE_DATACENTER Then Return "Datacenter Server" ElseIf (osverinfo.wSuiteMask And _ VER_SUITE_ENTERPRISE) = _ VER_SUITE_ENTERPRISE Then Return "Advanced Server" Else Return "Server" End If Else ' This is XP/.NET If (osverinfo.wSuiteMask And _ VER_SUITE_DATACENTER) = _ VER_SUITE_DATACENTER Then Return "Windows.Net Datacenter Server" ElseIf (osverinfo.wSuiteMask And _ VER_SUITE_ENTERPRISE) = _ VER_SUITE_ENTERPRISE Then Return "Windows.NET Enterprise Server" Else Return "Server" End If End If End If End If ' If we get here, we're lost Return "Failed" End Function End Module 

3.

建立应用程序。

4.

从命令行运行该应用程序。根据当前的操作系统,您会看到反映该操作系统的信息。例如,由于我当前运行的是 Windows XP Professional,因此会看到下列信息:

C://drgui/My Documents/OSVerInfo/bin>OSVerInfo.exe Windows XP Professional 

如果想使用 C# 或其他语言来执行此操作,或者需要进一步信息,请参阅 Interoperating with Unmanaged Code

其他有用的链接:

OSVERIONSINFOEX 结构

声明语句

DllImport 属性

致谢!

GUI 博士在此感谢出色的专家小组,包括 Gray McDonald 及其专门助手 Maura Baughman Sharon Watts。如果 GUI 博士在回答问题时没有大家的帮助,问题的解答就不会这么令人满意。

GUI 博士每周问答

著名的问题解决专家“GUI 博士”很高兴在 Internet 和基于 Windows 的开发方面提供百科全书式的知识,使各地的开发人员从中受益。如果您有无法解决的问题,请将您的疑问发送到 drgui@microsoft.com。虽然博士忙碌的工作安排使他无法回复所有的问题,但他会尽可能地在这里回答更多的问题。如果恰好选中了您的问题,那么博士会送您一件 GUI 博士 T 恤衫!(请注意:问题可能经过整理,以确保语法正确,逻辑清晰。)

GUI 博士提供的知识还不够多?

有关博士提供的其他知识,请阅读 MSDN 库中每月发布的 Dr. GUI .NET 专栏文章。

转到原英文页面

(来源:http://www.microsoft.com/china/msdn/library/langtool/vbnet/SDaskgui06042002.mspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值