Ada Binding to Win32 (WinAPI)

Petzold Edition 4 Chapter 20 Samples

Developed by: John Walker, JSW Technology
Distributed by: Aonix

Copyright John Walker & JSW Technology 1999-2000. All Rights Reserved.
The information contained herein is subject to change without notice.

ObjectAda is a trademark of Aonix
Microsoft, Visual C++, Win32 and Windows NT are trademarks of Microsoft, Inc.

Last updated: 8 September 2000

Contents

The Fourth Release of Petzold Edition 4 Samples is available from this web site and is also distributed with Aonix ObjectAda OpenPack Version 7.2. This page completes that release with the samples from Chapter 20 of Programming Windows 95 Edition 4 by Charles Petzold and published by Microsoft Press.

Go back to Ada Binding to Win32 (WinAPI)

Go back to start of JSW Technology Home Page


Rationale

These samples are intended to help Ada programmers who are using Petzold Programming Windows 95 Edition 4 to learn about Win32. The Ada code is kept as close to the C samples as possible. This is intended to assist with cross-referencing between Petzold and the Ada code. When developing real Ada applications it is expected that a stronger Ada flavour will be adopted, particularly for string handling.

Go back to Contents


Microsoft Articles

This document makes reference to some Microsoft articles. You can obtain these articles by e-mail from mshelp@microsoft.com. Enter the Article ID number (Qnnnnnn) in the Subject line of your message.

Go back to Contents


Compatibility

These samples have been built as described using:

Go back to Contents


Installation

The samples can be downloaded using petzold420.zip (25 KB) into objectada\winapi.

The sources can be extracted directly into the samples directories set up by the product installation. For example, assuming that ObjectAda is installed in c:\program files\aonix\objectada then the files can be extracted as follows:

>c:
>cd \"program files"\aonix\objectada\winapi
>..\bin\unzip petzold420.zip
Note that unzip.exe is supplied with ObjectAda in objectada\bin.

That should have installed the following samples directories:

objectada\winapi\samples\petzold\edition4
objectada\winapi\samples\petzold\edition4\ch20
objectada\winapi\samples\petzold\edition4\ch20\caller
objectada\winapi\samples\petzold\edition4\ch20\callpub
objectada\winapi\samples\petzold\edition4\ch20\imalloc
objectada\winapi\samples\petzold\edition4\ch20\pubmem
objectada\winapi\samples\petzold\edition4\ch20\regpubmem
This file (petzold420.htm) is included in:
objectada\winapi\samples\petzold\edition4

Go back to Contents


Resource Files

Resource files (*.res) are included with the Ada sources where required. They should be included in Project Files. The resource files can be rebuilt from their source files using the resource compiler provided with ObjectAda as described in Programming Windows 95 Edition 4.

Go back to Contents


Missing DLLs

The following DLLs should be installed in order to run executables on Windows 95:

OpenGL.dll
Glu32.dll
Note that error messages relating to missing DLLs are displayed when running Windows applications directly but not when invoked using Project Execute in the ObjectAda IDE.

Go back to Contents


Helpers

The WinAPI bindings are generated using the general purpose C++ to Ada Binding Technology. The package Helpers includes extensions to the bindings which have been found useful in the development of the Petzold samples. Helpers is included in the following source files:

petzold\edition4\helpers.ads
petzold\edition4\helpers.adb
Helpers includes the following functions which are bound to Ada runtime functions which return the arguments available to WinMain in C and C++ programs:
hInstance
hPrevInstance
lpCmdLine
nCmdShow
The Character nul provides the null character used at the end of Win32 null terminated strings.

The function To_AddressOfChar returns a pointer, of type VC.AddressOfChar, to the first character of the string parameter. This is the correct type and value for Win32 strings of type char * in C and C++. Typically a null terminated Ada string can be passed to a Win32 function as follows:

Helpers.To_AddressOfChar ("An Ada string" & Helpers.nul)
The remainder of package Helpers includes implementations of some Win32 macros as Ada subprograms.

Go back to Contents


ExtraConstants

The package ExtraConstants includes additional constants to those generated by the C++ to Ada Binding Technology in WinAPIConstants. These constants have been found useful in the development of the Petzold samples. ExtraConstants is included in the source file:

petzold\edition4\extracon.ads
The following constants provide null values for some Win32 types:
Null_HINSTANCE
Null_HWND
Null_HMENU
The specification of these types changed between version 4.2 and 6.0 of Visual C++ causing an incompatibility when using GNAT 3.10p. The constants are provided to ease migration from 4.2 to 6.0 using GNAT.

The remainder of the package ExtraConstants includes some Win32 constants not included in WinAPIConstants.

Go back to Contents


Variable Arguments

The function wsprintfA, used in many of the samples, has variable arguments in C. It is used in Ada by copying the specification from WinAPI and adding the variable arguments required as shown in petzold\edition4\sysmets1\wndpack.adb (for example). The pragma Import has been modified so that it will work with GNAT 3.10p as well as ObjectAda.

Go back to Contents


"Optimisation" on toupper et al

The Link_Name used for some functions is incorrect in versions of WinAPI previous to 3.2 (see Release Note - Optimisation). This affects the function toupper in sample HexCalc. The workaround described in Release Note - Optimisation is used.

In some cases, such as strupr and ltoa also used in HexCalc, the optimisation is valid.

Go back to Contents


Aliased Record Components

The components of records will be aliased in a future release of WinAPI. In the meantime the sample OwnerDrw illustrates a workaround for the current release.

Go back to Contents


Chapter 20

IMalloc

Create a project using ObjectAda File New Project. Set Project name to IMalloc. Choose a directory for the project, for example:

c:\program files\aonix\objectada\winapi\samples\petzold\edition4\ch20\imalloc

Use Project Add Files to add the Ada sources:

petzold\edition4\extracon.ads
petzold\edition4\helpers.ads
petzold\edition4\helpers.adb

petzold\edition4\ch20\imalloc\imalloc.adb
petzold\edition4\ch20\imalloc\dmalloc.ads
petzold\edition4\ch20\imalloc\dmalloc.adb

Use Project Settings Search to add the WinAPI library:

..\winapi\binding\lib

Use Project Settings Build to set the Main unit to imalloclib.

Use Project Settings Link to set the Application type to DLL and set Remove uncalled code.

Select Build Compile All to compile all files.

Use Build imalloclib.dll to generate IMallocLib.dll and IMallocLib.lib.

By default that will build an application with debug options. Use Project Target Win32(Intel)Release to build without debug options.

The package DMalloc implements the class DAlloc and the exported function CreateAllocator from IMALLOC.CPP. Note that only the function CreateAllocator is exported from the DLL.

The interface functions are accessed through the VFT of an object created by CreateAllocator using the interface package IMalloc which forms part of the WinAPI bindings (see the implementation of the client Caller). The specification of the IMalloc interface requires that the calling convention for these functions is stdcall.

The main program, IMallocLib, takes the name of the DLL and must with the package DMalloc, which implements the DLL. The C++ name, IMalloc, cannot be used in Ada because that already refers to an Ada package referenced by the application.

IMallocLib.dll can be tested by copying it to a directory containing caller.exe and invoking caller.exe. If caller.exe is the Ada version then imalloclib.dll can be used directly. If using caller.exe from the Petzold CD then imalloclib.dll should be renamed imalloc.dll since that is what is expected. Petzold describes alternative directories and the search path used to find DLLs.

Go back to Contents

Caller

Create a project using ObjectAda File New Project. Set Project name to Caller. Choose a directory for the project, for example:

c:\program files\aonix\objectada\winapi\samples\petzold\edition4\ch20\caller

Use Project Add Files to add the Ada sources:

petzold\edition4\extracon.ads
petzold\edition4\helpers.ads
petzold\edition4\helpers.adb

petzold\edition4\ch20\caller\caller.adb
petzold\edition4\ch20\caller\dmalloc.ads
petzold\edition4\ch20\caller\wndpack.ads
petzold\edition4\ch20\caller\wndpack.adb
Use Project Add Files to add the resource file:
petzold\edition4\ch20\caller\caller.res
The resource file can be rebuilt from its source files using the resource compiler provided with ObjectAda as described in Programming Windows 95 Edition 4.

Use Project Add Files to add the library imalloclib.lib generated by the project IMalloc (see above), for example:

petzold\edition4\ch20\imalloc\imalloc-Win32(Intel)-Debug\imalloclib.lib

Use Project Settings Search to add the WinAPI library:

..\winapi\binding\lib

Use Project Settings Build to set the Main unit to caller.

Use Project Settings Link to set the Application type to Windows and set Remove uncalled code.

Copy imalloclib.dll from the project IMalloc to the target directory for caller, for example:

from: petzold\edition4\ch20\imalloc\imalloc-Win32(Intel)-Debug
to:   petzold\edition4\ch20\caller\caller-Win32(Intel)-Debug
Petzold describes alternative directories and the search path used to find DLLs.

Select Build Compile All to compile all files.

Use Build Build caller.exe to build the application and Build Execute caller.exe to run it.

By default that will build an application with debug options. Use Project Target Win32(Intel)Release to build without debug options.

Caller includes the package DMalloc, which imports the function CreateAllocator exported by package DMalloc in the project IMalloc. Unfortunately there seems to be no way of sharing the specification of DMalloc between the two projects because one needs to export the function and the other to import it.

Notice that WndPack.adb accesses the interfaces IUnknown, IMalloc and IMarshal using the interface class packages provided in the bindings. WinAPI Version 3.1 or later is required for these packages.

Caller.exe can be tested by copying it to a directory containing IMallocLib.dll and invoking caller.exe. If IMallocLib.dll is the Ada version then it can be used directly. If using IMalloc.dll from the Petzold CD then it should be renamed imalloclib.dll since that is what is expected. Petzold describes alternative directories and the search path used to find DLLs.

Go back to Contents

PubMem

Create a project using ObjectAda File New Project. Set Project name to PubMem. Choose a directory for the project, for example:

c:\program files\aonix\objectada\winapi\samples\petzold\edition4\ch20\pubmem

Use Project Add Files to add the Ada sources:

petzold\edition4\extracon.ads
petzold\edition4\helpers.ads
petzold\edition4\helpers.adb

petzold\edition4\ch20\imalloc\dmalloc.ads
petzold\edition4\ch20\imalloc\dmalloc.adb

petzold\edition4\ch20\pubmem\pubmem.adb
petzold\edition4\ch20\pubmem\pubmeminterface.ads
petzold\edition4\ch20\pubmem\compobj.ads
petzold\edition4\ch20\pubmem\compobj.adb
petzold\edition4\ch20\pubmem\dclassfactory.ads
petzold\edition4\ch20\pubmem\dclassfactory.adb

Use Project Settings Search to add the WinAPI library:

..\winapi\binding\lib

Use Project Settings Build to set the Main unit to pubmem.

Use Project Settings Link to set the Application type to DLL and set Remove uncalled code.

Select Build Compile All to compile all files.

Use Build pubmem.dll to generate pubmem.dll and pubmem.lib.

By default that will build an application with debug options. Use Project Target Win32(Intel)Release to build without debug options.

PubMem uses the same implementation for DMalloc as project IMalloc. That is CreateAllocator and class DAlloc in PUBMEM.CPP.

The package DClassFactory implements the class DClassFactory in CLASSFAC.CPP.

The package CompObj implements the Component Object Registration from COMPOBJ.CPP.

The class ID from PUBMEM.H is declared in package PubMemInterface.

The main program, PubMem, takes the name of the DLL and must with the packages DMalloc, DClassFactory and CompObj.

The DLL exports the following functions:

CompObj.DllGetClassObject
CompObj.DllCanUnloadNow
DMalloc.CreateAllocator

DllGetClassObject and DllCanUnloadNow use the DLL_stdcall calling convention as required by OLE. CreateAllocator uses the DLL calling convention, which is equivalent to DLL_cdecl, as defined by DMalloc. The exported names can be verified using:

dumpbin /exports pubmem.dll
DumpBin is included in objectada\bin.

Go back to Contents

RegPubMem

Create a project using ObjectAda File New Project. Set Project name to RegPubMem. Choose a directory for the project, for example:

c:\program files\aonix\objectada\winapi\samples\petzold\edition4\ch20\regpubmem

Use Project Add Files to add the Ada sources:

petzold\edition4\helpers.ads
petzold\edition4\helpers.adb

petzold\edition4\ch20\regpubmem\regpubmem.adb

Use Project Settings Search to add the WinAPI library:

..\winapi\binding\lib

Use Project Settings Build to set the Main unit to regpubmem.

Use Project Settings Link to set the Application type to console and set Remove uncalled code.

Select Build Compile All to compile all files.

Use Build Build regpubmem.exe to build the application and Build Execute regpubmem.exe to run it.

By default that will build an application with debug options. Use Project Target Win32(Intel)Release to build without debug options.

RegPubMem uses the code in Figure 20-6 of Petzold Programming Windows 95 Edition 4 to register PUBMEM.DLL. RegPubMem.lpValue assumes the location:

c:\program files\aonix\objectada\winapi\samples\petzold\edition4\chap20\pubmem\pubmem-win32(intel)-debug\pubmem.dll
The declaration should be changed, if necessary, to match the actual location.

The key can be checked using the Registry Editor. Note that rerunning RegPubMem with a different value will not change the registry. The existing value should be deleted using the Registry Editor before rerunning RegPubMem.

Go back to Contents

CallPub

Create a project using ObjectAda File New Project. Set Project name to CallPub. Choose a directory for the project, for example:

c:\program files\aonix\objectada\winapi\samples\petzold\edition4\ch20\callpub

Use Project Add Files to add the Ada sources:

petzold\edition4\extracon.ads
petzold\edition4\helpers.ads
petzold\edition4\helpers.adb

petzold\edition4\ch20\pubmem\pubmeminterface.ads

petzold\edition4\ch20\callpub\callpub.adb
petzold\edition4\ch20\callpub\wndpack.ads
petzold\edition4\ch20\callpub\wndpack.adb
Use Project Add Files to add the resource file:
petzold\edition4\ch20\callpub\callpub.res
The resource file can be rebuilt from its source files using the resource compiler provided with ObjectAda as described in Programming Windows 95 Edition 4.

Use Project Settings Search to add the WinAPI library:

..\winapi\binding\lib

Use Project Settings Build to set the Main unit to callpub.

Use Project Settings Link to set the Application type to Windows and set Remove uncalled code.

Select Build Compile All to compile all files.

Use Build Build callpub.exe to build the application and Build Execute callpub.exe to run it. Note that pubmem.dll must be registered before executing callpub.exe. That can be done using RegPubMem as described in RegPubMem.

By default that will build an application with debug options. Use Project Target Win32(Intel)Release to build without debug options.

Go back to Contents