Andrei Smolin

Exception from HRESULT 0x800A01A8 in PowerPoint solutions

On an example of a simple scenario, this article demonstrates what causes 0x800A01A8 and how to avoid it in C#, VB.NET, VBA, Delphi. Exception from HRESULT: 0x800A01A8 is also known as OLE error 800A01A8 and also known as Object Required.

Program. Here’s a method reproducing the issue. The method is an event handler of the Click event of a Ribbon button shown by a PowerPoint add-in. In the method, I get a shape object, retrieve the object’s Parent property, and delete the shape.

C#:

private void adxRibbonButton1_OnClick(object sender, IRibbonControl control, bool pressed) {
    PowerPoint.Shape titleShape = (PowerPointApp.ActiveWindow.View.Slide as PowerPoint.Slide).Shapes.Title;
    object parent = null;
    try {
        titleParent = titleShape.Parent;
    } catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
    if (titleParent != null) {
        // use titleParent
    }
    titleShape.Delete();
}

Scenario. Now run the method, click the Undo command in the PowerPoint UI, run the method again and you see the exception.

In this scenario the following properties of the PowerPoint.Shape object produce the same exception:

Solution. To solve the issue in the example above, release the shape object after you delete it. In C# and VB.NET, you do this by calling System.Runtime.InteropServices.Marshal.ReleaseComObject(titleShape). In VBA and Delphi, just set titleShape to Nothing (VBA) and nil (Delphi).

Conclusion. What you saw is just another manifestation of all those problems that occur if you don’t release COM objects in Office solutions. Releasing COM objects immediately after use is the best practice. See also When to release COM objects in Office add-ins developed in .NET.

Good luck!

Updated on 1-Jul-2014. I gladly accept the suggestion from Fabske. Below are the modified VB.NET and C# versions of the code. These versions demonstrate releasing all COM objects. The suggestion to set the just released variable to null (Nothing in VB.NET) is given in When to release COM objects in Office add-ins developed in .NET

10 Comments

  • Fabske says:

    Following your advice, you should put the shapes collection in a separate variable so you can release it later.

  • Andrei Smolin (Add-in Express Team) says:

    Although the code sample doesn’t refer to the Shapes collection, you are absolutely right: there are COM objects left unreleased in the code sample. Since releasing all COM objects guarantees that the code will work in ALL situations, not just in the described one, I’ll consider adding the code variant demonstrating all COM objects released. Thank you!

  • Kailas Lokhande says:

    I am facing same exception with same repro steps but for ConvertTextToSmartArt operation, even after releasing object.

  • Andrei Smolin (Add-in Express Team) says:

    Hello Kailas,

    Your code and exact repro steps?

  • Kailas Lokhande says:

    My Code looks as below:
    public void AnalyzeSlide(Office.IRibbonControl control)
    {

    PowerPoint.Slide slide = getActiveSlide();
    Office.SmartArtLayout selectedLayout = getSmartArtLayout(1);
    if( slide.Shapes.Count > 0)
    {
    PowerPoint.Shape shape = slide.Shapes[1];
    if( shape.HasSmartArt == Office.MsoTriState.msoFalse )
    shape.ConvertTextToSmartArt();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(shape);
    shape = null;
    }
    System.Runtime.InteropServices.Marshal.ReleaseComObject(slide);
    slide = null;
    }

    Message: Exception from HRESULT: 0x800A01A8
    at Microsoft.Office.Interop.PowerPoint.Shape.get_HasSmartArt()

  • Kailas Lokhande says:

    My Code looks as below:
    public void AnalyzeSlide(Office.IRibbonControl control)
    {

    PowerPoint.Slide slide = getActiveSlide();
    Office.SmartArtLayout selectedLayout = getSmartArtLayout(1);
    if( slide.Shapes.Count > 0)
    {
    PowerPoint.Shape shape = slide.Shapes[1];
    if( shape.HasSmartArt == Office.MsoTriState.msoFalse )
    shape.ConvertTextToSmartArt();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(shape);
    shape = null;
    }
    System.Runtime.InteropServices.Marshal.ReleaseComObject(slide);
    slide = null;
    }

    Message: Exception from HRESULT: 0x800A01A8
    at Microsoft.Office.Interop.PowerPoint.Shape.get_HasSmartArt()

  • Kailas Lokhande says:

    Repro Steps:
    1. Envoke AnalyzeSlides
    2. It converts first shape to smartArt
    3. Do Undo
    4. Envoke AnalyzeSlides again
    5. Exception Occurs

  • Andrei Smolin (Add-in Express Team) says:

    Hello Kailas,

    The code below works fine for me.

    using System.Runtime.InteropServices;
    using PowerPoint = Microsoft.Office.Interop.PowerPoint;
    using Office = Microsoft.Office.Core;

    private void adxRibbonButton1_OnClick(object sender, IRibbonControl control, bool pressed) {
    AnalyzeSlide();
    }

    public void AnalyzeSlide() {
    PowerPoint.Slide slide = getActiveSlide();
    Office.SmartArtLayout selectedLayout = getSmartArtLayout(1);
    PowerPoint.Shapes shapes = slide.Shapes;
    if (shapes.Count > 0) {
    PowerPoint.Shape shape = shapes[1];
    if (shape.HasSmartArt == Office.MsoTriState.msoFalse)
    shape.ConvertTextToSmartArt(selectedLayout);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(shape);
    shape = null;
    }
    Marshal.ReleaseComObject(shapes); shapes = null;
    Marshal.ReleaseComObject(selectedLayout); selectedLayout = null;
    Marshal.ReleaseComObject(slide); slide = null;
    }

    private Office.SmartArtLayout getSmartArtLayout(int p) {
    Office.SmartArtLayouts layouts = PowerPointApp.SmartArtLayouts;
    Office.SmartArtLayout layout = layouts[p];
    Marshal.ReleaseComObject(layouts); layouts = null;
    return layout;
    }

    private PowerPoint.Slide getActiveSlide() {
    PowerPoint.DocumentWindow activeWindow = PowerPointApp.ActiveWindow;
    PowerPoint.View view = activeWindow.View;
    PowerPoint.Slide currentSlide = null;
    try {
    currentSlide = view.Slide as PowerPoint.Slide;
    } catch (Exception ex) {
    //
    }
    Marshal.ReleaseComObject(view);
    Marshal.ReleaseComObject(activeWindow);
    return currentSlide;
    }

  • Kailas Lokhande says:

    Thanks,Andrei Smolin. Yes, code that you have gave works fine.

    Is there any way to figure out, which object is not yet released? because of which such problems can happen? I am asking this because, my code will become complex and will keep passing and storing references inside , I want to make sure it is not holding any object with it.

    Is there any tool which can help me with this?

  • Andrei Smolin (Add-in Express Team) says:

    There’s no such way or tool. You have to be careful and attentive. And you need to debug your code. As to storing references, it isn’t recommended. Instead, you can recreate a COM object. Say, you can find a shape using its ID, a slide using its SlideId, etc. That is, you can store an ID (or index or name), rather than the object. This approach allows you to have a COM object unreleased any time except for the moment when the COM object is created and used. Also, we recommend using this strategy: a COM object’s creator is responsible for releasing the COM object. An example: if a COM object is passed to a method, the method should not release such a COM object; instead the caller should release it.

Post a comment

Have any questions? Ask us right now!