Using VB4 as a 16/32 bit thunking layer

Updated May 18, 1997

Introduction

One of the questions I see posted very often on comp.lang.basic.visual.misc is "How do I call this 16-bit DLL/VBX" from 32-bit VB4?". The purpose of this document is explain how to use Visual Basic and OLE as a thunking layer to allow 16-bit components to be used from 32-bitVB4.

Background Info

As we all know Windows started off in the 16-bit world (actually in the 8-bit world, but Windows wasn't popular back then). In the 16-bit model introduced in Windows 3.0, a common memory space was available to all applications and hardware was unprotected. Put simply, this meant that you could just about any low-level operation you can think of, but at the same time, programs could step on top of each other or write some value to a sensitive hardware register, therefore bringing down the entire system. The typical end result was a lot of UAFs, which became GPFs or General Protection Faults in Windows 3.1.

With the introduction of Windows NT, a new model was chosen based on 32-bit instructions and memory addressing schemes available only on 386 and higher processors (remember that when Windows 3.0 was introduced, the predominant processor was the 286). Because of the more advanced memory management unit in the 386, protected memory could be enabled, which protected 32-bit applications from each other and also prevented applications from stepping on the hardware when they weren't supposed to.

In order to get developers to switch over from 16-bit to 32-bit, the big incentive that Microsoft offered was a much easier to program "flat memory" model where if you need 5Mb of RAM, you just allocate it (in 16-bit code, programmers still have to deal with 64K chunks of memory at a time), preemptive scheduling and a host of other features.

However, in making the move to 32-bit code, programmers lost the ability to talk directly to hardware or directly use 16-bit DLLs (which could of course talk directly to the hardware and therefore potentially crash the system). While this can impact people that have a legitimate reason to talk directly to the hardware, generally speaking it's a good thing because true 32-bit operating systems like Windows NT, running 32-bit applications do not crash and if a single app goes haywire, it doesn't bring down the entire system. The Windows NT Server I have at the office has crashed once in the year or more that it's been up and that's because the hard drive failed!

All about hardware I/O

Since one of the reasons that people want to use a 16-bit DLL from VB4/32 is to do low level I/O, lets talk about that for a second. Without a lot of programming work, 32-bit applications cannot talk directly to hardware. For Windows 95, this means writing a VxD to interface to hardware and under Windows NT, a device driver must be written. Both of these require the DDK (Device Driver Kit) and a lot of knowledge of how Windows internally operates.

Because Microsoft wants to maintain backward compatibility with older 16-bit applications on Windows 95, 16-bit code can talk directly to hardware. However, on Windows NT, the same proviso applies - no application can talk directly to hardware without a device driver.

There are a number of commercial products available for 32-bit development that allow low-level I/O by providing either a VxD or device driver, but these aren't cheap. A list of the ones I've seen advertised are:

Back to the OLE thunking layer

OK, so despite all the reasons why you can't use your 16-bit DLL from VB4/32 and the fact that if you're doing hardware I/O and it'll work only on Windows 95, you still want it to happen. How do you go about making a thunking layer using OLE? The first thing you'll need is either the Professional or Enterprise Edition of VB4. The Standard Edition is 32-bit only, so you can't do this with that version.

The next step involves thinking about which calls to the DLL you use from your application. These will become either properties or methods in the 16-bit OLE server, called from the 32-bit application much like any other OLE automation process.

Creating the 16-bit server

In this example, we'll use Jonathan Wood's VBASM.DLL. This DLL allows 16-bit applications to do all kinds of low-level stuff including DOS interrupts, hardware I/O and so on. The OLE server will allow a read and write to any hardware port.

  1. Get VBASM from the COOL.STF web site and put the .DLL into your Windows\System folder.
  2. Fire up 16-bit VB4. Remove Form1 from the project and then use the Insert option to add a module and a class module.
  3. In the class module property page, set the following values:
  4. Next go to the Tools, Options menu and select the Project tab. Set the following values:
  5. Now go the module code Window and add the following code:

  6. Select the IO class module code Window and click on Insert, Procedure. In the Name field type "Port" and then set the type to Property.
  7. Repeat this procedure. This time, in the Name field type "ByteIO" and set the type to "Property".
  8. Now go into the IO class module and change the code to look like:

  9. Save you project and pay attention to the next steps, because they are important:
  10. Now you can exit 16-bit Visual Basic.

Creating the 32-bit client

  1. Fire up the 32-bit version of VB. Create a new project and select the Tools, References option. Scroll down to the end of the list and you should see "Low Level I/O". Select it.
  2. Add a command button to the form, and add the following code:

  3. That's pretty much it. Setting IO.Port selects the port you want to communicate with. Reading IO.ByteIO causes the port to be read and writing to IO.ByteIO, causes the port to be written to. For example:

Final Notes

The reason why the 16-bit project gets built twice (once into bServer.EXE and then into ioserver.EXE) is to prevent the GUID of the OLE server from changing each time. When you compile an OLE automation server, a new GUID (Globally Unique ID) is generated, unless the "Compatible OLE Server" field is filled in. What this means is that every time you re-compile the OLE Server without this field, the GUID will change and you will then need to re-reference the OLE Server in each project that uses it, which is a royal pain because it takes so long to do!

Also note that each time you click on the command button, the 16-bit OLE server gets created, used and then deleted. If you're going to be using the 16-bit OLE server throughout your 32-bit program, Dim the IO object variable at the form level and put the creation of the server at the Form Load time and it's removal (i.e. Set IO = Nothing) in the Form Unload event.

I hope this article explains how to use 16-bit code from 32-bit VB4. It's not exactly fast, but it does work and is a better alternative than not being able to do it at all!

Copyright © 1996 Rod Hewitt