我正在为 excel 创建一个 VSTO 功能区插件,并将一些工作簿状态信息存储在我的应用程序中,用于更新已启用的可视按钮。考虑到可能有多个工作簿,我将此状态对象存储在 ThisAddIn 类的字典中。我的问题是我不知道如何为工作簿获取唯一的哈希/密钥/Guid,因为我得到的只是一个不断更改哈希的 COM 包装器。很公平,我完全理解这一点。
我使用了很长时间的一种解决方案是创建一个 guid 并将其存储在工作簿的 CustomDocumentProperties 中,并基于它作为键映射状态。这至少有效,但是如果我创建工作簿的副本并在同一个应用程序实例中打开它并且现在有多个具有相同 guid 的工作簿,它将失败。
我现在有了一个想法,我想我可以在 Workbook_Open 事件上刷新这个 Guid。但这似乎仍然是一个狡猾的解决方案。
我在这里找到的第二个解决方案:http: //social.msdn.microsoft.com/Forums/en-US/vsto/thread/04efa74d-83bd-434d-ab07-36742fd8410e/
所以我使用了那些人的代码并创建了这个:
public static class WorkbookExtensions
{
public static IntPtr GetHashery(this msExcel.Workbook workbook)
{
IntPtr punk = IntPtr.Zero;
try
{
punk = Marshal.GetIUnknownForObject(workbook);
return punk;
}
finally
{
//Release to decrease ref count
Marshal.Release(punk);
}
}
}
它在几分钟内运行良好,直到它在访问 Application.ActiveWorkbook 时开始给我一个臭名昭著的错误“无法使用已与其底层 RCW 分离的 COM 对象”。
这是引用 Workbook COM 对象的安全方式吗?如果我有两个功能区应用程序都使用此方法来获取单个工作簿 GUID,该怎么办?如果其中一个应用程序在我的状态对象上运行垃圾收集器,它调用终结器来调用 Marshal.FinalReleaseComObject(workbook),该怎么办?有什么方法可以让我获得工作簿的 Ref Count,这样我就不会在其他功能区应用程序完成之前调用 FinalRelease?清理 VSTO 中的 Workbook COM 对象以保持与这些其他应用程序公平竞争的最佳实践是什么?
当然,我不是第一个想要根据工作簿状态启用按钮的人,其他人是如何做到这一点的?我在 Stack Overflow 上查看了其他几篇文章,但没有一篇对 Workbook Guid 解决方案有帮助。
我正在使用功能区设计器,并连接到工作簿加载和停用事件。
在此先感谢,希望我包括了所有细节。