delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/1997/04/12/15:52:07

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: <ww03-BDLP5s2143.cygnus.gnu-win32@netaddress.usa.net>
Mime-Version: 1.0
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 <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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019