>> Rodney Roberts IS & Education Professional Homepage   >> Programming Tutorials And Downloads






Science makes it known,
Engineering makes it work,
Art makes it beautiful.




 

Using a simple D program to call Pascal .dll - D files

This page discusses developing D main programs calling functions and procedures in a Pascal dynamic link Library (.dll). Many of the same restrictions of D calling FORTRAN also apply to D calling Pascal :
- use extern (Pascal) {...}1 to declare the external functions/procedures, their return data type (if any), and their passed arguments' data types;
- external Pascal function/procedure identifier names must be in upper case letters;
- arguments are passed in reverse order

The focus is on a simple Win32 Command Prompt D program calling financial functions in a Pascal .dll. Two source files were used - dfinc.d (D main program) and finance.pas (Object Pascal compiled into Library finance.dll). The DMD D and Free Pascal compilers were used.


Sample D Code

Below is a listing of the D main program (dfinc.d) used to call three Pascal functions CMPT_PV (...) (compute present value), CMPT_FV (...) (compute future value), and NPVPROJCT (...) (project net present value) in Pascal library finance.dll - compiled from source file finance.pas. Each of the Pascal functions returns a single 4 byte float value (as indicated in the example below by float preceding each of the function names).

(Define/Pass data as short and float to match Pascal's smallint and single data types - see Variable Storage Compatibility and Equivalency;
D's ref serves the same purpose as Pascal's VAR - pass by reference)
import std.stdio;

extern (Pascal)
{
	float CMPT_PV (ref short, ref short, ref float, ref float);
	float CMPT_FV (ref short, ref short, ref float, ref float);
	float NPVPROJCT (ref short, ref short, ref float[200], ref float[200], ref float, ref float);
}

int main(string[] args)
{
	float[200] ft, pt;
	float a0, k, NPV, FV;
	short n, m, iErr;
	
	ft[] = pt[] = 0.0;
	k = 0.06;
	FV = 100.0;
	m = 1;
	n = 5;
	printf (" Present Value CMPT_PV (n, m, k, FV) \n");
	NPV = CMPT_PV (n, m, k, FV);
	printf ("  NPV:%f \n", NPV);
	NPV = 100.0;
	printf (" Future Value CMPT_FV (n, m, k, NPV) \n");
	FV = CMPT_FV (n, m, k, NPV);
	printf ("  FV:%f \n", FV);
	a0 = -9000.0;
	k = 0.0;
	ft[0] = 6000.0;
	ft[1] = 4000.0;
	ft[2] = 3000.0;
	ft[3] = 2000.0;
	pt[0] = 0.1;
	pt[1] = 0.1;
	pt[2] = 0.1;
	pt[3] = 0.1;
	n = 4;
	NPV = NPVPROJCT (iErr, n, pt, ft, k, a0);
	printf (" NPVprojct (iErr, n, pt, ft, k, a0) status:%d \n", iErr);
	printf ("  NPV:%f \n", NPV);
	return (0);
    
(The screen shot shown on financial functions in a Pascal .dll was taken during initial prototyping and only shows the NPVPROJCT output line; as can be seen in the D program above, added CMPT_PV and CMPT_PV output as well)


extern (...) {...}

The extern (Pascal) {...} statement specifies the external functions/procedures, their return data type (if any), and the passed data types (and it is the only linkage type that produced a clean compile).

It appears that extern (Pascal) {...} (could be wrong) is the only linkage type that at least works with the stdcall convention (D is very cdecl convention oriented; while not recommended, it has been my experience that you can occasionally use cdecl calling program to call a stdcall subprogram; as an alternative, could include in the same Pascal .dll "wrapper" functions declared as cdecl which call the stdcall functions, but this defeats the condition of a licensed library whose source code is unavailable mentioned elsewhere).

One side effect of using extern (Pascal) {...} is that the arguments be Pushed/Popped to/from the stack in reverse order - requiring the parameters passed to the external Pascal procedures be in reverse order as defined in the Pascal procedure.



Call by Reference vs. Call by Value

Unlike FORTRAN, Pascal does not requires its parameters to be passed By Reference by default; can be passed By Value instead. As an example, consider the following Pascal procedure (which has been successfully called by a D windows program, a Pascal command console program, and a Pascal Windows program) defined by2:
//--------------------------------------------------------------------------
// Main Procedure (capitalized name so procedure can be called by D)
//    hWindow      : if called by Windows program, the window handle;
//                   otherwise nil or 0
//      ix         : smallint array, x coordinates
//                 : ix[nPts-1] = gene.x, ix[nPts] = gene.newx
//      iy         : smallint array, y coordinates
//                 : iy[nPts-1] = gene.y, ix[nPts] = gene.newy
//                 : draw line segment between (ix[nPts-1], iy[nPts-1])
//                 : and (ix[nPts], iy[nPts])
//     alpha       :
//   treeHeight    : desired height of tree (gene.height; initial gene.blength)
//   branchAngle   : angle of branches (gene.angle)
//  branchLength   : desired change of branch length (gene.length)
// biQuadSymtryInd : 2 sided or 4 sided symmetry indicator
//      nPts       : number of points generated (2*line segments)
//      iErr       : returned error code
  PROCEDURE DAWKINS (hWindow, hEditOutput : HWnd;
                 VAR ix, iy : iXYZ_array;
                 VAR alpha, treeHeight, branchAngle,
                     branchLength,
                     biQuadSymtryInd, nPts, iErr : smallint); stdcall;
    
This is defined to be called from D using the following extern declaration:
extern (Pascal)
{
	void DAWKINS (ref short, ref short, ref short, ref short, ref short, ref short, ref short, 
			ref short[NRI], ref short[NRI], HWND, HWND);
}
    
(void indicates this is a procedure - does not return a value like a function)

DAWKINS (...) receives hWindow and hEditOutput by value, all other parameters by reference (NRI is a constant defined in D module dnrprocs and Pascal include file genetyp.inc). DAWKINS (...) is called from a D program with the statement:
DAWKINS (iErr, n, biQuadSymtryInd, branchLength, branchAngle, treeHeight, alpha, iy, ix, null, hWnd);
    
This would be called from Pascal as:
DAWKINS (hWindow, hEditOutput, ix, iy, alpha, treeHeight, 
         branchAngle, branchLength, biQuadSymtryInd, nPts, iErr);
    
The Window Handles are passed by value to DAWKINS (...), so DAWKINS (...) can display a copyright notice in a Windows Message box (the biomorphs produced by DAWKINS (...) are plotted as lines by function plotLines2(...) in module dnrprocs). As a reminder, the parameters are passed to the external Pascal procedure in reverse order when called from D.



Compiling and Linking

Compiling and linking is very similar to the D calling FORTRAN tutorials. Digital Mars compilers use a different object and import library file format (Intel 32 bit OMF object and library file format) than Microsoft's 32 bit tools (the .dll's produced are compatible). The DMD compiler/linker requires the external procedures' import libraries (*.lib), not dynamic link libraries (*.dll), for linking. After compiling and linking the external procedures into a .dll, will need to use a DMD utility to create the import library from the dynamic link library.

After compiling finance.pas, use the Digital Mars implib utility (file bup.zip) to create a DMD compatible finance.lib import library. The DMD D compiler and linker uses finance.lib to create the dfinc.exe executable. To build finance.lib, type
implib finance.lib finance.dll
	
in a MS-DOS command prompt.

The command
dmd dfinc.d finance.lib
compiles dfinc.d, links in the finance.lib import library, and creates dfinc.exe.

To execute dfinc.exe, in a MS-DOS command prompt simply type dfinc.



1. In the statement extern (Pascal) {...}, Pascal is the LinkageType. Other available D LinkageTypes are: C, C++, D, Windows, and System. Judging by the compiler behavior, using these other LinkageTypes (with the possible exception of C - see Pascal calling D and FORTRAN footnotes) seems to cause some sort of name mangling.
2. PROCEDURE DAWKINS is a part of a major rewrite of Dawkins8.pas (MS-DOS program to Windows .dll) from
Rietman, Edward (1994). Genesis Redux: Experiments Creating Artificial Life. Windcrest.

Any and all © copyrights, ™ trademarks, or other intellectual property (IP) mentioned here are the property of their respective owners.

Feel free to use any of the above in your project (without violating any intellectual property rights); please give credit (same idea as Copyleft).

Page best viewed with Mozilla FireFox 3.6.13 (or higher). Avoid Smart Applications Speed Browser.

Web hosting provided by  
Award Space Web Hosting Free Web Hosting X10hosting Free Web Hosting. , &  Gigarocket Web Hosting


>> Rodney Roberts IS & Education Professional Homepage   >> Programming Tutorials And Downloads