- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的组织有时需要使用 Excel 生成一堆格式化的报表(从文档的意义上说“您的账户余额是 $X”),将它们打印成 PDF,然后将它们合并成一个大的 PDF。通常使用的方法涉及由索引单元格驱动的单个工作表和另一工作表上的人员/数据列表。 VBA 宏将索引单元格从 1 迭代到 N,然后使用 Adobe Distiller API 每次打印格式化的工作表并组合结果。
出于各种原因,我想在我们的 VSTO Excel 加载项中用 C# 实现此宏的大部分逻辑,以便该过程的 VBA 端减少到几行。
我决定公开一个大致如下所示的 API:
AcroPDDoc PdfBegin(Worksheet worksheet, string filename);
void PdfAddPage(AcroPDDoc pdf, Worksheet worksheet);
void PdfComplete(AcroPDDoc pdf);
您的想法是编写以下形式的 VBA:
Sub PrintToPdf()
Dim obj As IMySharedObject
Set obj = Application.COMAddIns("MyAddIn").Object
Dim pdf As Acrobat.AcroPDDoc
Dim i As Long
For i = 1 To 10
Range("counter").Value = i
If i = 1 Then
Set pdf = obj.PdfBegin(Sheets("Statement"), "C:\myFile.pdf")
Else
PdfAddPage pdf, Sheets("Statement")
End If
Next i
PdfComplete pdf
End Sub
我对 AcroPDDoc
对象的生命周期以及打开的文件句柄、Acrobat.exe 进程等感到好奇/担心,以防宏遇到错误或在执行中途终止。 super 并不担心,因为必要时“关闭 Excel 并重新打开”是一个可接受的解决方案。我用 C# 编写了以下代码:
internal static class Printing
{
private static WeakReference weakref;
public static AcroPDDoc PdfBegin(Worksheet worksheet, string filename)
{
SetAdobeOutputFile(filename);
worksheet.PrintOut(ActivePrinter: "Adobe PDF");
AcroPDDoc pdf = new AcroPDDoc();
pdf.Open(filename);
weakref = new WeakReference(pdf);
return pdf;
}
public static void GC()
{
System.GC.Collect();
}
public static void test(AcroPDDoc pdf)
{
if (weakref != null) {
System.Diagnostics.Debug.WriteLine("IsAlive pre: " + weakref.IsAlive);
if (weakref.IsAlive) System.Diagnostics.Debug.WriteLine("ReferenceEquals: " + Object.ReferenceEquals(pdf, weakref.Target));
}
GC.Collect();
if (weakref != null) System.Diagnostics.Debug.WriteLine("IsAlive post: " + weakref.IsAlive);
}
}
我已经删除了一堆额外的 Debug.WriteLine
和一些其他无关的代码。我使用以下 VBA 对其进行了测试:
Sub foo()
Dim obj As IUDFSharedObject
Set obj = Application.COMAddIns("MyAddIn").Object
Dim pdf As Acrobat.AcroPDDoc
Set pdf = obj.PdfBegin(Sheets("Statement"), "C:\myFile.pdf")
'obj.GC
'obj.test pdf
End Sub
我发现一般情况下,.NET 在其垃圾收集引用计数中不包括发送到 VBA 领域的引用。
例如,如果我只取消注释 obj.GC
和 obj.test pdf
,我会被告知 weakref
不存在。
但是,如果我只取消注释 obj.test pdf
,weakref
在之前和之后都有效(并且我发出“ReferenceEquals: true”)。
请注意 pdf
一直在 VBA 范围内。我最初测试过如果让 pdf
也转义 VBA 范围会发生什么,但事实证明这无关紧要。
这对我来说是一个比资源链接大得多的问题。除了将 List
中生成的每个 AcroPDDoc
对象永久存储在某处以使引用计数保持在零以上之外,是否有任何解决方案?
最佳答案
感谢上面的@yms,我已经弄清楚发生了什么,并提出了一个我相当满意的解决方案。首先,对 API 进行轻微修改:
void PdfBegin(AcroPDDoc pdf, Worksheet worksheet, string filename);
void PdfAddPage(AcroPDDoc pdf, Worksheet worksheet);
void PdfComplete(AcroPDDoc pdf);
每个 C# 方法在返回之前都会调用 Mashal.ReleaseComObject(pdf)
。我读过Marshal.ReleaseComObject
considered dangerous ,但我测试了他所说的特定故障模式,发现它在实践中似乎并未发生。
VBA 现在必须从一开始就提供 AcroPDDoc 对象。因此,典型的用法如下所示:
Sub PrintToPdf()
Dim obj As IMySharedObject
Set obj = Application.COMAddIns("MyAddIn").Object
Dim pdf As New AcroPDDoc
Dim i As Long
For i = 1 To 10
Range("counter").Value = i
If i = 1 Then
obj.PdfBegin pdf, Sheets("Statement"), "C:\myFile.pdf"
Else
obj.PdfAddPage pdf, Sheets("Statement")
End If
Next i
obj.PdfComplete pdf
End Sub
本质上只是声明现在是 As New AcroPDDoc
而不是 As AcroPDDoc
和后来的 Set
。
测试表明,一旦 AcroPDDoc 的引用计数超出范围或引用设置为 Nothing
,VBA 会非常迅速地减少它的引用计数。这包括在子例程中出现错误并且用户结束执行的情况。
最后,Acrobat.exe 进程也会在其引用计数达到零时提示自行终止,即使它打开了一个文件也是如此。
关于c# - 从 .NET 传递到 VBA 的 COM 对象的对象生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26288984/
创建使用.NET框架的asp.net页面时,访问该页面的客户端是否需要在其计算机上安装.NET框架? IE。用户访问www.fakesite.com/default.aspx,如果他们没有安装框架,他
我阅读了很多不同的博客和 StackOverflow 问题,试图找到我的问题的答案,但最后我找不到任何东西,所以我想自己问这个问题。 我正在构建一个应用程序,其中有一个长时间运行的工作线程,它执行一些
已锁定。这个问题及其答案是locked因为这个问题是题外话,但却具有历史意义。目前不接受新的答案或互动。 我一直想知道为什么微软为这样一个伟大的平台选择了一个如此奇怪的、对搜索引擎不友好的名称。他们就
.Net Framework .Net .NET Standard的区别 1、.NET Framework 在未来.NET Framework或许成为过去时,目前还是有很多地方在使用的。这一套
如果有选择的话,您会走哪条路? ASP.NET Webforms + ASP.NET AJAX 或 ASP.NET MVC + JavaScript Framework of your Choice
我有一个 Web 服务,它通过专用连接通过 https 使用第三方 Web 服务,我应用了 ServicePointManager.ServerCertificateValidationCallbac
为什么我应该选择ASP.NET Web Application (.NET Framework)而不是ASP.NET Core Web Application (.NET Framework)? 我在
我在网络上没有找到任何关于包含 .NET Standard、.NET Core 和 .NET Framework 项目的 .NET 解决方案的公认命名约定。 就我而言,我们在 .NET 框架项目中有以
.NET Compact 是 .NET 的完美子集吗? 假设我考虑了屏幕大小和其他限制并避免了 .NET Compact 不支持的类和方法,或者 .NET Compact 是一个不同且不兼容的 GUI
我已经阅读了所有我能找到的关于 connectionManagement 中的 maxconnection 设置的文章:即 http://support.microsoft.com/kb/821268
我现在正在使用asp.net mvc,想知道使用内置的Json或 Json.Net哪个是更好的选择,但我不确定一个人是否比另一个人有优势。 另外,如果我确实选择沿用Json.Net的路线,那么我应该选
在 Visual Studio 中,您至少可以创建三种不同类型的类库: 类库(.NET Framework) 类库(.NET 标准) 类库(.NET Core) 虽然第一个是我们多年来一直使用的,但我
.NET 和 ASP.NET 之间有什么区别?它们有什么关系? 最佳答案 ASP.Net 基于 .Net 框架构建,提供有关 Web 开发的附加功能。 你可以去看看wikipedia article
在安装更高版本(3.0)之前,我需要安装.net框架1.1和2.0吗?或者单独安装 3.0 框架就足够了,并为在早期框架版本上编写的软件提供支持?谢谢 ,丽然 最佳答案 不,您不必安装以前的框架。 我
我正在开发一个项目,人们可以“更新”类别,例如更改类别的名称。我收到以下消息 This is called after clicking update 按钮 with the SQL statemen
.NET 类 System.Net.CookieContainer 线程安全吗? --更新:交 key 答复-- 是否有任何方法可以确保异步请求期间修改的变量(即 HttpWebRequest.Coo
我正在使用 JScript.NET 在我编写的 C# WinForms 应用程序中编写脚本。它工作得很好,但我只是尝试在脚本中放置一些异常处理,但我无法弄清楚如何判断我的 C# 代码抛出了哪种类型的异
我需要你的帮助, 比如我有一个小数类型的变量,我想这样取整。 例如 3.0 = 3 3.1 = 4 3.2 = 4 3.3 = 4 3.4 = 4 3.5 = 4 3.6 = 4 3.7 = 4 3.
我使用过这样的代码:http://msdn.microsoft.com/en-us/library/dw70f090.aspx在 ASP.NET 中工作之前访问数据库(2-3 年前)。我没有意识到我正
自 ConfigurationManager .NET Standard 中不存在,检索正在执行的程序集的应用程序设置的最佳方法是什么,无论是 web.config或 appSettings.{env
我是一名优秀的程序员,十分优秀!