上下文菜单在Word自动化时消失

16

当我正在OleContainer(即地点编辑)中编辑Word文档时,如果切换到另一个Word文档,然后再切换回来,我无法使用鼠标右键。上下文菜单将不会显示。

这在Word 2000上发生,而在Word 2007上不会发生(我不知道其他版本情况如何)。

如何解决这个问题?

操作步骤:

  • 创建一个新的VCL应用程序
  • 添加一个菜单栏
  • 添加一个TOleContainer,对齐方式为alClient,AllowInPlace和AllowActiveDoc都设置为True。
  • 使用TOleContainer插入一个Word 97-2003文档
  • 向菜单栏添加一个名为“关闭”的菜单项,在其事件处理程序中添加OleContainer1.DestroyObject,以停止编辑
  • 运行该应用程序,双击OleContainer使其进入编辑模式
  • 现在打开Word 2000
  • 切换回您的应用程序,上下文菜单将不再起作用。

注: 我在以下系统上重现了上述行为(使用Citrix):

Windows Server 2003企业版
版本5.2(构建3790.srv03_sp2_rtm.070216-1710:服务包2)

Microsoft Word 2000(9.0.6926 SP-3)

我使用Delphi 7(版本8.1)创建了该应用程序。


1
请问您使用的是哪个版本和服务包级别(操作系统、Delphi、Word)? - macf00bar
这个错误是否发生在 Citrix 之外? - Judah Gabriel Himango
@Judah Himango:很抱歉,我没有Word 2000的系统,除了Citrix之外,所以无法回答你的问题。 - The_Fox
好的。请记住,大约一两年前我们在 Citrix 中看到了一些奇怪的焦点和窗口激活行为。您可能需要确认此错误是否发生在 Citrix 之外。 - Judah Gabriel Himango
3个回答

4
当通过ActiveX托管Office应用程序时,您会发现某些版本的某些Office应用程序对于被告知窗口激活更改非常敏感,这尤其会影响它们的上下文菜单。
基本上,如果您不在它们失去或获得焦点以及您的顶级窗口获得或失去焦点时告诉它们(即使它们的子控件在窗口中没有获得焦点),那么它们可能会出现问题。
这是我长期以来一直在努力解决的问题,特别是当您不得不告诉应用程序一些它们比您更了解的东西时(例如它们直接失去或获得焦点时......或者当它们创建一个弹出式菜单将焦点从它们身上取走并且必须以与其他应用程序/窗口不同的方式进行处理时,你需要自己去理解...呃。
无论如何,Office应用程序应该公开一个IOleInPlaceActiveObject接口,并确保您调用其OnFrameWindowActivate方法来告诉它有关激活/停用的信息。
从记忆中和快速查看我自己用于托管Office的代码,这是最重要的事情之一。它也是一个很容易忽略的事情,认为“不,它不可能那么重要......为什么任何事情都会那么关心窗口是否处于活动状态?”您可能认为这只会导致一些轻微的外观问题(例如在不活动时出现活动状态),但它可能会导致整个系统锁定或崩溃。相信我,Office对此非常关注!我有印象,在Office内部,仍然存在着一种非常古老的单线程设计,来自合作式多任务处理的日子,当两个窗口似乎同时处于活动状态时,它可能会变得非常困惑。
抱歉我无法给出比指向该方向更多的建议......编写ActiveX宿主是黑魔法(所有文档都针对被托管而非作为宿主 :( ),我让自己的代码工作的唯一方法是经过数月的试错和大量的调试输出。不幸的是,这是一场噩梦。
最后一个建议:不要害怕为特定应用程序硬编码修补程序。这就是IE本身所做的,使用注册表设置来控制应用于哪些修补程序(我怀疑某些已硬编码到代码中)。ActiveX是如此定义不清的混乱,各种控件都有自己的怪癖和错误,不可能编写一个干净的通用宿主与所有控件一起使用。 (修复一个的更改将破坏另一个。)您还会发现,只有在尝试IE以相同顺序的接口时才能正常工作,因为它们只与IE一起进行了测试;稍微以不同的方式处理事情,它们就会崩溃。 :(

1
有点晚了,但还是谢谢,这解决了问题!这也修复了在 Word 2007 中切换我们的应用程序和 Word 时无法使用菜单的问题。(我通过调用 uiActivate 来解决了这个问题,但这种方法更好更快)。PS:你说得对,这确实是黑魔法,你不想知道我们从客户那里收到了多少完全无法重现的错误报告。 - The_Fox
@The_Fox,很高兴它有用! - Leo Davidson

0
也许您可以使用一个组件来调用应用程序。我从未在通过接口调用Word并在菜单中注册特殊命令时创建自定义组件方面遇到过问题。在容器中,您不能在表单上设计特殊菜单吗?有一些WordSink事件可用于保存和关闭,并可与Word com对象结合使用。

0

我想知道您是否能够从包含OLE容器的表单中捕获任何“失去焦点”类型的事件,在此时您可以销毁OLE容器中的文档但保留其在内存中。然后,在表单上的任何“获得焦点”类型的事件上,您可以检查是否拥有该文档;如果是,则重新加载到OLE容器中。

这对您有用吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接