Build and test a simple DLL

Continuing with the walkthrough of making a DLL from my previous blog...  
As a reminder, I'm following along with Chapter 19 (Dynamic Link Libraries) from Programming Windows 95 by Charles Petzold. 
 
I have a header file with a macro defined for exporting the function. Now I need to declare my function. The DLL from this book isn’t something I’ll use with installers, but it’s pretty simple and lets me get my feet wet. 
 
EXPORT BOOL CALLBACK EdrCenterText (HDC, PRECT, PSTR);
 
I typed this into my header file. Then took a step back to identify what these pieces parts all mean.
  • First we have the EXPORT macro that was defined earlier.
  • Next is the type of value that the function will return (BOOL).
  • The CALLBACK constant is something that I had trouble with. I did several searches in MSDN help and wasn’t finding any reference to an all caps CALLBACK. I finally got lucky and happened to have my mouse hovered over the word in the VS window. A tool tip popped up that said:

#define CALLBACK __stdcall.

Ooo! So this told me that CALLBACK is actually just a macro for the __stdcall calling convention. This convention has to do with how the function reads parameters off the stack and how it will clean up after itself. The __stdcall calling convention is… well… standard and in fact the Windows API uses it. In addition, I happen to know that we will want to use this convention when creating DLLs to be read by an installer. So.. CALLBACK is fine. 

And I have an important tip for myself -- go ahead and type the code in and use tool tips as an additional 'help' feature rather than trying to figure the code out before I type it in.  

That’s it for the header file. Moving on to the source code.  In Visual Studio I go to Source Files, Add, New Item. Then select the .cpp template and name my new file. We start off by including a few standard files, followed by our own header file.
#include <windows.h>
#include <string.h>
#include "edrlib.h" 

I’ve learned before that the <> symbols tell it to look for the header in a list of standard places, where as surrounding the filename in quotes tells it to look for it in the same directory as the .cpp file. 

Now I’ll type in the definition for the DllMain function. We don’t have any special actions needed to initialize this DLL so DllMain doesn’t do anything except just return TRUE. If I understand correctly, your DLL 'must' have a DllMain function so this should be pretty standard.

BOOL APIENTRY DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
 return TRUE; 
}

Now I’ll enter in the definition for the actual function in this DLL. The function takes some text in a window and centers it. Again, nothying I'd use in an installer so the details of this function aren't important. I'm just copying the code out of the book so I  won't repeat it all here.

After entering in the code I go wild and try to build it. (Silly me!)  I get an error (fatal error LNK1561: entry point must be defined).

It took me a bit of research to figure out what was needed here. Keep in mind that the book I'm using is 'old school' and assumes you are using a command line compiler and editing your code in notepad. So I'm having to figure out how to use Visual Studio to achieve the same result. Eventually I ended up making a project for a non-MFC DLL and comparing the resulting project properties between it and my test project. I realize that my only problem is that my project is defined as an EXE instead of a DLL (due to the fact that I started with an Empty generic project.) So to fix the build problem I go to the project properties, General tab and set the Configuration Type to .dll.

Sweet! Now it builds without error. In the output directory I see my DLL, a .exp and a .lib. Let's just take a moment to celebrate this minimal amount of success, considering that I'm *not* a C++ programmer. Smile

Now the test to find out if the function can actually be called from an external program. Still within my original DLLtest solution, I choose to create a New Project, Other Languges, Visual C++, General, Empty Project. At the bottom of that dialog is a Solution combo box. I select Add to Solution and OK. Now I have a single solution with a project for the DLL and a project for the EXE to test it.  Skimming over the next few steps - I just copy the code from the book to create a .cpp file for an EXE that opens a window and calls the function from the DLL to show text centered in the window. Now what my book tells me to do is:

  1. Include a reference to the header file from the DLL
  2. link the OBJ file from the DLL to the EXE (using a .MAK file) 
Since I'm using Visual Studio to do this, I did a little searching around and used some knowledge that I already happened to have and figured out that I needed to do these steps in my EXE project:
  • Add the directory that contains the DLL’s .h file to the Additional Include Directories on the C/C++ General property page.
  • Add the directory that contains the DLL’s .lib file to the Additional Library Directories on the Linker General property page.
  • Add the DLL’s lib file name to the Additional Dependencies on the Linker Input property page.

Once that's done I can build my DLL, then build my EXE. Then I run the EXE and voila! I get a window with the text centered in it. 

First major accomplishment is achieved!

Published Monday, April 14, 2008 8:04 PM by SusanGorman
Filed under: , ,

Comments

No Comments