Please see the MFC Advanced Concepts sample program DLLScreenCap for a complete sample. Several interesting thing to note:
-
The compiler flags of the DLL and the application are very different.
-
The link lines and .DEF files for the DLL and the application are also very different.
-
The application using the DLL doesn't even have to be in C++.
-
The interface between the application and the DLL is a "C"-like API and are exported with DLLScreenCap.DEF.
The following illustrates what is needed for one API that is defined in a regular DLL that statically links to MFC:
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct TracerData
{
BOOL bEnabled;
UINT flags;
};
BOOL FAR PASCAL EXPORT PromptTraceFlags(TracerData FAR* lpData);
#ifdef __cplusplus
}
#endif
In this example, the declaration is enclosed in an 'extern "C" { }' block for C++ users. This has several advantages. First, it makes your DLL APIs usable by non-C++ client applications. Second, it reduces DLL overhead since C++ name mangling will not be applied to the exported name. Lastly, it makes it easier to explicitly add to a .DEF file (for exporting by ordinal) without having to worry about name mangling.
All API functions are "FAR PASCAL EXPORT". Although not strictly necessary for Win32 DLLs, these definitions have been kept for easy back-porting to 16-bit Windows. The FAR, PASCAL, and EXPORT macros all expand to nothing under Win32.
The structures used by the API are not derived from MFC classes and are defined completely in the API header. This reduces the complexity of the interface between the DLL and the application and, once again, makes the DLL usable by C programs as well.
Any data pointers used in the API are explicit FAR pointers. Again, FAR, is not really necessary for Win32, but is useful if you plan to compile the code for 16-bit Windows sometime in the future.