www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Problem calling a function with a '...' parameter in a DLL

reply David L. Davis <SpottedTiger yahoo.com> writes:
In adding functions to my Financial project, and ran along a problem using a
"..." parameter in a Windows' DLL. The function real npv( in real rRate, ... )
works fine in a .exe build, but not as a exported function in a DLL build. So I
was wondering, if any one else has ran across this problem, and that maybe
there's a better to do this...or is this an error in which case I should report
this a an error to Walter?

Many thanks in advance! :))

Below is the command-line used to compile and run the test code, there aren't
any errors displaying...but the npv() function returns a zero. Also I've added
all the test code (npv.d, npv.def, and loader.d) below.

Command-line: Compiling and running the test code below
-------------------------------------------------------
C:\dmd>bin\dmd npv.d npv.def
C:\dmd\bin\..\..\dm\bin\link.exe npv,,,user32+kernel32,npv.def/noi;

C:\dmd>bin\dmd loader.d
C:\dmd\bin\..\..\dm\bin\link.exe loader,,,user32+kernel32/noi;

C:\dmd>loader
sLibName="C:\dmd\npv.dll", hLibWithDLL=268435456
"C:\dmd\npv.dll" is loaded

npv's dll hex addry=10003060, 
Testing npv( 0.1, -10_000, 3_000, 4_200, 6_800 )= 0.00, ans=$1,188.44

sln's dll hex addry=100033AC, 
Testing sln( 30000, 7500, 10 )=2250.00, ans=$2,250.00

"C:\dmd\npv.dll" is unloaded

C:\dmd>

# // -- npv.d starts --
# // npv.d - npv.dll test function call with a "..." parameter
# // To compile: C:\dmd>bin\dmd npv.d npv.def
# // Creates npv.dll
# private import std.math;
# private import std.c.windows.windows;
# 
# 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;
#     }
#
#     return true;
# }
#
# /+
#  ' NPV - Net Present Value. 
#  ' -------------------------------------------
#  ' Excel/VBA: npv( Rate, Value1, Value2, ... )
#  +/
# extern( D )
# export real npv( in real rRate, ... )
# {
#     real[] rValues;
#     real   rSum = 0.0;
#     uint   uiy;
#
#     rValues.length = _arguments.length;
#
#     for ( uint uix = 0; uix < _arguments.length; uix++)
#     {
#         if ( _arguments[ uix ] == typeid( real ) )
#         {
#             rValues[ uix ] = *cast( real * )_argptr;
#             _argptr += real.sizeof;
#         }
#         else if ( _arguments[ uix ] == typeid( double ) )
#        {
#             rValues[ uix ] = *cast( double * )_argptr;
#             _argptr += double.sizeof;
#         }
#         else if ( _arguments[ uix ] == typeid( float ) )
#         {
#             rValues[ uix ] = *cast( float * )_argptr;
#             _argptr += float.sizeof;
#         }
#         else if ( _arguments[ uix ] == typeid( long ) )
#         {
#             rValues[ uix ] = *cast( long * )_argptr;
#             _argptr += long.sizeof;
#         }
#         else if ( _arguments[ uix ] == typeid( int ) )
#         {
#             rValues[ uix ] = *cast( int * )_argptr;
#             _argptr += int.sizeof;
#         }
#         else if ( _arguments[ uix ] == typeid( ulong ) )
#         {
#             rValues[ uix ] = *cast( ulong * )_argptr;
#             _argptr += ulong.sizeof;
#         }
#         else if ( _arguments[ uix ] == typeid( uint ) )
#         {
#             rValues[ uix ] = *cast( uint * )_argptr;
#             _argptr += uint.sizeof;
#         }
#     }
#
#     uiy  = rValues.length - 1;
#     rSum = 0.0;
#    
#     for ( uint uix = 0; uix < rValues.length; uix++ )
#     {
#         rSum += ( rValues[ uix ] / 
#                 std.math.pow( 1 + rRate, rValues.length - uiy ) );
#         uiy--;
#     }
#    
#     return rSum;
#
# } // end real npv( in real, ... )
#
# /+
#  ' SLN - Straight-Line Depreciation.
#  ' --------------------------------------
#  ' Excel/VBA: sln( Cost, Salvage, Life ) 
#  +/
# extern( D )
# export real sln   
# ( 
#     in real rCost, 
#     in real rSalvage, 
#     in real rLife
# )
# {
#     return ( rCost - rSalvage ) / rLife; 
#     
# } // end sln( in real, in real, in real )
# // -- npv.d ends --

# ; -- npv.def starts --
# LIBRARY      npv
# DESCRIPTION  'test def for the npv call in a DLL'
#
# EXETYPE      NT
# SUBSYSTEM    WINDOWS
# CODE         PRELOAD DISCARDABLE
# DATA         PRELOAD SINGLE
#
# EXPORTS     
# ; -- npv.def ends --

# // -- loader.d starts --
# // loader.d - DLL Loader Code
# // To compile: C:\dmd>bin\dmd loader.d
# // Creates loader.exe
# import std.stdio;
# import std.c.windows.windows;
#
# typedef real ( *pfn_npv )( in real, ... );
# typedef real ( *pfn_sln )( in real, in real, in real );
#
# int main( in char[][] args )
# {
#     HINSTANCE hLibWinDLL = null; 
#     char[]    sLibName   = "";  //r"C:\dmd\npv.dll";
#     char[]    sPath      = "";
#
#     /+
#      ' Set sPath to the Drive and Directory path of 
#      ' the executeable that is running.
#      '
#      ' (for example: if args[ 0 ] == "C:\dmd\loader.exe" 
#      '  then sPath == r"C:\dmd")
#      +/
#     sPath = args[0][ 0 .. std.string.rfind( args[ 0 ], r"\" ) ].dup;
#     sLibName = sPath ~ r"\npv.dll";
#
#     hLibWinDLL = LoadLibraryA( std.string.toStringz( sLibName ) );
#     writefln("sLibName=\"%s\", hLibWithDLL=%d", 
#               sLibName, cast(int)hLibWinDLL );
#     
#     if ( hLibWinDLL <= cast(HINSTANCE)0)
#     {
#         writefln( "\"%s\" not found!", sLibName );
#         hLibWinDLL = null;
#
#         return -1;
#     } 
#      
#     writefln("\"%s\" is loaded", sLibName );
#    
#     pfn_npv npv = 
#         cast(pfn_npv)GetProcAddress( hLibWinDLL, "D3npv3npvFeYe" ); 
#     writefln( "npv's dll hex addry=%X, 
#     Testing npv( 0.1, -10_000, 3_000, 4_200, 6_800 )=%5.2f, ans=$1,188.44", 
#             cast(long)npv, npv( 0.1, -10_000, 3_000, 4_200, 6_800 ) );
#    
#     pfn_sln sln = 
#        cast(pfn_sln)GetProcAddress( hLibWinDLL, "D3npv3slnFeeeZe" ); 
#     writefln( "sln's dll hex addry=%X, 
#     Testing sln( 30000, 7500, 10 )=%5.2f, ans=$2,250.00", 
#              cast(long)sln, sln( 30000, 7500, 10 ) );
#
#     writefln("\"%s\" is unloaded", sLibName );
#    
#     FreeLibrary( hLibWinDLL );
#    
#     return 0;
#
# } // end int main()  
# // -- loader.d ends --

David L.

-------------------------------------------------------------------
"Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
Dec 10 2004
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
David L. Davis wrote:
 In adding functions to my Financial project, and ran along a problem using a
 "..." parameter in a Windows' DLL. The function real npv( in real rRate, ... )
 works fine in a .exe build, but not as a exported function in a DLL build. So I
 was wondering, if any one else has ran across this problem, and that maybe
 there's a better to do this...or is this an error in which case I should report
 this a an error to Walter?
 
 Many thanks in advance! :))

This is just a shot in the dark, since I have *0* DLL experience. Maybe the code in the DLL uses different typeid() data than the executable which links to it? I would try putting a final "else" block in your function, which says, "I don't recognize the type, this is an error."
Dec 10 2004
parent reply David L. Davis <SpottedTiger yahoo.com> writes:
In article <cpclti$1uue$1 digitaldaemon.com>, Russ Lewis says...
David L. Davis wrote:
 In adding functions to my Financial project, and ran along a problem using a
 "..." parameter in a Windows' DLL. The function real npv( in real rRate, ... )
 works fine in a .exe build, but not as a exported function in a DLL build. So I
 was wondering, if any one else has ran across this problem, and that maybe
 there's a better to do this...or is this an error in which case I should report
 this a an error to Walter?
 
 Many thanks in advance! :))

This is just a shot in the dark, since I have *0* DLL experience. Maybe the code in the DLL uses different typeid() data than the executable which links to it? I would try putting a final "else" block in your function, which says, "I don't recognize the type, this is an error."

with a message, and I can clearly see that it's got the number of parameters being passed in right, but somehow the typeid() is unknown / wrong. For now I'll just use a real[] array for the DLL build, but it would've been nice to have a bit more feed back from the forum. I was really hoping for more help on this "..." parameter subject, than what can be found in the DigitalMars D html help files. ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
Dec 11 2004
parent reply Georg Wrede <Georg_member pathlink.com> writes:
In article <cpfobd$fbc$1 digitaldaemon.com>, David L. Davis says...
bit more feed back from the forum. I was really hoping for more help on this
"..." parameter subject, than what can be found in the DigitalMars D html help
files. 

Well, this is an exceptional time for D. "Real Soon Now" version 1.0 is coming out. That means Walter is (my condolences to his Family) over- worked, most of the other Gurus are busy fixing, suggesting, or creating least-lines-proofs of bugs -- not to mention that nobody has even started to ponder over updating the existing documentation to a form suitable for a Release! My bet is, 2 months after D 1.0 is out, this forum might really be the place to ask things. But definitely not before that.
Dec 11 2004
parent David L. Davis <SpottedTiger yahoo.com> writes:
In article <cpfu29$jmr$1 digitaldaemon.com>, Georg Wrede says...
In article <cpfobd$fbc$1 digitaldaemon.com>, David L. Davis says...
bit more feed back from the forum. I was really hoping for more help on this
"..." parameter subject, than what can be found in the DigitalMars D html help
files. 

Well, this is an exceptional time for D. "Real Soon Now" version 1.0 is coming out. That means Walter is (my condolences to his Family) over- worked, most of the other Gurus are busy fixing, suggesting, or creating least-lines-proofs of bugs -- not to mention that nobody has even started to ponder over updating the existing documentation to a form suitable for a Release! My bet is, 2 months after D 1.0 is out, this forum might really be the place to ask things. But definitely not before that.

Georg Wrede: Thanks for the reply. Yeah, I agree with you that this is a great time with D v1.0 just around the corner to be programming in D, and that everyone here has been pretty busy. I too, feel for Walter...he's been working pretty hard these past few years on the D compiler / Phobos runtime library. Again thanks for the reply. David L. ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
Dec 11 2004