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;