1

I am trying to update a powerpoint slide with a lot of data (around 600 items). This was taking around 3 minutes.

If I load the shapes into memory up front, it still takes 35 seconds, so there's a lot of drawing time.

Excel has a simple means to get round this, but it's not so easy with ppt.

I found this post which supposedly uses VBA to suspend drawing and tried to convert it to C# (see below). The methods run without error, but don't stop drawing and don't increase the speed.

Is it possible using C# to suspend drawing in PowerPoint, then update the lot in one go, or is there any way to speed up updating PowerPoint shapes?

My C# Conversion attempt to suspend drawing:

public class PowerPointSuspendDrawing
{

    // --------------------------------------------------------------------------------
    // Converted from Shyam Pillai's code - see https://stackoverflow.com/questions/28511508/turn-off-screenupdating-for-powerpoint
    // --------------------------------------------------------------------------------

    // API declarations for FindWindow() & LockWindowUpdate()
    // Use FindWindow API to locate the PowerPoint handle. 
    [DllImport("user32.dll", SetLastError = true)]
    static extern long FindWindow(string lpClassName, long lpWindowName);

    // Use LockWindowUpdate to prevent/enable window refresh
    [DllImport("user32.dll", SetLastError = true)]
    static extern long LockWindowUpdate(long hwndLock);

    //Use UpdateWindow to force a refresh of the PowerPoint window  
    [DllImport("user32.dll", SetLastError = true)]
    static extern long UpdateWindow(long hwnd);



    /// <summary>
    /// Should start/stop the screen updating
    /// </summary>
    /// <param name="state">false = stop animating, true = refresh</param>
    /// <param name="fullVersionNumber">Microsoft.Interop.PowerPoint.Application.Version</param>
    public void ScreenUpdating(bool state, string fullVersionNumber)
    {
        long hwnd = 0;

        // will come in e.g. as 16.0
        var versionNo = fullVersionNumber.Split('.')[0];

        if ((state == false))
        {
            //  Get handle to the main application window using ClassName
            switch (versionNo)
            {
                case "8":
                    hwnd = FindWindow("PP97FrameClass", 0);
                    break;
                case "9":
                    hwnd = FindWindow("PP9FrameClass", 0);
                    break;
                case "10":
                    hwnd = FindWindow("PP10FrameClass", 0);
                    break;
                case "11":
                    hwnd = FindWindow("PP11FrameClass", 0);
                    break;
                case "12":
                    hwnd = FindWindow("PP12FrameClass", 0);
                    break;
                case "14":
                case "15":
                case "16":
                    hwnd = FindWindow("PPTFrameClass", 0);
                    break;
                default:

                    Console.WriteLine("Version not found. Version too new.");
                    break;
            }
            if ((hwnd == 0))
            {
                Console.WriteLine("Unable to get the PowerPoint Window handle");
            }

            // Lock the window
            if ((LockWindowUpdate(hwnd) == 0))
            {
                Console.WriteLine("Unable to set a PowerPoint window lock");
            }

        }
        else
        {
            //  Unlock the Window to refresh
            LockWindowUpdate(0);
            UpdateWindow(hwnd);
            hwnd = 0;
        }

    }
}

Approx Calling code.

PowerPointSuspendDrawing pptSuspension = new PowerPointSuspendDrawing();
pptSuspension.ScreenUpdating(false, myPresentation.CurrentApplication.Version);


// loop here

var shapeName = "box_number_" + boxNumber;

var thisShape = lookup[shapeName];
if (thisShape != null)
{
    thisShape.TextFrame.TextRange.Text = "Bob";
}

// end loop


pptSuspension.ScreenUpdating(true, myPresentation.CurrentApplication.Version);
Balagurunathan Marimuthu
  • 2,927
  • 4
  • 31
  • 44
JsAndDotNet
  • 16,260
  • 18
  • 100
  • 123
  • I haven't found a direct answer to this, but I can get it down to around 6-7 seconds by loading the shapes into memory and then updating in a Parallel.Foreach. Still not ideal, but better than 3 minutes. – JsAndDotNet Jun 14 '17 at 13:42
  • [This is not how `LockWindowUpdate` is meant to be used.](https://blogs.msdn.microsoft.com/oldnewthing/20070222-01/?p=27913/) – Cody Gray - on strike Jun 16 '17 at 17:49

1 Answers1

1

I couldn't find a direct answer, so to close this off, the best thing i could do was:

  1. Create a dictionary of the 'shape name'/ 'ppt shape object' before any processing was required.
  2. When the time came to update the values, create a new dictionary with the key value pairs being 'ppt shape object' / 'new value'.
  3. Use a Parallel.Foreach loop to loop through the 'ppt shape object' / 'new values' dictionary and update the values.

This should be safe from cross threading issues. It's not perfect, but beats the 3 minutes starting effort.

Final timings 5.5 seconds for 650 shapes, though this doubles if in presentation mode.

JsAndDotNet
  • 16,260
  • 18
  • 100
  • 123