我们很高兴地宣布发布 Spire.Presentation for JavaScript 11.4.1。本次更新引入了两项主要增强功能:将 PowerPoint 转换为 PDF/A,可直接从演示文稿中创建符合长期存档要求的文档;以及将带图片的 HTML 添加到 PowerPoint,可将包括图片在内的丰富 HTML 内容无缝嵌入到幻灯片中。
新功能:
https://www.e-iceblue.cn/Downloads/Spire-Presentation-JavaScript.html
Spire.PDF for Android via Java 10.8.0 现已正式发布。该版本引入了用于处理 PDF 图片的 PdfImageHelper 类,并优化了获取签名证书名称、注册表格布局事件的相关方法。详情请查阅以下内容。
优化:
变更前:
// 获取图片信息
PdfImageInfo[] imageInfo = page.getImagesInfo();
// 替换图片
page.replaceImage(0, image)
// 删除图片
page.deleteImage(0);
变更后:
// 获取图片信息
PdfImageHelper imageHelper = new PdfImageHelper();
PdfImageInfo[] imagesInfos = imageHelper.getImagesInfo(page);
// 替换图片
imageHelper.replaceImage(imagesInfos[0], image);
// 删除图片
imageHelper.deleteImage(imagesInfos[0]);
变更前:
signature.getCertificate().get_IssuerName().getName()
变更后:
signature.getCertificate().getDistinguishedName());
变更前:
table.beginRowLayout.add() / table.endCellLayout.add()
变更后:
table.addBeginRowLayoutEventHandler() / table.addEndCellLayoutEventHandler()
https://www.e-iceblue.cn/Downloads/pdf-for-android-via-java.html

将数据库查询结果导出为 PDF 是报告生成、数据归档和文档创建等常见应用场景中的需求。通常需要将 SQL 查询结果转换为结构清晰、易于阅读的文档,以便后续共享、存档或打印使用。
由于数据库中的数据通常以表格形式存储,因此在导出过程中保持其结构完整性对于确保文档的清晰度和可读性至关重要。若缺乏合理的布局控制,生成的 PDF 很容易变得杂乱,尤其是在处理大规模数据集时,这一问题会更加明显。
本文将演示如何使用 Spire.XLS for .NET 在 C# 中将数据库转换为 PDF,包括如何检索查询结果、将其组织为结构化表格,以及最终导出为格式清晰的 PDF 文档的完整实现过程。
目录
将数据库内容转换为 PDF 通常包含以下几个关键步骤:
在实际应用中,这一流程通常用于生成报表、制作发票或归档查询结果等场景,其核心目标是确保数据以清晰、结构化的方式呈现,便于后续查看与使用。
本节提供将数据库查询结果转换为 PDF 文档的完整工作流程,涵盖数据检索、表格构建、格式设置和导出等环节。
在实现解决方案之前,请确保您的开发环境已准备就绪:
.NET 环境
安装 Visual Studio 或使用具有兼容 .NET 版本(例如 .NET 6 或更高版本)的 .NET CLI。
数据库访问
准备一个 SQL Server 数据库(或任何关系型数据库),并确保您拥有有效的连接字符串。对于现代 .NET 应用程序,请使用推荐的 SQL 客户端库:
dotnet add package Microsoft.Data.SqlClient
此包提供了 SQL Server 的 ADO.NET 实现,并取代了传统的 System.Data.SqlClient。
Spire.XLS for .NET 通过 NuGet 安装 Spire.XLS 以处理表格格式化和 PDF 导出:
dotnet add package Spire.XLS
您也可以下载 Spire.XLS for .NET 包并手动将其添加到项目中。
配置完成后,您可以从数据库检索数据并使用 Spire.XLS 生成和导出 PDF 文档。
第一步是执行 SQL 查询并将结果加载到 DataTable 中。这种数据结构能够保留查询结果的架构和数据类型,便于后续转换处理。
在本示例中,通过在 SQL 查询中为字段设置中文别名(如“订单编号”、“客户名称”等),可以使导出的报表更符合实际业务阅读习惯。这种方式避免了在导出阶段额外处理列名,同时提升了报表的可读性和专业性。
using System.Data;
using Microsoft.Data.SqlClient;
string connectionString = "Server=localhost\\SQLEXPRESS;Database=SalesDB;User ID=demouser;Password=YourPassword;Encrypt=true;TrustServerCertificate=true;";
string query = @"
SELECT
o.OrderID AS 订单编号,
c.CustomerName AS 客户名称,
o.OrderDate AS 订单日期,
o.TotalAmount AS 订单金额
FROM Orders o
JOIN Customers c ON o.CustomerID = c.CustomerID
WHERE YEAR(o.OrderDate) = 2026;
";
DataTable dataTable = new DataTable();
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(query, conn);
adapter.Fill(dataTable);
}
此示例使用 Microsoft.Data.SqlClient,这是适用于 .NET 的现代 SQL 客户端库,推荐使用它来替代传统的 System.Data.SqlClient。
SqlDataAdapter 充当数据库与内存数据之间的桥梁。它负责执行查询并填充 DataTable,无需手动管理读取操作的连接。
在实际开发中,可以对此步骤进行扩展,包括:
通过在此阶段准备好干净且结构化的数据,可以降低后续格式处理的复杂度,并提升整体性能。
如需了解将数据库查询结果导出到 Excel(而非 PDF)的类似场景,可参考:在 C# 中将数据库导出到 Excel。
获取数据后,下一步是将其映射到工作表、应用格式设置,然后导出为 PDF 文档。这里利用基于工作表的布局控制,确保输出内容保持结构化和可读性。
using Spire.Xls;
using System.Drawing;
// 创建工作簿和工作表
Workbook workbook = new Workbook();
Worksheet sheet = workbook.Worksheets[0];
// 导入包含标题的 DataTable
sheet.InsertDataTable(dataTable, true, 1, 1);
// 格式化表头
CellRange headerRange = sheet.Range[1, 1, 1, dataTable.Columns.Count];
headerRange.Style.Font.IsBold = true;
headerRange.Style.Font.Size = 11;
headerRange.Style.Color = Color.LightGray;
// 应用边框以增强表格结构
CellRange dataRange = sheet.AllocatedRange;
dataRange.BorderAround(LineStyleType.Thin);
dataRange.BorderInside(LineStyleType.Thin);
// 对齐内容以保持一致性
dataRange.Style.HorizontalAlignment = HorizontalAlignType.Center;
dataRange.Style.VerticalAlignment = VerticalAlignType.Center;
// 应用全局字体
sheet.AllocatedRange.Style.Font.FontName = "微软雅黑";
// 自动调整列宽以获得更好的布局
sheet.AllocatedRange.AutoFitColumns();
// 在页面中水平居中内容
sheet.PageSetup.CenterHorizontally = true;
// 导出为 PDF
workbook.SaveToFile("SalesReport_2026.pdf", FileFormat.PDF);
此步骤将布局控制和 PDF 生成整合到一个工作流程中。
需要注意的关键点:
工作表作为布局引擎 工作表充当结构化画布,数据库数据在其中按行和列排列。这确保了原始表格结构在最终文档中得以完整保留。
格式化直接影响 PDF 输出效果 列宽、字体样式和边框等调整不仅仅是视觉美化——它们直接决定了内容在 PDF 中的渲染效果。不当的格式设置可能导致文本被截断或布局难以阅读。
自动分页功能 导出时,工作表内容会根据布局和纸张大小自动进行分页处理,这对于处理大型数据集特别有用。
如需进一步优化布局,可以通过以下方式增强表格格式:
如果您的项目需要更灵活的 PDF 结构控制,还可以探索使用 Spire.PDF for .NET 直接将 DataTable 转换为 PDF,为复杂的报表需求提供更高级的文档级操作功能。
以下是将数据库检索、数据格式化和 PDF 导出整合到单一工作流中的完整实现代码。
using System;
using System.Data;
using Microsoft.Data.SqlClient;
using Spire.Xls;
using System.Drawing;
class Program
{
static void Main()
{
// 步骤 1:从数据库检索数据
string connectionString = "Server=localhost\\SQLEXPRESS;Database=SalesDB;User ID=demouser;Password=YourPassword;Encrypt=true;TrustServerCertificate=true;";
string query = @"
SELECT
o.OrderID AS 订单编号,
c.CustomerName AS 客户名称,
o.OrderDate AS 订单日期,
o.TotalAmount AS 订单金额
FROM Orders o
JOIN Customers c ON o.CustomerID = c.CustomerID
WHERE YEAR(o.OrderDate) = 2026;
";
DataTable dataTable = new DataTable();
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(query, conn);
adapter.Fill(dataTable);
}
// 步骤 2:创建工作簿并导入数据
Workbook workbook = new Workbook();
Worksheet sheet = workbook.Worksheets[0];
sheet.InsertDataTable(dataTable, true, 1, 1);
// 步骤 3:应用专业格式化
// 格式化表头
CellRange headerRange = sheet.Range[1, 1, 1, dataTable.Columns.Count];
headerRange.Style.Font.IsBold = true;
headerRange.Style.Font.Size = 11;
headerRange.Style.Color = Color.LightGray;
// 应用边框
CellRange dataRange = sheet.AllocatedRange;
dataRange.BorderAround(LineStyleType.Thin);
dataRange.BorderInside(LineStyleType.Thin);
// 设置对齐方式
dataRange.Style.HorizontalAlignment = HorizontalAlignType.Center;
dataRange.Style.VerticalAlignment = VerticalAlignType.Center;
// 应用全局字体
sheet.AllocatedRange.Style.Font.FontName = "微软雅黑";
// 自动调整列宽
sheet.AllocatedRange.AutoFitColumns();
// 在页面中水平居中内容
sheet.PageSetup.CenterHorizontally = true;
// 步骤 4:导出为 PDF
workbook.SaveToFile("SalesReport_2026.pdf", FileFormat.PDF);
Console.WriteLine("数据库查询结果已成功导出为 PDF。");
}
}
以下是生成的 PDF 预览:

此示例展示了从执行 SQL 查询到生成 PDF 的完整工作流程。
在实际应用中,将数据库数据导出为 PDF 往往不止于基本转换,还可能需要处理批量导出、提升文档可读性,或调整布局设置以获得更好的展示效果。以下示例展示了实际使用中常见的增强功能。
对于批量报表生成或定时任务等场景,可能需要执行多个查询,并将每个查询结果导出为独立的 PDF 文档:
string[] queries = {
"SELECT * FROM Orders WHERE Status = 'Pending'",
"SELECT * FROM Customers WHERE Region = 'North'"
};
for (int i = 0; i < queries.Length; i++)
{
DataTable dt = ExecuteQuery(queries[i]);
Workbook wb = new Workbook();
Worksheet ws = wb.Worksheets[0];
ws.InsertDataTable(dt, true, 1, 1);
ws.AllocatedRange.AutoFitColumns();
wb.SaveToFile($"Report_{i + 1}.pdf", FileFormat.PDF);
}
这种方法适用于需要独立导出多个数据集的自动化报表生成场景。
为提升可读性并提供上下文信息,可以在导出数据之前,在数据上方添加标题行:
// 插入标题行
sheet.InsertRow(1);
sheet.Range[1, 1].Text = "销售报告 - 2026";
sheet.Range[1, 1].Style.Font.IsBold = true;
sheet.Range[1, 1].Style.Font.Size = 14;
// 合并标题单元格
sheet.Range[1, 1, 1, dataTable.Columns.Count].Merge();
// 自动调整标题行
sheet.AutoFitRow(1);
下图显示了应用标题行后生成的 PDF:

添加标题有助于用户快速理解文档内容,尤其在共享或打印报表时非常实用。
为确保 PDF 布局能够很好地适配您的数据,可以在导出前配置页面大小、方向和边距:
// 设置页面大小和方向
sheet.PageSetup.PaperSize = PaperSizeType.PaperA4;
sheet.PageSetup.Orientation = PageOrientationType.Portrait;
// 设置页面边距
sheet.PageSetup.TopMargin = 0.5f;
sheet.PageSetup.BottomMargin = 0.2f;
sheet.PageSetup.LeftMargin = 0.2f;
sheet.PageSetup.RightMargin = 0.2f;
调整这些设置有助于防止内容溢出,并确保不同报表之间的布局保持一致。
处理大型表格时,可能需要控制内容在页面间的分布方式。默认情况下,内容会自动分页,但也可以调整缩放行为,以便在单个页面中容纳更多数据。
// 将内容适应页面宽度
workbook.ConverterSetting.SheetFitToWidth = true;
// 将整个工作表适应单个页面(可能会降低可读性)
workbook.ConverterSetting.SheetFitToPage = true;
SheetFitToWidth 确保表格宽度适应页面,同时允许垂直方向的分页SheetFitToPage 将整个工作表缩放到单个页面内这些设置在生成紧凑报表时很有用,但应谨慎使用,避免文字过小影响阅读。
页眉和页脚可用于添加上下文信息,如报表标题、生成时间或页码:
sheet.PageSetup.LeftHeader = "&\"微软雅黑,Bold\"&16 销售报告 - 2026";
sheet.PageSetup.RightHeader = "&\"微软雅黑,Italic\"&10 生成日期:&D";
sheet.PageSetup.CenterFooter = "&\"微软雅黑,Regular\"&16 第 &P 页,共 &N 页";
下图显示了应用页眉和页脚后生成的 PDF:

这些元素提升了文档的导航体验,对于多页报表尤其有价值。
为了保护敏感数据,您可以对导出的 PDF 应用加密:
workbook.ConverterSetting.PdfSecurity.Encrypt("openpsd");
加密功能确保只有授权用户才能访问文档,这对于包含机密信息或关键业务数据的报表非常重要。
如需了解更多关于文档导出和 PDF 自定义的相关场景,还可探索C# 中的 Excel 转 PDF 转换。
请确保连接字符串正确无误,且数据库服务器可正常访问。验证身份验证设置(如 SQL 身份验证或集成安全性),并确认加密相关参数与环境配置相匹配。
在继续处理之前,请检查 DataTable 是否包含数据。空结果集可能导致生成空白 PDF 或出现意外的格式问题。
if (dataTable.Rows.Count == 0)
{
Console.WriteLine("未找到指定查询的数据。");
return;
}
在生产环境中,您还可以选择生成占位符 PDF 或记录错误日志,而不是直接退出程序。
处理长文本字段时,AutoFitColumns() 可能会产生过宽的列,从而对 PDF 布局造成负面影响。
为提升可读性,建议考虑以下方案:
这在导出包含可变长度文本的大型数据集时尤为重要。
如果导出的 PDF 包含特殊字符(如非拉丁文字)或自定义字体,请确保所需字体已安装且在运行时可访问。
缺少字体会导致文本渲染异常或使用替代字体,从而影响文档的外观和可读性。
如果导出的 PDF 布局显得拥挤或缩放不当,请检查页面设置和缩放选项,如 SheetFitToWidth 或 SheetFitToPage。
不正确的缩放设置可能导致内容显示过小,或使原始表格结构变形。
本文介绍了在 C# 中将数据库查询结果转换为 PDF 的实用方法。通过将结构化数据检索与基于工作表的格式设置相结合,您可以直接从 SQL 数据生成清晰、专业的文档。
这种方法在报表生成和数据呈现场景中特别有效,尤其是在需要保持表格结构和可读性的情况下。
如果您正在评估 Spire.XLS,可以申请免费临时许可证,以便在开发过程中去除评估限制。
是的。Spire.XLS 独立执行所有操作,不需要 Microsoft Office 或任何其他外部工具。
对于大型数据集,建议对结果进行分页处理,或通过过滤查询仅检索必要的数据。此外,还可以调整 PDF 页面设置以优化输出文件大小。
是的。Spire.XLS 允许您在导出为 PDF 之前配置页面设置,包括方向、边距和纸张大小等。
是的。该方法适用于支持 ADO.NET 数据提供程序的任何数据库,包括 MySQL、PostgreSQL 和 Oracle。只需使用相应的连接类和数据适配器即可。
对于现代 .NET 应用程序,建议使用 Microsoft.Data.SqlClient。该库持续更新维护,并为新版 SQL Server 功能提供更好的支持;而 System.Data.SqlClient 被视为遗留库,不再接收主要功能更新。
Spire.XLS for JavaScript 16.4.0 现已正式发布。该版本支持转换 Excel 和 ChartSheet 到 SVG。此外,还支持在克隆单元格范围时,通过配置 OnlyCopyFormulaValue 仅拷贝公式值。更多详情如下。
新功能:
https://www.e-iceblue.cn/Downloads/Spire-XLS-Javascript.html
我们很高兴宣布发布 Spire.Doc for Java 14.4.0。本次更新修复了在调用 appendHTML 方法时导致 NoClassDefFoundError 的缺陷。
问题修复:
新功能:
workbook.HidePivotFieldList = true;
workbook = Workbook()
workbook.LoadFromFile(inputFile)
markdownOptions = MarkdownOptions()
markdownOptions.SavePicInRelativePath = False
markdownOptions.SaveHyperlinkAsRef = False
workbook.SaveToMarkdown(outputFile, markdownOptions)
workbook.Dispose()
workbook = Workbook()
workbook.LoadFromFile(inputFile)
wb.SaveToFile("out.xlsx", ExcelVersion.Version2010);
问题修复:
在查看大型 Excel 工作表中的数据时,当你滚动到工作表的其他位置,往往会丢失对标题行或标题列的视线。在这种情况下,Microsoft Excel 提供了"冻结窗格(Freeze Panes)"功能,帮助你锁定必要的行和/或列,使其始终保持可见。
在本文中,你将学习如何使用 Spire.XLS for C++ 以编程方式冻结 Excel 工作表中的行或列。
Spire.XLS for C++ 提供了 Worksheet->FreezePanes(int rowIndex, int columnIndex) 方法,用于冻结该单元格上方的所有行和左侧的所有列,其中 rowIndex 和 columnIndex 用于指定目标单元格的位置。
本教程将针对以下几种情况提供代码示例:
将 Spire.XLS for C++ 集成到你的应用程序中有两种方式:
通过 NuGet 安装更加简单,也更推荐使用。
你也可以通过访问以下链接了解更详细的集成步骤:
如何将 Spire.XLS for C++ 集成到 C++ 程序中
要冻结首行,需要将选定单元格设置为 (2, 1),即 "A2"。具体步骤如下:
#include "Spire.Xls.o.h"
using namespace Spire::Xls;
using namespace std;
int main()
{
//指定输入文件路径
std::wstring data_path = L"Data\\";
std::wstring inputFile = data_path + L"sample.xlsx";
//指定输出文件路径
std::wstring outputPath = L"Output\\";
std::wstring outputFile = outputPath + L"FreezeFirstRow.xlsx";
//创建工作簿
intrusive_ptr<Workbook> workbook = new Workbook();
//从磁盘加载 Excel 文档
workbook->LoadFromFile(inputFile.c_str());
//获取第一个工作表
intrusive_ptr<Worksheet> sheet = dynamic_pointer_cast<Worksheet>(workbook->GetWorksheets()->Get(0));
//冻结第一行
sheet->FreezePanes(2, 1);
//保存文件
workbook->SaveToFile(outputFile.c_str(), ExcelVersion::Version2013);
workbook->Dispose();
}

要冻结首列,需要将选定单元格设置为 (1, 2),即 "B1"。以下是在 Excel 工作表中冻结首列的具体步骤:
#include "Spire.Xls.o.h"
using namespace Spire::Xls;
using namespace std;
int main()
{
//指定输入文件路径
std::wstring data_path = L"Data\\";
std::wstring inputFile = data_path + L"sample.xlsx";
//指定输出文件路径
std::wstring outputPath = L"Output\\";
std::wstring outputFile = outputPath + L"FreezeFirstColumn.xlsx";
//创建工作簿
intrusive_ptr<Workbook> workbook = new Workbook();
//从磁盘加载 Excel 文档
workbook->LoadFromFile(inputFile.c_str());
//获取第一个工作表
intrusive_ptr<Worksheet> sheet = dynamic_pointer_cast<Worksheet>(workbook->GetWorksheets()->Get(0));
//冻结第一列
sheet->FreezePanes(1, 2);
//保存文件
workbook->SaveToFile(outputFile.c_str(), ExcelVersion::Version2013);
workbook->Dispose();
}

如果你希望同时冻结首行和首列,需要将选定单元格设置为 (2, 2),即 "B2"。具体步骤如下:
#include "Spire.Xls.o.h"
using namespace Spire::Xls;
using namespace std;
int main()
{
//指定输入文件路径
std::wstring data_path = L"Data\\";
std::wstring inputFile = data_path + L"sample.xlsx";
//指定输出文件路径
std::wstring outputPath = L"Output\\";
std::wstring outputFile = outputPath + L"FreezeFirstRowAndColumn.xlsx";
//创建工作簿
intrusive_ptr<Workbook> workbook = new Workbook();
//从磁盘加载 Excel 文档
workbook->LoadFromFile(inputFile.c_str());
//获取第一个工作表
intrusive_ptr<Worksheet> sheet = dynamic_pointer_cast<Worksheet>(workbook->GetWorksheets()->Get(0));
//冻结第一行和第一列
sheet->FreezePanes(2, 2);
//保存文件
workbook->SaveToFile(outputFile.c_str(), ExcelVersion::Version2013);
workbook->Dispose();
}

如果您希望删除结果文档中的评估信息,或者摆脱功能限制,请联系销售获取有效期 30 天的临时许可证。

在服务于中国市场的 C++ 项目中,将 Word 文档转换为 OFD(开放版式文档,国家标准 GB/T 33190)是一项常见需求——无论是后端服务、报表生成器还是文档处理系统,都可能涉及这一场景。然而,传统方案通常依赖 Microsoft Office COM 自动化,部署繁琐,且难以适应服务器端环境。
本文将演示如何使用 Spire.Doc for C++ 通过编程方式实现 Word 转换为 OFD,涵盖基础文档转换与导出指定页面等进阶用法。
相比便于编辑的 Word 文档,OFD 更适合用于正式发布和长期存档。在中国的政务和企业应用中,将 Word 转换为 OFD 通常具有以下实际价值:
在 C++ 中实现 Word 转 OFD,通常有几种方式:COM 自动化、调用外部工具,或手动解析 .docx 文件。但这些方式往往存在平台限制、环境依赖或实现复杂的问题。
相比之下,Spire.Doc for C++ 提供了一种更直接的实现方式:
虽然它不能覆盖所有极端场景,但对于大多数生产环境需求来说已经足够稳定可靠。
在开始转换之前,请确保开发环境已正确配置。
详细的安装教程可参考:如何将 Spire.Doc for C++ 集成到 C++ 程序中
安装完成后,在代码中添加以下内容:
#include "Spire.Doc.o.h"
using namespace Spire::Doc;
项目准备就绪后,只需几行代码即可完成转换。
完整 C++ 示例:
#include "Spire.Doc.o.h"
#include <iostream>
using namespace Spire::Doc;
int main()
{
// 创建 Document 对象
Document* document = new Document();
try {
// 加载 Word 文档
document->LoadFromFile(L"C:\\Users\\Desktop\\测试.docx");
// 将文档转换并保存为 OFD 格式
document->SaveToFile(L"C:\\Users\\Desktop\\测试.ofd", FileFormat::OFD);
document->Close();
std::cout << "转换成功!" << std::endl;
}
catch (const std::exception& ex) {
std::cerr << "错误: " << ex.what() << std::endl;
delete document;
return -1;
}
delete document;
return 0;
}

核心代码说明:
除了基础转换,Spire.Doc for C++ 还支持更灵活的控制,例如导出指定页面、调整图片压缩、嵌入字体等。
有些场景下,你只需要转换文档中的部分页面。以下示例演示了如何提取指定页面并保存为单独的 OFD 文件。
#include "Spire.Doc.o.h"
#include <iostream>
using namespace Spire::Doc;
int main()
{
// 使用智能指针管理内存
intrusive_ptr<Document> document = new Document();
try {
document->LoadFromFile(L"C:\\Users\\Desktop\\报告.docx");
// 提取第 2 页(索引从 0 开始,所以第 2 页索引为 1)
intrusive_ptr<Document> newDoc = document->ExtractPages(1, 1);
newDoc->SaveToFile(L"C:\\Users\\Desktop\\报告_Partial.ofd", FileFormat::OFD);
document->Close();
newDoc->Close();
std::cout << "第2页转换成功!" << std::endl;
}
catch (const std::exception& ex) {
std::cerr << "错误: " << ex.what() << std::endl;
return -1;
}
return 0;
}

核心代码说明:
在一些场景中,你可能希望控制输出文件大小或字体显示效果,例如:
#include "Spire.Doc.o.h"
#include <iostream>
using namespace Spire::Doc;
int main()
{
intrusive_ptr<Document> document = new Document();
try {
document->LoadFromFile(L"C:\\Users\\Desktop\\手册.docx");
// 设置图片压缩质量 (0-100)
document->SetJPEGQuality(75);
// 设置嵌入文档中使用的所有字体
intrusive_ptr<ToPdfParameterList> parameters = new ToPdfParameterList();
parameters->SetIsEmbeddedAllFonts(true);
document->SaveToFile(L"C:\\Users\\Desktop\\手册.ofd", FileFormat::OFD);
document->Close();
std::cout << "自定义转换成功!" << std::endl;
}
catch (const std::exception& ex) {
std::cerr << "错误: " << ex.what() << std::endl;
return -1;
}
return 0;
}

核心代码说明:
答:不需要。Spire.Doc for C++ 独立运行,无需依赖 Office。
答:如上文所述,你可以使用 document->ExtractPages() 提取指定页面后再转换,或者将内容复制到新文档中处理。
答:这通常是因为系统缺少相应字体。建议在保存前调用 SetIsEmbeddedAllFonts(true) 启用字体嵌入。
答:可以通过 SetJPEGQuality(75) 开启图片压缩或降低图片质量来减小文件大小。
答:OFD 是中国国家标准,主要用于政务系统。PDF 是国际标准。两者都支持固定版式,但 OFD 在中国政务和官方场景中更常见。
对于需要满足中国国家标准、实现可靠文档共享或存档的应用程序来说,实现 C++ Word 转 OFD 至关重要。借助 Spire.Doc for C++,开发者无需依赖 Office 自动化即可完成高效转换。无论是全文转换、指定页面提取还是自定义转换参数设置,该库都提供了一个实用且强大的 C++ 文档处理方案。
如需了解更多文档转换和操作功能,请查阅官方文档。

VBA 宏为 Excel 内自动化数据处理、格式化和业务逻辑提供了便捷的方式,特别适用于重复性或基于规则的任务。然而,当需要大规模生成、更新或维护文件时,手动在 Excel 内部管理宏会变得效率低下。
对于.NET 开发者而言,更具扩展性的方法是使用 C# 以编程方式向 Excel 添加宏。通过在 C# 中处理 Excel VBA,可以实现跨多个文件编写 Excel 宏、读取现有宏代码以及修改 VBA 逻辑,而无需打开 Excel 并手动编辑 VBA 代码。
本文将介绍如何使用 C# 添加、读取、编辑和删除 Excel VBA 宏,以实现自动化工作流。此方案使用 Spire.XLS for .NET 直接操作嵌入在 Excel 文件中的 VBA 项目,而无需安装 Microsoft Excel。
快速导航
Excel 宏本质上是存储在 workbook 中的 VBA(Visual Basic for Applications)代码。在启用宏的文件(如 .xlsm)中,这些代码被组织在 VBA 项目 中,包含模块和过程。
在实践中,大多数编程宏操作都专注于标准模块,它们是 VBA 过程(Sub 或 Function)的简单容器。使用 C# 时,通常不会与 Excel UI 元素(如按钮或事件)交互。相反,您直接创建模块并注入 VBA 代码。
从技术角度来看,宏不仅仅是可执行脚本,它们是文件结构的一部分。这意味着只要工具支持 VBA 项目操作,就可以以编程方式访问和修改。
在 C# 中,处理 Excel 宏主要有两种方法:
第一种方法依赖已安装的 Excel,通常用于执行宏。第二种方法允许直接在 Excel 文件中创建、读取、编辑和删除 VBA 代码,使其更适合后端服务和自动化工作流。
在以下部分中,我们将重点关注第二种方法,并演示如何完全在 C# 中管理 Excel 宏。
在使用 C# 处理 Excel 宏之前,需要安装 Spire.XLS for .NET 来管理 Excel 文件并操作 VBA 项目。
可使用 NuGet 包管理器安装 Spire.XLS for .NET:
Install-Package Spire.XLS
或通过.NET CLI:
dotnet add package Spire.XLS
也可以下载 Spire.XLS for .NET 包 并手动添加到项目中。
该库与运行时无关,可用于任何.NET 支持的环境,包括 Web、桌面和跨平台应用程序。
安装后,在项目中包含以下命名空间:
using Spire.Xls;
设置完成后,就可以开始以编程方式创建、读取和修改 Excel VBA 宏。
在编写宏代码之前,了解 Spire.XLS 如何处理 Excel 中的 VBA 结构非常重要:
除了模块之外,VBA 项目还支持项目级配置,例如名称、描述、密码保护和条件编译设置。
以下示例展示如何创建 VBA 项目、配置其属性、添加模块并将宏写入 Excel 文件中。
using Spire.Xls;
// 创建工作簿实例
Workbook workbook = new Workbook();
// 创建 VBA 项目
IVbaProject vbaProject = workbook.VbaProject;
// 配置项目级属性(可选,但在实际场景中很重要)
vbaProject.Name = "报告生成器";
vbaProject.Description = "用于生成季度报告的 VBA 项目";
vbaProject.Password = "securepassword"; // 设置密码保护
vbaProject.LockProjectView = false; // 是否锁定项目视图
vbaProject.HelpFileName = "报告生成器帮助文档.chm";
vbaProject.ConditionalCompilation = "DEBUG_MODE=1"; // 外部编译时标志
// 设置编码方式(936 表示 GBK 编码)
vbaProject.CodePage = 936;
// 添加 VBA 模块
IVbaModule vbaModule = vbaProject.Modules.Add("报告模块", VbaModuleType.Module);
// 编写 VBA 宏代码
vbaModule.SourceCode = @"
Sub 生成季度报告 ()
Dim ws As Worksheet
Dim i As Integer
Dim quarter As String
Set ws = ActiveSheet
ws.Cells.Clear
' 提示用户输入
quarter = InputBox(""请输入季度(例如:2026 年第一季度):"",""报告生成"")
With ws
.Range(""A1:E1"").Value = Array(""日期"", ""产品"", ""区域"", ""销售额"", ""状态"")
For i = 1 To 50
.Cells(i + 1, 1).Value = DateSerial(2026, 1 + Int((i - 1) / 17), 1 + ((i - 1) Mod 17))
.Cells(i + 1, 2).Value = ""产品 "" & (1 + Int((i - 1) / 10))
.Cells(i + 1, 3).Value = Choose((i Mod 5) + 1, ""华北"", ""华南"", ""华东"", ""华西"", ""华中"")
.Cells(i + 1, 4).Value = Round(Rnd() * 10000, 2)
.Cells(i + 1, 5).Value = IIf(.Cells(i + 1, 4).Value > 5000, ""达标"", ""未达标"")
Next i
.Columns(""A:E"").AutoFit
' 条件编译示例
#If DEBUG_MODE = 1 Then
MsgBox ""调试:已生成报告(50 行)"", vbInformation, ""调试信息""
#End If
End With
MsgBox ""季度报告 "" & quarter & "" 已成功生成!"", vbInformation, ""报告状态""
End Sub";
// 保存为启用宏的 Excel 文件
workbook.SaveToFile("季度报告生成器.xlsm", FileFormat.Version2016);
workbook.Dispose();
以下是生成的 Excel 宏的预览:

在此流程中,Spire.XLS 以代码形式构建完整的 VBA 结构,包括模块和宏代码以及项目级元数据和编译行为。这在概念上类似于在编辑器中配置 VBA 项目,但完全自动化且不依赖 Excel。
workbook.VbaProject
初始化或检索工作簿内的 VBA 项目。
vbaProject.Modules.Add(name, type)
向项目添加新模块作为宏代码的容器。
vbaModule.SourceCode
定义模块中的完整 VBA 脚本。
vbaProject.Description
为 VBA 项目添加描述。
vbaProject.CodePage
定义 VBA 项目中使用的字符编码。
注意:写入 VBA 代码前请确保通过该属性正确设置字符编码,否则可能导致 Excel 文件无法打开。
vbaProject.Password / LockProjectView
控制 VBA 项目的访问和可见性。
vbaProject.ConditionalCompilation
在 VBA 中使用 #If 启用编译时标志(例如调试逻辑)。
包含宏的工作簿必须保存在启用宏的格式中,如 .xls、.xlsm、.xltm 或 .xlsb,其他格式(如 .xlsx)不支持 VBA。参考 FileFormat 枚举 以在保存时正确设置输出格式。
对于存在 VBA 宏的项目,可以使用 Spire.XLS 直接检查和管理其内容,包括模块代码和项目级元数据。
在实际场景中,这样的能力可以分析现有宏、更新业务逻辑、实施安全设置或删除遗留 VBA 代码,而无需打开 Excel。无论是维护自动化报告系统还是处理第三方 Excel 文件,完全控制 VBA 项目都是必不可少的。
要从 Excel 文件读取宏,请加载工作簿并遍历 VBA 项目中的所有模块。
using Spire.Xls;
// 创建工作簿实例并加载文件
Workbook workbook = new Workbook();
workbook.LoadFromFile("季度报告生成器.xlsm");
// 获取 VBA 项目
IVbaProject vbaProject = workbook.VbaProject;
// 构建宏信息字符串
string macroInfo = "VBA 项目名称:" + vbaProject.Name + Environment.NewLine;
macroInfo += "代码页:" + vbaProject.CodePage + Environment.NewLine;
macroInfo += "是否受保护:" + vbaProject.IsProtected + Environment.NewLine;
// 遍历所有模块
foreach (IVbaModule module in vbaProject.Modules)
{
macroInfo += Environment.NewLine + "模块:" + module.Name + Environment.NewLine;
macroInfo += "源代码:" + Environment.NewLine;
macroInfo += module.SourceCode + Environment.NewLine;
}
// 输出到控制台
Console.WriteLine(macroInfo);
// 保存到文本文件
System.IO.File.WriteAllText("宏分析.txt", macroInfo);
workbook.Dispose();
以下是控制台输出的预览:

在这里,每个模块通过 SourceCode 属性公开其 VBA 代码,而 VBA 项目本身提供元数据,如名称、编码和保护状态。
示例中的 vbaProject.IsProtected 属性指示 VBA 项目是否受保护(锁定查看或编辑)。
如果需要编辑宏代码,可访问特定模块并更新其 SourceCode;如果需要编辑宏项目的元数据,还可以通过 IVbaProject 类的其他属性修改项目级元数据。
需要注意的是,如果 VBA 项目受保护,则在进行此类更改之前必须提供正确的密码。
using Spire.Xls;
// 创建工作簿实例并加载文件
Workbook workbook = new Workbook();
workbook.LoadFromFile("季度报告生成器.xlsm");
// 获取 VBA 项目
IVbaProject vbaProject = workbook.VbaProject;
// 更新宏逻辑
IVbaModule module = vbaProject.Modules["报告模块"]; // 如果名称未知,也可以使用索引
module.SourceCode = module.SourceCode.Replace(
"\"华北\", \"华南\", \"华东\", \"华西\", \"华中\"",
"\"华北区\", \"华南区\", \"华东区\", \"华西区\", \"华中区\"");
// 更新项目元数据
// 对于受保护的 VBA 项目,需要密码才能修改项目级元数据
vbaProject.Password = "securepassword";
vbaProject.Description = "已更新报告逻辑,使用全球区域";
vbaProject.Name = "更新后的报告生成器";
// 保存文件
workbook.SaveToFile("更新后的报告生成器.xlsm", FileFormat.Version2016);
workbook.Dispose();
以下是更新后的宏代码预览:

Spire.XLS 将宏代码视为模块中的可编辑文本,因此更新通常通过修改现有源代码并保存工作簿来完成。
要删除宏,请从 VBA 项目中删除模块。这将有效地从工作簿中删除所有宏逻辑。
using Spire.Xls;
// 创建工作簿实例并加载文件
Workbook workbook = new Workbook();
workbook.LoadFromFile("季度报告生成器.xlsm");
// 获取 VBA 项目
IVbaProject vbaProject = workbook.VbaProject;
// 按名称删除特定模块
vbaProject.Modules.Remove("报告生成器");
// 或按索引删除模块
vbaProject.Modules.RemoveAt(0);
// 删除所有模块
vbaProject.Modules.Clear();
// 保存文件
workbook.SaveToFile("清理后的文档.xlsm", FileFormat.Version2016);
workbook.Dispose();
删除所有模块后,工作簿不再包含可执行的 VBA 代码,使其等同于无宏的 Excel 文件。
还可以将启用宏的 Excel 文件转换为 .xlsx从而直接删除所有宏,因为 .xlsm 文件保存为不支持 VBA 代码的 .xlsx 格式时,宏项目和模块代码都会被删除。
宏需要启用宏的格式,如 .xlsm、.xls 或 .xlsb。.xlsx 格式不支持 VBA 代码。请务必使用适当的扩展名保存文件。
VBA 代码使用特定的编码(通常包含简体中文字符时使用 CodePage 936),处理国际字符时,请在写入宏代码之前确保正确设置 CodePage,否则可能导致 Excel 文件无法打开。
常见的 CodePage 值包括:
Excel 宏安全设置可能会阻止宏运行。分发启用宏的文件时,请考虑添加启用宏的说明或对 VBA 项目进行数字签名。
为新版本 Excel 编写的 VBA 代码可能在旧版本中无法正常工作,在目标 Excel 版本上测试宏以确保兼容性。
C# 提供了强大的功能来以编程方式管理 Excel 宏。使用 Spire.XLS for .NET,开发者可以直接通过 C# 在 Excel 文件中添加、读取、编辑和删除 VBA 宏代码,而无需安装 Excel。
这种方法能够直接在开发环境中管理宏代码和项目属性,使其非常适合自动化工作流、后端服务和大规模文档处理。
如需测试宏相关操作能力而移除所有限制,可申请 Spire.XLS for .NET 的免费临时许可。
可以。Spire.XLS for .NET 等库允许您直接操作 VBA 项目,而无需安装 Excel。
宏需要启用宏的格式,如 .xlsm、.xls、.xlsb 或 .xltm(用于模板)。.xlsx 格式不支持 VBA 代码。
可以。您可以访问 VBA 模块并以编程方式修改其源代码,以更新业务逻辑或修复多个文件中的问题。
可以。由于它不依赖 Microsoft Excel,因此非常适合后端服务、自动化系统和基于云的应用程序。
这取决于应用于 Excel 文件的保护类型。
此外,如果 Excel 文件具有数字签名,则对文档的任何修改(包括宏或元数据)都将使签名失效。
Spire.PDF 12.4.0 现已正式发布。该版本优化了 PDF 合并功能的内存占用并修复了一些在操作 PDF 文档时出现的问题。详情请查阅以下内容。
优化:
问题修复: