4342024 2023-11-16 14:27 采纳率: 46.7%
浏览 14
已结题

c# 线程中对ppt进行操作,出现The message filter indicated that the application is busy.异常,Ox8001010A

在visual studio2022中开发c# 程序,多个线程同时生成多个ppt,线程设置为后台线程。其中每个线程以每个ppt模板生成新的ppt。


//使用MicsoftOffice.Interop.PowerPoint.Application类,


//每个线程中调用
MicsoftOffice.Interop.PowerPoint.Application PPT = new MicsoftOffice.Interop.PowerPoint.Application();
Presentation presentation = PPT.Presentations.Open(sSource, MoTriState.mso.False,MoTriState.mso.False, MoTriState.mso.False);
GeneratePage(presentation);//这里是生成每页ppt


presentation.SaveAs(sSavePath, PpSaveAsDefault,MoTriState.mso.False);
presentation.Close();
PPT.Quit();
GC.Collect();

当需要新增ppt页页数比较多时,偶发性出现

img

这个是什么问题呢?如何解决?

  • 写回答

12条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2023-11-16 14:28
    关注

    引自强大而免费的微信小程序:皆我百晓生

    问题描述
    在使用C#线程操作PowerPoint时,出现异常"The message filter indicated that the application is busy. (0x8001010A)"。当需要新增PPT页数比较多时,此异常偶发出现。

    解决方案
    出现此异常的原因是因为PowerPoint应用程序忙于处理其他操作,无法立即响应新的请求。为了解决这个问题,可以使用消息过滤器来确保PowerPoint应用程序能够处理后台线程的请求。

    以下是解决方案的思路和步骤:

    1. 引入消息过滤器

    首先,我们需要引入消息过滤器以确保PowerPoint应用程序能够处理后台线程的请求。可以使用消息过滤器包装我们的PPT生成逻辑。

    using System.Runtime.InteropServices;
    ...
    
    public class MessageFilter : IOleMessageFilter
    {
        // 定义常量
        private const int SERVERCALL_ISHANDLED = 0;
        private const int SERVERCALL_RETRYLATER = 2;
        private const int PENDINGMSG_WAITDEFPROCESS = 2;
    
        // 实现接口方法
        public int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
        {
            return SERVERCALL_ISHANDLED;
        }
    
        public int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
        {
            if (dwRejectType == SERVERCALL_RETRYLATER && dwTickCount < 10000)
            {
                // 等待100毫秒再重试
                return 100;
            }
            
            return -1;
        }
    
        public int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
        {
            return PENDINGMSG_WAITDEFPROCESS;
        }
    
        // 注册消息过滤器
        public static void Register()
        {
            MessageFilter newFilter = new MessageFilter();
            CoRegisterMessageFilter(newFilter, out IOleMessageFilter oldFilter);
        }
    
        // 取消注册消息过滤器
        public static void Revoke()
        {
            CoRegisterMessageFilter(null, out IOleMessageFilter oldFilter);
        }
    
        // DllImport
        [DllImport("ole32.dll")]
        private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
    }
    
    // IOleMessageFilter接口
    [ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IOleMessageFilter
    {
        [PreserveSig]
        int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
    
        [PreserveSig]
        int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
    
        [PreserveSig]
        int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
    }
    

    2. 注册和取消注册消息过滤器

    在多线程操作之前,需要在主线程中注册消息过滤器,操作完成后再取消注册。

    MessageFilter.Register();
    // 执行多线程操作
    // ...
    MessageFilter.Revoke();
    

    3. 修改生成PPT逻辑

    在生成PPT的逻辑中,调用PPT操作前先使用MessageFilter.Register()注册消息过滤器,操作完成后再使用MessageFilter.Revoke()取消注册。

    MicsoftOffice.Interop.PowerPoint.Application PPT = new MicsoftOffice.Interop.PowerPoint.Application();
    
    MessageFilter.Register(); // 注册消息过滤器
    
    Presentation presentation = PPT.Presentations.Open(sSource, MoTriState.mso.False,MoTriState.mso.False, MoTriState.mso.False);
    GeneratePage(presentation);
    
    presentation.SaveAs(sSavePath, PpSaveAsDefault,MoTriState.mso.False);
    presentation.Close();
    PPT.Quit();
    
    MessageFilter.Revoke(); // 取消注册消息过滤器
    
    GC.Collect();
    

    完整代码示例

    下面是一个完整的示例代码,展示了如何在C#中使用多线程生成多个PPT时,避免出现"The message filter indicated that the application is busy."异常。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using MicsoftOffice.Interop.PowerPoint;
    using MoTriState = MicsoftOffice.Core.MsoTriState;
    
    namespace PowerPointThread
    {
        class Program
        {
            static void Main(string[] args)
            {
                // 注册消息过滤器
                MessageFilter.Register();
    
                // 创建线程
                Thread thread1 = new Thread(GeneratePPT);
                Thread thread2 = new Thread(GeneratePPT);
    
                // 启动线程
                thread1.Start();
                thread2.Start();
    
                // 等待线程完成
                thread1.Join();
                thread2.Join();
    
                // 取消注册消息过滤器
                MessageFilter.Revoke();
    
                Console.WriteLine("Finished generating PPTs");
                Console.ReadKey();
            }
    
            static void GeneratePPT()
            {
                MicsoftOffice.Interop.PowerPoint.Application PPT = new MicsoftOffice.Interop.PowerPoint.Application();
                Presentation presentation = null;
    
                try
                {
                    string sSource = "template.pptx";
                    string sSavePath = $"output_{Guid.NewGuid()}.pptx";
    
                    presentation = PPT.Presentations.Open(sSource, MoTriState.msoFalse, MoTriState.msoFalse, MoTriState.msoFalse);
                    GeneratePage(presentation);
    
                    presentation.SaveAs(sSavePath, PpSaveAsDefault, MoTriState.msoFalse);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error generating PPT: {ex.Message}");
                }
                finally
                {
                    if (presentation != null)
                    {
                        presentation.Close();
                    }
                    PPT.Quit();
                    GC.Collect();
                }
            }
    
            static void GeneratePage(Presentation presentation)
            {
                // 生成PPT页面的逻辑
                // ...
            }
    
            // 消息过滤器的实现代码
            // ...
        }
    }
    

    使用上述代码,你可以在多个线程中同时生成多个PPT,每个线程以PPT模板生成新的PPT。同时,使用消息过滤器将确保PowerPoint应用程序能够处理后台线程的请求,避免出现"The message filter indicated that the application is busy."异常。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(11条)

报告相同问题?

问题事件

  • 系统已结题 11月25日
  • 已采纳回答 11月17日
  • 创建了问题 11月16日

悬赏问题

  • ¥100 我想找人帮我写Python 的股票分析代码,有意请加mathtao
  • ¥20 Vite 打包的 Vue3 组件库,图标无法显示
  • ¥15 php 同步电商平台多个店铺增量订单和订单状态
  • ¥15 关于logstash转发日志时发生的部分内容丢失问题
  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现