Tar
Tar

Reputation: 9015

Why closing window created in a unit-test raises an InvalidComObjectException?

when unit-testing using MSTest, I create a WPF window. When this window closes, Visual Studio shows InvalidComObjectException:

COM object that has been separated from its underlying RCW cannot be used.

it is raised after the [TestMethod] exits, and the stack contains only external code (no InnerException). This is what I have:

StackTrace:
       at System.Windows.Input.TextServicesContext.StopTransitoryExtension()
       at System.Windows.Input.TextServicesContext.Uninitialize(Boolean appDomainShutdown)
       at System.Windows.Input.TextServicesContext.TextServicesContextShutDownListener.OnShutDown(Object target, Object sender, EventArgs e)
       at MS.Internal.ShutDownListener.HandleShutDown(Object sender, EventArgs e)

DeclaringType:
    {Name = "TextServicesContext" FullName = "System.Windows.Input.TextServicesContext"}

    Assembly:
        {PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}

And this is the code that creates the window:

var myWindow = new SomeWindow(errors);
myWindow.ShowDialog();

The window contains two ListViews with some text elements and check-boxes in them

Upvotes: 3

Views: 1285

Answers (1)

quetzalcoatl
quetzalcoatl

Reputation: 33506

I've stumbled upon this some time ago. If I recall correctly, it is because between the tests the default Dispatcher for your AppDomain is not properly cleaned up and reinitialized.

To solve it, I've created a DomainNeedsDispatcherCleanup attribute class that takes care of proper setup&teardown of the Dispatcher. I'll include it here as soon as I find it, but mind that I use XUnit, not MSTest.

EDIT: Just found it. Here you go:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;
using Xunit;

namespace Boost.Utils.Testing.XUnit.WPF
{
    /// <summary>helful if you stumble upon 'object disconnected from RCW' ComException *after* the test suite finishes,
    /// or if you are unable to start the test because the VS test runner tells you 'Unable to start more than one local run'
    /// even if all tests seem to have finished</summary>
    /// <remarks>only to be used with xUnit STA worker threads</remarks>
    [AttributeUsage(AttributeTargets.Method)]
    public class DomainNeedsDispatcherCleanupAttribute : BeforeAfterTestAttribute
    {
        public override void After(MethodInfo methodUnderTest)
        {
            base.After(methodUnderTest);

            Dispatcher.CurrentDispatcher.InvokeShutdown();
        }
    }
}

Hahha.. So, as you see, the fix is trivial. I did not remember that. Surely, you just need to InvokeShutdown in your teardown and it should be fixed.

Upvotes: 6

Related Questions