Download demo project - 11 Kb
Usually, programmers use static linking when using functions in a DLL. This
is the most easiest way to use a DLL. However, if a DLL is missing, application
cannot be started. This is not a big problem: missing DLL means that something
is wrong with application installation and the application should not be started
anyway.
However, if an application is designed in such a way as to offer some optional
features with the help of one or more DLLs, missing DLL should not prevent the
application to run normally (but without optional features). In this case, DLL
must be loaded dynamically. This article presents a base class which offers
all the necessary functionality for dynamic DLL loading. It is limited to DLLs
exporting plain functions (not C++ classes). This is not a big limitation since
all platform DLLs are written in this way. DLLs which export C++ classes are
almost always used with static linking.
Complete functionality is implemented in a class TDllModule. This class is
not intended to be used directly, instead programmers should derive application
specific class and extend it in a way explained in the following example. Only
2 virtual functions are important in this class: Create() and Destroy(). Create()
function returns TRUE if the DLL is loaded correctly and an instance handle
obtained. Destroy() will unload the DLL from process memory.
Let's assume that some application needs the services of Microsoft's PSAPI
(Process Status API) DLL to enumerate all running processes and display process
executable filename. PSAPI DLL may not be installed on the machine since it
is not part of the operating system. So, we need to dynamically load it and
check whether it is loaded before using it.
Therefore, we create a class TProcessStatusModule derived from TDllModule.
We also need to create typedefs for functions needed from the DLL (this is not
necessary but will keep the code easier to read).
typedef BOOL (WINAPI *TFEnumProcesses)(
DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded
);
typedef BOOL (WINAPI *TFEnumProcessModules)(
HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded
);
typedef DWORD (WINAPI *TFGetModuleBaseName)(
HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize
);
typedef DWORD (WINAPI *TFGetModuleFileNameEx)(
HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize
);
typedef BOOL (WINAPI *TFGetModuleInformation)(
HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb
);
class TProcessStatusModule : public TDllModule {
private:
TFEnumProcesses FEnumProcesses;
TFEnumProcessModules FEnumProcessModules;
TFGetModuleBaseName FGetModuleBaseName;
TFGetModuleFileNameEx FGetModuleFileNameEx;
TFGetModuleInformation FGetModuleInformation;
public:
TProcessStatusModule();
virtual ~TProcessStatusModule();
virtual BOOL Create(void);
virtual void Destroy(void);
BOOL EnumProcesses(DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded);
BOOL EnumProcessModules(HANDLE hProcess,HMODULE *lphModule,DWORD cb,
LPDWORD lpcbNeeded);
DWORD GetModuleBaseName(HANDLE hProcess,HMODULE hModule,LPSTR lpBaseName,
DWORD nSize);
DWORD GetModuleFileNameEx(HANDLE hProcess,HMODULE hModule,
LPSTR lpFilename,DWORD nSize);
BOOL GetModuleInformation(HANDLE hProcess,HMODULE hModule,
LPMODULEINFO lpmodinfo,DWORD cb);
};
Most important function in the class example above is Create(). It needs first
to call the base class that loads the DLL into the process memory and obtains
a handle and second, to obtain pointers to functions in a DLL that are needed
for the current application. If this function returns FALSE, then the DLL is
not loaded correctly and cannot be used. Its implementation is the following:
BOOL TProcessStatusModule::Create(void)
{
if (TDllModule::Create()) {
FEnumProcesses = (TFEnumProcesses)::GetProcAddress(m_hHandle,
_T("EnumProcesses"));
FEnumProcessModules = (TFEnumProcessModules)::GetProcAddress(m_hHandle,
_T("EnumProcessModules"));
...
return TRUE;
}
return FALSE;
}
All that is left to be done is the actual execution of functions in a DLL.
All DLL functions needed in the application have a corresponding method in the
class above (each method has exactly the same arguments as the actual DLL function,
the return code is also the same). Example of one function is the following:
BOOL TProcessStatusModule::EnumProcesses(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded)
{
ASSERT(FEnumProcesses != NULL);
if (FEnumProcesses)
return FEnumProcesses(lpidProcess,cb,cbNeeded);
return FALSE;
}
The only remaining issue is the error handling of the function(s) like the
one above. Original DLL function returns BOOL as the function above. Even if
the DLL is loaded correctly, we still do not know (if the return code of the
function is FALSE) whether the function really returned FALSE or the function
is not defined as exported from the DLL (this is valid for release version of
the code since debug version will assert). There are 2 solutions for this problem:
- Check whether all needed DLL functions are exported from the DLL (in Create())
by comparing all obtained function pointers to NULL. If any one of them is
NULL, unload the DLL and prevent application to use it.
- In the function above (and all other functions), use exception handling
instead of a simple return code. If the function succeeds then it is guarantied
that the return code comes from the DLL function.
I have used this technique in many application for DLLs like Winsock2, TAPI,
PDH (Performance Data Helper), PSAPI (Process Status API) and similar.
Latest update of this article may be found here.
| You must Sign In to use this message board. |
|
|
 |
|
|
 |
|
 |
Dear all:
A dll file may be used by many different applications. When we want to update it, it may be used by some applications and the dll file is locked. How can we update it successfully in this case?
Thank you very much.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
 | plugin  doctrane | 7:56 24 Sep '04 |
|
 |
Is this action similar to that of plugin technologies, yet perhaps in a different architecture and utilization
Dave
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I have some problem with inpout32.dll in win32 console application project my code is:
#include "stdio.h" #include "string.h" #include "stdlib.h" /* ----Prototypes of Inp and Outp--- */
void _stdcall Out32(short PortAddress, short data);
/*--------------------------------*/ /*
int main() {
Out32(888,20);
return 0; } but in MFC project ,it error (i use the same code ,except int out() {
Out32(888,20);
return 0; }
Linking... thulpt1Dlg.obj : error LNK2001: unresolved external symbol "void __stdcall Out32(short,short)" (?Out32@@YGXFF@Z) Debug/thulpt1.exe : fatal error LNK1120: 1 unresolved externals Error executing link.exe. thulpt1.exe - 2 error(s), 0 warning(s)
how can i solve it ? please help me
dnqhung
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
~Hi I neede help to run this code, since I´m not finding "psapi.h" Where is it?
Thanks Best regards
Nuno Mig
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|
 |
|
 |
Is it possible to dynamic load a dll and then to create objects of class defined in DLL. if yes, then how to accomplish it. thanx Rubel
|
| Sign In·View Thread·PermaLink | 1.33/5 |
|
|
|
 |
|
 |
Hi all, I wrote a Corba client by C++ with Visibroker complier. But I don't know to make the client's function into a dll because it used some library of Visibroker and used Makefile.cpp rather than use build tool of VC.
When I buil there are errors: c:\bes\include\vdef.h(204) : fatal error C1189: #error : VisiBroker for C++ only supports /MD or /MDd
How can I do now, give me a hand plz.
Thank alot! ngtrungthanh@hotmail.com
Nguyen Trung Thanh
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello,
I want to know the solution to authorize just numeric character in a edit box and if a user enters other things a message error appeared. The problem is the following: after a bad entry the user DEL this one and it is here that an error occurs "assertion error". What is the remedy, please?
Here is my code: /***************************************************************************** FUNCTION: OnChangeSaisie DETAILS: public DESCRIPTION: Detects a pressed key RETURNS: None ARGUMENTS: None NOTES: This function is called whenever an action may have altered text in an edit control *****************************************************************************/ void MDlg::OnChangeSaisie() { // TODO: If this is a RICHEDIT control, the control will not // send this notification unless you override the CDialog::OnInitDialog() // function and call CRichEditCtrl().SetEventMask() // with the ENM_CHANGE flag ORed into the mask. // TODO: Add your control notification handler code here ///////////////////////////////// // GESTION DES ENTREES A REVOIR ///////////////////////////////// UpdateData(true); //pos: the ArrayCString index char car = m_Saisie.GetAt(pos); if(car >= '0' && car <= '9') { // //a compute function luhn(m_Saisie); } else { GetDlgItem(IDC_CARINV)->ShowWindow(true); // AfxMessageBox("Invalide Character!"); pos = m_Saisie.GetLength(); // m_Saisie.Delete(0, m_Saisie.GetLength());//SetAt(pos, ' '); if(pos > 0) pos = 0;
return; } pos++; UpdateData(false); }//Thanks for your answer!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
you have not told any thing about .def file which is required while bulding the project which loads the dll's dynamically

|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
You don't need a def file, because the DLL is used in a VERY Dynamic way. Your app doesn't need to know nothing about DLL and what is inside it during the compilation & linking. You really don't need def's.
First You load the Library and then you search function pointers (ok, here you must know what you are about to load and what functions you are going to use).
During the years I have used this same technique in multiple apps that have need for it (e.g plugins) and I have found this method more than usefull.
-JuhaS-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I want to create a ATL Dll.Alraedy I have a ATL COM EXE(in which a Component is created using COM)I want to call a function of the That component.How can I do that ?Can anyone help me with steps to do that ?
Y.Yamini Devi
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
I want to create a ATL Dll.Alraedy I have a ATL COM EXE(in which a Component is created using COM)I want to call a function of the That component.How can I do that ?Can anyone help me with steps to do that ?
Y.Yamini Devi
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
I want to create a ATL Dll.Alraedy I have a ATL COM EXE(in which a Component is created using COM)I want to call a function of the That component.How can I do that ?Can anyone help me with steps to do that ?
Y.Yamini Devi
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
I want to create a ATL Dll.Alraedy I have a ATL COM EXE(in which a Component is created using COM)I want to call a function of the That component.How can I do that ?Can anyone help me with steps to do that ?
Y.Yamini Devi
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
I wrote a test dll. in the dll I export a function ShowDlgA. the ShowDlgA belows: __declspec(dllexport) void ShowDlgA(CString &string) { // AFX_MANAGE_STATE(AfxGetStaticModuleState()); CADlg dlg;
dlg.m_edit = string; if(dlg.DoModal() == IDOK) { string = dlg.m_edit; // error!? } AfxMessageBox("test dialog A"); } when i domodal dlg, i update m_edit and i click OK button. there is an error
is there anyone to help me? regards.
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
For one: Don't remove the AFX_MANAGE_STATE! otherwise MFC might fail you  Furthermore: If your EXE is a release version, your DLL should be as wel!! Same for debug: EXE is a debug version, so should your DLL be! Why? Because in debugmode classes (like CString) contain all the debug overhead... you need to allocate this in both the exe and dll. When in release mode, this overhead is removed, so the size of the class (CString in your example) is less and no debug info is present. This is a short description of why not do that But there is more... But i can't tell you in short here... But don't mix debug and release, that's the point here!
Regards, Albert van Peppen
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I've the same problem. I think that error occurs because DLL has different memory space and trying to write to memory that belongs to application memory space isn't possible.. Or maybe I'm wrong.
Whatever it is it do not resolve the problem so I tried to return CString normally
extern CString PASCAL EXPORT Function(LPCTSTR buffor_in) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString buffor_out buffor_out = buffor_in; return buffor_out }
but it works for the first time i call the function and get some errors if I try to call it second time.
Has anybody found a solution to this? Or would be so nice to give some tips on how to do it?
Regards
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Yes it is possible.
You can use AfxLoadLibrary. The trick is to create two exported functions in the DLL for each class you want to export. One function must create an instance of the desired exported class and pass a pointer to the object as a return value. The other function must destroy the object.
|
| Sign In·View Thread·PermaLink | 4.00/5 |
|
|
|
 |
|
 |
But why can I export classes, if I can write 2 functions MyObject* CreateMyObject() { return new MyObject(); }
DeleteOblect(MyObject* pMyObj) { delete pMyObj; }

|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
But why can I export classes, if I can write 2 functions MyObject* CreateMyObject() { return new MyObject(); }
DeleteOblect(MyObject* pMyObj) { delete pMyObj; }

|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|