How to get operating system version information (part 4 of 6)
Getting Information About NT 4 from the Registry
It has been noted above that the extended operation system information provided by the Windows API is not available in versions of NT 4 prior to Service Pack 6. In this section we will look at how to overcome this problem by reading the required information from the registry.
There are two pieces of relevant information we can get from the registry:
- The NT product type.
- Whether NT 4 Service Pack 6 or 6a is installed.
Let us first look at how to get the product type. Windows stores information about the edition of the NT4 OS in the registry under this key:
The key's ProductName value stores a code that indicates the product type. Values and their interpretation are shown in Table 6.
Service Pack 6a
We detect whether NT Service Pack 6a is installed by checking that Win32CSDVersion contains the string 'Service Pack 6' and then checking for the existence of the registry key:
If the key exists we have Service Pack 6a.
OS Version Information Class: Version 3
Having seen what information we can find from the registry, and how to get it, we can update our operating system information class to work correctly with earlier versions of Windows NT 4.
First we will define a couple of new private static methods to get the required information from the registry and will then update various public methods.
Registry Access Methods
We will create two new private methods that access the registry: GetNT4ProductType to read the product type and IsNT4SP6a to check for NT 4 Service Pack 6a.
GetNT4ProductType will read the product type from the registry and return the equivalent TOSProductType code. Before doing this we will need to define a new TOSProductType value – ptNTAdvancedServer to represent NT 4 Advanced Server. Listing 21 shows the revised declaration of TOSProductType.
type TOSProductType = ( ptNA, // not applicable: not a Windows NT platform ptUnknown, // unknown NT product type ptNTWorkstation, // NT workstation ptNTServer, // NT server ptNTDomainController, // NT domain controller ptNTAdvancedServer // NT advanced server );
Having extended TOSProductType we can now implement GetNT4ProductType as per Listing 22.
class function TOSInfo.GetNT4ProductType: TOSProductType; var Reg: TRegistry; ProductType: string; begin Result := ptUnknown; Reg := TRegistry.Create; try Reg.RootKey := HKEY_LOCAL_MACHINE; if Reg.OpenKeyReadOnly( 'SYSTEM\CurrentControlSet\Control\ProductOptions' ) then begin ProductType := Reg.ReadString('ProductType'); if SameText(ProductType, 'WINNT') then Result := ptNTWorkstation else if SameText(ProductType, 'LANMANNT') then Result := ptNTServer else if SameText(ProductType, 'SERVERNT') then Result := ptNTAdvancedServer; Reg.CloseKey; end; finally Reg.Free; end; end;
We first set a default result of ptUnknown in case we can't read an expected value from the registry. Then we create a TRegistry object via which we access the registry. Next we open the key described in the previous section and read the ProductType value. Finally the product type code is mapped onto an equivalent TOSProductType value. Remember that Table 6 lists the possible values of the ProductType registry entry.
Now we can look at the definition of IsNT4SP6a. See Listing 23.
class function TOSInfo.IsNT4SP6a: Boolean; var Reg: TRegistry; begin if (Product = osWinNT4) and SameText(Win32CSDVersion, 'Service Pack 6') then begin // System is reporting NT4 SP6 // we have SP 6a if particular registry key exists Reg := TRegistry.Create; try Reg.RootKey := HKEY_LOCAL_MACHINE; Result := Reg.KeyExists( 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Hotfix\Q246009' ); finally Reg.Free; end; end else // System not reporting NT4 SP6, so not SP6a! Result := False; end;
First we check whether we have Windows NT 4 and that Service Pack 6 is being reported by Delphi's Win32CSDVersion global variable. Then we create a TRegistry object and use it to check for the presence of the registry key that indicates Service Pack 6a is present. We return true if the key is present and false otherwise.
Now we have the registry access methods we need it's time to move on to modify some of TOSInfo's public methods to make use of the registry information.
Updated Public Methods
We need to update four public methods to take account of the new information we have about NT 4. They are:
- ProductType – to get the NT 4 product types from the registry.
- IsServer – to take account of the new ptNTAdvancedServer product type.
- Edition – to describe the NT 4 editions that we learn about from the registry.
- ServicePack – to include detection of NT 4 service pack 6a.
We begin with ProductType. Listing 24 shows the revised method in full.
class function TOSInfo.ProductType: TOSProductType; begin if IsWinNT then begin if Win32HaveExInfo then begin case Win32ProductType of VER_NT_WORKSTATION: Result := ptNTWorkstation; VER_NT_SERVER: Result := ptNTServer; VER_NT_DOMAIN_CONTROLLER: Result := ptNTDomainController; else Result := ptUnknown; end; end else Result := GetNT4ProductType; end else Result := ptNA; end;
We now check if Win32HaveExInfo is true and proceed as before if so. When extended version information is not present we know we must look in the registry for the product type, which we do by calling the new GetNT4ProductType private method.
Next up is IsServer. As Listing 25 shows, all we need to do is add ptNTAdvancedServer to the list of server product types that are tested.
class function TOSInfo.IsServer: Boolean; begin Result := ProductType in [ptNTServer, ptNTDomainController, ptNTAdvancedServer]; end;
The changes we must make to the Edition method are show in Listing 26. For the sake of brevity the listing shows only the required changes and the surrounding context.
class function TOSInfo.Edition: string; begin Result := ''; if IsWinNT then begin if Win32HaveExInfo then begin ... end else begin // No extended info: use regsitry case GetNT4ProductType of ptNTWorkstation: Result := 'WorkStation'; ptNTServer: Result := 'Server'; ptNTAdvancedServer: Result := 'Advanced Server' end; if Result <> '' then Result := Result + Format( ' %d.%d', [Win32MajorVersion, Win32MinorVersion] ); end; end; end;
Taking our lead from Listing 24, we add an else clause that executes when Win32HaveExInfo returns false on an NT platform OS. The code in the else clause gets the product type from the registry by calling GetNT4ProductType and then returns a description of the returned product type. We then append the major and minor versions of the OS to the description.
The last method to be modified is ServicePack. Listing 27 shows the changes. Only the code relating to the NT platform is changed, so the existing Windows 9x code is omitted from the listing.
class function TOSInfo.ServicePack: string; begin Result := ''; if IsWin9x then begin ... end else if IsWinNT then begin if IsNT4SP6a then Result := 'Service Pack 6a' else Result := Win32CSDVersion; end; end;
All that needs to be done after testing for the Windows NT platform is to call IsNT4SP6a to check for NT 4's service pack 6a. If SP6a is found, we return 'Service Pack 6a', otherwise the value of the Win32CSDVersion variable is returned as before.
We have now completed our review of NT 4 version information that can be read from the registry. In the next section we will find out more about different versions of Windows XP.
This article is copyright © Peter Johnson 2005-2006
Licensed under a Creative Commons License.