Mail Archives: cygwin/1997/04/12/15:52:07
Days ago I had a problem making DLL's that I don't knew how to solve.
I ask
the mailing list, saw the faq ... and well, now I KNOW how to build a
relocatable
DLL that can be linked whith an application or be loaded via
LoadLibrary()...
that is, a working DLL.
This has been tested with Windows 95 but is supposed to work with NT
as well.
If you don't want to have pain building your own DLL, follow my
instructions ...
and have luck!
Ismael Jurado
ismaelj AT hotmail DOT com
PS: Thanks to
John Cerney <j-cerney1 AT ti DOT com> (for his answer in the mailing
list)
Gunther Ebert <gunther DOT ebert AT ixos-leipzig DOT de> (for his
procedure in the cygnus web)
Colin Peters <colin AT bird DOT fu DOT is DOT saga-u DOT ac DOT jp> (for is mingw32
files)
who have helped me in making this procedure with their work.
How to build a DLL
------------------
0. Before starting your DLL, be sure that the functions that you want
to export
(those that will be called by Windows or other application) DON'T
have any
modifier like _export or even WINAPI or CALLBACK (in the h, c or
cpp code).
Functions with WINAPI or CALLBACK modifier are exported internally,
so if you
export then again in the DEF file, the DLL will not work or even be
build, and
you NEED a DEF file to build a DLL, as dlltool needs it.
You also need an entry point in the DLL prototyped as:
int WINAPI DllMain(HANDLE hDll, DWORD reason, LPVOID reserved);
Some use dllentry, dll_entry or else for the name of the function,
but it don't
matters as long as you tell the linker (and you MUST) which name it
is. This
funtion initializes the DLL when it is loaded (any Win32 reference
explains it
in detail), but the only thing you must remember about it it's just
to return TRUE.
1. Compile al your files as usually
gcc -c mydll.c
2. Compile fixup.c (or add it to one of your sources):
file fixup.c:
#ifdef __GNUC__
/*
* This section terminates the list of imports under GCC.
* If you do not include this then you will have problems
* when linking with DLLs.
*/
asm (".section .idata$3\n" ".long 0,0,0,0,0,0,0,0");
#endif
3. Optionally, If you have more than one file to build the DLL,
put then together in a library:
ar rc temp.a <objects>
4. Make a DEF file. You can do it manually (glups!) or use this:
echo EXPORTS > mydll.def
nm <libnames> | grep " [TC] " | sed '/ _/s// /' | awk '{print
$3;}' >> mydll.def
nm <objnames> | grep '^........ [T] _' | sed 's/[^_]*_//' >>
mydll.def
if necessary, edit the DEF file to make sure that includes only
those functions
that will be really called by Windows to avoid extra overhead in
the entry/exit
code for the function.
5. Build the DLL using one of the procedures listed below. The first
is like the one
used to build CYGNUS.DLL. Both seems to produce the same code, but
the second
is faster. Folow these instructions when using any of them:
- library names must be in the form
$LIBPATH/libxxx.a (this is, the true name as
$LIBPATH/libcygwin.a)
or tell the linker where they are
-L/path/for/my/libs -lmylib (whithout libxxx or .a as
-lcygwin)
- the entry point is declared as
-e _entrypoint AT 12 (both, the underscore and the @12 are
needed)
- if you build a GUI DLL, be sure to declare it at the BEGINING of
every
linker line as in
ld --dll --subsystem windows -e _DllMain AT 12 ....
- a) 6 steps procedure (in an example to build a console DLL)
----------------------------------------------------------
ld --base-file mydll.base --dll -o mydll.dll <objects> \
<$LIBPATH/libname> -e _DllMain AT 12
dlltool --as=as --dllname mydl.dll --def mydll.def --base-file
\
mydll.base --output-exp mydll.exp
ld --base-file mydll.base mydll.exp --dll -o mydll.dll
<objects> \
<$LIBPATH/libname> -e _DllMain AT 12
dlltool --as=as --dllname mydll.dll --def mydll.def
--base-file \
mydll.base --output-exp mydll.exp
ld mydll.exp --dll -o mydll.dll <objects> \
<$LIBPATH/libname> -e _DllMain AT 12
dlltool --as=as --dllname mydll.dll --def mydll.def
--output-lib mydll.a
- b) 3 steps procedure (in an example to build a GUI DLL)
-------------------------------------------------------
ld --dll --subsystem windows -e _DllMain AT 12 -o jnk --base-file
\
mydll.base <objects> <libs>
dlltool --dllname mydll.dll --base-file mydll.base --def
mydll.def \
--output-lib mydll.a --output-exp mydll.exp
ld --dll --subsystem windows -e _DllMain AT 12 -o mydll.dll \
<objects> <libs> mydll.exp
rm jnk mydll.base mydll.exp
6. Now you have mydll.dll and mydll.a. With the source files given
below, you
can compile appa and appb this way:
gcc -c appa.c appb.c
gcc -o appa appa.o -mwindows --subsystem windows
gcc -o appb appb.o mydll.a -mwindows --subsystem windows
- appa is a program that loads mydll.dll dinamically at runtime, so
it don't have
to be linked with mydll.a
- appb is a program linked with mydll.a
- both are GUI apps.
------------------------------------------------------------------------
-------------
MYDLL.H
------------------------------------------------------------------------
-------------
#include <windows.h>
typedef void (*foop)();
void foof();
------------------------------------------------------------------------
-------------
MYDLL.C
------------------------------------------------------------------------
-------------
#include "mydll.h"
int WINAPI DllMain(HINSTANCE H, DWORD d, PVOID p) {
MessageBox(NULL, "Hello from DllMain", "DLL", MB_OK);
return TRUE;
}
void foof() {
MessageBox(NULL, "Hello from foof", "DLL", MB_OK);
}
// note that I include directly the code of fixup.c
asm (".section .idata$3\n" ".long 0,0,0,0,0,0,0,0");
------------------------------------------------------------------------
-------------
MYDLL.DEF
------------------------------------------------------------------------
-------------
EXPORTS
foof
------------------------------------------------------------------------
-------------
APPA.C
------------------------------------------------------------------------
-------------
#include <stdio.h>
#include "mydll.h"
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR
szCmdLine, int iCmdShow) {
HANDLE dllh;
foop foo;
char buf[126];
dllh=LoadLibrary("mydll.dll");
if ((UINT)dllh <= HINSTANCE_ERROR){
sprintf(buf,"Error loading dll: %d", dllh);
MessageBox(NULL, buf, "APP", MB_OK);
}
else {
foo=(foop)GetProcAddress(dllh, "foof");
if (foo==NULL)
MessageBox(NULL, "foo == null", "APP", MB_OK);
else
foo();
}
if ((UINT)dllh > HINSTANCE_ERROR)
FreeLibrary(dllh);
return 0;
}
------------------------------------------------------------------------
-------------
APPB.C
------------------------------------------------------------------------
-------------
#include "mydll.h"
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR
szCmdLine, int iCmdShow) {
foof();
return 0;
};
-
For help on using this list (especially unsubscribing), send a message to
"gnu-win32-request AT cygnus DOT com" with one line of text: "help".
- Raw text -