Spire.Pdf.CPP (12.10.7) 与以前版本的差异

本次更新是一次结构性升级,而非可热替换的补丁:头文件入口从单头改为按需 include,命名空间从扁平改为镜像 .NET,字符串 ABI 从宽字符改为 UTF-8;并新增 169 个类名、原生集合 / 嵌套数组 / 字典三种消费形态。旧项目需要修改源码并全量重新编译,不能只替换库文件。


Spire.Pdf for C++ 12.10.7 对比旧版 C++ 包变更明细


源库:Spire.Pdf.dll 12.10.7(netstandard2.0,FileVersion 12.10.7.1420)
适用对象:使用旧版 C++ 包的客户代码 —— #include <Spire.Pdf.o.h>、扁平 Spire::Pdf 命名空间、wchar_t 宽字符接口
对照基准:下称「旧包」= 厂商旧版 C++ 包(src/CPP 的形态);「新包」= 本包交付包


1. 关键数字

维度 旧包 12.10.7 变化
目标平台 3 族(Windows x64 / Linux x64 / macOS) 10 个 RID(Windows 2 / Linux glibc 2 / musl 2 / OHOS 2 / macOS 2) 3 → 10;已交付验证仅 win-x64
包体大小 —(仓库内无旧包归档) 75.9 MB(75,894,559 B,win-x64) —
.h 文件数 675 业务 + 42 common(+ Spire.Pdf.o.h) 746 业务 + 25 common + pch.h(共 772) +71 / −17 / +1
class EXPORTS 定义 558 616(571 个唯一类名) 新增 169 / 移除 156
C 接口头 无 Spire.Pdf.C.h 6398 条声明 新增(内部对接头,非公开 C API)
AOT 库版本 — 12.10.7.1420 —
导出符号总数 — 6398 —
内置 boost 头 38 41 +3
随包示例 .cpp(仓库内) —(无旧包示例) 1 +1
文件级差异(业务头基名) 675 个唯一名 686 个唯一名 +201 / −190

类名按基名比对,不含路径;改名(如 PdfFieldActions → PdfFormFieldAdditionalActions)在两侧各计一次。
156 个「移除」里含 5 个旧包用于消歧的前缀名与若干改名接替,不是 156 个能力消失,见 4.7。

兼容性结论

维度 结论
源码兼容 否 —— 需按第 3、4、6 节改造
二进制兼容 否 —— 必须重新编译并重新链接;只替换 .dll / .lib 去链接旧目标文件会失败
行为兼容 大体一致。类型下溯的失败语义变了(4.4),其余为机械改动

一句话:接口形态变了(头文件 / 命名空间 / 字符串 / 少量类名),业务逻辑基本不用动。
需要重新设计的只有三处:Object 的下溯写法(含失败语义)、PdfDestination 的构造方式、
以及被厂商删除的 KeyPressed(见 4.3)。


2. 平台与二进制变化

平台族 旧包 12.10.7
Windows x64(Debug / Release 两档;Spire.Pdf.Cpp.dll / .lib) win-x64、win-arm64(SpirePdfCpp.dll / .lib,无 debug 目录)
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 有(CMake APPLE 分支,.so) osx-x64、osx-arm64(.dylib)
图形 / 文本依赖 Skia(libSkiaSharp) Skia + HarfBuzz(libHarfBuzzSharp,新增)
包内容 仅 wrapper:AOT 的 Spire.Pdf.Base.dll 与 libSkiaSharp.dll 需自行拷到同目录 自带 wrapper + AOT Base + Skia + HarfBuzz

关键二进制差异:

新增的部署约束(来自随包 README):


3. 头文件与命名空间重组

3.1 目录结构

旧版:

include/
  Spire.Pdf.o.h          # 48 KB 手写总入口,内部 713 条 include
  pdf/h/*.h              # 675 个扁平业务头
  common/h/*.h           # 42 个基础类型头
  boost/**               # 38 个 boost 头

新版:

include/
  Spire.Pdf.C.h          # 6398 条内部 C 对接声明(非公开 C API)
  Spire/Pdf/**           # 746 个按 .NET 命名空间分层的业务头
    Graphics/ Texts/ Tables/ Actions/ Annotations/ Forms/
    Layout/Tables/ Destinations/ Security/ Print/ Utilities/ ...
  Spire/Pdf/common/h/**  # 25 个基础类型头
  Spire/Pdf/pch.h
  boost/**               # 41 个 boost 头(含 macOS 配置)

3.2 常用类的命名空间映射

类型 旧包 新包
PdfDocument / PdfPageBase / PdfPageSize / FileFormat Spire::Pdf::… 不变(根命名空间)
PdfCanvas / PdfBrush / PdfFont Spire::Pdf::PdfCanvas 等(均在根) Spire::Pdf::Graphics::PdfCanvas / …::PdfBrush / …::PdfFont
PdfGrid Spire::Pdf::PdfGrid Spire::Pdf::Grid::PdfGrid
PdfTable(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 只有一个 Annotations::PdfAnnotation 与 Interactive::Annotations::PdfAnnotation
PdfField 只有一个 Fields::PdfField 与 Interactive::Forms::PdfField
PdfSignature 只有一个 Security::PdfSignature 与 Interactive::DigitalSignatures::PdfSignature
PdfTableElement 无此类 Spire::Pdf::Layout::Tables::PdfTableElement(新增)

让裸名可用:在 namespace Spire::Pdf 内部打开子命名空间(写在外部只能让裸名可见, 限定名 Spire::Pdf::Graphics::… 仍解析不到那层):

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

using namespace Spire::Pdf;
namespace Spire { namespace Pdf {
    using namespace ::Spire::Pdf::Graphics;   // 让 PdfCanvas、PdfFont 等裸名可用
} }

3.3 同名类型:62 组,每对只打开一侧

62 组同名类型(46 类 + 16 枚举)分处两个命名空间(如 Annotations::PdfAnnotation 与 Interactive::Annotations::PdfAnnotation 都是真类型)。每组只能打开一侧, 两侧都打开会让裸名当场二义(C2872);补一条 using X::PdfTable; 也压不过去。

// ❌ 两侧都打开:裸名 PdfTable 当场二义
using namespace ::Spire::Pdf::Tables;
using namespace ::Spire::Pdf::Utilities;

// ✅ 只开一侧;另一侧写全限定名
using namespace ::Spire::Pdf::Tables;
intrusive_ptr<PdfTable> a = /* Tables 版 */;
intrusive_ptr<Spire::Pdf::Utilities::PdfTable> b = /* Utilities 版 */;

// ✅✅ 更推荐:两侧都用命名空间别名,谁也不打开
namespace Tables = ::Spire::Pdf::Tables;
namespace Util   = ::Spire::Pdf::Utilities;
intrusive_ptr<Tables::PdfTable> a;
intrusive_ptr<Util::PdfTable>   b;

编译报 C2872 'X': ambiguous symbol 时就是这一条 —— 按报错位置的类名判断它属于哪一侧。
⚠ 62 组是 12.10.7 实测;换 dll 会改变冲突面本身,不要把它当常量。


4. 破坏性 API 变更

4.1 字符串:宽字符 → UTF-8

LPCWSTR_S 这个名字保留,但定义变了:

typedef const wchar_t* LPCWSTR_S;   // 旧包
typedef const char*    LPCWSTR_S;   // 新包

接口签名随之统一为 const std::string&:

API 旧包 新包
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
旧写法 改法
L"abc" 删掉 L → "abc"
LPCWSTR_S 可保留(现为 const char*),或改 const char* / std::string
std::wstring 变量 改 std::string,并自行做编码转换(GBK / UTF-16 → UTF-8)
x.c_str() 删掉 —— 新接口形参就是 const std::string&,直接传即可

⚠ .c_str() 是最容易多写的:加了它只是走一遍 std::string → const char* → std::string 的往返,
编译得过、行为也对,但没必要,还容易让人误以为接口不兼容。

规模参照:旧包头文件里 LPCWSTR_S 出现 1599 处;新包 const std::string& 形参 809 处, wchar_t 残留 0 处。MSVC 需加 /utf-8;新版头文件含 UTF-8 中文注释。

4.2 PdfDestination:可构造基类 → 抽象基类(PdfDestinationMode 一并消失)

旧包:PdfDestination 是具体类,先 new 再逐个设属性。

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

新包:PdfDestination 是抽象基类(protected 构造、零公开成员), PdfDestinationMode 不存在;能力由 Destinations::PdfExplicitDestinationType(8 值) 与具体子类提供,改为一次性构造:

intrusive_ptr<PdfDestination> dest = new Destinations::PdfXYZExplicitDestination(page, 0, y, 2.f);
目的地类型 新包类
XYZ Destinations::PdfXYZExplicitDestination(page, left, top[, zoom])
Fit / FitH / FitV / FitR / FitB / FitBH / FitBV Destinations::PdfFit*ExplicitDestination(…)

相应地,PdfEmbeddedGoToAction 的构造形参也从「目的地对象」改成了「页码 + 缩放」(见 4.3)。

4.3 类与成员改名(含被厂商删除的 KeyPressed)

以下为实测的旧 → 新对应(表单 / 注记的动作类在 .NET 侧经过一轮改名, GetActions() / GetAdditionalActions() 返回的类型尤其容易命中):

旧包 新包 差异
Spire::Pdf::PdfFieldActions Spire::Pdf::Actions::PdfFormFieldAdditionalActions 成员改名:GetFormat/GetValidate/GetCalculate → GetOnFormat/GetOnValidate/GetOnCalculate(setter 同);鼠标进出上移到基类 PdfAnnotationAdditionalActions(OnEnter/OnExit);KeyPressed 无替代
Spire::Pdf::PdfAnnotationActions Spire::Pdf::Actions::PdfAnnotationAdditionalActions 鼠标 / 焦点动作加 On 前缀:GetMouseDown → GetOnMouseDown、GetGotFocus → GetOnReceiveFocus 等;另新增 OnOpenPage/OnClosePage/OnShowPage/OnHidePage;Format/Validate/Calculate 不再在此类
Spire::Pdf::PdfDocumentActions Spire::Pdf::Actions::PdfDocumentAdditionalActions 成员改为 GetBeforeClosing/GetBeforeSaving/GetBeforePrinting/GetAfterSaving/GetAfterPrinting(旧 GetBeforeCloseAction 等改为动名词形);GetAfterOpenAction 在新类中无同名成员
Spire::Pdf::PdfEmbeddedGoToAction Spire::Pdf::Actions::PdfGoToEmbeddedAction 构造改为 (fileName, pageNumber, zoom);GetIsNewWindow → GetNewWindow、GetFileName → GetEmbeddedFileName(只读)
Spire::Pdf::PdfTextFind(结果对象) Spire::Pdf::Texts::PdfTextFragment 检索入口改为 new Texts::PdfTextFinder(page)->Find(text);GetBounds/GetPositions/GetSizes 由单值改为 std::vector
PdfDocument::GetSecurity() PdfDocument::GetSecurityPolicy() 读取改走 GetSecurityPolicy();写入改走 Encrypt(policy)。旧名仍导出但带告警
Spire::Pdf::License(类) Spire::Pdf::License::LicenseProvider(类) License 现在是命名空间;SetLicenseKey/SetLicenseFileName/ClearLicense 仍在,文件路径改 SetLicense(path)、流改 SetLicense(intrusive_ptr<Stream>)
Spire::Pdf::PdfPaperSizes Spire::Pdf::Print::PdfPaperSize 类改名,但静态常量 A4 等仍不导出(见 6.4)
Security_PdfSignature / Utilities_PdfTable / Utilities_PdfImageInfo / Collections_PdfCollection / Security_IPdfSignatureFormatter Security::PdfSignature / Utilities::PdfTable / Utilities::PdfImageInfo / Collections::PdfCollection / … 旧包用前缀名消歧;新包改由命名空间区分,裸名不变
// 旧包
intrusive_ptr<PdfFieldActions> actions = field->GetActions();
actions->SetFormat(jsAction);
actions->SetKeyPressed(jsAction);

// 新包
intrusive_ptr<Actions::PdfFormFieldAdditionalActions> actions = field->GetActions();
actions->SetOnFormat(jsAction);
// SetKeyPressed:无对应成员

旧包的两个动作类在新 API 里是「基类 + 派生类」关系
(PdfFormFieldAdditionalActions : PdfAnnotationAdditionalActions),成员有交叉,按上表找对应即可。

以上是示例而非全集。.NET 侧跨版本的其他改名以编译错误为指引即可(名字不在即改错),
编译器会直接指出是哪个类型/成员。

KeyPressed 无替代:

API 旧包 新包 结论
KeyPressed(表单字段 / 注记的 JS 动作) PdfFieldActions::Get/SetKeyPressed、PdfAnnotationActions::Get/SetKeyPressed 无 厂商从 .NET API 删除,无替代,需重新设计该段逻辑

在厂商 Demo 套件覆盖到的范围内,其余旧成员都还有对应形态。
Demo 未覆盖的冷门类型可能存在其他 .NET 跨版本差异 —— 以编译错误为准,本文不宣称「除 KeyPressed 外零缺失」。

4.4 Object:类型判定与下溯(含行为变化)

成员 旧包 新包
GetInstanceTypeName() public,返回 C++ 修饰名(typeid(T).name()) private(调用即 C2248),且内容为托管全名
ManagedName() 不存在 private(仅生成器内部用)
CheckType<T>(p) public public,语义不变(true/false)
Dynamic_cast<T>(p) boost 转型,失败时回落到无校验重打标签 ⇒ 永不返回 null 只做 boost 转型:失败返回 null
Convert<T>(p) 无校验重打标签,传错类型也返回非空 受检:失败抛 SpireTypeError(带 Actual() / Target())
UncheckedCast<T>(p) 不存在 新增的显式逃生舱(仍是无校验重打标签)
// 旧包:按类型名字符串比较,再无校验强转
if (widget->GetInstanceTypeName() == /* 某个名字 */) { /* … */ }
intrusive_ptr<PdfNewPage> page = Object::Convert<PdfNewPage>(doc->GetPages()->Add());  // 从不失败

// 新包:三种受检写法
if (Object::CheckType<PdfNewPage>(obj)) { /* 只需要 yes/no */ }

if (auto page = Object::Dynamic_cast<PdfNewPage>(obj)) {   // 不是该类型 → nullptr
    page->DoSomething();
}

try {
    auto page = Object::Convert<PdfNewPage>(obj);          // 不是该类型 → 抛异常
    page->DoSomething();
}
catch (const SpireTypeError& e) {
    // e.Actual() = 实际托管全名;e.Target() = 期望全名
}

⚠ 行为变化要点:旧 Convert 是「打错标签也当成功」,新 Convert 会当场抛异常;
旧 Dynamic_cast 失败会悄悄返回一个「打了新标签」的对象,新 Dynamic_cast 返回 nullptr。
从旧包迁来的代码若依赖「永不为空」,必须补判空或改用 Convert + 异常处理。

4.5 返回类型变化

API 旧包返回 新包返回
PdfField::GetFullName() LPCWSTR_S(宽字符) std::string(UTF-8)
Pdf3DAnnotation::Get_3DData() intrusive_ptr<Stream> std::vector<uint8_t>
Texts::PdfTextFragment 的 GetBounds/GetPositions/GetSizes 旧 PdfTextFind 对应 GetBounds/GetPosition/GetSize,均为单值 std::vector<intrusive_ptr<…>>

4.6 事件注册:C++ 入口消失(旧包大多也不可用)

旧包在 10 个类上导出了 19 个事件的 add_* / remove_* 访问器,例如:

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

新包 C++ Spire/Pdf/** 中这些访问器一个都没有(现测 add_* 仅命中无关的 add_ref)。 但请注意旧包的事件注册本就不完整:16 个 *EventHandler 类里 15 个的 Invoke 是注释掉的 (//virtual void Invoke (…)),客户无法实现回调;只有 BeginRowLayoutEventHandler 有一个 可实现的 virtual void Invoke(...)。因此:

另外:

4.7 被移除的公开类:156 个旧类名不再出现

按类名基名比对,156 个旧类名在新包中不再出现。别把它读成 156 个能力消失:

类别 代表类 说明
基础值类型 / 集合接口 Byte、Char、Int16、Int64、Single、UInt16/32/64、DictionaryEntry、ICollection、IDictionary、IDictionaryEnumerator、IList、List、SpireString 不再需要包装类:字符串用 std::string,整数用原生类型,集合走原生协议,String / Decimal 独立导出
内部实现 / 序列化 / 格式转换 ZipArchive*、ZippedContentStream、ZlibZipWriter、XmpMetadata/XmpSchema/XmpStructure(→ PdfXmpMetadata / PdfXmpNamespace)、Story*、FixedDocument/FixedPage/Glyphs、HtmlConverter/HtmlToPdf*、Qt_HtmlConverter、TranslatorFactory 旧包泄漏的实现类,新包不导出
绘图 / XPS / WPF 模型(旧包泄漏的 .NET 类型) Brush、Canvas、Geometry、Path、PathFigure、PathGeometry、MatrixTransform、GradientStop(s)、SolidColorBrush、ImageBrush、Visual、Resources 不属于 PDF 公共 API,新包不导出
厂商重构 / 删除的 PDF 类型 PdfGraphicsState、PdfImageMask、PdfHTMLTextElement、PdfHtmlLayoutFormat、PdfPaperSourceTray、PdfButtonWidgetWidgetItem、PdfTexBoxWidgetItem 等 厂商 .NET API 侧已改名 / 删除;以编译错误为准

旧包的 PdfPaperSizes 里那些常量(Letter / A4 …)整段就是注释掉的,两代都没导出过(见 6.4)。


5. 新增能力

5.1 新增类(169 个类名,含改名接替类)

功能域 代表类
文档比较 PdfComparer、PdfCompareOptions
内容构建 / 绘制 PdfContentBuilder、PdfContentResult、PdfDrawer、PdfAppearances、PdfAppearanceCharacteristics、PdfDefaultAppearance、PdfFreeTextAppearanceBuilder、PdfWatermarkAppearanceBuilder、PdfWatermarkInfo、PdfHatchBrush、PdfIconFit
布局元素(表格 / 图表 / 段落) 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
图表元素 PdfBarChartElement/PdfBarChartStyle、PdfLineChartElement/PdfLineChartStyle、PdfPieChartElement/PdfPieChartStyle、PdfScatterChartElement/PdfScatterChartStyle、PdfStackedBarChartElement/PdfStackedBarChartStyle、PdfHistogramElement/PdfHistogramStyle
条码 PdfBarcodeElement、PdfBarcodeStyle、PdfInlineBarcode
注记 PdfCaretAnnotation、PdfCircleAnnotation、PdfFileAttachmentAnnotation、PdfHighlightAnnotation、PdfUnderlineAnnotation、PdfStrikeOutAnnotation、PdfSquigglyAnnotation、PdfSquareAnnotation、PdfPolyAnnotation、PdfPolylineAnnotation、PdfRedactionAnnotation、PdfTextAnnotation、PdfWidgetAnnotation(Collection)、PdfMarkupAnnotation
表单 PdfChoiceField、PdfChoiceItem(Collection)、PdfPushButtonField、PdfRadioButtonField、PdfTextField、XfaForm + Xfa{Barcode,Button,CheckBox,Choice,ComboBox,DateTime,Image,ListBox,Numeric,RadioButton,Signature,Text}Field
3D / 富媒体 Pdf3DArtwork、Pdf3DLightingScheme、Pdf3DRenderMode、PdfRichMediaAnnotation、PdfRichMediaAnnotationWidget、PdfRichMediaContent、PdfMovie、PdfMovieAnnotation、PdfScreenAnnotation
安全 / 签名 / 元数据 PdfSecurityPolicy、PdfPasswordSecurityPolicy、PdfDocumentPrivilege、PdfXmpMetadata、PdfXmpNamespace
转换器 / 导出选项 PdfToImageConverter、PdfToMarkdownConverter、PdfToSvgConverter、PdfToWordConverter、MarkdownOptions、SvgOptions、PptxOptions、OfdOptions、MetafileOptions、RenderingOptions、IgnoreOptions、ImageCompressionOptions、XlsxSpecialTableLayoutOptions
目的地 PdfExplicitDestination + PdfXYZExplicitDestination、PdfFitExplicitDestination、PdfFitH/V/R/B/BH/BVExplicitDestination(共 8 个具体子类)
动作 PdfAnnotationAdditionalActions、PdfDocumentAdditionalActions、PdfFormFieldAdditionalActions、PdfGoToEmbeddedAction、PdfHideAction、PdfResetFormAction、PdfSubmitFormAction、PdfURIAction
字体 / 打印 PdfFontStore、PdfEmbeddedFontConverter、PdfFontFamilySpec、PdfPaperSize、DefaultPrintLogger、PdfHeaderFooter
文件 / 导入导出 PdfEmbeddedFile、PdfFileSpecification、PdfFormExportResult、PdfFormImportResult、PdfFixedPrint
基础类型 String、Decimal、LicenseProvider
其他 PdfAnchorEntry、PdfAnchorRegistry、PdfNavigationEntry、PdfNavigationRegistry、PdfCollectionItem、PdfImageInfo、PdfNumberFormatter、PdfStandardOptions、PdfThemeProfile、PdfRectangleDifferences、PdfDynamicData、TSAResponse、BitmapOptions

5.2 原生集合 / 嵌套数组 / 字典

旧包只能用 GetCount() + GetItem(i)(部分集合连 GetCount 都没有,无法遍历); 新包在保留 GetCount/GetItem 的同时,List<T> 派生集合额外提供原生集合协议:

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

// 新包(旧写法仍然可用;下面是更地道的写法)
for (intrusive_ptr<PdfPageBase> page : *doc->GetPages()) { /* … */ }

int n = doc->GetPages()->size();
intrusive_ptr<PdfPageBase> first = (*doc->GetPages())[0];
doc->GetPages()->RemoveAt(0);   // 集合支持时

⚠ 每次访问都打回同一个托管集合(活对象语义,不是快照)。
⚠ 别用句柄指针相等判断「是否同一元素」—— 每次 getter 都会新建句柄,请比较状态。

交错数组 T[][] 从「不导出」变为 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,返回同一个表

std::vector<std::vector<int>> ink = {{1,2,3}, {}};      // 空内层合法
intrusive_ptr<Annotations::PdfInkAnnotation> ann = new Annotations::PdfInkAnnotation(ink);
std::vector<std::vector<int>> back = ann->GetInkList();

字典 Dictionary<K,V> 从「不可枚举句柄 / 不导出」变为原生 std::map<K,V>:

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

// 值按托管真类型建壳,不是裸 Object
std::map<Security::SignInfoType, intrusive_ptr<Object>> fonts;
fonts[Security::SignInfoType::DigitalSigner] = new Common::String("Times New Roman");
sig->SetSignInfoFont(fonts);

null 与空可区分:C++ 侧用配套的 GetX(bool& isNull) / SetX(std::nullptr_t) 重载(现测 54 / 54 条,涉及 46 类)。

5.3 过时([Obsolete])API:仍导出,但给编译告警

厂商在 .NET 侧标了 [Obsolete] 的成员,新包照常导出(共 72 条声明 / 17 个类), 只在声明前加 SPIRE_DEPRECATED("…厂商原文…"):

类 过时成员 建议替代
PdfDocument GetSecurity() GetSecurityPolicy() + Encrypt(policy)
PdfDocument 返回文档式的 MergeFiles(…) 重载 static void MergeFiles(inputFiles, outputFile)(自动释放资源)
PdfViewerPreferences SetBookMarkExpandOrCollapse(bool) PdfBookmark::SetExpandBookmark(bool)
PdfUnidimensionalBarcode GetEnableCheckDigit() / GetShowCheckDigit() 无(厂商未给替代)
PdfSignatureMaker 12 个 Set{Name,Location,Reason,Date,ContactInfo,DistinguishedName}{,Label} PdfSignature / PdfSignatureAppearance 的同名属性
PdfTrueTypeFont PdfTrueTypeFont(fontFile, size[, style]) 构造 PdfTrueTypeFont::FromFontFile(path, size[, style])

不建议用 /wd4996 或 -Wno-deprecated-declarations 全局压制 —— 这些告警就是升级路线图。

5.4 内部 C 对接头(刻意不公开)

include/Spire.Pdf.C.h 是新包新增的一种对接形态:6398 条 SPIRE_PDF_API 函数声明, 服务 AOT 原生库与 C++ wrapper 之间的对接。它不是与 DOC 包同款的公开 C API:


6. 迁移清单

6.1 搜索替换清单

按顺序扫一遍即可覆盖绝大部分改动:

# 搜索 改成 备注
1 #include <Spire.Pdf.o.h> 按需 include 具体头(#include "Spire/Pdf/<路径>.h") 见 3.1
2 编译命令缺 -I 补 include + include/Spire/Pdf + include/Spire/Pdf/common/h 见 3.1
3 L" "(删 L) 见 4.1
4 .c_str() 直接传 std::string 删掉,新接口不需要
5 LPCWSTR_S 可保留(现为 const char*) 若声明了宽字符变量则改 std::string
6 std::wstring std::string 注意编码转换(UTF-16 / GBK → UTF-8)
7 GetInstanceTypeName() / ManagedName() CheckType<T> / Dynamic_cast<T> / Convert<T> 两访问器现为 private,见 4.4
8 Object::Convert<T> 依赖「永不失败」的写法 补判空,或改用 CheckType / Dynamic_cast 新 Convert 会抛 SpireTypeError
9 new PdfDestination( 具体目的地子类构造 见 4.2
10 PdfDestinationMode PdfExplicitDestinationType / 具体子类 见 4.2
11 PdfFieldActions / PdfAnnotationActions Actions::PdfFormFieldAdditionalActions / …AdditionalActions 见 4.3
12 PdfDocumentActions Actions::PdfDocumentAdditionalActions 成员名也变,见 4.3
13 PdfEmbeddedGoToAction Actions::PdfGoToEmbeddedAction 构造与属性均变,见 4.3
14 PdfTextFind Texts::PdfTextFragment + Texts::PdfTextFinder 检索入口与返回类型均变,见 4.3 / 4.5
15 GetKeyPressed / SetKeyPressed 无替代 见 4.3,需重新设计
16 License::SetLicenseKey 等 License::LicenseProvider::SetLicenseKey 等 License 现在是命名空间,见 4.3
17 GetSecurity() GetSecurityPolicy() + Encrypt(policy) 旧的仍可用但告警
18 add_* / remove_* 事件访问器 无 C++ 入口 旧包回调大多也不可用(仅行布局事件可注册),见 4.6
19 PdfPaperSizes Print::PdfPaperSize 类改名,但 A4 等常量仍不可用,见 6.4
20 裸 byte(vector<byte>) unsigned char 仅 C++17 及以上档需要
21 PdfPaperSize::A4 等 PdfPageSize::A4() 两代都没有,非回归
22 编译报 C2872 ambiguous 按 3.3 写全限定名或命名空间别名 62 组同名