This article was contributed by Tair Abdurman.
This article illustrates how to create and use Statically linked Non-MFC (Implicit) DLLs. In order to build applications using DLLs in this way you must have .dll distribution with .lib & .h files. Lemme create DLL which can export whole class with method and variable and global variable with global procedure. I call this as HookWorks because have used this code to window's hook, and leave without changes. To start from 0, select New->Project->Win32 DLL. Select empty project and click finish (no need to help from wizards! ;). First going to planning our exports and declare them in
//**************HWMain.h file***************** //HWMain.h Non-MFC DLL header file //sure it will be included only once #ifndef _ATM_HWMAIN_H_ #define _ATM_HWMAIN_H_ #pragma once //to speedup & reduce size #define VC_EXTRALEAN //Header bodyYou can use .DEF file if wanna to use ordinal exports, but here I use exports by names. Create some usefull macros
//export macros #define DLL_EXPORT __declspec(dllexport) //import macro #define DLL_IMPORT __declspec(dllimport)After completing your DLL, you can use DUMPBIN [options] files to view export table of DLL.
// ... #include <windows.h> //to export for C++ & C #ifdef __cplusplus extern "C" { #endifHere, the class will be exported with all of its members. Now you only need to create a new instance of the object and all members will be accessable
//class export, with all definitions class DLL_EXPORT CHookWorks { public: //blah blah method int HookWorksFunc(void); //blah blah variable int m_iHookWorks; //con and decon CHookWorks(); ~CHookWorks(); };Here is a variable which will be accesable as extern in your "client"
//exported variable DLL_EXPORT int exp_iVar=99; this function will be directly accessable //exported function DLL_EXPORT BOOL ExportedFunc(BOOL bParam); copmleted ... only close this "language unconveniences". #ifdef __cplusplus } #endif //EOF Header body #endif
//*******************HWMain.h file********************** implementation is too simple with some explains: //*******************HWMain.cpp file******************** #include "HWMain.h" //Regular DLL Entry Point, do not have any importancy //to me here BOOL WINAPI DllMain(HINSTANCE hinstDLL, // DLL module handle DWORD fdwReason, // for calling function LPVOID lpvReserved // reserved ) { switch(fdwReason) { case DLL_PROCESS_ATTACH: /* Indicates that the DLL is being loaded into the virtual address space of the current process as a result of the process starting up or as a result of a call to LoadLibrary.DLLs can use this opportunity to initialize any instance data or to use the TlsAlloc function to allocate a Thread Local Storage (TLS) index.*/ break; case DLL_THREAD_ATTACH: /* Indicates that the current process is creating a new thread.When this occurs, the system calls the entry-point function of all DLLs currently attached to the process. The call is made in the context of the new thread. DLLs can use this opportunity to initialize a TLS slot for the thread. A thread calling the DLL entry-point function with DLL_PROCESS_ATTACH does not call the DLL entry-point function with DLL_THREAD_ATTACH. Note that a DLL's entry-point function is called with this value only by threads created after the DLL is loaded by the process. When a DLL is loaded using LoadLibrary, existing threads do not call the entry-point function of the newly loaded DLL.*/ break; case DLL_THREAD_DETACH: /* Indicates that a thread is exiting cleanly. If the DLL has stored a pointer to allocated memory in a TLS slot, it uses this opportunity to free the memory. The system calls the entry-point function of all currently loaded DLLs with this value. The call is made in the context of the exiting thread.*/ break; case DLL_PROCESS_DETACH: /* Indicates that the DLL is being unloaded from the virtual address space of the calling process as a result of either a process exit or a call to FreeLibrary. The DLL can use this opportunity to call the TlsFree function to free any TLS indices allocated by using TlsAlloc and to free any thread local data.*/ break; default: break; } return TRUE; } //class export, with all definitions //member method int CHookWorks::HookWorksFunc() { m_iHookWorks=10; return 2; } //constructor CHookWorks::CHookWorks() { m_iHookWorks=1; } //destructor CHookWorks::~CHookWorks() { } //exported function declaration DLL_EXPORT BOOL ExportedFunc(BOOL bParam) { return bParam; } //*******************HWMain.cpp file********************Yep. It's ready. Simply compile after checking that you don't want MFC support (in the Linker settings). After building the project, you will 3 files that you need to distribute:
- DEBUG build
- HookWorks.dll
- HookWorks.lib
- HWMain.h
- RELEASE build
- HookWorks.dll
- HookWorks.lib
- HWMain.h
Now create new project File->New->Project->Win32 application, select empty project (no need to wizards). Go to Project->Settings and use MFC as dynamic linked. I put my DEBUG and RELEASE .lib files in DEBUG and RELEASE paths for client project and point to Project's linker seek them there related on client version RELEASE/DEBUG. Only unconvenience it's a rewriting of dll file when switch from RELEASE to DEBUG and back. In client app, I only call export variables and procedures and show them in wnd.
//*************** stdafx.h file ************************ #ifndef _ATM_STD_AFX_H_ #define _ATM_STD_AFX_H_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define WIN32_LEAN_AND_MEAN #include#endif //*************** stdafx.h file ************************ //************** stdafx.cpp file *********************** #include "stdafx.h" //************** stdafx.cpp file *********************** //************** HWImplicitUse.h *********************** // HWImplicitUse.h // #ifndef _ATM_HW_IMPLICITUSE_H_ #define _ATM_HW_IMPLICITUSE_H_ #pragma once #include "stdafx.h" //its my DLL project's path #include "D:\Developing\cpp\HookWorks\HWMain.h" //CMainApp Declarations class CMainApp:public CWinApp { public: CMainApp(); ~CMainApp(); //will be test here virtual int Run( ); protected: BOOL InitInstance(); }; //CMainWnd Declarations class CMainWnd:public CFrameWnd { public: CMainWnd(); ~CMainWnd(); }; #endif //************** HWImplicitUse.h *********************** //************* HWImplicitUse.cpp ********************** // HWImplicitUse.cpp // #include "stdafx.h" #include "HWImplicitUse.h" //CMainApp Implementation CMainApp::CMainApp() {} CMainApp::~CMainApp() {} BOOL CMainApp::InitInstance() { if (!CWinApp::InitInstance()) return FALSE; CMainWnd* t_pMainWnd=new CMainWnd(); if (t_pMainWnd==NULL) return FALSE; m_pMainWnd=t_pMainWnd; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } int CMainApp::Run( ) { CClientDC t_cDC(m_pMainWnd); char szDLLParams[]=" "; //easy to create new instance CHookWorks* t_hwDLLClass=new CHookWorks(); //easy access to instance's method int t_iDLLClassVar=t_hwDLLClass->HookWorksFunc(); wsprintf(szDLLParams,"HookWorksFunc=%d",t_iDLLClassVar); t_cDC.TextOut(0,0,szDLLParams); //easy access to instance's variable t_iDLLClassVar=t_hwDLLClass->m_iHookWorks; wsprintf(szDLLParams,"m_iHookWorks=%d",t_iDLLClassVar); t_cDC.TextOut(0,15,szDLLParams); //easy access to global export variable t_iDLLClassVar=exp_iVar; wsprintf(szDLLParams,"exp_iVar=%d",t_iDLLClassVar); t_cDC.TextOut(0,30,szDLLParams); //and easy access to global export function UINT t_bDLLExpFunc=(UINT)ExportedFunc(FALSE); wsprintf(szDLLParams,"ExportedFunc(FALSE)=%d",t_bDLLExpFunc); t_cDC.TextOut(0,45,szDLLParams); //all other works to parents return CWinApp::Run(); } CMainApp MainApplication; //CMainWnd Implementation CMainWnd::CMainWnd() { Create(NULL,"HookWorks DLL Implicit Usage Demo"); } CMainWnd::~CMainWnd() { } //************* HWImplicitUse.cpp **********************