Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9
      Miscellaneous

General: C/C++ DLL's
By: Jack Hoxley (with help from Torsten Damberg and David Goodlad)
Written: June 2000

Download: GM_CppDll.Zip (20kb) GM_DLLDemo (363kb)


I've been programming in VB for several years and am a firm supporter of the language; however, every so often you get a really good idea in your head that needs raw power to be done. Then you hit the boundaries of the VB language - you've gone so far and it wont take you any faster. In my experience this comes when you're doing maths, algorithms and array manipulation (including memory arrays). You just need that extra speed.

Visual Basic is and always will be the easier and more fun language to write; the equivilant game written in C++ is much harder, much less friendly to read and will take longer. VB with the power of directX behind it has become a serious contender for making games; It's just several small things that limit your creativity, and these are the things that C++ developers enjoy the ability of using.

Without a doubt C/C++ and assembler can wipe the floor with VB's array and mathematics functions. There is a way however to keep the bulk of your code in VB and use another (faster) language to the time-critical maths functions. The easiest way is to write a simple C/C++ DLL and link your VB project to it.

This is what this tutorial will be discussing. There are two points you will need to bare in mind first though:

  1. You will need a basic knowledge of C/C++. I'm no expert of the language, but I can just about pull off most of the things I try. This tutorial can't and won't attempt to teach you C/C++, It will demonstrate how to get started - the rest is up to you.
  2. You will need a C++ compiler. All the examples here will be saved in Visual C++ format, I do believe that the code will work in other compilers, but I have no way of checking. For the record, I will be using Visual C++ 6.0 professional. Everything will work fine in this version and the enterprise edition, but I'm not sure how it will in the learning edition.

If you do some simple tests with equivelant VB and C++ code with full optimizations you will find that C++ can sometimes double VB's speed:
C++ DLL; 307,200 calculations: <=1ms
VB DLL; 307,200 calculations: 170ms

C++ DLL; counting 0 to 1000: <1ms
VB DLL; counting 0 to 1000: 28ms

For the record, these tests were done on an AMD 500mhz computer.
As you can see, in the first test the C++ DLL was an amazing 170x faster. In the second test it was 28x faster - still a substantial improvement. These tests cannot be taken as standards as they were done once on my computer - and are likely to be different from computer to computer. Even if these differences aren't entirely accurate, with even a wide margin you can see that C++ out-performs VB quite dramatically.


Now we can get onto some code. The first part is understanding the differences in variables between C/C++ and Visual Basic. You will need to bare this in mind when it comes to writing your DLL.

C/C++ Variable name Visual Basic Variable Name
Short Integer
Long Long
LPLong Long
Float Single
Double Double
unsigned __int8 Byte
BStr String

This will be needed when you write the entry point for your DLL and when you declare you're DLL in VB. For example:

void _stdcall DoSomething(short Val); In C++ becomes:
Private Declare Sub DoSomething Lib "dllname.dll" (ByVal Val as Integer)

Note the ByVal part - this is important. If you didn't have it here, VB would pass "0", or Nothing. As a general rule you'll need byVal for everything, except pointers that need ByRef.

You can then use the table above to create the function that you need. The next part of this tutorial will deal with the C++ side of things; If you don't understand this you're best not going any further.

  1. Launch Visual C++ developer Studio - This should be easy
  2. Create a new "Win32 Dynamic Link Library" project from the new project library
  3. When the AppWizard screen appears, select "Empty Application" - We want to add the files ourself.
  4. Visual C++ will then present you with an empty project. On the project menu, select add file.
  5. In the dialog select "C++ source File" and give it a name
  6. You will now have a blank document to play with.
  7. At the same time create another blank document and save it as "projectName.Def" - replace ProjectName with the real project name. This will be discussed later

Now open up the blank C++ source file and add this code:

#include "Windows.h"
//Any other files that you want can go here...

//We must prototype all the functions that we wish to use.
short _stdcall Multiply(short Num1, short Num2);

//Now we can create the function
short _stdcall Multiply(short Num1, short Num2)
{
//This code here is executed when VB calls this function
return Num1*Num2; //Multiply the numbers and return them
}

Okay; so this DLL would do nothing useful whatsoever - VB can do multiplications on it's own. Although C++ may well do it faster; when we only want it done once we'll probably slow the program down as we have to call the DLL, and wait for it to return information.

There is one last part though: The .Def file. This is important, and can be thought of as a DEFinition file.

LIBRARY dllname
EXPORTS
Multiply

This is very simple and very small; but it will get bigger as you add more procedures. You will have to change the part after LIBRARY to suit your project's name, but that;s it. After EXPORTS you need to name all of the procedures in your project that you want other applications to use, currently for us that only includes "Multiply".

Compile you're DLL and copy it from the folder to the C:\windows\System folder. Note: you may as well do a straight release version, you're not going to get any Debug data when using it in VB. The Release version can be 4-7x faster as well.

Now open up VB and start a new Standard EXE project. One form will appear, open it up in the code window and add these lines of code.

'This goes in the declarations section.
Private Declare Function Multiply Lib "dllname.dll" (ByVal Num1 as Integer, ByVal Num2 as Integer) as integer

Private Sub Form_Load()
'We need a value to hold it.
dim RetVal as integer
RetVal = Multiply(10,170)
'RetVal now holds the number 1700 = 10*170
'We now convert it to a string for output as a message box.

msgbox CStr(RetVal)
End Sub

Done! You now have a working DLL. It is quite easy to modify this to suit your needs - but you'll need a little bit of C++ knowledge. A word of warning; if you generate an error it may well crash VB - losing everything. Save your project first.

Using Strings
Having a function that returns strings has two main uses as far as I can see:
1. Encryption - You could write a DLL that encrypts a string or decrypts a string. This encryption could be quite complicated, as C++ will be able to run through it very quickly
2. File access; you could pass it a Filename and it could return an entry in the file; or you could use it with the first option and make it decrypt an encrypted level file and give you're program the data it wants.

Open the DLL project that you should just have created - and open the source file.

//Remember to prototype this function

LONG _stdcall GetStringFromDLL ( BSTR S )
{
int i;
LPSTR pS;
pS = (LPSTR) S;
for (i=0; i<26; i++)
{
*pS++='A'+i;
}
return 26;
}

Add an entry in the .Def File to allow VB to access this function. Then open up you're VB project and add this code in:

'You'll have to declare the DLL in the declaration section - You should be able to do this.

'The VB string must be big enough to hold the data that the C++ DLL will put in this. The only way of
'doing this is to fill it with stuff - the C++ DLL will then overwrite whatever rubbish we put in it.

Dim S as String
Dim length as Long
S = Space(200) 'you should be more precise; but we'll give ourselves a 200 character limit
Length = GetStringFromDLL(S)
'Output what the DLL returned...
MsgBox (Left$(S,Length))

Using Arrays
This is the important part, and also where it gets fun. The example project above is fairly useless; it does nothing new, and it wouldn't give us any speed advantages. Array manipulation is where this method will shine. Through arrays you could pass hundreds of thouands of values, even millions. Arrays can also represent picture data - in particular, you could pass a C++ DLL the array of data behind a DirectDraw surface (GetLockedArray) - and allow C++ to modify your surface. This suddenly opens up the door to an amazing amount of possibilities. This example will show you how to invert the colours of A DirectDraw surface (in theory). It also doubles up as a benchmarking program. This First part is the C++ side of things:

#include "windows.h" //Had to change this to stop it
//messing up the HTML!!


//This is our Prototype
//Note the use of pointers

void _stdcall BltNot(unsigned __int8 *myarray, short width, short height);

//This is our actual procedure.
void _stdcall BltNot(unsigned __int8 *myarray, short width, short height)
{
int x=0; //Create us a variable
x= width * height; //This is the total number of entries in the array.
unsigned __int8 Val; //Temporary Value
for(int i = 0; i x; i++) //Run a loop through the data. There should
//be a less-than sign in the prev. line - but it messed up the HTML...
{
Val = *myarray; //Copy our variable
Val = 255 - Val; //Invert our variable
*myarray = Val; //Put our variable back
myarray++; //Increment the address by one.
}

Now; accessing the array probably isn't quite what you expected. So I'll explain. In memory, the 2D array:
0 1 2
0 1 2
0 1 2
is represented like this:
012012012
or, -FirstRow-SecondRow-Thirdrow-
This makes it slightly difficult to access it. You could, if you knew C++, write a loop that did it as a
for(x)
for(y)
loop, but we're not going to do that here - just for simplicity. We'll just change the whole lot in order - which is fine if you don't mind what the X/Y position the entry represents.

You cant actually pass an array in a DLL call. Mostly on the grounds that VB will include lots of junk other languages wont like. Instead we use a pointer, this points to where the array starts - it says "This is where the array starts, keep reading from this point onwards". This means that we rely on the VB programmer to give us the correct size - overwise we may screw up.

When we get into our loop it's fairly simple. On the first run we'll get the value behind the first value - the one that the function is given; then we just keep on going through incrementing the memory address by one each time.

Now onto VB. This is fairly easy. When it comes to declaring the the DLL use this:

private declare sub BltNot lib "Bltnot.Dll" (ByRef myarray as byte, byVal width as integer, ByVal height as integer)

It is important that you pass the "myarray" as ByRef - otherwise it wont work. ByRef simply means By Reference - ie, give the DLL it's address. As far as both parts are concerned we are only passing one variable - that's why at no point is there an array declaration.

When it comes to using the DLL, use this:

BltNot Array(0,0),640,480

We want the myarray variable to be where you start from; most cases this will be the first variable in the array (0,0). You could set it so it started elsewhere, but for now we'll let it start at the beginning. Then we specify the height and width. These are 1-x entries, not 0-x. Basically, start counting as normal (we count from 1), not like computers which count starting from 0. Be careful here - if you specify a number greater than the size of the array you'll crash everything.

You could quite easily modify this to take a 3 dimensional array, or do many other things - it's up to you to experiment; but be careful - one error and you could say goodbye to your computer (until you restart).

Download the example from the top of this page, or get it from the downloads page. Make sure you read the Info.txt file included. Note, the C++ code is not included, but it is all on this page here. NB: there is a demo application to show you how to use the DLL with DirectDraw surfaces.

DirectX 4 VB © 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster