HotPDF Stable C Callback ABI
HotPDFABI.dll exposes flat cdecl functions with fixed-width status values, opaque handles, explicit byte lengths, and the versioned hpdf_io_v1 callback structure declared in Lib/hotpdf_abi.h
Build outputs
Run build-HotPDF-ABI.cmd to build Win32 and Win64 DLLs plus import libraries under Lib/ABI/<platform>/Release
The public ABI uses stable lowercase export names, while hpdf_abi_version and hpdf_abi_io_v1_size let callers verify the contract before creating a document
Core functions
uint32_t hpdf_abi_version(void);
uint32_t hpdf_abi_io_v1_size(void);
hpdf_status hpdf_document_create(hpdf_document *handle);
hpdf_status hpdf_document_destroy(hpdf_document handle);
hpdf_status hpdf_document_load_from_io(
hpdf_document handle,
const hpdf_io_v1 *io,
const char *password,
size_t password_length);
hpdf_status hpdf_document_page_count(
hpdf_document handle,
uint32_t *page_count);
hpdf_status hpdf_document_save_to_io(
hpdf_document handle,
const hpdf_io_v1 *io);
Versioned I/O structure
hpdf_io_v1 io = {0};
io.struct_size = sizeof(io);
io.abi_version = HPDF_ABI_VERSION_1;
io.user_data = state;
io.read_at = read_at;
io.get_size = get_size;
io.write = write;
io.is_cancelled = is_cancelled;
io.progress = progress;
io.diagnostic = diagnostic;
struct_size is 48 bytes on Win32 and 72 bytes on Win64, flags must be zero for ABI v1, and larger future structures can be distinguished without guessing field layout
All callbacks and exported functions use cdecl, every text pointer has an explicit byte length, and no Delphi string, class, interface, enum, exception, or Boolean crosses the boundary
Random-access input
read_at receives an absolute 64-bit offset and writes directly into the parser's destination buffer, while get_size reports the immutable source size once when the source is attached
Partial successful reads are accepted and completed through repeated callback calls, so range stores and bounded network readers do not need to allocate an intermediate complete-file buffer
The callback state and source bytes must remain valid until the document handle is destroyed or another source is loaded into the handle
Streamed output
write receives sequential output chunks directly from SaveLoadedDocumentToStream; partial successful writes are retried until the complete chunk is accepted
A zero-byte successful write is rejected as an I/O error because it cannot make forward progress
Status and lifecycle
| Status | Meaning |
|---|---|
HPDF_STATUS_OK | The operation completed |
HPDF_STATUS_INVALID_ARGUMENT | A required pointer or callback is absent or a byte range is invalid |
HPDF_STATUS_INVALID_HANDLE | The handle is null, unknown, or already destroyed |
HPDF_STATUS_INCOMPATIBLE_ABI | The structure size, version, or flags are unsupported |
HPDF_STATUS_CANCELLED | The cancellation callback requested termination |
HPDF_STATUS_IO_ERROR | An input or output callback failed or violated its count contract |
HPDF_STATUS_PARSE_ERROR | The input was read successfully but was not accepted as a PDF |
HPDF_STATUS_INTERNAL_ERROR | An internal failure was caught before it crossed the ABI |
Each successful hpdf_document_create must be paired with one successful hpdf_document_destroy; repeated destruction returns HPDF_STATUS_INVALID_HANDLE
Opaque handles are monotonic process-local tokens rather than object addresses, so allocator reuse cannot revive a stale handle
Exceptions never cross the C boundary, and the optional diagnostic callback receives the corresponding message bytes before an operation returns an error status
Concurrency
Different handles may be used concurrently, but callers must serialize operations and destruction for the same handle
Legacy Pascal callbacks
THPDFABICallbacks and the HPDFDoc* Pascal helpers remain source compatible for Delphi and C++Builder applications, but native C integrations should use hotpdf_abi.h and the lowercase v1 exports