BOOL APIENTRY DllMain (HINSTANCE hInst / Library instance handle. / ,
DWORD reason / Reason this function is being called. / ,
LPVOID reserved / Not used. / )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
extern "C" declspec (dllexport) stdcall void DisplayMessage()
{
MessageBox(0,"This was called from within a dll","DLL Called!!!", MB_OK);
}
You your project name and your project folder name contain a space character. That is what is screwing it up.
The issue of spaces in paths is dealt with in the thread titled: "PLEASE READ BEFORE POSTING A QUESTION". I suggest you read it before posting another question. ;-)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
... Oh and putting your project in a sub-folder of the Dev-C++ installation is also a bad idea. There is some sort of weird bug that can in some circumstances prevent such projects from building. It is also a bad idea in general to 'pollute' an applications installation with your own data.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
One other doubt though. Why do I have a class defined by default whenever I start a dll project. If it is only meant to be a "class" how can I create an object of its kind and use in my program?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm curious about that too, deostroll. They probably want a new thread to answer/explain it though. Your thread interested me because I was thinking about learning to make/use dlls with Dev-C++, as I use them in VC++/embedded C++. I thought the declspec(dllexport) attribute specifiers were Microsoft specific, but I guess they're not. That's why I was wondering about making dlls with Dev-C++. Was thinking one might have to use module definition files, which I don't like much, but I guess not.
Anyway, I tried your code and it worked for me too. It appears you can just delete all that class stuff you referred too, and it still works. Here's my code, first the dll then host app. The latter calls your function in the WM_CLOSE message. What I can't understand is why DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH are'nt getting called.
To get it to work you have to add the library in Project >> Options
//dllMain.cpp >> results in dllTest.dll (that's how I named my project)
/ Replace "dll.h" with the name of your header /
include <windows.h>
include <stdio.h>
FILE* fp;
extern "C" declspec (dllexport) stdcall void DisplayMessage()
{
MessageBox(0,"This was called from within a dll","DLL Called!!!", MB_OK);
}
long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
fp=fopen("Output.txt","w");
Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
hDll=LoadLibrary("dllTest.dll");
fprintf(fp,"hDll=%u\n",hDll);
return 0;
}
long fnWndProc_OnClose(lpWndEventArgs Wea) //This function handles the WM_CLOSE message
{ //sent when the 'x' button is clicked.
if(MessageBox(Wea->hWnd,"Do You Wish To Exit This App?","Exit Check?",MB_YESNO)==IDYES)
{
BOOL blnFree=FALSE;
DisplayMessage();
fprintf(fp,"Addition(1.5,1.6)=%f\n",Addition(1.5,1.6));
blnFree=FreeLibrary(hDll);
fprintf(fp,"blnFree=%u\n",blnFree);
fclose(fp);
DestroyWindow(Wea->hWnd);
PostQuitMessage(WM_QUIT);
}
return 0;
}
long __stdcall fnWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) //This is the all important Window
{ //Procedure. Note that in WinMain()
static WndEventArgs wea; //the WNDCLASSEX variable wc has a
//field lpfnWndProc. This is pro-
switch (msg) //nounced long pointer to Window
{ //Procedure. Below you can see where
case WM_CREATE: //this variable was set to the
wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //address of this function. All
return fnWndProc_OnCreate(&wea); //mouse, keyboard, COM, etc., inputs
case WM_CLOSE: //destined for this program Windows
wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //will package up into a message
return fnWndProc_OnClose(&wea); //packet consisting of the four
} //parameters to this function and
//and it will come blowing through
return DefWindowProc(hwnd,msg,wParam,lParam); //here at blinding speed.
}
int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow)
{ //The program starts in WinMain(). The WNDCLASSEX structure variable
char szClassName[]="Form1"; //wc is filled out with general characteristics of a window. Then
WNDCLASSEX wc; //the class is RegisteredClassEx()'ed. Directly after that a
MSG messages; //CreateWindow() call instantiates an instance of the class. Then
HWND hWnd; //the program drops into a message processing loop in which any messages
//destined for this program are DispatchMessage()'ed to the fnWndProc().
wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc;
wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_DBLCLKS;
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns;
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND; wc.cbWndExtra=0;
wc.lpszMenuName=NULL; wc.cbClsExtra=0;
RegisterClassEx(&wc);
hWnd=CreateWindow(szClassName,"Form1",WS_OVERLAPPEDWINDOW,200,100,400,350,HWND_DESKTOP,0,hIns,0);
ShowWindow(hWnd,iShow);
while(GetMessage(&messages,NULL,0,0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
For all I know what I am doing below can be alleged as slander:
To answer the question: why classes are there?...
It is probably there bcuz
a) for modularizing things inside the dll(?)
b) or if we brought the dll in the project like a header file we could probably use the class (Implicit linking...check http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/
But what I am really interested to know is that if we brought the dll into the program dynamically how do we make use of the class which lies inside?
-- deostroll
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
CodeGear (formerly Borland development tools) appear to make it easy with CreateClassInstance()and CreateClassObject() functions, ( http://dn.codegear.com/article/20165 ) but these are not standard Win32 API function as far as I am aware, and not available in Dev-C++. You could of course create them using information in the first link.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
__declspec is merely a macro defined in windef.h in terms of the GNU attribute keyword for function attributes.
The code in the template is there for no other reason than as a starting point. You get different code depending upon whether you select C or C++ as the project language. You can modify the template code by editing the appropriate files in the Templates folder.
Note that if you implement a C++ interface (i.e. compile as C++ and do not use extern "C"), the resulting DLL is unlikely to be compatible with other compilers since there is no standard convention for C++'s 'name mangling'.
Fred, this is the second time you have mentions "embedded C++" but you appear to be using it in an entirely different way to that which I understand it (as an embedded systems engineer of so 18 years experience). There is a (somewhat obsolete) subset of C++ for embedded systems known as EC++, and C++ itself can be used in embedded systems in any case, but you mention "embedded C++" in relation to Windows API calls and DLLs. I am guessing that you are referring to WinCE perhaps? But the term 'embedded' has broader meaning, so it would be more usual to refer to the target to avoid any confusion - only the tiniest minority or embedded systems code is targeted at the WinCE platform.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I get an error while making the DLL... I am posting the code and the compile log below. (The code is just newbie stuff...)
---mydll.h----
ifndef SAMPLE_DLL_H_
define SAMPLE_DLL_H_
if BUILDING_DLL
define DLLIMPORT __declspec (dllexport)
else / Not BUILDING_DLL /
define DLLIMPORT __declspec (dllimport)
endif / Not BUILDING_DLL /
class DLLIMPORT DllClass
{
public:
DllClass();
virtual ~DllClass(void);
private:
};
extern "C" declspec (dllexport) stdcall void DisplayMessage();
extern "C" declspec (dllexport) stdcall double Addition(double arg1, double arg2);
endif / SAMPLE_DLL_H_ /
----mydllmain.cpp----
include "mydll.h"
include <windows.h>
DllClass::DllClass()
{
}
DllClass::~DllClass ()
{
}
BOOL APIENTRY DllMain (HINSTANCE hInst / Library instance handle. / ,
DWORD reason / Reason this function is being called. / ,
LPVOID reserved / Not used. / )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
}
extern "C" declspec (dllexport) stdcall void DisplayMessage()
{
MessageBox(0,"This was called from within a dll","DLL Called!!!", MB_OK);
}
extern "C" declspec(dllexport) stdcall double Addition(double arg1, double arg2)
{
return arg1 + arg2;
}
----compile log----
Compiler: Default compiler
Building Makefile: "D:\Dev-Cpp\Sample DLL\Makefile.win"
Executing make...
make.exe -f "D:\Dev-Cpp\Sample DLL\Makefile.win" all
g++.exe -c mydllmain.cpp -o mydllmain.o -I"d:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"d:/Dev-Cpp/include/c++/3.4.2/backward" -I"d:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"d:/Dev-Cpp/include/c++/3.4.2" -I"d:/Dev-Cpp/include" -DBUILDING_DLL=1
dllwrap.exe --output-def "libSample DLL.def" --driver-name c++ --implib "libSample DLL.a" mydllmain.o -L"d:/Dev-Cpp/lib" --no-export-all-symbols --add-stdcall-alias -o "Sample DLL.dll"
dlltool: Unable to open object file: DLL.dll
dllwrap.exe: no export definition file provided.
Creating one, but that may not be what you want
dllwrap.exe: dlltool exited with status 1
make.exe: *** ["Sample] Error 1
Execution terminated
You your project name and your project folder name contain a space character. That is what is screwing it up.
The issue of spaces in paths is dealt with in the thread titled: "PLEASE READ BEFORE POSTING A QUESTION". I suggest you read it before posting another question. ;-)
... Oh and putting your project in a sub-folder of the Dev-C++ installation is also a bad idea. There is some sort of weird bug that can in some circumstances prevent such projects from building. It is also a bad idea in general to 'pollute' an applications installation with your own data.
Clifford
Ha, the space was the culprit. Thanx.
One other doubt though. Why do I have a class defined by default whenever I start a dll project. If it is only meant to be a "class" how can I create an object of its kind and use in my program?
I'm curious about that too, deostroll. They probably want a new thread to answer/explain it though. Your thread interested me because I was thinking about learning to make/use dlls with Dev-C++, as I use them in VC++/embedded C++. I thought the declspec(dllexport) attribute specifiers were Microsoft specific, but I guess they're not. That's why I was wondering about making dlls with Dev-C++. Was thinking one might have to use module definition files, which I don't like much, but I guess not.
Anyway, I tried your code and it worked for me too. It appears you can just delete all that class stuff you referred too, and it still works. Here's my code, first the dll then host app. The latter calls your function in the WM_CLOSE message. What I can't understand is why DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH are'nt getting called.
To get it to work you have to add the library in Project >> Options
//dllMain.cpp >> results in dllTest.dll (that's how I named my project)
/ Replace "dll.h" with the name of your header /
include <windows.h>
include <stdio.h>
FILE* fp;
extern "C" declspec (dllexport) stdcall void DisplayMessage()
{
MessageBox(0,"This was called from within a dll","DLL Called!!!", MB_OK);
}
extern "C" declspec(dllexport) stdcall double Addition(double arg1, double arg2)
{
return arg1 + arg2;
}
BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
switch(reason)
{
case DLL_PROCESS_ATTACH:
fp=fopen("Output1.txt","w");
fprintf(fp,"In DLL_PROCESS_ATTACH\n");
break;
case DLL_PROCESS_DETACH:
fprintf(fp,"In DLL_PROCESS_DETACH\n");
fclose(fp);
break;
}
return TRUE;
}
//LoadDll is this project
include <windows.h>
include <stdio.h>
typedef struct WindowsEventArguments //Package Window Procedure Parameters into structure
{
HWND hWnd; //Handle of Window
WPARAM wParam; //Window Parameter
LPARAM lParam; //Long Parameter
HINSTANCE hIns; //Instance Handle (Resolves To Process Address)
}WndEventArgs, *lpWndEventArgs;
extern "C" declspec (dllimport) stdcall void DisplayMessage();
extern "C" declspec (dllimport) stdcall double Addition(double arg1, double arg2);
HINSTANCE hDll;
FILE* fp;
long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
fp=fopen("Output.txt","w");
Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
hDll=LoadLibrary("dllTest.dll");
fprintf(fp,"hDll=%u\n",hDll);
return 0;
}
long fnWndProc_OnClose(lpWndEventArgs Wea) //This function handles the WM_CLOSE message
{ //sent when the 'x' button is clicked.
if(MessageBox(Wea->hWnd,"Do You Wish To Exit This App?","Exit Check?",MB_YESNO)==IDYES)
{
BOOL blnFree=FALSE;
DisplayMessage();
fprintf(fp,"Addition(1.5,1.6)=%f\n",Addition(1.5,1.6));
blnFree=FreeLibrary(hDll);
fprintf(fp,"blnFree=%u\n",blnFree);
fclose(fp);
DestroyWindow(Wea->hWnd);
PostQuitMessage(WM_QUIT);
}
return 0;
}
long __stdcall fnWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) //This is the all important Window
{ //Procedure. Note that in WinMain()
static WndEventArgs wea; //the WNDCLASSEX variable wc has a
//field lpfnWndProc. This is pro-
switch (msg) //nounced long pointer to Window
{ //Procedure. Below you can see where
case WM_CREATE: //this variable was set to the
wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //address of this function. All
return fnWndProc_OnCreate(&wea); //mouse, keyboard, COM, etc., inputs
case WM_CLOSE: //destined for this program Windows
wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //will package up into a message
return fnWndProc_OnClose(&wea); //packet consisting of the four
} //parameters to this function and
//and it will come blowing through
return DefWindowProc(hwnd,msg,wParam,lParam); //here at blinding speed.
}
int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow)
{ //The program starts in WinMain(). The WNDCLASSEX structure variable
char szClassName[]="Form1"; //wc is filled out with general characteristics of a window. Then
WNDCLASSEX wc; //the class is RegisteredClassEx()'ed. Directly after that a
MSG messages; //CreateWindow() call instantiates an instance of the class. Then
HWND hWnd; //the program drops into a message processing loop in which any messages
//destined for this program are DispatchMessage()'ed to the fnWndProc().
wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc;
wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_DBLCLKS;
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns;
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND; wc.cbWndExtra=0;
wc.lpszMenuName=NULL; wc.cbClsExtra=0;
RegisterClassEx(&wc);
hWnd=CreateWindow(szClassName,"Form1",WS_OVERLAPPEDWINDOW,200,100,400,350,HWND_DESKTOP,0,hIns,0);
ShowWindow(hWnd,iShow);
while(GetMessage(&messages,NULL,0,0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
For all I know what I am doing below can be alleged as slander:
To answer the question: why classes are there?...
It is probably there bcuz
a) for modularizing things inside the dll(?)
b) or if we brought the dll in the project like a header file we could probably use the class (Implicit linking...check http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/
But what I am really interested to know is that if we brought the dll into the program dynamically how do we make use of the class which lies inside?
-- deostroll
Same as anything else you would use in a DLL - a declaration in an associated header, link the generated export (.a) library.
Does this mean if we are trying to link at runtime we will not be able to use the classes inside the dll?
- deostroll
I've never tried, but it seems I know how to use Google! ;-)
http://www.codeguru.com/Cpp/W-P/dll/importexportissues/article.php/c123
CodeGear (formerly Borland development tools) appear to make it easy with CreateClassInstance()and CreateClassObject() functions, ( http://dn.codegear.com/article/20165 ) but these are not standard Win32 API function as far as I am aware, and not available in Dev-C++. You could of course create them using information in the first link.
Clifford
__declspec is merely a macro defined in windef.h in terms of the GNU attribute keyword for function attributes.
The code in the template is there for no other reason than as a starting point. You get different code depending upon whether you select C or C++ as the project language. You can modify the template code by editing the appropriate files in the Templates folder.
Note that if you implement a C++ interface (i.e. compile as C++ and do not use extern "C"), the resulting DLL is unlikely to be compatible with other compilers since there is no standard convention for C++'s 'name mangling'.
Fred, this is the second time you have mentions "embedded C++" but you appear to be using it in an entirely different way to that which I understand it (as an embedded systems engineer of so 18 years experience). There is a (somewhat obsolete) subset of C++ for embedded systems known as EC++, and C++ itself can be used in embedded systems in any case, but you mention "embedded C++" in relation to Windows API calls and DLLs. I am guessing that you are referring to WinCE perhaps? But the term 'embedded' has broader meaning, so it would be more usual to refer to the target to avoid any confusion - only the tiniest minority or embedded systems code is targeted at the WinCE platform.