MKoD - D Programming Language

Demystifying D DLLs - Part I : Exporting Free Functions

Prologue: Well to start off (as of July 2004), I couldn't find any good sources of information, or examples about D DLLs within the D Community of sites. And although the main DigitalMars D web site does carry a LibMain() basic example with a .DEF file, which does creates a DLL file, it doesn't have an example on how to use it beyond that point. Thus upon the creation of this site, it has become one of my main goals to discover more about how to build and use D created DLLs...and then share that newfound knowledge with my fellow D developers.


Below I'd like to walk thru a few pointers I used when creating the "D Financial Package" DLL (please download it, as I'll be using both financial_dll.d and financial_dll.def files in examples) that I was able to then explicitly load all its functions into a D application .exe for use (much like Windows' does in loading a DLL into a Windows application).

1) In viewing financial_dll.d you'll notice it uses a very basic DllMain() code, this is the same code you'll need in your own future DLLs. (Note: This code was found at the DigitalMars D site within the "D for Win32" section.)

import std.c.windows.windows;

HINSTANCE g_hInst;

extern( C )
{
    void gc_init();
    void gc_term();
    void _minit();
    void _moduleCtor();
    void _moduleUnitTests();
}

extern( Windows ) 
BOOL DllMain
( 
    HINSTANCE hInstance,
    ULONG     ulReason,
    LPVOID    pvReserved
)
{
    switch( ulReason )
    {
      case DLL_PROCESS_ATTACH:
          gc_init();          // initialize GC
          _minit();           // initialize module list
          _moduleCtor();      // run module constructors
          _moduleUnitTests(); // run module unit tests
          break;
          
      case DLL_PROCESS_DETACH:
          gc_term();          // shut-down the GC
          break;
          
      case DLL_THREAD_ATTACH:
           DLL_THREAD_DETACH:
          // Multiple threads not supported yet
          break;
    }

    g_hInst = hInstance;
    
    return true;
}

and a very basic .def Module Definition File:

LIBRARY      MYDLL
DESCRIPTION  'My DLL written in D'

EXETYPE      NT
CODE         PRELOAD DISCARDABLE
DATA         PRELOAD SINGLE

EXPORTS 

2) Next, to export the functions into the DLL, the keywords "extern( D )" and "export" (which are in red below) were added to the functions. Please don't add anything to the .def file's "Exports" section at this time.

extern( D )
export real fv
( 
    in real rRate, 
    in real rNPer, 
    in real rPmt, 
    in real rPV = 0, 
    in uint uiType = 0
)
{
    // code ...  
    return rValue;
        
} // end fv( in real, in real, in real, in real = 0, in uint = 0 )

3) Once the above has been done, compile the code: dmd financial_dll.d financial_dll.def

(Please note that the compiler uses the case the filenames to generate its decorated D name into the DLL...so it's best to type them in as lowercase.) After which, one can then check the compiled DLL with a "Dependency Walker" for the entry (if you don't have a "Dependency Walker", then follow this link to download one... Dependency Walker v2.1 [freeware] for Win95, Win98, WinMe, WinNT, Win2000. and WinXP [there are other versions also for other OSs]), look at the screenshot below.


Dependency Walker

4) In the above screenshot that's pointing to the "real fv(real,real,real,real,uint)" function, we can see in the "Function" column that its D Decorated Name became "D13financial_dll2fvFeeeekZe", and after a little bit of research I discovered some useful information as shown below.


D's Decorated Name Layout
Pulling fv()'s "D13financial_dll2fvFeeeekZe" Decorated Name apart, we find that:
  1. "D" is a constant, meaning it was compiled in D
  2. "13" is the length of the string that follows it.
  3. "financial_dll" the name of the DLL in the case we compiled it in.
  4. "2" the length of the string that follows it.
  5. "fv" the name of the exported free function.
  6. "F" is a constant, meaning parameter types follow.
  7. "eeeek" are the parameter types matching the chart below.
    "e" = real, "e" = real, "e" = real, "e" = real, and "k" = uint
  8. "Z" is a constant, meaning the return data type follows.
  9. "e" is the return data type, which is a "real"
D's Decorated Name Datatypes

5) So what can be done with this information?

  • You could edit the .def file's EXPORTS section and add a line like fv=D13financial_dll2fvFeeeekZe and now the "Dependency Walker" would see "fv" in the function column.

  • You could create D loader applications which uses the D DLL's functions, without having the original D source code. (Of course, it would be great to have a help file of what the functions do, and the kind of data needed for their parameters (like dollar amount, or percentage, or etc).

  • You could create an application that used DLLs as plugins, where the name of the DLL could be placed in a INI and as long as it's function names and parameters remained the same to match the interface...you could extend the app. (Afterall, each function would have a unique name because of its DLL name was add as part of the function's full name)
Mars: fourth Rock from the Sun.