skip to Main Content

Creating PowerPoint presentations in C# Visual Studio, I realized that my WinForm timer hangs; I can’t even move my Application around the screen. Is there a way to create my PowerPoint in the background?

To illustrate the issue, I have this code example in "C:myPowerPointHangs" for C# Windows Forms .NET

I have added from Reference Manager>COM>Type Libraries the assembly reference "Microsoft Office 16.0 Object Library" (Version 2.8), or also from NuGet: "Microsoft.Office.Interop.PowerPoint" (Version 15.0.4420.1018) added to my project…

I have created two Timers.

  • Timer1 will show 100ms steps counting in the caption of my WinForm, and it will start Timer2 at 2000 milliseconds then continue counting.

  • Timer2 runs once. It creates the slide and the matrix of boxes. This takes several seconds. Finally, it saves the presentation. After that, my WinForm is alive again.

// Project>Add Reference>COM>Type Libraries>Microsoft Office 16.0 Object Library
// Tools>NuGet Package Manager>Manage NuGet Packages for solution>Microsoft.Office.Interop.PowerPoint 15.0.4420.1018
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Office = Microsoft.Office.Core;
using State = Microsoft.Office.Core.MsoTriState;
using System;
using System.Windows.Forms;

namespace myPowerPointHangs
{
    public partial class Form1 : Form
    {
        readonly float u = 72.0f; // Inches
        int t = 0;
        int t0 { get => (++t); set => t = 0; }
        string fileName = @"C:myPowerPointHangsmySlides.ppt";
        public Form1() { InitializeComponent(); timer1.Start(); }
        private void timer1_Tick(object sender, EventArgs e)
        { 
            this.Text = t0.ToString() + "00ms";
            if (t == 20) timer2.Start();
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            timer2.Stop();
            PowerPoint.Application pptApplication = new PowerPoint.Application();
            PowerPoint.Presentation ppt;
            PowerPoint.Slide slide;
            PowerPoint.Slides slides;
            Office.MsoAutoShapeType shape;
            ppt = pptApplication.Presentations.Add(State.msoTrue);
            slides = ppt.Slides;
            slides.Application.Caption = "mySlides";
            slide = slides.Add(1, PowerPoint.PpSlideLayout.ppLayoutBlank);
            shape = Office.MsoAutoShapeType.msoShapeFlowchartTerminator;

            float left = 6.61f * u;
            for (int col = 0; col < 5; col++)
            {
                float top = 0.1f * u;
                for (int row = 0; row < 20; row++)
                {
                    slide.Shapes.AddShape(shape, left, top, 0.77f * u, 0.23f * u);
                    int i = slide.Shapes.Count;
                    slide.Shapes[i].Fill.ForeColor.RGB = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.White);
                    slide.Shapes[i].Line.ForeColor.RGB = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.FromArgb(58, 58, 58));
                    slide.Shapes[i].TextFrame.TextRange.Font.Color.RGB = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.FromArgb(19, 40, 79));
                    slide.Shapes[i].TextFrame.TextRange.Font.Size = 6.0f;
                    slide.Shapes[i].TextFrame.WordWrap = State.msoFalse;
                    slide.Shapes[i].TextFrame.TextRange.Text = col.ToString("00")+row.ToString("00");
                    top += slide.Shapes[i].Height + 0.02f * u;
                }
                left += slide.Shapes[slide.Shapes.Count].Width + 0.05f * u;
            }

            if (System.IO.File.Exists(fileName)) System.IO.File.Delete(fileName);
            ppt.SaveAs(fileName, PowerPoint.PpSaveAsFileType.ppSaveAsPresentation, Office.MsoTriState.msoCTrue);
            ppt.Close();
        }
    }
}

There are similar topics here and there, but do not address my question: how to run Office.Interop.PowerPoint in the background without hanging my WinForm application?

In addition, if for any reason we open a popup message in the PowerPoint App before or while creating the presentation, it generates an Exception as:

System.Runtime.InteropServices.COMException: 'Call was rejected by callee. (Exception from HRESULT: 0x80010001 

Opening_PowerPoint_Popup => Call_was_rejected_by_callee

2

Answers


  1. You can write a simple void function and use multi-threading to create a new thread for power point process.

    Notice: First you need to create timer1 manually.

    // Project>Add Reference>COM>Type Libraries>Microsoft Office 16.0 Object Library
    // Tools>NuGet Package Manager>Manage NuGet Packages for solution>Microsoft.Office.Interop.PowerPoint 15.0.4420.1018
    using PowerPoint = Microsoft.Office.Interop.PowerPoint;
    using Office = Microsoft.Office.Core;
    using State = Microsoft.Office.Core.MsoTriState;
    using System;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace myPowerPointHangs
    {
        public partial class Form1 : Form
        {
    
            public Form1() { InitializeComponent(); timer1.Start(); }
            
            readonly float u = 72.0f; // Inches
            int t = 0;
            string fileName = @"C:myPowerPointHangsmySlides.ppt";
            int cnt = 0;
            Thread trd;
    
            private void timer1_Tick(object sender, EventArgs e)
            {
                Text=cnt.ToString() + "00ms";
                if (cnt++ >= 20) { cnt = 0; trd = new Thread(power_point); trd.Start(); timer1.Stop(); }
            }
    
            void power_point()
            {
                PowerPoint.Application pptApplication = new PowerPoint.Application();
                PowerPoint.Presentation ppt;
                PowerPoint.Slide slide;
                PowerPoint.Slides slides;
                Office.MsoAutoShapeType shape;
                ppt = pptApplication.Presentations.Add(State.msoTrue);
                slides = ppt.Slides;
                slides.Application.Caption = "mySlides";
                slide = slides.Add(1, PowerPoint.PpSlideLayout.ppLayoutBlank);
                shape = Office.MsoAutoShapeType.msoShapeFlowchartTerminator;
    
                float left = 6.61f * u;
                for (int col = 0; col < 5; col++)
                {
                    float top = 0.1f * u;
                    for (int row = 0; row < 20; row++)
                    {
                        slide.Shapes.AddShape(shape, left, top, 0.77f * u, 0.23f * u);
                        int i = slide.Shapes.Count;
                        slide.Shapes[i].Fill.ForeColor.RGB = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.White);
                        slide.Shapes[i].Line.ForeColor.RGB = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.FromArgb(58, 58, 58));
                        slide.Shapes[i].TextFrame.TextRange.Font.Color.RGB = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.FromArgb(19, 40, 79));
                        slide.Shapes[i].TextFrame.TextRange.Font.Size = 6.0f;
                        slide.Shapes[i].TextFrame.WordWrap = State.msoFalse;
                        slide.Shapes[i].TextFrame.TextRange.Text = col.ToString("00") + row.ToString("00");
                        top += slide.Shapes[i].Height + 0.02f * u;
                    }
                    left += slide.Shapes[slide.Shapes.Count].Width + 0.05f * u;
                }
    
                if (System.IO.File.Exists(fileName)) System.IO.File.Delete(fileName);
                ppt.SaveAs(fileName, PowerPoint.PpSaveAsFileType.ppSaveAsPresentation, Office.MsoTriState.msoCTrue);
                ppt.Close();
                trd.Abort();
            }
    
        }
    }
    
    Login or Signup to reply.
  2. As an answer to joshua-tristancho’s question:
    I don’t know anything about powerpoint. But the process is the same as other file-handling.

    using System.ComponentModel;
    namespace myPowerPointHangs
    {
        public partial class Form1 : Form
        {
            private BackGroundWorker bgProcessPP = new BackGroundWorker();
            public Form1()
            {
                InitializeComponent();
                LoadSettings();
            }
    
            private void LoadSettings()
            {
                bgProcessPP.DoWork += new DoWorkEventHandler(bgProcessPP_DoWork);
                bgProcessPP.WorkerReportsProgress = true;
                bgProcessPP.WorkerSupportsCancellation = true;
                bgProcessPP.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgProcessPP_RunWorkerCompleted);
                bgProcessPP.ProgressChanged += new ProgressChangedEventHandler(bgProcessPP_ProgressChanged);
            }
    
            private void bgProcessPP_DoWork(object sender, DoWorkEventArgs e)
            {
                string fullSavePath = e.Argument;
                //You can insert your code from timer2_Tick in here
            }
    
            private void timer2_Tick(object sender, EventArgs e)
            {
                timer2.Stop();
                if(!bgProcessPP.IsBusy)
                {
                    bgProcessPP.RunWorkerAsync(@"C:myPowerPointHangsmySlides.ppt");
                }
            }
    
            private void bgProcessPP_RunWorkerCompleted(object sender, RunWorkerCompleteEventArgs e)
            {
                if(e.Cancelled)
                {
                    //Show message in a Label or MessageBox
                }
                else if(e.Error != null)
                {
                    //Show some other error in a Label or MessageBox
                }
                else
                {
                     //Optional show a message when the backgroundworker is finished
                }
            }
    
            private void bgProcessPP_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                //Show the progress in a Label or calculate to a ProgressBar.
            }
        }
    }
    

    Hope this will help you to the right way. If there are some errors, my apologies. Having a few glasses of Whisky 😉

    Oh, you are using System.Windows.Forms.Timer….There is also a System.Timers.Timer which runs in the background and will not hookup your form. But you have to use Innnvke…Inkoke…Invoke(new action(().. (Just fooling around ;))

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search