The CALL_EXTERNAL function calls a function in an external sharable object and returns a scalar value. Parameters can be passed by reference (the default) or by value.
CALL_EXTERNAL is supported under all operating systems supported by IDL, although there are system specific details of which you must be aware. This function requires no interface routines and is much simpler and easier to use than the LINKIMAGE procedure. However, CALL_EXTERNAL performs no checking of the type and number of parameters. Programming errors are likely to cause IDL to crash or to corrupt your data.
Note: Input and output actions should be performed within IDL code, using IDL’s built‑in input/output facilities, or by using the internal IDL_Message() function. Performing input or output from external code, especially to the user console or tty (e.g. using printf() or equivalent functionality in other languages to send text to stdout) may create errors or generate unexpected results.
CALL_EXTERNAL supports the IDL Portable Convention, a portable calling convention that works on all platforms. This convention passes two arguments to the called routine, an argument count (argc) and an array of arguments (argv).
CALL_EXTERNAL offers the Auto Glue feature, which can simplify use of the CALL_EXTERNAL portable convention if you have the appropriate C compiler installed on your system. Auto glue automatically writes the glue function required to convert the (argc, argv) arguments to the actual function call, then compiles and loads the glue function transparently. To have auto glue automatically write the glue function, but not compile it, use the WRITE_WRAPPER keyword.
The result of the CALL_EXTERNAL function is a scalar value returned by the external function. By default, this is a scalar long (32-bit) integer. This default can be changed by specifying one of the keywords described below that alter the result type.
Examples
See the section Using CALL_EXTERNAL() for examples.
Syntax
Result = CALL_EXTERNAL(Image, Entry [, P0, ..., PN-1] [, /ALL_VALUE] [, /B_VALUE | , /D_VALUE | , /F_VALUE | , /I_VALUE | , /L64_VALUE | , /S_VALUE | , /UI_VALUE | , /UL_VALUE | , /UL64_VALUE] [, /CDECL] [, RETURN_TYPE=value] [, /UNLOAD] [, VALUE=byte_array] [, WRITE_WRAPPER=wrapper_file] [, /AUTO_GLUE] [, CC=string] [, COMPILE_DIRECTORY=string] [, EXTRA_CFLAGS=string] [, EXTRA_LFLAGS=string] [, /IGNORE_EXISTING_GLUE] [, LD=string] [, /NOCLEANUP] [, /SHOW_ALL_OUTPUT] [, /VERBOSE] )
Return Value
This function calls a function in an external sharable object and returns a scalar value.
Arguments
Image
The name of the file, which must be a sharable library (UNIX), or DLL (Windows), which contains the routine to be called.
Entry
A string containing the name of the symbol in the library which is the entry point of the routine to be called.
P0, ..., PN-1
The parameters to be passed to the external routine. All array and structure arguments are passed by reference (address). The default is to also pass scalars by reference, but the ALL_VALUE or VALUE keywords can be used to pass them by value. Care must be taken to ensure that the type, structure, and passing mechanism of the parameters passed to the external routine match what it expects. There are some restrictions on data types that can be passed by value, and how IDL passes strings. Both issues discussed in further detail below.
Keywords
ALL_VALUE
Set this keyword to indicate that all parameters are passed by value. There are some restrictions on data types that should be considered when using this keyword, as discussed below.
B_VALUE
If set, this keyword indicates that the called function returns a byte value.
CDECL
The Microsoft Windows operating system has two distinct system defined standards that govern how routines pass arguments: stdcall, which is used by much of the operating system as well as languages such as Visual Basic, and cdecl, which is used widely for programming in the C language. These standards differ in how and when arguments are pushed and removed from the system stack. The standard used by a given function is determined when the function is compiled, and can usually be controlled by the programmer. If you call a function using the wrong standard (e.g. calling a stdcall function as if it were cdecl, or the reverse), you could get incorrect results, corrupted memory, or you could crash IDL. Unfortunately, there is no way for IDL to know which convention a given function uses; this information must be supplied by the user of CALL_EXTERNAL. If the CDECL keyword is present, IDL will use the cdecl convention to call the function. Otherwise, stdcall is used.
D_VALUE
If set, this keyword indicates that the called function returns a double-precision floating value.
F_VALUE
If set, this keyword indicates that the called function returns a single-precision floating value.
I_VALUE
If set, this keyword indicates that the called function returns an integer value.
L64_VALUE
If set, this keyword indicates that the called function returns a 64-bit integer value.
RETURN_TYPE
The type code to set the type of the result. See the description of the SIZE function for a list of the IDL type codes.
S_VALUE
If set, this keyword indicates that the called function returns a pointer to a null‑terminated string.
UI_VALUE
If set, this keyword indicates that the called function returns an unsigned integer value.
UL_VALUE
If set, this keyword indicates that the called function returns an unsigned long integer value.
UL64_VALUE
If set, this keyword indicates that the called function returns an unsigned 64-bit integer value.
UNLOAD
Normally, IDL keeps Image loaded in memory after the call to CALL_EXTERNAL completes. This is done for efficiency—loading a sharable object can be a slow operation. Setting the UNLOAD keyword will cause IDL to unload Image after the call to it is complete. This is useful if you are debugging code in Image, as it allows you to iterate on your code without having to exit IDL between tests. It can also be a good idea if you do not intend to make any subsequent calls to routines within Image.
If IDL is unable to unload the sharable object, it will issue an error to that effect. In addition to any operating system reported problem that might occur, IDL cannot perform the UNLOAD operation if the sharable library has been used for any other purpose in addition to CALL_EXTERNAL (e.g. LINKIMAGE).
VALUE
A byte array, with as many elements as there are optional parameters, indicating the method of parameter passing. Arrays are always passed by reference. If parameter Pi is a scalar, it is passed by reference if VALUE[i] is 0; and by value if it is non-zero. There are some restrictions on data types that should be considered when using this keyword, as discussed below.
WRITE_WRAPPER
If set, WRITE_WRAPPER supplies the name of a file for CALL_EXTERNAL to create containing the C function required to convert the (argc, argv) interface used by the CALL_EXTERNAL portable calling convention to the interface of the target function. If WRITE_WRAPPER is specified, CALL_EXTERNAL writes the specified file, but does not attempt to actually call the function specified by Entry. The result from CALL_EXTERNAL is an integer 0 in this case, and has no special meaning. Use of WRITE_WRAPPER implies the PORTABLE keyword.
Note: This is similar to Auto Glue only in that CALL_EXTERNAL writes a function on your behalf. Unlike Auto Glue, WRITE_WRAPPER does not attempt to compile the resulting function or to use it. You might want to use WRITE_WRAPPER to generate IDL interfaces for an external library in cases where you intend to combine the interfaces with other code or otherwise modify it before using it with IDL.
Auto Glue Keywords
Auto Glue, discussed in the section Auto Glue, offers a simplified way to use the CALL_EXTERNAL portable calling convention. The following keywords control its use. Many of these keywords correspond to the same keywords to the MAKE_DLL procedure, and are covered in more detail in the documentation for that routine.
AUTO_GLUE
Set this keyword to enable the CALL_EXTERNAL Auto Glue feature.
CC
If present, a template string to be used in generating the C compiler command(s) to compile the automatically generated glue function. For a more complete description of this keyword, see MAKE_DLL.
COMPILE_DIRECTORY
Specifies the directory to use for creating the necessary intermediate files and the final glue function sharable library. For a more complete description of this keyword, see MAKE_DLL.
EXTRA_CFLAGS
If present, a string supplying extra options to the command used to execute the C compiler. For a more complete description of this keyword, see MAKE_DLL.
EXTRA_LFLAGS
If present, a string supplying extra options to the command used to execute the linker. For a more complete description of this keyword, see MAKE_DLL.
IGNORE_EXISTING_GLUE
Normally, if Auto Glue finds a pre-existing glue function, it will use it without attempting to build it again. Set IGNORE_EXISTING_GLUE to override this caching behavior and force CALL_EXTERNAL to rebuild the glue function sharable library.
LD
If present, a template string to be used in generating the linker command to build the glue function sharable library. For a more complete description of this keyword, see MAKE_DLL.
NOCLEANUP
If set, CALL_EXTERNAL will not remove intermediate files generated in order to build the glue function sharable library after the library has been built. This keyword can be used to preserve information for debugging in case of error, or for additional information on how Auto Glue works. For a more complete description of this keyword, see MAKE_DLL.
SHOW_ALL_OUTPUT
Auto Glue normally produces no output unless an error prevents successful building of the glue function sharable library. Set SHOW_ALL_OUTPUT to see all output produced by the process of building the library. For a more complete description of this keyword, see MAKE_DLL.
VERBOSE
If set, VERBOSE causes CALL_EXTERNAL to issue informational messages as it carries out the task of locating, building, and executing the glue function. For a more complete description of this keyword, see MAKE_DLL.
String Parameters
IDL represents strings internally as IDL_STRING descriptors, which are defined in the C language as:
typedef struct {
unsigned short slen
unsigned short stype
char *s
} IDL_STRING
To pass a string by reference, IDL passes the address of its IDL_STRING descriptor. To pass a string by value the string pointer (the s field of the descriptor) is passed. Consider the following when manipulating IDL strings:
- Called code should treat the information in the passed IDL_STRING descriptor and the string itself as read-only, and should not modify these values.
- The slen field contains the length of the string without including the NULL termination that is required at the end of all C strings.
- The stype field is used internally by IDL to know keep track of how the memory for the string was obtained, and should be ignored by CALL_EXTERNAL users.
- s is the pointer to the actual C string represented by the descriptor. If the string is NULL, IDL represents it as a NULL (0) pointer, not as a pointer to an empty null terminated string. Hence, called code that expects a string pointer should check for a NULL pointer before dereferencing it.
These issues are detailed in The CALL_EXTERNAL Function.
Calling Convention
CALL_EXTERNAL uses the IDL Portable convention for calling user-supplied routines. The IDL Portable calling convention can be simplified by using the Auto Glue extension, described below.
The portable interface convention passes all arguments as elements of an array of C void pointers (void *). The C language prototype for a user function called this way looks like one of the following:
RET_TYPE xxx(int argc, void *argv[])
Where RET_TYPE is one of the following: UCHAR, short, IDL_UINT, IDL_LONG, IDL_ULONG, IDL_LONG64, IDL_ULONG64, float, double, or char *. The return type used must agree with the type assumed by CALL_EXTERNAL as specified via the keywords described above.
Argc is the number of arguments, and the vector argv contains the arguments themselves, one argument per element. Arguments passed by reference map directly to these (void *) pointers, and can be cast to the proper type and then dereferenced directly by the called function. Passing arguments by value is allowed, but since the values are passed in (void *) pointers, there are some limitations and restrictions on what is possible:
- Types that are larger than a pointer cannot be passed by value, and CALL_EXTERNAL will issue an error if this is attempted. This limitation applies only to the standard portable calling convention. Auto Glue does not have this limitation, and is able to pass such variables by value.
- Integer values can be easily passed by value. IDL widens any of the integer types to the C int type and they are then converted to a (void *) pointer using a C cast operation.
- There is no C language-defined conversion between pointers and floating point types, so IDL copies the data for the value directly into the pointer element. Although such values can be retrieved by the called routine with the correct C casting operations, this is inconvenient and error prone. It is best to pass non-integer data by reference.
Auto Glue
Auto Glue is an extension to the IDL Portable Calling Convention that makes it easier to use.
The portable calling convention requires your function to use the IDL defined (argc, argv) interface for passing arguments. However, functions not explicitly written for use with CALL_EXTERNAL may not have this interface. A common solution using the portable convention is for the IDL user to write a glue function that serves as an interface between IDL and the called function. The entire purpose of this glue function, which is usually very simple, is to convert the IDL (argc, argv) method of passing parameters to a form acceptable to the called function. Writing this wrapper function is easy for programmers who understand the C language, the system C compiler and linker, and how sharable libraries work on their target operating system. However, it is also tedious and error prone, and can be difficult for users that do not already have these skills.
Auto Glue uses the MAKE_DLL procedure to automate the process of using glue code to call functions via the CALL_EXTERNAL portable calling convention. Since it depends so closely on MAKE_DLL, an understanding of how MAKE_DLL works is necessary to fully understand Auto Glue. As with MAKE_DLL, Auto Glue requires that your system have a suitable C compiler installed. Please refer to the documentation for MAKE_DLL.
Auto Glue maintains a cache of previously built glue functions, and will reuse them on subsequent requests, even between IDL sessions. Glue function libraries can be recognized by their name, which starts with the prefix idl_ce, and ends with the proper suffix for a sharable library on the target system (most UNIX: .so, Windows: .dll). CALL_EXTERNAL finds a suitable glue function by performing the following steps in order, stopping after the first one that works:
-
Look for a ce_glue subdirectory within the IDL distribution bin subdirectory for the current platform. (For example, on a Windows system the subdirectory could be located in <IDL_DEFAULT>\bin\bin.x86.) If this directory exists, it looks there for a sharable library containing the appropriate glue function.
Note: For customer security reasons, the ce_glue subdirectory does not exist in the distribution shipped with IDL, and IDL does not use it to create glue functions. However, if an individual site creates this directory and places glue library files within it, IDL will use them. Multiple IDL sessions on a given system can all share these same glue files, even when run by different users on a multi-user system. If you keep your IDL distribution on a network based file server shared by multiple clients, and if you provide a sufficient selection of glue files, it is possible that your users will not require a locally installed C compiler to use Auto Glue.
If you do create the ce_glue subdirectory on a multi-user system, we recommend that you make it along with all files contained within belong to the owner of the IDL distribution, and apply file protections that prevent non-privileged users from creating files in the directory or modifying them.
- Look in the directory given by the COMPILE_DIRECTORY keyword, or if COMPILE_DIRECTORY is not present, in the directory given by the !MAKE_DLL.COMPILE_DIRECTORY system variable for the appropriate glue function.
- If this step is reached, there is no pre-existing glue function available. CALL_EXTERNAL will create one in the same directory searched in the previous step by generating a C language file containing the needed glue function, and then compiling and linking it into a sharable library using the functionality of the MAKE_DLL procedure.
- IDL loads the sharable library containing the glue function found in the previous step, as well as the library you specified with the Image argument.
- CALL_EXTERNAL calls the glue function, causing your function to be called with the correct parameters.
The first time CALL_EXTERNAL encounters the need for a glue function that does not already exist, it will automatically build it, and then use it without any external indication that this has happened. You may notice a brief hesitation in IDL’s execution as it waits for this process to occur. Once a glue function exists, IDL can load it immediately on subsequent calls (even in unrelated later IDL sessions), and no delay will occur.
Important Changes Since IDL 5.0
The current version of CALL_EXTERNAL differs from IDL versions up to and including IDL 5.0 in a few ways that are important to users moving code to the current version:
- Under Windows, CALL_EXTERNAL would pass IDL strings by value no matter how the ALL_VALUE or VALUE keywords were set. This was inconsistent with all the other platforms and created unnecessary confusion. IDL now uses these keywords to decide how to pass strings on all platforms. Windows users with existing code that expects strings to be passed by value without having specified it via one of these keywords will need to adjust their use of CALL_EXTERNAL or their code.
- Older versions of IDL would quietly pass by value arguments that are larger than a pointer without issuing an error when using the portable calling convention. Although this might work on some hardware, it is error prone and can cause IDL to crash. IDL now issues an error in this case. Programmers with existing code moving to a current version of IDL should change their code to pass such data by reference.
Version History
Pre 4.0 |
Introduced |
Pre 6.1 |
Deprecated the DEFAULT, PORTABLE, and VAX_FLOAT keywords
|
See Also
LINKIMAGE