DECLARE (External Functions)
Syntax
Syntax: DECLARE FUNCTION|SUB name LIB "dll" ALIAS "export" ([BYVAL|BYREF] param AS type, ...) AS rettype
Source: PB parser + import table generator
Description
Declares an external function or subroutine from a DLL so it can be called with CALL. The compiler generates entries in the PE32+ import table (.idata section) for each declared function. At load time, the Windows PE loader resolves these entries to actual DLL addresses. Multiline parameter lists with _ continuation are supported for readability.
Parameters
| Parameter | Description |
FUNCTION|SUB | Use FUNCTION if the DLL export returns a value, SUB if it returns void. |
name | The name used in your PowerBASIC code to call this function. |
LIB "dll" | The DLL filename (e.g., "user32.dll"). The PE loader searches standard system paths. |
ALIAS "export" | The actual exported function name in the DLL. Use this when the PB name differs from the DLL export name. |
BYVAL param AS type | A parameter passed by value. The value itself is placed in the register or stack slot. |
BYREF param AS type | A parameter passed by reference. A pointer to the variable is placed in the register or stack slot. |
AS rettype | The return type for FUNCTIONS. Omitted for SUBs. Common types: LONG, QUAD, STRING, SINGLE, DOUBLE. |
Example
DECLARE FUNCTION MessageBoxA LIB "user32.dll" _
ALIAS "MessageBoxA" ( _
BYVAL hWnd AS QUAD, _
BYVAL lpText AS ASCIIZ PTR, _
BYVAL lpCaption AS ASCIIZ PTR, _
BYVAL uType AS LONG _
) AS LONG
DECLARE FUNCTION GetTickCount LIB "kernel32.dll" _
ALIAS "GetTickCount" () AS DWORD
FUNCTION PBMAIN() AS LONG
LOCAL ticks AS DWORD
ticks = GetTickCount()
PRINT "System uptime: "; ticks; " ms"
CALL MessageBoxA(0, "Hello World", "PB x64", 0)
FUNCTION = 0
END FUNCTION
Generated Assembly
Import Table (.idata section)
; Import Directory Table entry for user32.dll:
dq __imp_MessageBoxA
; Import Address Table (IAT) entry:
__imp_MessageBoxA:
dq 0 ; resolved at load time by Windows PE loader
; Import Name Table (INT) entry:
dw 0 ; hint
db "MessageBoxA", 0 ; function name
Calling a Declared Function
; Evaluate arguments and stage them according to Win64 ABI:
mov rcx, 0 ; hWnd -> RCX
lea rdx, [__pb_str_hello] ; lpText -> RDX
lea r8, [__pb_str_cap] ; lpCaption -> R8
mov r9, 0 ; uType -> R9
; Call the function via the IAT pointer:
call [__imp_MessageBoxA] ; indirect call through import table
; Return value is in RAX (integer) or XMM0 (float)
mov rax, rax ; result is already in RAX
Supported Parameter Types
| PB Type | C Equivalent | Size | Register/Stack |
| LONG | int32_t | 4 | Integer register |
| QUAD | int64_t / void* | 8 | Integer register |
| BYTE | uint8_t | 1 | Integer register |
| WORD | uint16_t | 2 | Integer register |
| DWORD | uint32_t | 4 | Integer register |
| SINGLE | float | 4 | XMM register |
| DOUBLE | double | 8 | XMM register |
| STRING | char* (ASCIIZ) | 8 | Integer register (ptr) |
| ASCIIZ PTR | const char* | 8 | Integer register (ptr) |
Limitations
- No CALLBACK FUNCTION support yet
- No varargs (...) declarations
- No ordinal aliases (ordinal-only imports)
- No structure/UDT parameter passing
- BYREF only works for supported variable types