Subject: Making DLL�s
From: [email-masked]

12 Apr 1997 15:52:07 -0700
Approved: [email-masked]
Distribution: cygnus
Message-ID: <[email-masked]>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Original-To: [email-masked]
Original-Sender: [email-masked]

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
        [email-masked]

PS: Thanks to
        John Cerney <[email-masked]> (for his answer in the mailing 
list)
        Gunther Ebert <[email-masked]> (for his 
procedure in the cygnus web)
        Colin Peters <[email-masked]> (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@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@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@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@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@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@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@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
"[email-masked]" with one line of text: "help".