我希望能够:
为什么我要这样做?我正在尝试构建一个Word加载项,其作用类似于拼写检查器,因为它在后台运行(背景我的意思是通过使用SendMessage定期从主Word线程窃取时间)并扫描文档以确定文字“令牌”。我希望能够保留一组标记,并在文档更改时更新它们。一个具体的例子是,如果用户编辑给定的段落,我想重新扫描段落并更新指向该段落的数据结构。如果无法在用户编辑的段落(即选择范围的开头所在的段落)和我在数据结构中“存储”的段落之间进行映射,我就无法做到这一点。
上面第1项的示例代码
如果我写下面的VBA代码:
Dim Para1 As Paragraph
Dim Para2a As Paragraph
Dim Para2b As Paragraph
Set Para1 = ActiveDocument.Paragraphs(1)
Set Para2a = Para1.Next
Set Para2b = Para1.Next.Next.Previous
If Para2a Is Para2b Then
Debug.Print ("Para2a Is Para2b")
Else
Debug.Print ("Para2a Is Not Para2b")
End If
然后我得到输出:
"Para2a Is Not Para2b"
这可能是物理上真实的(不同的COM代理),但逻辑上不正确。我需要能够比较这些段落并确定它们在逻辑上是否是相同的基础段落。
(我打算用C#编写加载项,但上面的VBA代码演示了在编写太多代码之前需要克服的问题)。
对于上面的第2和第3项,希望它们不言自明。假设我有一个段落(互操作代理)参考。我想弄清楚它在文档中的“位置”。它属于第1节吗?是在页脚?如果没有这种能力,我可以合理地做一些事情来了解事物的来源,每次更改时都会重新扫描整个文档,这当然是非常低效的,并且对于应用程序用户来说不够及时。
任何想法都非常感谢!我很乐意根据需要发布其他信息。
答案 0 :(得分:2)
在COM Interop环境中浏览参考平等的细节总是一个有趣的练习。
我不了解Paragraph.Next()
和Paragraph.Previous()
方法的实现细节,但是它们展示的行为与基于COM的集合在运行时可调用方面的行为方式非常相似包装创作。
通常,如果可能,框架会避免创建新的RCW实例,以响应对已经初始化和分配RCW的COM对象的其他引用。如果已经存在针对IUnknown
的特定指针的RCW,则由该RCW维护的内部引用计数递增,然后返回RCW。这允许框架避免增加实际COM对象的引用计数(AddRef
)。
基于COM的集合是具有实现IEnumerable
的托管表示的COM对象,每次访问项时都会生成新的RCW,即使该项已在会话期间被访问过。
例如:
Word.Document document = Application.ActiveDocument;
Paragraphs paragraphs = document.Paragraphs;
Paragraph first = paragraphs[1];
Paragraph second = paragraphs[1];
bool thisIsFalse = (first == second);
如果要进行任何类型的“引用相等”检查,则需要从基于COM的集合中逃脱,特别是在您的情况下:Paragraphs
对象。你可以通过抓住它的孩子并将它们存储在你自己的,纯粹管理和可预测的集合中来实现这一点,如下所示:
List<Paragraph> niceParagraphs = paragraphs.Cast<Paragraph>().ToList();
虽然使用LINQ和COM Interop可能看起来有点可怕(如果它不适合你...它真的应该!)我相当确定上面的代码是安全的,不会留下任何悬空引用,或其他任何令人讨厌的。但是,我没有详尽地测试上面的代码。
当你完成这些资源时,不要忘记正确释放这些资源,至少如果你的要求需要那么谨慎。