losLab PDF Library предоставляет командам Delphi и C++Builder PDF-движок с доступным исходным кодом для настольных, серверных, DLL, ActiveX и Dylib процессов, включая встроенные проверки PDF/A и PDF/UA, подписи PAdES и выбор рендерера без отправки документов во внешний PDF-сервис.
Эта статья предназначена для teams exposing PDF functionality across Delphi, C++Builder, scripting, legacy automation, or cross-platform components. Она рассматривает DLL, ActiveX, and Dylib integration как промышленную инженерию документов, а не как одиночный вызов компонента.
Практический риск состоит в том, что native integration bugs often appear as memory corruption, string encoding issues, bitness mismatches, or exception-boundary failures rather than clear PDF errors. Поэтому процессу нужны письменный контракт, наблюдаемая диагностика и реалистичные регрессионные файлы.
Архитектурные решения
Define a binary contract before feature code. calling convention, bitness, thread model, and supported host languages / string encoding, path encoding, stream ownership, and buffer lifetime rules
- calling convention, bitness, thread model, and supported host languages
- string encoding, path encoding, stream ownership, and buffer lifetime rules
- error reporting style, exception translation, and diagnostic callback behavior
- deployment layout, dependency versioning, registration, and update policy
Порядок реализации
Keep ownership and errors explicit at the boundary. The order below keeps the workflow reviewable for Delphi and C++Builder teams.
- publish a minimal binary contract before wrapping high-level PDF operations
- return explicit handles or result objects rather than sharing unmanaged pointers
- translate exceptions into stable error codes and diagnostic messages
- validate bitness and dependency versions during initialization
- ship sample calls that exercise Unicode paths, large buffers, and failure paths
Доказательства проверки
Integration evidence for support cases. Keep these fields with the output or support record.
- module version, host process bitness, calling convention, and dependency path
- function name, input sizes, output buffer ownership, and returned status code
- encoded path or string policy used for the call
- diagnostic trace that does not cross memory ownership boundaries unsafely
The PDF API is only half of the contract
A DLL, ActiveX, or Dylib layer needs stable calling conventions, buffer ownership rules, string encoding, version reporting, error codes, and deployment checks. Treating it as a thin wrapper without those rules makes support difficult.
Decision table for DLL, ActiveX, and Dylib integration
A decision table keeps product ownership visible when the same workflow is reused by a desktop tool, service job, and support utility.
| Decision | Engineering reason | Evidence |
|---|---|---|
| calling convention, bitness, thread model, and supported host languages | publish a minimal binary contract before wrapping high-level PDF operations | module version, host process bitness, calling convention, and dependency path |
| string encoding, path encoding, stream ownership, and buffer lifetime rules | return explicit handles or result objects rather than sharing unmanaged pointers | function name, input sizes, output buffer ownership, and returned status code |
| error reporting style, exception translation, and diagnostic callback behavior | translate exceptions into stable error codes and diagnostic messages | encoded path or string policy used for the call |
Замечания для инженерного ревью по DLL, ActiveX, and Dylib integration
Используйте эти замечания, чтобы убедиться, что функция вышла за рамки демо и может быть обоснована на релизе, в поддержке и при эскалации клиента
- Решение: calling convention, bitness, thread model, and supported host languages. Точка приложения при реализации: return explicit handles or result objects rather than sharing unmanaged pointers. Доказательство приемки: encoded path or string policy used for the call. Триггер регрессии: uncaught native exceptions can terminate hosts that cannot inspect Delphi state
- Решение: string encoding, path encoding, stream ownership, and buffer lifetime rules. Точка приложения при реализации: translate exceptions into stable error codes and diagnostic messages. Доказательство приемки: diagnostic trace that does not cross memory ownership boundaries unsafely. Триггер регрессии: ANSI paths may work in tests and fail for customer names or localized folders
- Решение: error reporting style, exception translation, and diagnostic callback behavior. Точка приложения при реализации: validate bitness and dependency versions during initialization. Доказательство приемки: module version, host process bitness, calling convention, and dependency path. Триггер регрессии: ActiveX registration can succeed for one bitness and fail for another host
- Решение: deployment layout, dependency versioning, registration, and update policy. Точка приложения при реализации: ship sample calls that exercise Unicode paths, large buffers, and failure paths. Доказательство приемки: function name, input sizes, output buffer ownership, and returned status code. Триггер регрессии: callbacks must not outlive buffers owned by the caller
- Решение: calling convention, bitness, thread model, and supported host languages. Точка приложения при реализации: publish a minimal binary contract before wrapping high-level PDF operations. Доказательство приемки: encoded path or string policy used for the call. Триггер регрессии: uncaught native exceptions can terminate hosts that cannot inspect Delphi state
Пограничные случаи
- ANSI paths may work in tests and fail for customer names or localized folders
- ActiveX registration can succeed for one bitness and fail for another host
- callbacks must not outlive buffers owned by the caller
- uncaught native exceptions can terminate hosts that cannot inspect Delphi state
Примечания по Delphi / C++Builder
PDFlibPas should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. Важные термины включают DLL, ActiveX, Dylib, calling convention, buffer ownership, Unicode path.
Пример кода Delphi
Следующий эскиз Delphi показывает практическую границу сервиса для этой темы. Оставляйте проверки политики, журналирование и валидацию вне узкого блока вызова продукта, чтобы сценарий было проще тестировать.
procedure LoadPdfEngineForHost(const LibraryPath: string);
begin
RequireFileExists(LibraryPath);
FEngine := TPDFlib.Create;
FHostAdapter := CreateHostAdapter(FEngine);
FHostAdapter.RegisterErrorCallback(LogPdfEngineError);
FHostAdapter.RegisterBufferReleaseCallback(ReleaseReturnedBuffer);
end;
Производственный чек-лист
- Запускайте сценарий на пустом файле, обычном клиентском файле и файле худшего случая
- Открывайте сгенерированный PDF в целевом просмотрщике, валидаторе, принтере или downstream-приложении
- Записывайте версию продукта, версию профиля, хэш входа, путь вывода, затраченное время и число предупреждений
- Храните пароли, сертификаты, временные файлы и данные клиентов по явным правилам хранения
- Добавляйте регрессионные документы, когда клиентский файл выявляет новый граничный случай
Документация по продукту
Дополнительные примеры кода
var
Inst, Doc: Integer;
begin
Inst := DLCreateLibrary; // one instance per worker thread
try
Doc := DLLoadFromFile(Inst, 'in.pdf', ''); // returns a DocumentID, 0 on failure
if Doc <> 0 then
begin
DLEncrypt(Inst, 'owner-secret', 'user-secret', 3,
DLEncodePermissions(Inst, 1, 0, 0, 0, 0, 0, 0, 1));
DLSaveToFile(Inst, 'out.pdf');
end;
finally
DLReleaseLibrary(Inst); // frees every document the instance owns
end;
end;var
P: PWideChar;
PageText: string;
begin
P := DLGetPageText(Inst, 7); // pointer into a library-owned buffer
PageText := P; // copy now; a later call may reuse the buffer
end;