导致意外行为的 Visio Interop 应用程序事件

Visio Interop Application events causing undesired behaviour

我正在尝试使用 Visio 应用程序事件。当实例化一个新的 Application 对象并设置任何事件(即 BeforeDocumentClose)时,这似乎导致 Visio 在最小化后无法恢复 window。

我正在使用 VS/C# 2013,Windows Forms,Visio 2013(在 Windows 7 上)。虽然我的主要代码项目是使用加载项在各种办公应用程序之间实现交换的巨大项目,但以下简单代码重现了相同的问题。这是一个 Windows 表单项目(添加了对 Microsoft.Office.Interop.Visio 的引用)。

using Visio = Microsoft.Office.Interop.Visio;

Visio.Application app;
bool initialised = false;

private void visioButton_Click(object sender, EventArgs e)
{
    init();

    app.Documents.Add("c:\test.vst"); // creates new document from template
}

void init()
{
    if (!initialised)
    {
        // only initialise once
        app = new Visio.Application();
        app.BeforeDocumentClose += app_BeforeDocumentClose;
        initialised = true;
    }
}

void app_BeforeDocumentClose(Visio.Document doc)
{
}

问题 #1:这是主要问题。创建一个或多个Visio 文档,Visio Window 最小化后没有最大化。据我所知,没有抛出异常。 Windows 只是声音错误 'ping'。

问题 #2:这是次要问题。创建两个或多个 Visio 文档,将鼠标悬停在 Windows 任务栏上,预览 windows 显示等待光标而不是正常的文档预览。

条件:问题 #1 仅在应用程序上使用事件时发生。文档,Page/Shape 事件不会造成任何问题。所有事件都被捕获。问题 #2 总是会出现,但这对我来说不太重要。

我已经搜索这个问题一段时间了,但找不到任何相关内容,非常感谢您的帮助。

我不太确定是什么导致 Visio 不响应还原,但您可以尝试使用 "AddAdvise" 的方法:

[ComVisible(true)]
public partial class Form1 : Form, Visio.IVisEventProc
{
    public Form1()
    {
        InitializeComponent();
    }

    Visio.Application app;
    bool initialised = false;

    private void button1_Click(object sender, EventArgs e)
    {
        init();

        app.Documents.Add("C:\test.vst"); // creates new document from template
    }

    void init()
    {
        if (!initialised)
        {
            // only initialise once
            app = new Visio.Application();
            // app.BeforeDocumentClose += app_BeforeDocumentClose;
            app.EventList.AddAdvise(DocCloseEventCode, this, null, null);
            initialised = true;

            Application.DoEvents();
        }
    }

    const short DocCloseEventCode = unchecked((short)Visio.VisEventCodes.visEvtDoc + (short)Visio.VisEventCodes.visEvtDel);

    object Visio.IVisEventProc.VisEventProc(short eventCode, object source, int eventID, int eventSeqNum, object subject,object moreInfo)
    {
        if (eventCode == DocCloseEventCode)
            app_BeforeDocumentClose(subject as Visio.Document);

        return null;
    }

    void app_BeforeDocumentClose(Visio.Document doc)
    {
    }
}

为了使用 Nikolay 的建议为多个事件提供完整的解决方案,这里是完整的代码,包括事件和 Visio 应用程序的(取消)初始化,并且不使用模板。 (请注意,消息框可能会出现在背景中,位于 Visio window 后面。)

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Visio = Microsoft.Office.Interop.Visio;

namespace VisioInteropTest
{
    [ComVisible(true)]
    public partial class TestForm : Form, Visio.IVisEventProc
    {
        Visio.Application app;
        bool initialised = false;

        // all AddAdvise events:
        // https://msdn.microsoft.com/en-us/library/office/ff768620.aspx
        const short appCloseEventCode = (short)(Visio.VisEventCodes.visEvtApp | Visio.VisEventCodes.visEvtBeforeQuit);
        const short docCloseEventCode = (short)(Visio.VisEventCodes.visEvtDoc | Visio.VisEventCodes.visEvtDel);

        public TestForm()
        {
            InitializeComponent();
        }

        private void visioButton_Click(object sender, EventArgs e)
        {
            if (init())
            {
                app.Documents.Add("");
            }
        }

        bool init()
        {
            if (!initialised)
            {
                app = new Visio.Application();
                app.EventList.AddAdvise(appCloseEventCode, this, null, null);
                app.EventList.AddAdvise(docCloseEventCode, this, null, null);
                initialised = true;
            }
            return initialised;
        }

        object Visio.IVisEventProc.VisEventProc(short eventCode, object source, int eventID, int eventSeqNum, object subject, object moreInfo)
        {
            switch (eventCode)
            {
                case appCloseEventCode: app_BeforeAppClose((Visio.Application)subject); break;
                case docCloseEventCode: app_BeforeDocumentClose((Visio.Document)subject); break;
            }
            return null;
        }

        void app_BeforeAppClose(Visio.Application app)
        {
            initialised = false;
            MessageBox.Show("App closed");
        }

        void app_BeforeDocumentClose(Visio.Document doc)
        {
            MessageBox.Show("Doc closed");
        }

    }
}