From: ij AT usa DOT net Subject: Making DLL´s 12 Apr 1997 15:52:07 -0700 Approved: cygnus DOT gnu-win32 AT cygnus DOT com Distribution: cygnus Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Original-To: gnu-win32 AT cygnus DOT com Original-Sender: owner-gnu-win32 AT cygnus DOT com 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 (for his answer in the mailing list) Gunther Ebert (for his procedure in the cygnus web) Colin Peters (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 4. Make a DEF file. You can do it manually (glups!) or use this: echo EXPORTS > mydll.def nm | grep " [TC] " | sed '/ _/s// /' | awk '{print $3;}' >> mydll.def nm | 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 \ <$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 \ <$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 \ <$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 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 \ 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 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 #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".