Function DllCall() Foundation

Calls a DLL function dynamically at runtime. The function is deprecated. Use the EXTERN command instead.

Syntax
DllCall( <cDllName>|<nDllHandle>, [<nCallingConv>] , ;
        <cFuncName>|<nOrdinal>  [, <xParam,...>] ) --> xReturn
Parameters
<cDllName>
<cDllName> is a character string with the name of the DLL file that contains the function <cFuncName>. The file name must be specified when the DLL is not yet loaded (refer to DllLoad() ).
<nDllHandle>
Instead of a file name, the numeric handle <nDllHandle> of an already loaded DLL can be passed.
<nCallingConv>
A #define constant from the following table can be used for <nCallingConv>. It specifies the calling convention to be used for the DLL function.
Constants for the calling convention of DLL functions
Constant Description
DLL_CDECL C calling convention
DLL_OSAPI Calling convention for the operating system API
DLL_STDCALL Standard for the Windows 32bit API
DLL_SYSTEM Standard for the OS/2 API
DLL_XPPCALL *) Calling convention for Xbase++ DLLs
  1. Default
A calling convention constant can be combined with a calling mode constant using the '+' - operator, except DLL_XPPCALL:
Constants for calling mode
Constant Description
DLL_CALLMODE_NORMAL *) Fastest mode, original parameters passed
DLL_CALLMODE_COPY Safest mode, callee uses a copy of passed parameters
DLL_CALLMODE_RESTOREFPU Caller restores FPU control word
  1. Default
<cFuncName>
<FunctionName> designates the name of the DLL function to be executed. A function name must consist of alphanumeric characters.
<nOrdinal>
As an alternative, the numeric ordinal <nOrdinal> of the DLL function may be passed. This avoids a lookup of the function name in the symbol table of the DLL.
<xParam>
Optionally, <xParam> is a comma-separated list of parameters that are passed as arguments to the DLL function <cFuncName>. The arguments must have the correct data types as required by the called function. If a value of an illegal data type is passed to a non Xbase++ DLL, DllCall() will generate a runtime error. The exception in this case is the value NIL. It is accepted and passed as the numeric value 0 to the DLL function.
Return

DllCall() returns the return value of the executed DLL function. If the DLL complies with the Xbase++ calling convention, the value may be of any Xbase++ data type. Otherwise, the return value is of numeric data type.

In case of a runtime error, the value substituted by the error handler is returned.

Description

The function DllCall() executes a function which is contained in an external 32bit DLL file. When the DLL is not loaded, an implicit call to DllLoad() occurs prior to calling the DLL function. The DLL remains loaded.

DllCall() is able to call functions from DLLs which comply with different calling conventions. Functions in system DLLs (API functions) use a different calling convention than those in Xbase++ DLLs, for example. Many producers of DLLs use the C calling convention which is supported by DllCall() as well.

External DLLs

When parameters are passed to functions which do not comply with the Xbase++ calling convention, only values of the data type "character", "numeric" or "logical" can be used. They are converted to C data types as is shown in the following table:

Conversion of data types to C
Data type Passing as value Passing by reference
Character const *char *char
Numeric long *long
FLOAT is converted to unsigned *unsigned long
Logical long *long
NIL long with value zero n/a

The range of the Xbase++ data type Numeric is larger than the C data type unsigned long (0..0xFFFFFFFF). If the passed value is out of the unsigned long range, a runtime error is posted to indicate loss of data. NIL will be accepted and converted to a long with the value of zero. Passing a reference to a variable containing NIL is not possible and will cause a runtime error.

If the called API needs an undefined amount of time and the default calling mode DLL_CALLMODE_NORMAL is used, the runtime system is hindered by this call and cannot release garbage memory while the API is called. To avoid this, use the calling mode DLL_CALLMODE_COPY. It causes DllCall() to copy all passed parameters (which is slower) but unblocks the Xbase++ memory system.

Xbase++ DLLs

If a DLL file is created by Xbase++, all data types may be passed to a DLL function and can be processed by it. Executing a DLL function from an Xbase++ DLL is possible using DllCall(). However, it is recommended to use the macro-operator in this case, since it provides the fastest possible way to call a function contained in a dynamically loaded Xbase++ DLL. The following expression is used for that purpose:

&(<cFuncName>) ( [<xParam,...>] ) 

The macro-operator searches for the function name in the symbol table, the execution-operator () calls this function and passes the optional parameters<xParam> to it. If a DLL does not comply with the Xbase++ calling convention, this is not possible.

When the Xbase++ DLL is loaded with a function prefix specified, the character expression <cFuncName> must contain both prefix and function name. However, this is not necessary if the function is called via DllCall(). In that case, the prefix of the DLL will implicitly be retrieved and concatenated with the parameter <cFuncName> to the resulting function name before the call is executed.

Examples
Calling functions of Xbase++ DLLs

// The example demonstrates various possibilities of how to 
// dynamically call functions contained in Xbase++ DLLs. 

PROCEDURE Main 
   LOCAL nDll, cCall, i, p1 := 100, p2 := Space(10) 

   // Shortest syntactical notation: when the DLL is 
   // not loaded, it is implicitly loaded and remains 
   // loaded 

   ? DllCall( "MYXPP.DLL",, "MyFunction", p1, @p2 ) 

   // Normal usage: load the DLL and assign its 
   // handle to a LOCAL variable for subsequent calls 

   nDll := DllLoad( "MYXPP.DLL") 

   IF nDll <> 0 

      // Call via macro-operator (fastest call) 
      ? &("MyFunction")( p1, @p2 ) 

      // Call via DllCall() 
      ? DllCall( nDll,, "MyFunction", p1, @p2 ) 

      // Multiple calls using a call-template 
      cCall := DllPrepareCall( nDll,, "MyFunction") 
      FOR i:=1 TO p1 
         ? DllExecuteCall( cCall, i, @p2 ) 
      NEXT 

      // Release DLL 
      DllUnload( nDll) 

   ENDIF 
RETURN 
Calling a system API function

// A function of the Windows system API is executed in this example. 
// The function is contained in the file KERNEL32.DLL. It changes 
// the volume label of a disk drive. 

#include "Dll.ch" 

PROCEDURE Main 
   LOCAL nDll, cCall 

   // Shortest syntactical notation 
   ? DllCall( "KERNEL32.DLL"   , DLL_STDCALL, ; 
              "SetVolumeLabelA", "D:", "MY_VOLUME") 

   // The normal way 
   nDll := DllLoad( "KERNEL32.DLL" ) 

   IF nDll <> 0 
      // Call the API function 
      ? DllCall( nDll, DLL_STDCALL, ; 
                 "SetVolumeLabelA", "D:", "MY_VOLUME") 

      // Release DLL 
      DllUnload( nDll ) 
   ENDIF 

RETURN 
Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.