Exception from HRESULT 0x800A01A8 in PowerPoint solutions
Posted on Tuesday, June 24th, 2014 at 6:12 am by Andrei Smolin.
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.
PrivateSub AdxRibbonButton1_OnClick(sender As System.Object,
control As AddinExpress.MSO.IRibbonControl,
pressed As System.Boolean)Handles AdxRibbonButton1.OnClickDim titleShape As PowerPoint.Shape=CType(PowerPointApp.ActiveWindow.View.Slide, PowerPoint.Slide).Shapes.TitleDim titleParent AsObject=NothingTry
titleParent = titleShape.ParentCatch ex As Exception
MessageBox.Show(ex.Message)EndTryIf titleParent IsNotNothingThen' use titleParentEndIf
titleShape.Delete()EndSub
VBA:
Dim TitleShape As PowerPoint.Shape
'Sub test()
Dim CurrentSlide As PowerPoint.Slide
Set CurrentSlide = Application.ActiveWindow.View.Slide
Set TitleShape = CurrentSlide.Shapes.Title
Dim TitleParent AsObjectOnErrorResumeNextSet TitleParent = TitleShape.Parent
If Err <> 0 Then
MsgBox Err.Description
EndIfIfNot TitleParent IsNothingThen' use TitleParentEndIf
TitleShape.Delete
EndSub
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:
PowerPoint.Shape properties producing 0x800A01A8 in the given scenario
Adjustments
Callout
Chart
ConnectorFormat
Fill
Glow
GroupItems
HasSmartArt
Line
MediaFormat
MediaType
Nodes
Parent
ParentGroup
PictureFormat
Reflection
Shadow
SmartArt
SoftEdge
Table
TextEffect
TextFrame
TextFrame2
ThreeD
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
Modified code samples in C# and VB.NET
C#:
privatevoid adxRibbonButton1_OnClick(object sender, IRibbonControl control, bool pressed){
PowerPoint.DocumentWindow activeWindow = PowerPointApp.ActiveWindow;if(activeWindow !=null){
PowerPoint.View view = activeWindow.View;if(view !=null){object obj = view.Slide;if(obj !=null){if(obj is PowerPoint.Slide){
PowerPoint.Shapes shapes =(obj as PowerPoint.Slide).Shapes;if(shapes.HasTitle== Microsoft.Office.Core.MsoTriState.msoTrue){
PowerPoint.Shape titleShape = shapes.Title;object titleParent =null;try{
titleParent = titleShape.Parent;}catch(Exception ex){
MessageBox.Show(ex.Message);}if(titleParent !=null){// use titleParent}
titleShape.Delete();// leaving the COM object below unreleased causes 0x800A01A8 if you click Undo in the PP UI and invoke this code anew
Marshal.ReleaseComObject(titleShape); titleShape =null;}
Marshal.ReleaseComObject(shapes); shapes =null;}
Marshal.ReleaseComObject(obj); obj =null;}
Marshal.ReleaseComObject(view); view =null;}
Marshal.ReleaseComObject(activeWindow); activeWindow =null;}}
VB.NET:
PrivateSub AdxRibbonButton1_OnClick(sender As System.Object,
control As AddinExpress.MSO.IRibbonControl,
pressed As System.Boolean)Handles AdxRibbonButton1.OnClickDim activeWindow As PowerPoint.DocumentWindow= PowerPointApp.ActiveWindowIf activeWindow IsNotNothingThenDim view As PowerPoint.View= activeWindow.ViewIf view IsNotNothingThenDim obj AsObject= view.SlideIf obj IsNotNothingThenIfTypeOf obj Is PowerPoint.SlideThenDim shapes As PowerPoint.Shapes=TryCast(obj, PowerPoint.Slide).ShapesIf shapes.HasTitle= Microsoft.Office.Core.MsoTriState.msoTrueThenDim titleShape As PowerPoint.Shape= shapes.TitleDim titleParent AsObject=NothingTry
titleParent = titleShape.ParentCatch ex As Exception
MessageBox.Show(ex.Message)EndTryIf titleParent IsNotNothingThen' use titleParentEndIf
titleShape.Delete()' leaving the COM object below unreleased causes 0x800A01A8 if you click Undo in the PP UI and invoke this code anew
Marshal.ReleaseComObject(titleShape) : titleShape =NothingEndIf
Marshal.ReleaseComObject(shapes) : shapes =NothingEndIf
Marshal.ReleaseComObject(obj) : obj =NothingEndIf
Marshal.ReleaseComObject(view) : view =NothingEndIf
Marshal.ReleaseComObject(activeWindow) : activeWindow =NothingEndIfEndSub
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!
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.
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.
Solid framework for deep customization of Microsoft Office. Use solution templates,
visual designers and components to develop version-neutral, secure and easy deployable extensions for all Office versions.
Supported Office extensions
COM add-ins, Outlook plug-ins, RTD servers, smart tags, Excel XLL and UDF
Add-in Express™
for Microsoft® Office and Delphi® VCL
Get the best platform for building version-neutral, fast and easy deployable plug-ins by using Add-in Express projects templates, visual designers, components and wizards in combination with a perfect Delphi compiler.
Supported Office extensions
COM add-ins, Outlook plug-ins, smart tags, Excel RTD and UDF
This technology is now available for our custom development services only. Based on the Add-in Express for Office core, it is designed for building custom-tailored Office add-ins with far less coding than you usually have to do. Plus, it includes all Add-in Express features such as True RAD, visual designers, Outlook view and form regions, etc.
Extensions: VSTO-based application-level Office add-ins
Applications: Outlook, Excel, Word, PowerPoint, Visio, InfoPath
Office versions: 2003, 2007, 2010 (x86 and x64)
IDE: VSTO 2005 SE, 2008, 2010; VB.NET, C#
Add-in Express™ Regions for Microsoft® Outlook® and VSTO
Use this VSTO extension to develop advanced view and form regions for 17 different areas of the main Outlook Explorer window and all Outlook Inspector windows.
Supported extensions
Application-level Outlook add-ins
Requirements
Outlook versions: 2021 - 2003
IDE: Visual Studio 2022 - 2012 with VSTO installed
This is an extension for Visual Studio that allows developers to quickly create WiX-based setup projects in a familiar Visual Studio way.
The Designer for WiX Toolset lets you forget the plain Windows Installer XML and concentrate on your deployment logic. It integrates several editors with the Visual Studio IDE and provides a set of vdproj designers to configure the file system, registry, user interface, custom actions, launch conditions and more for your setup projects.
Requirements
Visual Studio versions: 2010, 2012, 2013, 2015, 2017, 2019
This technology is now available for our custom development services only. This visual toolkit allows creating secure, managed, isolated, deployable and version-neutral plug-ins for Outlook Express and Windows Mail. It provides powerful solution templates, Outlook Express - specific components, visual designers and wizards for advanced customization of Outlook Express menus, toolbars, panes and regions.
Extensions: Outlook Express plug-ins
Versions: Outlook Express 6.x, Windows Mail 6.x
IDE: VS 2005, 2008; VB.NET, C#, C++/CLI
Add just a few lines of code to bypass the Outlook Object Model guard and avoid security warnings in add-ins and applications that automate Microsoft Outlook.
Supported application types
Stand-alone apps, Outlook add-ins
Requirements
Outlook versions: 2021 - 2000
Languages: VB.NET, C#, Delphi XE2 - Delphi 11 Alexandria, C++ (MFC/ATL/CLI), VBA, etc.
The innovative technology for customizing Outlook views and forms. It is included in all Add-in Express for Office products and can be used to extend Outlook views, e-mail, task and appointment windows, To-Do bar, Reading and Navigation panes with your own custom sub-panes.
Extensions: application-level Outlook add-ins
Outlook versions: 2000, 2002, 2003, 2007, 2010 (x86 and x64)
.NET Edition: VS 2005, 2008, 2010; VB.NET, C#, C++/CLI
.NET Framework: 2.0 and higher
VCL Edition: Delphi 5 - XE
Microsoft and the Office logo are trademarks or registered trademarks of Microsoft Corporation in
the United States and/or other countries. All other trademarks are property of their respective owners.
10 Comments
Following your advice, you should put the shapes collection in a separate variable so you can release it later.
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!
I am facing same exception with same repro steps but for ConvertTextToSmartArt operation, even after releasing object.
Hello Kailas,
Your code and exact repro steps?
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()
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()
Repro Steps:
1. Envoke AnalyzeSlides
2. It converts first shape to smartArt
3. Do Undo
4. Envoke AnalyzeSlides again
5. Exception Occurs
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;
}
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?
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.