Command EXTERN Foundation

Declares a function in a non-Xbase++ DLL.

Syntax
[STATIC] EXTERN [<CallingConvention>] [<Type>]                     ;
                <FunctionName>( [[@] <Parameter> AS <Type>, ...] ) ;
                IN <Library> [NAME <ExportedName>]
Parameters
STATIC
The STATIC clause limits the visibility of a DLL function to the PRG file in which the EXTERN command is declared. Calling the DLL function from another PRG causes a link error.
<CallingConvention>
The calling convention to be used for the DLL function. One of the following key words may be specified.
Calling conventions of DLL functions
Key word Description
CDECL C calling convention
STDCALL *) Standard for the Windows 32bit API
  1. Default value
<Type>
The data type of the return value of the DLL function. This parameter is optional. It may set to one of the following key words. Omit this parameter if the DLL function does not return a value.
Return type of DLL functions
Key word Description Corresponding C/SDK types (examples)
BOOL8 8 bit boolean bool
BOOL 32 bit boolean BOOL
SHORT 16 bit integer SHORT, short int
USHORT Unsigned 16 bit integer USHORT, unsigned short
INTEGER 32 bit integer int
LONG 32 bit integer INT32
UINTEGER Unsigned 32 bit integer DWORD, LPDWORD, LPARAM, PVOID, HANDLE, HWND, UINT, ULONG
INTEGER64 64 bit integer INT64
UINTEGER64 Unsigned 64 bit integer UINT64, ULONG64, DWORD64
SINGLE 32 bit floating point FLOAT32, float
DOUBLE 64 bit floating point FLOAT64
STRING Character string LPSTR, PSZ, char, char*
IDISPATCH COM/ActiveX object (IDispatch) IDispatch*
Note regarding STRING: A NULL pointer is returned as the value NIL.
<FunctionName>
The name of the function to be declared via EXTERN. In most cases, this is the same as the name of the DLL function to be executed. See the <ExportedName> parameter for casing rules and further information.
[@] <Parameter> AS <Type>
Specifies the name and the data type of the parameters passed to the DLL function. The data type of the parameters expected by the DLL function must be specified following the keyword AS using one of the key words in the table below.
Parameters which should be passed by reference to the DLL function must be prefixed with the reference operator (@) in the parameter list of the EXTERN command. In addition, the reference operator must be included before the corresponding variable in the calling function. If the reference operator is not specified, the corresponding parameter is passed by value.
Mapping to Xbase++ types:
Integer and floating point return and parameter values of DLL functions are mapped to the corresponding Xbase++ native type. The same goes for strings and boolean values. For these, ValType() returns the values "N", "C" and "L", respectively.
- AutomationObjects (IDispatch): Input values in parameters of type IDISPATCH must be objects of a class derived from AutomationObject. Output values are instances of class AutomationObject. NIL as an input value denotes "no input".
- Callbacks: Input values in parameters of type CALLBACK or ACALLBACK must be objects of the class DllCallback().
- STRUCTURE: STRUCTURE instances can be passed as-is to a DLL or API function, provided the corresponding parameter is declared AS STRUCTURE. Structure parameters declared are type-safe, meaning is it not possible to assign a value of a different data type. Attempting to do so yields a runtime error. See the LOCAL statement for further details on creating structure instances.
Parameter types of DLL functions
Key word Description Corresponding C/SDK types (examples)
BOOL8 8 bit boolean bool
BOOL 32 bit boolean BOOL
SHORT 16 bit integer SHORT, short int
USHORT Unsigned 16 bit integer USHORT, unsigned short
INTEGER 32 bit integer int
LONG 32 bit integer INT32
UINTEGER Unsigned 32 bit integer DWORD, LPDWORD, LPARAM, PVOID, HANDLE, HWND, UINT, ULONG
INTEGER64 64 bit integer INT64
UINTEGER64 Unsigned 64 bit integer UINT64, ULONG64, DWORD64
SINGLE 32 bit floating point FLOAT32, float
DOUBLE 64 bit floating point FLOAT64
STRING Character string LPSTR, PSZ, char, char*
IDISPATCH COM/ActiveX object (IDispatch) IDispatch*
CALLBACK Callback function WNDENUMPROC, DLGPROC
ACALLBACK Asynchronous callback function WNDPROC, HOOKPROC
XPPVALUE An arbitrary Xbase++ value (not applicable)
STRUCTURE Memory structure RECT, PROCESS_INFORMATION, typedef struct
Notes:
- Value NIL: NIL can be passed as a value for all parameter types. It corresponds to the numeric value 0 or a NULL pointer.
- STRING: A pointer to the address of a character string may be passed as a numeric value.
<Library>
Specifies the name of the DLL file that contains the function specified in <FuncName>. If the constant WIN32API from dll.ch is specified, the function is automatically searched for in the following Win32 API libraries: Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll and Advapi32.dll.
<ExportedName>
<ExportedName> specifies the name of the exported DLL function to be executed via EXTERN. In most cases, this is the same as the <FunctionName>, in which case the <ExportedName> parameter can be omitted. In some cases, however, it may be desirable to declare a function whose name differs from the DLL function name. In this case, the <ExportedName> parameter must be used to specify the DLL function to execute when calling <FunctionName>.
In any case, the name of the DLL function is case-sensitive and must be specified exactly as it appears in the DLL's export table. A runtime error results if the function cannot be found in the DLL.
Note that many Win32 API functions exist in two flavors: an ANSI and a Unicode variant. The EXTERN command automatically respects the system's current charset setting when attempting to find the function in the DLL. In applications using an OEM or ANSI character set, an "A" is automatically appended to the name of the DLL function if the function cannot be found using <ExportedName>. This allows using the generic API name (eg. MessageBox()) instead of the character set-specific variant (MessageBoxA()).
Description

The EXTERN command is used for calling functions in non-Xbase++ DLLs. The command allows the utilization of functions within an Xbase++ application which are not known by the linker at the time when the EXE file is created. This includes operating system APIs as well as functions contained in 3rd party DLLs.

The command creates an Xbase++ wrapper function which has the same name as the function contained in the DLL file. This allows the DLL function to be called on the Xbase++ language level using a symbolic identifier. Because the EXTERN command creates a new function, it must appear outside of any existing function bodies.

When the Xbase++ function is called in a program, it first loads the DLL and then executes the DLL function of the same name. If parameters are declared in the EXTERN command, the Xbase++ function passes the received arguments to the DLL function. All parameters that are declared with a preceeding reference operator (@) are passed by reference to the DLL function. When the DLL function finishes, the DLL is unloaded and the Xbase++ function returns the return value of the DLL function.

When you use DLLs that are not created by Xbase++ you require a detailed knowledge about the interface of the called DLL function, the calling convention and parameter usage. Consult the documentation of the DLL function for obtaining this information. Incorrect usage may result in erratic behavior and application crashes.

Examples
Using the Win32 API for getting a window's title
// The example uses a Window API functions for reading the 
// title of the application window. 

#include "dll.ch" 

// Declare Win32 API for getting the title of an OS-level 
// window. Note the reference (out) parameter <cTxt>. 
// int WINAPI GetWindowText( HWND hWnd, LPTSTR lpString, int nMaxCount ); 
EXTERN LONG GetWindowText( nHWND AS LONG, @cTxt AS STRING, nCnt AS LONG ) IN WIN32API 

/// <summary> 
/// The application's main procedure 
/// </summary> 
PROCEDURE Main() 
LOCAL cTitle := Space( 255 ) 

 GetWindowText( SetAppWindow():getHWND(), @cTitle, 255 ) 
 ? "Window Title: " + cTitle 
 WAIT 
RETURN 
Using the Win32 API for getting the open windows
// The example uses Windows API functions for reading the 
// titles of the windows currently visible on the desktop. 

#include "dll.ch" 

// Declare the Win32 API for enumerating existing windows. The API 
// expects a callback function in the first, and an application-supplied 
// value in the second parameter. The second parameter is passed on to 
// the callback function. 
// BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam ); 
EXTERN BOOL EnumWindows( EnumProc AS CALLBACK, aParam AS XPPVALUE ) IN WIN32API 

// Declare Win32 APIs for getting the visible state and the caption 
// of an OS-level window. Note the reference (out) parameter <cTxt> 
// BOOL WINAPI IsWindowVisible( HWND hWnd ); 
EXTERN BOOL IsWindowVisible( nHWND AS LONG ) IN WIN32API 

// int WINAPI GetWindowText( HWND hWnd, LPTSTR lpString, int nMaxCount ); 
EXTERN LONG GetWindowText( nHWND AS LONG, @cTxt AS STRING, nCnt AS LONG ) IN WIN32API 

/// <summary> 
/// The application's main procedure 
/// </summary> 
PROCEDURE Main() 
  LOCAL aWins 

  DevPos( 2,5 ) 
  DevOut( "Visible Windows:" ) 

  // 
  // Get an array with the titles of the visible windows and display 
  // them on the screen 
  // 
  aWins := ListWindowHandles() 
  AChoice( 5,5,MaxRow()-5,MaxCol()-5, aWins ) 
RETURN 


/// <summary> 
/// Get the windows which are currently open on the desktop. Return 
/// is an array with the window titles. 
/// </summary> 
FUNCTION ListWindowHandles() 
LOCAL oCallback 
LOCAL aRet := {} 

  // 
  // Create a callback object for the callback function expected by 
  // the EnumWindows() Win32 API. This is a standard Xbase++ function 
  // which is called implicitly by the API. 
  // 
  oCallback := DLLCallBack():new( "EnumWindowProc",, DLL_TYPE_UINT32, DLL_TYPE_XPPVALUE ) 
  EnumWindows( oCallback, aRet ) 
RETURN aRet 


/// <summary> 
/// Xbase++ callback function to be executed by the EnumWindows() 
/// Win32 API. 
/// </summary> 
/// <param name="nHWND">The OS-level window handle</param> 
/// <param name="aWins">An array to be filled with window titles</param> 
/// <returns>1 to continue enumerating OS-level windows, 0 to cancel</returns> 
FUNCTION EnumWindowProc( nHWND, aWins ) 
LOCAL cTmp := Space( 255 ) 

  // Only visible windows should be listed 
  IF ! IsWindowVisible(nHWND) 
     RETURN 1 
  ENDIF 

  // Get the window's caption and add it to the title array 
  IF GetWindowText(nHWND, @cTmp, 255) == 0 
     RETURN 1 
  ENDIF 

  AAdd( aWins, RTrim(cTmp) ) 
RETURN 1 
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.