Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Bob Swart (aka Dr.Bob) - Medical Officer Delphi in a Nutshell
 Under The Hood #7 - How to Byte a Word
See Also: Delphi Papers and Dr.Bob's Examines Columns

Almost everybody has experienced a situation for which two Bytes had to be converted to a Word, or two Words to a LongInt, etc.
We can use the Lo and Hi built-in functions to get the low-order or high-order Byte of the argument, but we cannot go back easily
or can we?

In fact, there are many techniques we can use to 'merge' 2 Bytes to a single Word. The first way is to use the absolute keyword, to make sure the bytes and word use the same memory space, like this:

  var
    LowByte,
    HighByte: Byte;
    MergedWord: Word absolute LoWByte;
Now, the variable MergedWord contains the combined values of the two bytes LowByte and HighByte. We don't even have to do or call anything!
Another way is to use a variant-record, like this:
  type
    TWord = record
              case Boolean of
                true: (LowByte,
                      HighByte: Byte);
               false: (MergedWord: Word);
            end {TWord};
although this is in fact only a variation of the absolute method mapping MergedWord to the same address space occupied by LowByte and HighByte.

We can of course use the same techniques to convert two Words or four Bytes (or to Bytes and a Word) into a LongInt:

  type
    TLongInt = record
                 case Boolean of
                   True: (LWLoByte,
                          LWHiByte,
                          HWLoByte,
                          HWHiByte: Byte;
                  False: (LoWord: Word;
                          HiWord: Word);
               end {TLongInt};
Now we can simultaneously assign values to the HiWord, or to the HighByte of the LowWord (= LWHiByte). All without executing any code to convert between datatypes!!

As a useful example of this technique, let's take a look at how to obtain the DOS and Windows' version number. For dissecting the info returned by GetVersion you can use this variant record:

  var
    Version: record
               case Boolean of
                False: (
                       Windows: record
                                   major: Byte;
                                   minor: Byte;
                                 end;
                       DOS: record
                              minor: Byte;
                              major: Byte;
                            end;
                       );
                True: (GetVersion: LongInt);
              end {Version};
The GetVersion API returns 3.1 for Windows 3.1, Windows 3.11, Windows for Workgroups 3.11 and Windows NT (if called from a 16-bits Windows application), 3.95 for Windows 95 (when called from a 16-bits Windows applications), and 4.0 for Win32 applications (on Win95 or NT).
Note that the 32-bits version of GetVersion does not return the DOS version, but rather a revision of Windows' OS itself. We won't go into that in detail (check the Win32 API on-line help for more information).

As a bonus for this time, you can find out if you're really running on NT (vs. Win95) with the following 16-bits code:

  const
    WF_WINNT = $4000;

    NT := (GetWinFlags and WF_WINNT) <> 0;
This code doesn't work on Win32, however (GetWinFlags has been removed, and we need to call GetSystemInfo from now on).

The final example program - using the variant record technique - that tells you which version of DOS/Windows you're running is as follows:

  program Hood7;
  uses
    WinProcs, SysUtils, Dialogs;

  var
    Version: record
               case Boolean of
                False: (
                       Windows: record
                                   major: Byte;
                                   minor: Byte;
                                 end;
                       DOS: record
                              minor: Byte;
                              major: Byte;
                            end;
                       );
                True: (GetVersion: LongInt);
              end {Version};

  begin
    Version.GetVersion := GetVersion;
    if Version.Windows.major < 4 then
      ShowMessage(Format('DOS %d.%-d, Windows %d.%-d',
                         [Version.DOS.major,Version.DOS.minor,
                          Version.Windows.major,Version.Windows.minor]))
    else
      ShowMessage(Format('Windows 95/NT %d.%-d',
                         [Version.Windows.major,Version.Windows.minor]))
  end.
When compiled with Delphi 1.02 and run on Windows 95, this program returns "DOS 7.0, Windows 3.95". When compiled with Delphi 2.01 and run on Windows 95, this program returns "Windows 95/NT 4.00", and so it should.


This webpage © 1996-2017 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.