Contents | Prev | Next
7.6.1 Calling external functions and procedures
As an extension to Standard Pascal, Irie Pascal
supports calling functions and procedures in Windows DLLs, using the
external directive. NOTE: Only
32-bit DLLs are currently supported.
A number of include files, with declarations for many of the Windows API functions, are
distributed with Irie Pascal. You can use these include files to gain access to many
pre-written declarations of Windows API functions without having to create your own
declarations for these functions.
In order to write your own declarations for external functions and procedures, you need to
understand a little bit about the
calling convention used by Windows DLLs. Windows DLLs
support two calling conventions, stdcall and cdecl, the one most
often used is stdcall. By default Irie Pascal will assume that the calling
convention is stdcall unless cdecl is specified. Unfortunately the
two calling conventions are not implemented in exactly the same way by all Windows compilers.
So if you want to call functions and procedures in a DLL, you may need to know which compiler
was used to create it (and also what compiler options were used).
This document does not describe the various ways different compilers implement the
stdcall and cdecl calling conventions. Instead what this document
does is describe how Irie Pascal implements these conventions.
- Irie Pascal passes parameters from right to left for both the stdcall and
cdecl calling conventions.
- Irie Pascal expects the function or procedure being called to pop the parameters from
the stack after the call, when the stdcall calling convention is being used, but
the caller pops the parameters from the stack after the call, when the cdecl
calling convention is being used.
- For both calling conventions, Irie Pascal searches for the function or procedure in
the DLL using the name given, but if the function or procedure is not found then
"_" is prefixed to the name and the DLL is searched again. NOTE:
This is done because some compilers automatically prefix function and procedure names with
"_" but other compilers don't.
- For both calling conventions, Irie Pascal expects function results of
ordinal type,
pointer type, or
address type to be returned in the EAX register.
- For both calling conventions, Irie Pascal expects function results of
real type, single type,
or double type to be returned on the math coprocessor
stack.
- For both calling conventions, Irie Pascal expects function results of
record type or array type to
be returned using a pointer passed by the caller. The caller is expected to pass a pointer to
the memory location where the function should put the return value.
- For both calling conventions, Irie Pascal does not support returning
values of the following types:
(dir, file,
list, object,
set, or string) from
external functions and procedures.
- For both calling conventions, Irie Pascal supports passing
expressions of the following types by value
(ordinal types,
pointer types, record types,
address,
double, single, and
real).
- For both calling conventions, Irie Pascal supports passing
variables of the following types by reference
(array types,
ordinal types,
pointer types, record types,
string types,
address,
double, single, and
real).
- Irie Pascal does not yet support passing functions or procedures using either calling
convention.
In order to successfully call external functions and procedures you may need to understand
a little bit about how values of the Irie Pascal types are stored. Below is a brief
description of the what values of the Irie Pascal types are stored:
First the simple types:
- byte - unsigned 8-bit value.
- char - unigned 8-bit value.
- double - 64-bit floating point value (see ANSI/IEC std 754-1985).
- enumerated (including boolean) - signed 32-bit value.
- integer - signed 32-bit value.
- real - 64-bit floating point value (see ANSI/IEC std 754-1985).
- shortint - signed 16-bit value.
- shortword - unsigned 16-bit value.
- single - 32-bit floating point value (see ANSI/IEC std 754-1985).
- word - unsigned 32-bit value.
- subrange - subrange types are stored like their host types (e.g. subranges of
char are stored like chars, and subranges of integer are stored like integers).
Next the complex types:
- array - These are contiguous sequences of the elements. For example
array[1..4] of integer
is simply a sequence of 4 integers (with no gaps in between). Multi-demensional arrays are treated as follows:
array[m][n][o][p] of type
is treated like
array[m] of array[n] of array[o] of array[p] of type.
NOTE: This is the opposite of the way dimensions are ordered by C language compilers.
- address - This is a 32-bit value which is an operating system address (i.e.
an address that is meaningful to external functions and procedures).
- cstring - These are null terminated sequences of characters (the same
format used by C programs. to store strings.
- pointer - This is a 32-bit value which is a virtual address (i.e. an offset
from the beginning of the IVM Executable's Data segment). Virtual address are probably
meanless to external functions and procedures and therefore you should use the built-in
function addr to convert virtual addresses into
operating system addresses before passing them to external functions or procedures.
- record - These are simply sequences of the fields. The size of the gaps (if
any) between fields is determined by the size of the fields and the current alignment setting.
- string - These are length prefixed sequences of characters. Strings with
maximum lengths less than or equal to 255 are prefixed by a byte containing the actual length
of the string. String with maximun lengths greater than or equal to 256 are prefixed by an
integer containing the actual length of the string. NOTE: This representation
is typical of the way strings are represented in Pascal programs, but is very different from
the way way strings are repesented in C programs (i.e. null terminated sequences of char).
- The other types (such as file and list) are not described
here because they can not be passed to or from external functions or procedures.
Most functions in Windows DLLs are written in C, so you will usually be converting back of
forth between C types and Irie Pascal types.
NOTE: The C types in all capitals like BOOL, WORD, and DWORD are not
actually defined as part of the C language, but are common types declared in C programs.
Using BOOL Parameters
The C languages does not define a boolean type so it is common for C programs to define one,
however there are two popular ways this can be done. One way is to define the boolean type as
char or unsigned char, in which case the nearest Irie Pascal type
is byte. The other common way to define the boolean type is as a enumerated type
with the values FALSE, and TRUE. However sometimes C compilers
treat enumerated types with less than 256 elements as unsigned char, and at
other times as int (the C name for the integer type). So if boolean type is
defined as an enumerated type then it can either be treated as unsigned char,
in which case the nearest Irie Pascal type is byte, or as int,
in which case the nearest Irie Pascal type is boolean.
Using int And long Parameters
With most C compilers, the types int and long are signed 32-bit
integral types so the nearest Irie Pascal type is integer.
Using DWORD, unsigned int And unsigned long Parameters
With most C compilers, the types DWORD, unsigned int, and
unsigned long are unsigned 32-bit integral types so the nearest Irie Pascal type
is word.
Using short Parameters
With most C compilers, the type short is a signed 16-bit integral type so the
nearest Irie Pascal type is shortint.
Using unsigned short Parameters
With most C compilers, the type unsigned short is a unsigned 16-bit integral type
so the nearest Irie Pascal type is shortword.
Using Array Parameters
Passing multi-dimensional arrays between Irie Pascal and C requires care since the ordering
used by Pascal and C for the dimensions is opposite (i.e.
a : array[1..4][1..2] of integer;
is equivalent to
int a[2][4];
Using pointer Parameters
- The C language does not support call by reference so it is common when passing a
variable to a function to be modified, to pass a pointer to the variable. The function
can't modify the pointer but it can modify what the pointer is pointing at (i.e. the variable).
Pascal supports call by reference, so you may want to use it in cases where the C function or
procedure expects a pointer to a variable.
- The C language also does not support passing arrays to functions, however the close
relationship between arrays and pointers in C means that passing a pointer to the first
element in an array is almost equivalent to passing the array. Irie Pascal supports passing
arrays, so in this case you should pass an array by reference to the C function or procedure.
- A special case of passing arrays, is passing C strings (arrays of null-terminated chars).
In this case you may want to pass a cstring by reference.
- In cases where the pointer is pointing to a variable whose type is not fixed, or a
null value can be passed, or the pointer is pointing to a variable whose size is not fixed
then you may want to pass the operating system address of the variable directly.
When you want to call a C function that expects a pointer parameter it is up to you to
determine (perhaps by reading a description of the function) which one of the four scenarios
just described in being used.
The sample program winhello.pas is an example of how to call a function
in a Windows DLL. NOTE: This program uses the winuser.inc
include file, distributed with Irie Pascal, to gain access to a pre-written declaration for
the Windows API function MessageBox.
Contents | Prev | Next