Spire.Pdf.CPP (12.10.7) vs. Previous Version Differences

This update is a structural upgrade, not a hot-swappable patch: the header entry point changes from a single header to on-demand includes, the namespace layout changes from flat to mirroring .NET, and the string ABI changes from wide characters to UTF-8. It also adds 169 class names and three consumption forms — native collections, nested arrays, and dictionaries. Existing projects must modify source and fully recompile; replacing library files alone will not work.


Spire.Pdf for C++ 12.10.7 — Detailed Changes vs. the Old C++ Package


Source library: Spire.Pdf.dll 12.10.7 (netstandard2.0, FileVersion 12.10.7.1420)
Intended audience: customer code using the old C++ package — #include <Spire.Pdf.o.h>, flat Spire::Pdf namespace, wchar_t string interfaces
Baseline: "old package" below = the vendor's previous C++ package (the shape of src/CPP); "new package" = the package delivered here


1. Key numbers

Dimension Old package 12.10.7 Change
Target platforms 3 families (Windows x64 / Linux x64 / macOS) 10 RIDs (Windows 2 / Linux glibc 2 / musl 2 / OHOS 2 / macOS 2) 3 → 10; only win-x64 is delivered and verified
Package size — (no archived old package in the repo) 75.9 MB (75,894,559 B, win-x64) —
Number of .h files 675 business + 42 common (+ Spire.Pdf.o.h) 746 business + 25 common + pch.h (772 total) +71 / −17 / +1
class EXPORTS definitions 558 616 (571 unique class names) +169 added / −156 removed
C interface header None Spire.Pdf.C.h, 6398 declarations New (internal interop header, not a public C API)
AOT library version — 12.10.7.1420 —
Total exported symbols — 6398 —
Bundled boost headers 38 41 +3
Bundled sample .cpp (in repo) — (no old sample) 1 +1
File-level diff (business header base names) 675 unique names 686 unique names +201 / −190

Class names are compared by base name, ignoring paths; a rename (e.g. PdfFieldActions → PdfFormFieldAdditionalActions) counts once on each side.
The 156 "removed" entries include 5 disambiguation prefix names from the old package and several rename replacements — this is not 156 capabilities disappearing; see 4.7.

Compatibility verdict

Dimension Verdict
Source compatibility No — migration required per sections 3, 4, 6
Binary compatibility No — you must recompile and relink; linking old object files against only the replaced .dll / .lib will fail
Behavioral compatibility Largely the same. The failure semantics of type downcasting changed (4.4); everything else is mechanical

In one sentence: the interface shape changed (headers / namespaces / strings / a few class names), but business logic mostly needs no change.
Only three things need redesign: how Object downcasts (including failure semantics), how PdfDestination is constructed,
and the vendor-deleted KeyPressed (see 4.3).


2. Platform and binary changes

Platform family Old package 12.10.7
Windows x64 (Debug / Release builds; Spire.Pdf.Cpp.dll / .lib) win-x64, win-arm64 (SpirePdfCpp.dll / .lib, no debug directory)
Linux glibc x64 (SpirePdfCpp.so) linux-x64, linux-arm64 (libSpirePdfCpp.so)
Linux musl — linux-musl-x64, linux-musl-arm64
OpenHarmony — ohos-x86_64, ohos-arm64-v8a
macOS Yes (CMake APPLE branch, .so) osx-x64, osx-arm64 (.dylib)
Graphics / text dependencies Skia (libSkiaSharp) Skia + HarfBuzz (libHarfBuzzSharp, new)
Package contents Wrapper only: the AOT Spire.Pdf.Base.dll and libSkiaSharp.dll had to be copied into the same directory manually Bundles wrapper + AOT Base + Skia + HarfBuzz

Key binary differences:

New deployment constraints (from the bundled README):


3. Header and namespace reorganization

3.1 Directory structure

Old version:

include/
  Spire.Pdf.o.h          # 48 KB hand-written umbrella entry, 713 includes inside
  pdf/h/*.h              # 675 flat business headers
  common/h/*.h           # 42 base type headers
  boost/**               # 38 boost headers

New version:

include/
  Spire.Pdf.C.h          # 6398 internal C interop declarations (not a public C API)
  Spire/Pdf/**           # 746 business headers layered by .NET namespace
    Graphics/ Texts/ Tables/ Actions/ Annotations/ Forms/
    Layout/Tables/ Destinations/ Security/ Print/ Utilities/ ...
  Spire/Pdf/common/h/**  # 25 base type headers
  Spire/Pdf/pch.h
  boost/**               # 41 boost headers (including macOS configuration)

3.2 Namespace mapping for common classes

Type Old package New package
PdfDocument / PdfPageBase / PdfPageSize / FileFormat Spire::Pdf::… Unchanged (root namespace)
PdfCanvas / PdfBrush / PdfFont Spire::Pdf::PdfCanvas etc. (all in the root) Spire::Pdf::Graphics::PdfCanvas / …::PdfBrush / …::PdfFont
PdfGrid Spire::Pdf::PdfGrid Spire::Pdf::Grid::PdfGrid
PdfTable (derived from PdfLayoutWidget) Spire::Pdf::PdfTable Spire::Pdf::Tables::PdfTable
PdfTextExtractor Spire::Pdf::PdfTextExtractor Spire::Pdf::Texts::PdfTextExtractor
PdfBookmark Spire::Pdf::PdfBookmark Spire::Pdf::Bookmarks::PdfBookmark
PdfAnnotation Only one Annotations::PdfAnnotation and Interactive::Annotations::PdfAnnotation
PdfField Only one Fields::PdfField and Interactive::Forms::PdfField
PdfSignature Only one Security::PdfSignature and Interactive::DigitalSignatures::PdfSignature
PdfTableElement No such class Spire::Pdf::Layout::Tables::PdfTableElement (new)

Making bare names usable: open the sub-namespaces inside namespace Spire::Pdf (writing it outside only makes bare names visible; qualified names like Spire::Pdf::Graphics::… still will not resolve to that level):

#include "Spire/Pdf/PdfDocument.h"
#include "Spire/Pdf/Graphics/PdfCanvas.h"

using namespace Spire::Pdf;
namespace Spire { namespace Pdf {
    using namespace ::Spire::Pdf::Graphics;   // makes bare names such as PdfCanvas, PdfFont usable
} }

3.3 Same-named types: 62 groups, open only one side of each pair

62 groups of same-named types (46 classes + 16 enums) live in two different namespaces (e.g. Annotations::PdfAnnotation and Interactive::Annotations::PdfAnnotation are both real types). You may open only one side of each group; opening both makes the bare name immediately ambiguous (C2872), and adding a using X::PdfTable; will not suppress it either.

// ❌ Both sides opened: the bare name PdfTable is immediately ambiguous
using namespace ::Spire::Pdf::Tables;
using namespace ::Spire::Pdf::Utilities;

// ✅ Open one side only; write the other side fully qualified
using namespace ::Spire::Pdf::Tables;
intrusive_ptr<PdfTable> a = /* Tables version */;
intrusive_ptr<Spire::Pdf::Utilities::PdfTable> b = /* Utilities version */;

// ✅✅ Preferred: alias both sides in namespaces and open neither
namespace Tables = ::Spire::Pdf::Tables;
namespace Util   = ::Spire::Pdf::Utilities;
intrusive_ptr<Tables::PdfTable> a;
intrusive_ptr<Util::PdfTable>   b;

When the compiler reports C2872 'X': ambiguous symbol, this is the cause — use the class name at the error location to tell which side it belongs to.
⚠ The count of 62 groups is measured on 12.10.7; swapping the DLL changes the collision surface itself, so do not treat it as a constant.


4. Breaking API changes

4.1 Strings: wide characters → UTF-8

The name LPCWSTR_S is retained, but its definition changed:

typedef const wchar_t* LPCWSTR_S;   // old package
typedef const char*    LPCWSTR_S;   // new package

Interface signatures are correspondingly unified to const std::string&:

API Old package New package
PdfDocument::LoadFromFile void LoadFromFile(LPCWSTR_S fileName) void LoadFromFile(const std::string& fileName)
PdfDocument::SaveToFile void SaveToFile(LPCWSTR_S fileName, FileFormat f) void SaveToFile(const std::string& fileName, FileFormat f)
PdfField::GetFullName LPCWSTR_S GetFullName() std::string GetFullName() const
Old form How to change
L"abc" Delete the L → "abc"
LPCWSTR_S Can be kept (it is now const char*), or change to const char* / std::string
std::wstring variables Change to std::string, and perform the encoding conversion yourself (GBK / UTF-16 → UTF-8)
x.c_str() Delete it — the new interface parameter is already const std::string&, so pass it directly

⚠ .c_str() is the easiest thing to over-add: it merely round-trips through std::string → const char* → std::string.
It compiles and behaves correctly, but it is unnecessary and can mislead people into thinking the interface is incompatible.

Scale for reference: LPCWSTR_S appears 1599 times in the old package headers; the new package has 809 const std::string& parameters and 0 remaining wchar_t. MSVC requires /utf-8; the new headers contain UTF-8 Chinese comments.

4.2 PdfDestination: constructible base class → abstract base class (PdfDestinationMode is gone too)

Old package: PdfDestination was a concrete class; you newed it and then set properties one by one.

intrusive_ptr<PdfDestination> dest = new PdfDestination(page);
dest->SetMode(PdfDestinationMode::Location);   // old enum: Location/FitToPage/FitH/FitR/FitBH
dest->SetLocation(new PointF(0, y));
dest->SetZoom(2.f);

New package: PdfDestination is an abstract base class (protected constructor, zero public members), PdfDestinationMode does not exist; the capability is provided by Destinations::PdfExplicitDestinationType (8 values) and concrete subclasses, and construction becomes one-shot:

intrusive_ptr<PdfDestination> dest = new Destinations::PdfXYZExplicitDestination(page, 0, y, 2.f);
Destination type New package class
XYZ Destinations::PdfXYZExplicitDestination(page, left, top[, zoom])
Fit / FitH / FitV / FitR / FitB / FitBH / FitBV Destinations::PdfFit*ExplicitDestination(…)

Correspondingly, the constructor parameters of PdfEmbeddedGoToAction also changed from "a destination object" to "page number + zoom" (see 4.3).

4.3 Class and member renames (including the vendor-deleted KeyPressed)

The following are measured old → new mappings (the action classes for form fields / annotations went through a round of renames on the .NET side, and types returned by GetActions() / GetAdditionalActions() are especially likely to be affected):

Old package New package Differences
Spire::Pdf::PdfFieldActions Spire::Pdf::Actions::PdfFormFieldAdditionalActions Members renamed: GetFormat/GetValidate/GetCalculate → GetOnFormat/GetOnValidate/GetOnCalculate (setters likewise); mouse enter/exit moved up to the base class PdfAnnotationAdditionalActions (OnEnter/OnExit); KeyPressed has no replacement
Spire::Pdf::PdfAnnotationActions Spire::Pdf::Actions::PdfAnnotationAdditionalActions Mouse / focus actions gained an On prefix: GetMouseDown → GetOnMouseDown, GetGotFocus → GetOnReceiveFocus, etc.; OnOpenPage/OnClosePage/OnShowPage/OnHidePage added; Format/Validate/Calculate are no longer on this class
Spire::Pdf::PdfDocumentActions Spire::Pdf::Actions::PdfDocumentAdditionalActions Members changed to GetBeforeClosing/GetBeforeSaving/GetBeforePrinting/GetAfterSaving/GetAfterPrinting (old GetBeforeCloseAction etc. became gerund forms); GetAfterOpenAction has no same-named member in the new class
Spire::Pdf::PdfEmbeddedGoToAction Spire::Pdf::Actions::PdfGoToEmbeddedAction Constructor changed to (fileName, pageNumber, zoom); GetIsNewWindow → GetNewWindow, GetFileName → GetEmbeddedFileName (read-only)
Spire::Pdf::PdfTextFind (result object) Spire::Pdf::Texts::PdfTextFragment Search entry changed to new Texts::PdfTextFinder(page)->Find(text); GetBounds/GetPositions/GetSizes changed from single values to std::vector
PdfDocument::GetSecurity() PdfDocument::GetSecurityPolicy() Reads go through GetSecurityPolicy(); writes go through Encrypt(policy). The old name is still exported but warns
Spire::Pdf::License (class) Spire::Pdf::License::LicenseProvider (class) License is now a namespace; SetLicenseKey/SetLicenseFileName/ClearLicense remain, file paths use SetLicense(path), streams use SetLicense(intrusive_ptr<Stream>)
Spire::Pdf::PdfPaperSizes Spire::Pdf::Print::PdfPaperSize Class renamed, but static constants such as A4 are still not exported (see 6.4)
Security_PdfSignature / Utilities_PdfTable / Utilities_PdfImageInfo / Collections_PdfCollection / Security_IPdfSignatureFormatter Security::PdfSignature / Utilities::PdfTable / Utilities::PdfImageInfo / Collections::PdfCollection / … The old package used prefix names for disambiguation; the new package distinguishes by namespace, and the bare names are unchanged
// Old package
intrusive_ptr<PdfFieldActions> actions = field->GetActions();
actions->SetFormat(jsAction);
actions->SetKeyPressed(jsAction);

// New package
intrusive_ptr<Actions::PdfFormFieldAdditionalActions> actions = field->GetActions();
actions->SetOnFormat(jsAction);
// SetKeyPressed: no corresponding member

The old package's two action classes have a "base class + derived class" relationship in the new API
(PdfFormFieldAdditionalActions : PdfAnnotationAdditionalActions); their members overlap, so just look up the mapping in the table above.

The above are examples, not the complete set. For other cross-version renames on the .NET side, simply follow the compiler errors (if the name is missing, it was renamed),
and the compiler will point directly at the type/member.

KeyPressed has no replacement:

API Old package New package Conclusion
KeyPressed (JS action of form fields / annotations) PdfFieldActions::Get/SetKeyPressed, PdfAnnotationActions::Get/SetKeyPressed None Removed from the .NET API by the vendor, no replacement; that part of the logic must be redesigned

Within the scope covered by the vendor's demo suite, all other old members still have a corresponding form.
Cold types not covered by the demos may have other .NET cross-version differences — treat compiler errors as authoritative; this document does not claim "zero gaps other than KeyPressed".

4.4 Object: type checking and downcasting (including behavioral changes)

Member Old package New package
GetInstanceTypeName() public, returns the C++ mangled name (typeid(T).name()) private (calling it gives C2248), and its content is the managed full name
ManagedName() Does not exist private (used only internally by the generator)
CheckType<T>(p) public public, semantics unchanged (true/false)
Dynamic_cast<T>(p) boost cast; on failure falls back to unvalidated retagging ⇒ never returns null boost cast only: returns null on failure
Convert<T>(p) Unvalidated retagging; returns non-null even for the wrong type Checked: throws SpireTypeError on failure (carrying Actual() / Target())
UncheckedCast<T>(p) Does not exist New explicit escape hatch (still unvalidated retagging)
// Old package: compare by type-name string, then cast without validation
if (widget->GetInstanceTypeName() == /* some name */) { /* … */ }
intrusive_ptr<PdfNewPage> page = Object::Convert<PdfNewPage>(doc->GetPages()->Add());  // never fails

// New package: three checked forms
if (Object::CheckType<PdfNewPage>(obj)) { /* only need yes/no */ }

if (auto page = Object::Dynamic_cast<PdfNewPage>(obj)) {   // not that type → nullptr
    page->DoSomething();
}

try {
    auto page = Object::Convert<PdfNewPage>(obj);          // not that type → throws
    page->DoSomething();
}
catch (const SpireTypeError& e) {
    // e.Actual() = actual managed full name; e.Target() = expected full name
}

⚠ Key behavioral change: the old Convert "counted success even if it mislabeled the object"; the new Convert throws on the spot.
The old Dynamic_cast silently returned an object "with a new label" on failure; the new Dynamic_cast returns nullptr.
Code migrated from the old package that relies on "never null" must add null checks, or switch to Convert + exception handling.

4.5 Return type changes

API Old package return New package return
PdfField::GetFullName() LPCWSTR_S (wide characters) std::string (UTF-8)
Pdf3DAnnotation::Get_3DData() intrusive_ptr<Stream> std::vector<uint8_t>
GetBounds/GetPositions/GetSizes of Texts::PdfTextFragment The old PdfTextFind counterpart GetBounds/GetPosition/GetSize, all single values std::vector<intrusive_ptr<…>>

4.6 Event registration: the C++ entry points are gone (mostly unusable in the old package too)

The old package exported add_* / remove_* accessors for 19 events across 10 classes, for example:

add_PageAdded / remove_PageAdded
add_BeginPageLayout / remove_BeginPageLayout
add_BeginPrint / add_EndPrint
add_QueryRowCount / add_QueryNextRow
add_SaveProgress / add_PaperSettings

In the new package's C++ Spire/Pdf/** these accessors do not exist at all (measured: add_* only matches the unrelated add_ref). Note, however, that event registration in the old package was already incomplete: 15 of the 16 *EventHandler classes have their Invoke commented out (//virtual void Invoke (…)), so customers could not implement callbacks; only BeginRowLayoutEventHandler has an implementable virtual void Invoke(...). Therefore:

Also:

4.7 Removed public classes: 156 old class names no longer appear

Comparing by class base name, 156 old class names no longer appear in the new package. Do not read this as 156 capabilities disappearing:

Category Representative classes Notes
Base value types / collection interfaces Byte, Char, Int16, Int64, Single, UInt16/32/64, DictionaryEntry, ICollection, IDictionary, IDictionaryEnumerator, IList, List, SpireString Wrapper classes are no longer needed: strings use std::string, integers use native types, collections use the native protocol; String / Decimal are exported separately
Internal implementation / serialization / format conversion ZipArchive*, ZippedContentStream, ZlibZipWriter, XmpMetadata/XmpSchema/XmpStructure (→ PdfXmpMetadata / PdfXmpNamespace), Story*, FixedDocument/FixedPage/Glyphs, HtmlConverter/HtmlToPdf*, Qt_HtmlConverter, TranslatorFactory Implementation classes leaked by the old package; the new package does not export them
Drawing / XPS / WPF model (.NET types leaked by the old package) Brush, Canvas, Geometry, Path, PathFigure, PathGeometry, MatrixTransform, GradientStop(s), SolidColorBrush, ImageBrush, Visual, Resources Not part of the PDF public API; the new package does not export them
PDF types refactored / removed by the vendor PdfGraphicsState, PdfImageMask, PdfHTMLTextElement, PdfHtmlLayoutFormat, PdfPaperSourceTray, PdfButtonWidgetWidgetItem, PdfTexBoxWidgetItem, etc. Already renamed / removed on the vendor's .NET API side; treat compiler errors as authoritative

The constants in the old package's PdfPaperSizes (Letter / A4 …) were commented out entirely and were never exported in either generation (see 6.4).


5. New capabilities

5.1 New classes (169 class names, including rename replacements)

Functional area Representative classes
Document comparison PdfComparer, PdfCompareOptions
Content building / drawing PdfContentBuilder, PdfContentResult, PdfDrawer, PdfAppearances, PdfAppearanceCharacteristics, PdfDefaultAppearance, PdfFreeTextAppearanceBuilder, PdfWatermarkAppearanceBuilder, PdfWatermarkInfo, PdfHatchBrush, PdfIconFit
Layout elements (tables / charts / paragraphs) PdfTableElement, PdfTable{Cell,Column,Row,Section}Element, PdfLayoutElement, PdfAtomicElement, PdfBlockElement, PdfInlineElement, PdfInlineBlockElement, PdfTextRun, PdfTextWrapElement, PdfImageElement, PdfHeadingElement, PdfListElement/PdfListItemElement, PdfPanel*Element, PdfTocElement, PdfDividerElement, PdfPageTemplate(Set), PdfParagraphElement, PdfTitleElement
Chart elements PdfBarChartElement/PdfBarChartStyle, PdfLineChartElement/PdfLineChartStyle, PdfPieChartElement/PdfPieChartStyle, PdfScatterChartElement/PdfScatterChartStyle, PdfStackedBarChartElement/PdfStackedBarChartStyle, PdfHistogramElement/PdfHistogramStyle
Barcodes PdfBarcodeElement, PdfBarcodeStyle, PdfInlineBarcode
Annotations PdfCaretAnnotation, PdfCircleAnnotation, PdfFileAttachmentAnnotation, PdfHighlightAnnotation, PdfUnderlineAnnotation, PdfStrikeOutAnnotation, PdfSquigglyAnnotation, PdfSquareAnnotation, PdfPolyAnnotation, PdfPolylineAnnotation, PdfRedactionAnnotation, PdfTextAnnotation, PdfWidgetAnnotation(Collection), PdfMarkupAnnotation
Forms PdfChoiceField, PdfChoiceItem(Collection), PdfPushButtonField, PdfRadioButtonField, PdfTextField, XfaForm + Xfa{Barcode,Button,CheckBox,Choice,ComboBox,DateTime,Image,ListBox,Numeric,RadioButton,Signature,Text}Field
3D / rich media Pdf3DArtwork, Pdf3DLightingScheme, Pdf3DRenderMode, PdfRichMediaAnnotation, PdfRichMediaAnnotationWidget, PdfRichMediaContent, PdfMovie, PdfMovieAnnotation, PdfScreenAnnotation
Security / signatures / metadata PdfSecurityPolicy, PdfPasswordSecurityPolicy, PdfDocumentPrivilege, PdfXmpMetadata, PdfXmpNamespace
Converters / export options PdfToImageConverter, PdfToMarkdownConverter, PdfToSvgConverter, PdfToWordConverter, MarkdownOptions, SvgOptions, PptxOptions, OfdOptions, MetafileOptions, RenderingOptions, IgnoreOptions, ImageCompressionOptions, XlsxSpecialTableLayoutOptions
Destinations PdfExplicitDestination + PdfXYZExplicitDestination, PdfFitExplicitDestination, PdfFitH/V/R/B/BH/BVExplicitDestination (8 concrete subclasses in total)
Actions PdfAnnotationAdditionalActions, PdfDocumentAdditionalActions, PdfFormFieldAdditionalActions, PdfGoToEmbeddedAction, PdfHideAction, PdfResetFormAction, PdfSubmitFormAction, PdfURIAction
Fonts / printing PdfFontStore, PdfEmbeddedFontConverter, PdfFontFamilySpec, PdfPaperSize, DefaultPrintLogger, PdfHeaderFooter
Files / import-export PdfEmbeddedFile, PdfFileSpecification, PdfFormExportResult, PdfFormImportResult, PdfFixedPrint
Base types String, Decimal, LicenseProvider
Other PdfAnchorEntry, PdfAnchorRegistry, PdfNavigationEntry, PdfNavigationRegistry, PdfCollectionItem, PdfImageInfo, PdfNumberFormatter, PdfStandardOptions, PdfThemeProfile, PdfRectangleDifferences, PdfDynamicData, TSAResponse, BitmapOptions

5.2 Native collections / nested arrays / dictionaries

The old package could only use GetCount() + GetItem(i) (some collections did not even have GetCount, so they could not be enumerated); while keeping GetCount/GetItem, the new package's List<T>-derived collections additionally provide the native collection protocol:

// Old package
intrusive_ptr<PdfPageCollection> pages = doc->GetPages();
for (int i = 0; i < pages->GetCount(); ++i) {
    intrusive_ptr<PdfPageBase> page = pages->GetItem(i);
}

// New package (the old style still works; below is the more idiomatic style)
for (intrusive_ptr<PdfPageBase> page : *doc->GetPages()) { /* … */ }

int n = doc->GetPages()->size();
intrusive_ptr<PdfPageBase> first = (*doc->GetPages())[0];
doc->GetPages()->RemoveAt(0);   // when the collection supports it

⚠ Every access goes back to the same managed collection (live-object semantics, not a snapshot).
⚠ Do not test "same element" by comparing handle pointers — each getter creates a new handle; compare state instead.

Jagged arrays T[][] go from "not exported" to std::vector<std::vector<T>>:

std::vector<std::vector<std::string>> data = {{"a","b","c"}, {"d","e","f"}};
intrusive_ptr<Layout::Tables::PdfTableElement> table = new Layout::Tables::PdfTableElement(3);
table->AddRows(data);                                   // fluent, returns the same table

std::vector<std::vector<int>> ink = {{1,2,3}, {}};      // empty inner vector is valid
intrusive_ptr<Annotations::PdfInkAnnotation> ann = new Annotations::PdfInkAnnotation(ink);
std::vector<std::vector<int>> back = ann->GetInkList();

Dictionaries Dictionary<K,V> go from "non-enumerable handles / not exported" to native std::map<K,V>:

std::map<std::string, std::string> props =
    doc->GetDocumentInformation()->GetAllCustomProperties();

// Values are wrapped by their true managed type, not bare Object
std::map<Security::SignInfoType, intrusive_ptr<Object>> fonts;
fonts[Security::SignInfoType::DigitalSigner] = new Common::String("Times New Roman");
sig->SetSignInfoFont(fonts);

null and empty are distinguishable: on the C++ side use the companion GetX(bool& isNull) / SetX(std::nullptr_t) overloads (measured: 54 / 54 signatures, across 46 classes).

5.3 Obsolete ([Obsolete]) APIs: still exported, but emit compiler warnings

Members that the vendor marked [Obsolete] on the .NET side are still exported as usual in the new package (72 declarations across 17 classes), with only a SPIRE_DEPRECATED("…vendor text…") added before the declaration:

Class Obsolete member Suggested replacement
PdfDocument GetSecurity() GetSecurityPolicy() + Encrypt(policy)
PdfDocument The document-returning MergeFiles(…) overload static void MergeFiles(inputFiles, outputFile) (releases resources automatically)
PdfViewerPreferences SetBookMarkExpandOrCollapse(bool) PdfBookmark::SetExpandBookmark(bool)
PdfUnidimensionalBarcode GetEnableCheckDigit() / GetShowCheckDigit() None (the vendor provided no replacement)
PdfSignatureMaker 12 Set{Name,Location,Reason,Date,ContactInfo,DistinguishedName}{,Label} Same-named properties on PdfSignature / PdfSignatureAppearance
PdfTrueTypeFont The PdfTrueTypeFont(fontFile, size[, style]) constructor PdfTrueTypeFont::FromFontFile(path, size[, style])

Do not globally suppress these with /wd4996 or -Wno-deprecated-declarations — these warnings are the upgrade roadmap.

5.4 Internal C interop header (deliberately not public)

include/Spire.Pdf.C.h is a new interop form added by the new package: 6398 SPIRE_PDF_API function declarations serving the interop between the AOT native library and the C++ wrapper. It is not a public C API like the one in the DOC package:


6. Migration checklist

6.1 Search-and-replace checklist

Scanning through in order covers the vast majority of changes:

# Search for Change to Notes
1 #include <Spire.Pdf.o.h> Include the concrete headers on demand (#include "Spire/Pdf/<path>.h") See 3.1
2 Missing -I in the compile command Add include + include/Spire/Pdf + include/Spire/Pdf/common/h See 3.1
3 L" " (remove the L) See 4.1
4 .c_str() Pass the std::string directly Delete it; the new interfaces do not need it
5 LPCWSTR_S Can be kept (it is now const char*) If you declared wide-character variables, change them to std::string
6 std::wstring std::string Watch the encoding conversion (UTF-16 / GBK → UTF-8)
7 GetInstanceTypeName() / ManagedName() CheckType<T> / Dynamic_cast<T> / Convert<T> Both accessors are now private; see 4.4
8 Code relying on Object::Convert<T> "never failing" Add null checks, or switch to CheckType / Dynamic_cast The new Convert throws SpireTypeError
9 new PdfDestination( Construct a concrete destination subclass See 4.2
10 PdfDestinationMode PdfExplicitDestinationType / a concrete subclass See 4.2
11 PdfFieldActions / PdfAnnotationActions Actions::PdfFormFieldAdditionalActions / …AdditionalActions See 4.3
12 PdfDocumentActions Actions::PdfDocumentAdditionalActions Member names also change; see 4.3
13 PdfEmbeddedGoToAction Actions::PdfGoToEmbeddedAction Constructor and properties both change; see 4.3
14 PdfTextFind Texts::PdfTextFragment + Texts::PdfTextFinder Search entry and return types both change; see 4.3 / 4.5
15 GetKeyPressed / SetKeyPressed No replacement See 4.3; requires redesign
16 License::SetLicenseKey etc. License::LicenseProvider::SetLicenseKey etc. License is now a namespace; see 4.3
17 GetSecurity() GetSecurityPolicy() + Encrypt(policy) The old one still works but warns
18 add_* / remove_* event accessors No C++ entry points Most old callbacks were unusable too (only row-layout events could be registered); see 4.6
19 PdfPaperSizes Print::PdfPaperSize Class renamed, but constants such as A4 are still unavailable; see 6.4
20 Bare byte (vector<byte>) unsigned char Only needed for C++17 and above
21 PdfPaperSize::A4 etc. PdfPageSize::A4() Missing in both generations; not a regression
22 Compiler reports C2872 ambiguous Use fully qualified names or namespace aliases per 3.3 62 groups of same-named types