Thread overview
Problem calling a function with a '...' parameter in a DLL
Dec 10, 2004
David L. Davis
Dec 10, 2004
Russ Lewis
Dec 11, 2004
David L. Davis
Dec 11, 2004
Georg Wrede
Dec 12, 2004
David L. Davis
December 10, 2004
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!"
December 10, 2004
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."

December 11, 2004
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."
>
Russ Lewis: Thanks for your reply. I took your suggestion and added a final else 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!"
December 11, 2004
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.


December 12, 2004
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!"