Hi Scott
I have a feeling that you do not quite understand what "regular DLL" is.
It's a single executable file compiled to machine code (not MSIL, ie.
not .NET assembly - just old-fashioned Win32 executable) exporting
C-style functions, which can be called from other DLL-s or programs, but
cannot be started in own process (like .exe executables). It's also
called "dynamic library", as it's just a library of functions which can
be dynamically loaded into memory by other programs and then called.
Prior to this use such DLL file must be loaded into memory by host
process, and when it's no longer needed it might be unloaded. When DLL
file is loaded to or unloaded from memory by host process, function
DllMain contained within this DLL is called to notify
your code to prepare for work or do final cleanup. It's also called when
process hosting your DLL starts new threads or terminates them. There
are some restrictions on what can be called from within DllMain - most
notably you may not create new threads. Thanks to recent additions to
Visual C++ it's also possible to export variables or C++ classes from
DLL, as you will see later on. Do not use these features if you want to
make your DLL usable from other compilers or other programming
languages, though. Please also note that I did not use words "MFC" or
"Managed C++" above - as those are NOT plain dynamic libraries!
Let me first show you how to make "regular DLL". Start Visual Studio
..NET (I'm talking about version 2002, aka 7.0), select menu File > New >
Project... . Select "Visual C++ Project" on the left pane and then
"Win32 Project" on right one (last icon, at least on my computer). Name
your project (your .dll file will use this name - make is short and
without special characters) and click OK. "Win32 Application Wizard -
your_name" appears, but do not close it yet! Click on "Application
Settings" on the left side of the wizard window. Now you can see
"Application type" option - default one is "Windows application". Change
it to "DLL". If you press "Finish" now, you will get what you are
looking for: project for plain Win32 dynamic library, aka "regular
DLL". Before you click OK you have two options, NONE of them is related
to MFC or Managed C++:
* "Empty project" means that wizard will not create any source file
(like .c, .cpp or .h) for your project - you need to manually create
these files in your project. It also means that wizard will not create
precompiled header and will setup your project not to use it (I will
explain later what's "precompiler header"). If you leave this option
unchecked, wizard will setup your project to use precompiled header and
create few source files:
stdafx.cpp - it's used to compile precompiled header (you compile it
whenever you change project settings or content of stdafx.h)
your_name.cpp - here you can put functions you are going to export
from your DLL, but there's nothing special about this file. Currently it
contains only DllMain function. You can read more about this function
in MSDN. If your code do not need to do anything on startup (when loaded
into memory, just before any of its functions is called) or cleanup
(just before being unloaded from memory) you may leave this function as
it is. I advice that you look for more information here:
http://msdn.microsoft.com/library/en-us/dllproc/base/dynamic_link_library_entry_point_function.asp
stdafx.h - here you may include all headers you are going to put in
precompiled header. By default there's only <windows.h>. I usually
include there number of standard C++ headers, like:
#include <string>
#include <vector>
#include <algorithm>
#include <memory>
#include <sstream>
(because I use standard C++ library in my code quite often), but you
may leave it as it is, or put any other common includes (ie. ones you
are going to include from all .cpp files in your project). Make sure all
your .cpp files start with:
#include "stdafx.h"
This will indirectly include to your .cpp files all files included in
stdafx.h. There is performance gain however - all these headers has been
processed once, when you compiled stdafx.cpp. As a result all .cpp files
which included "stdafx.h" header will compile faster, thus saving your
(developer) time. This is the sole purpose of precompiled header - as
you can see, it has nothing to do with MFC. Of course MFC projects do
use stdafx.h for own purposes, as you can - without all burden of MFC.
Just remember that whatever you put into stdafx.h will be included by
all .cpp files (technically it's called "translation units", not ".cpp
files") and anytime you change it, you need to recompile stdafx.cpp
* If you do not check "Empty project", you may check "Export symbols".
This will result in slightly longer your_name.cpp file and new file
named your_name.h.
your_name.h - this file is intended to contain declarations of all
entities you are exporting from your DLL library. It also contains
sample definition of simple class, declaration of variable and
declaration of function - all exported from your DLL. I suggest that you
comment out everything below #endif preprocessor directive and use it
later only for reference. This file is designed to accompany your DLL
file when you want others to see declarations of exported functions (or
classes or variables) - it will help them to use your DLL properly. It's
specific to Visual C++ - other compilers might not understand
"__declspec" keyword. If someone with different compiler is going to use
your DLL, he/she will probably need to manually adjust this header file.
your_name.cpp - this file now contains little longer DllMain and
definitions of entities declared in your_name.h - namely body of
constructor of sample class, definition of variable and body of sample
function. If you commented out in your_name.h everything below #endif,
you also need to comment out in this file everything below DllMain.
Please note that there's no .def file - it's no longer required in
Visual Studio .NET . Instead you put "__declspec(dllexport)" before
declaration or definition of entities (functions, classes, variables)
you are going to export from DLL. If you do not use it, users of your
dynamic library will not see these entities (but you can still use .def
file for required effect). BTW: If you are going to use this DLL from
other compilers than Visual C++ or programs compiled in other languages
(like Delphi or .NET), do not export anything else but functions, and
make sure you put:
extern "C"
prior to function definition (and declaration), just before
"__declspec(dllexport)" if your function is defined in .cpp file (ie. is
written in C++, not C). Otherwise users of your library will see mangled
name of your function instead of expected name. As mangling is specific
to compiler, users of other compilers will not be able to find your
function using name you provided, also GetProcAddress won't be able to
find your exported function.
Here is sample implementation file of dynamic library - you may use it
in place of of your_name.cpp if you did not checked "Export symbols" (or
if you checked it but commented out parts of your_name.h and
your_name.cpp, as advised above).
#include "stdafx.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
; // your initialization code goes here
}
else if (reason == DLL_PROCESS_DETACH)
{
; // your cleanup code goes here
}
return TRUE;
}
extern "C" __declspec(dllexport) int Add(int a, int b)
{
return a + b;
}
You may also use it in "Empty project", but please change first line
from:
#include "stdafx.h"
to:
#include <windows.h>
as "empty project" by default is set not to use precompiled header.
If you define exported function inside .c file (ie. you write it in C,
not in C++ programming language) do not use extern "C"
You should consider adding version resource to your project. Select
menu Project > Add Resource, in "Add Resource" dialog select "Version"
(last one) and press "New" - version info will appear. Here you can put
some information about your DLL - like version number, full project name
and copyright.
Another thing you should take care of is to select right runtime version
- by default its static, but if you want to return pointers from
functions exported in your DLL and allow your users to free these
pointers, you need to use dynamic runtime instead. Click on your project
in one of windows "Solution Explorer", "Class View" or "Resource View"
then select Properties from right-click menu. You will see project
properties window. On the left pane select "C/C++" (you need to have at
least one .c or .cpp file in your project, otherwise you won't see this
option there), then "Code Generation" below. Now you need to change
Runtime Library on the right pane - in Debug configuration it should be
"Multi-threaded Debug DLL (/MDd)" (by default it's "Multi-threaded Debug
(/MTd)"); in Release configuration it should be "Multi-threaded DLL
(/MD)" (by default it's "Multi-threaded (/MT)"). Make sure you change
both configurations - Debug and Relase! You will also need to distribute
your DLL file together with runtime libraries: msvcr70.dll and
msvcp70.dll (together with Release version of your DLL) or msvcr70d.dll
and msvcp70d.dll (together with Debug version of your DLL). These files
have nothing to do with MFC - you are not using it! It's just Microsoft
C and C++ runtime library for Visual C++ 7.0 . Good news is that you do
not always need to redistribute these files (as many users already have
them) and thanks to use of dynamic runtime your own DLL will be smaller.
If you want to use static runtime library (and not to worry about
distribution of DLLs stated above) there's nothing wrong, just make sure
that functions exported from your DLL do not allow your users to free
any kind of resources you are allocating. Otherwise they will experience
all kinds of strange errors. These errors will also happen if you are
using dynamic runtime, but your users are using different dynamic
runtime or static runtime. It's best not to allow your users to free any
resources allocated by your dynamic library - if you follow this advice,
you do not need to worry about runtime version your DLL is using.
I hope you get the basics now. Good luck and best regards!
B.
PS. it's updated version