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.
However if you decide to create your own declarations for external functions and procedures, you will need to understand a little bit about the calling convention used by Windows DLLs. Windows DLLs support two calling conventions, "stdcall" and "cdecl". The most popular calling convention is "stdcall".
By default Irie Pascal will assume that the calling convention is "stdcall" unless you specifiy "cdecl".
Unfortunately, calling conventions are not implemented in exactly the same way by all Windows compilers. So if you want to call a function or procedures in a DLL, you not only need to know the calling convention it uses, 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.
Item | stdcall | cdecl |
---|---|---|
Direction of parameter passing. | Left to right. | Left to right. |
Who is responsible for removing parameters from the stack. | The function/procedure being called. | The caller. |
First, search the DLL for the function/procedure, using the name you specified when you made the call, but if the function/procedure is not found then prefix "_" to the name and search again. NOTE: This is done because some compilers automatically add a "_" prefix to function/procedure names but other compilers don't. | Yes | Yes |
Function results of ordinal type | Returned in the EAX register. | Returned in the EAX register. |
Function results of pointer type | Returned in the EAX register. | Returned in the EAX register. |
Function results of address type | Returned in the EAX register. | Returned in the EAX register. |
Function results of real type | Returned on the math coprocessor stack. | Returned on the math coprocessor stack. |
Function results of single type | Returned on the math coprocessor stack. | Returned on the math coprocessor stack. |
Function results of double type | Returned on the math coprocessor stack. | Returned on the math coprocessor stack. |
Function results of record type or array type are 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. | Yes | Yes |
Function results of dir type | Not supported. | Not supported. |
Function results of file type | Not supported. | Not supported. |
Function results of list type | Not supported. | Not supported. |
Function results of object type | Not supported. | Not supported. |
Function results of set type | Not supported. | Not supported. |
Function results of string type | Not supported. | Not supported. |
Passing by value: expressions of ordinal type | Yes | Yes |
Passing by value: expressions of pointer type | Yes | Yes |
Passing by value: expressions of record type | Yes | Yes |
Passing by value: expressions of address type | Yes | Yes |
Passing by value: expressions of real type | Yes | Yes |
Passing by value: expressions of single type | Yes | Yes |
Passing by value: expressions of double type | Yes | Yes |
Passing by value: expressions of all other types. | No | No |
Passing by reference: variables of array type | Yes | Yes |
Passing by reference: variables of ordinal type | Yes | Yes |
Passing by reference: variables of pointer type | Yes | Yes |
Passing by reference: variables of record type | Yes | Yes |
Passing by reference: variables of string type | Yes | Yes |
Passing by reference: variables of address type | Yes | Yes |
Passing by reference: variables of double type | Yes | Yes |
Passing by reference: variables of single type | Yes | Yes |
Passing by reference: variables of real type | Yes | Yes |
Passing by reference: functions/procedures | No | No |
First the simple types:
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.
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.
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.
With most C compilers, the types int and long are signed 32-bit integral types so the nearest Irie Pascal type is integer.
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.
With most C compilers, the type short is a signed 16-bit integral type so the nearest Irie Pascal type is shortint.
With most C compilers, the type unsigned short is a unsigned 16-bit integral type so the nearest Irie Pascal type is shortword.
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];
This can be a problem if the function has to return more than one value. C programs commonly solve this problem by passing a pointer to the argument instead of the argument itself. The function will receive a copy of the pointer, but because the copy points at the argument the C function can modify the argument my modifying what the pointer is pointing to.
Internally, Irie Pascal implements call be reference in the same way, so you can use call by reference in cases where the C function expects a pointer to a variable.
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.