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 |
Engineering review notes for DLL, ActiveX, and Dylib integration
Use these review notes to make sure the feature has moved beyond a demo and can be defended during release, support, and customer escalation.
- Decision: calling convention, bitness, thread model, and supported host languages. Implementation pressure point: return explicit handles or result objects rather than sharing unmanaged pointers. Acceptance evidence: encoded path or string policy used for the call. Regression trigger: uncaught native exceptions can terminate hosts that cannot inspect Delphi state
- Decision: string encoding, path encoding, stream ownership, and buffer lifetime rules. Implementation pressure point: translate exceptions into stable error codes and diagnostic messages. Acceptance evidence: diagnostic trace that does not cross memory ownership boundaries unsafely. Regression trigger: ANSI paths may work in tests and fail for customer names or localized folders
- Decision: error reporting style, exception translation, and diagnostic callback behavior. Implementation pressure point: validate bitness and dependency versions during initialization. Acceptance evidence: module version, host process bitness, calling convention, and dependency path. Regression trigger: ActiveX registration can succeed for one bitness and fail for another host
- Decision: deployment layout, dependency versioning, registration, and update policy. Implementation pressure point: ship sample calls that exercise Unicode paths, large buffers, and failure paths. Acceptance evidence: function name, input sizes, output buffer ownership, and returned status code. Regression trigger: callbacks must not outlive buffers owned by the caller
- Decision: calling convention, bitness, thread model, and supported host languages. Implementation pressure point: publish a minimal binary contract before wrapping high-level PDF operations. Acceptance evidence: encoded path or string policy used for the call. Regression trigger: 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 notes
PDFlibPas should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. Important terms include 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;
本番チェックリスト
- Run the workflow on an empty file, a normal customer file, and a worst-case file
- Open the generated PDF with the target viewer, validator, printer, or downstream application
- Log product version, profile version, input hash, output path, elapsed time, and warning count
- Keep passwords, certificates, temporary files, and customer data under explicit retention rules
- Add regression documents when a customer file exposes a new edge case