DirectX and Delphi 5

Abstract: Updating Delphi 3 and 4 Projects to Use Delphi 5. The emphasis is on the DirectX header translations.

Delphi 5 does not accept many of the old DirectX header file
translations that worked with Delphi 4

DirectX in Delphi 5

Copyright ) 1999 by Charlie Calvert

Delphi 5 does not accept many of the old DirectX header file
translations that worked with Delphi 4. In particular, you are likely to get
the error:

Type IDirectDrawSurface needs finalization not allowed in
variant record

This article is designed to explain what that error means,
and what you can do about it. In the process, you will also learn how to use
the new JEDI translations of the DirectX headers. The text should be of
interest to all readers of the DirectX sections of my Unleashed books, and to
others who have a general interest in DirectX program.

Numerous DirectX and several Direct3D retained mode examples
are available from hyperlinks found at the bottom of this article. These are
updates of the examples in Delphi 4 Unleashed.

This error occurs because the Delphi team has made it
illegal to include COM objects in variant records. For instance, the following
record is now illegal:

TDDFake = record

dwSize: DWORD;

dwDDFX: DWORD;

case Integer of

0: (

dwZDestConst:
DWORD;

dwZSrcConstBitDepth:
DWORD;

);

1: (

lpDDSZBufferDest:
IDirectDrawSurface;// This is the bad
line

UNIONFILLER1b: DWORD;

);

2: (

UNIONFILLER2a: DWORD;

UNIONFILLER2b: DWORD;

);

end;

The problem is that an IDirectDrawSurface is a COM object.
Delphi performs special memory management techniques on COM objects. In
particular, it will automatically destroy them when they go out of scope.

It happens that variant records are complex structures to
manage. In particular, the first item in the variant part of this record can be
either a DWORD or an IDirectDrawSurface depending on the whim of an individual
developer. As a result, Delphi cant be sure when it needs to free a COM object
in a variant record and when it should leave it alone. In other words, it cant
know ahead of time whether the developer wants to work with a DWord, or an
IDirectDrawSurface. The only reasonable solution to this problem is to simply
make it illegal to include COM objects in variant records. Indeed, this type of
declaration should always have been illegal, and it was a mistake to have
allowed it to compile in Delphi 4.

One solution to this problem is to simply re-declare
lpDDSZBufferDest as a pointer:

lpDDSZBufferDest: Pointer;

You can now typecast lpDDSZBufferDest as an IDirectDrawSurface
whenever you need to access it. The code will compile, and all works as
planned. However, you might want to explicitly free the memory when you are
through with it, rather than having Delphi free it automatically.

By this time you should understand why the DirectX Pascal
files you might have used with Delphi 4 do not work in Delphi 5. The next step
is to introduce you to a new set of DirectX files that do work with Delphi 5.

Working with the New DirectX Header Translations.

Microsoft creates C++ header files as the primary means for
developers to access the DirectX API. Delphi programmers need Pascal
translations of these header files in order to program in DirectX.

Erik Unger and the JEDI project (www.delphi-jedi.org) provide one of the
most commonly used translations of these header files. Erik is a very talented
and hard working programmer, who keeps up to date with the latest changes in
the SDK. You can get his translations from the following URL:

http://www.delphi-jedi.org/DelphiGraphics/index.htm

In the past, he translated the numerous DirectX files into
one big Delphi file. In recent times he has switched to one of two ways of
organizing the files he translates into Pascal. In the first scheme, he
provides a one to one mapping of the DirectX header files to Pascal files. In
this scheme, DDraw.h gets translated into Pascal as DDraw.pas, D3D.h becomes
D3D.pas, DInput.h becomes DInput.pas, and so on.

In a newer scheme, he is grouping the major sets of DirectX
files as follows:

DirectDraw.pas= DDraw.h +
DVP.h (+ MultiMon.h)

Direct3D.pas= D3D.h +
D3DTypes.h + D3DCaps.h +

D3DVec.inl
+ DXFile.h

Direct3DRM.pas= D3DRM.h +
D3DRMDef.h + D3DRMObj.h +

D3DRMWin.h
+ RMXFGUID.h + RMXFTmpl.h

DirectInput.pas = DInput.h (+ DinputD.h)

DirectPlay.pas= DPlay.h +
DPLobby.h

DirectSound.pas = DSound.h

DirectMusic.pas = DLS1.h + DLS2.h + DMDLS.h + DMError.h +

DMKSCtrl.h
+ DMusicC.h + DMusicF.h +

DMusicI.h + DMusBuff.h

DirectSetup.pas = DSetup.h

Both of these schemes are perfectly reasonable and Erik has
done what he can to create solutions that he believes appeals to the largest
number of users of his files. In particular, he tirelessly queried the
community as to their preferences, and tried to follow the will of the
majority.

In the DirectX programs that I shipped in Delphi 4
Unleashed, most of the DirectX header files were encapsulated in a single
Pascal unit called DirectX.pas. If you try to compile these projects under
Delphi 5, you will get the variant record error mentioned earlier in this
article. If you download Eriks newest headers, you will have to edit my files,
since DirectX.pas no longer exists.

In all the DirectX examples I give, the solution is very
straightforward: simply changes references to the DirectX unit to DDraw or to
DirectDraw. In some cases, you may have to add DSound to your uses clause.

The Direct3D examples I include are a bit more complicated.
For instance, you might create a uses clause that looks like this:

uses

Windows, Graphics, DDraw,

D3DRM, D3DTypes, D3DRMObj,

D3DRMDef, D3DRMWin;

If you are using the second of Eriks new schemes, what you
come up with will probably look like this:

Uses

Windows, Graphics,
DirectDraw,

Direct3D, Direct3DRM.

Obviously there are no hard and fast rules as to which files
you should include. The only way to know for sure is to try to compile your
code, and see if some of the variables you use are not known by the compiler.
If that is the case you can use the Grep utility that ships with Delphi to find
the header file translation that you need to use.

One final note on this issue involves where you choose to
place Eriks header translations. Readers of my books know that I usually place
all my shared units in a single directory called units. In this case, I have
finally broken down and created a new subdirectory just for DirectX files. I
believe this is a wise thing to do, because you may need to delete or update
some or all of these files on a regular basis as both Erik and Microsoft
continue their work. Putting them all in a single dedicated directory is the
simplest way to accomplish this goal. As a result, I now have a Units/DirectX
directory where I keep these files.

Examples

In this section you will find two examples of how to use
Eriks header. The first, shown in Listing 1, is a basic DirectDraw example. The
second, shown in Listing 2, is a simple Direct3D retained mode example.

Example 1:
A few simple DirectX examples using the DDraw JEDI translation. In some cases
you may want to use DirectDraw instead of DDraw.