COM Interop with .NET Core 2.0

We previously discussed that COM Interop does not function in .NET Core 1.0.  What about .NET Core 2.0?  The answer is YES… with limitations.

The first and most obvious is that COM Interop only works with Windows, not other platforms.

The second limitation is that the .NET Core implementation does not include IDispatch, which means that late binding is not supported.  Almost 10 years ago, Microsoft introduced the dynamic keyword in C# 4.0, which made late binding with COM and other platforms much easier.

dynamic excel = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application", true));
excel.Visible = true;
Console.WriteLine("Press Enter to close Excel.");

The above code will function in .NET Framework, but in .NET Core 2.0, an exception occurs:

‘System.__ComObject’ does not contain a definition for ‘Visible’

If you look in Task Manager, you’ll see that Excel.exe has indeed started, but the object members cannot be access directly without IDispatch.  To work around this, you can use interop techniques that pre-date the dynamic keyword.

Interop assemblies are wrappers that enable .NET Core to interact with COM objects using early binding.  Microsoft provides interop assemblies for Office automation on NuGet and elsewhere.  Once the assemblies are installed, this code will work:

using Excel = Microsoft.Office.Interop.Excel;
var excel = new Excel.Application();
excel.Visible = true;
Console.WriteLine("Press Enter to close Excel.");

Aside: For web applications, Office automation is not recommended.  Check out the Open XML SDK.

What about your own COM objects? .NET Core projects do not provide a means to reference them directly.  However, you can create a .NET Framework 4.x project and add a reference to the COM object.  This will create an Interop.MyCOMObject.dll assembly in the obj/Debug folder, which you can then reference directly in the .NET Core project.

A COM object may return other objects that are not part of the type library, and early binding is not an option. This happens often in my Visual FoxPro interop code. You can use reflection to access the object members.

object excel = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application", true));
excel.GetType().InvokeMember("Visible",BindingFlags.SetProperty, Type.DefaultBinder, excel, new object[] { true });
Console.WriteLine("Press Enter to close Excel.");
excel.GetType().InvokeMember("Quit", BindingFlags.InvokeMethod, null, excel, null);

The dynamic keyword makes for more natural code, but you can make reflection less cumbersome than above with your own wrapper methods.

For the adventurous, the Powershell team has created their own implementation of IDispatch. I don’t know how reusable this implementation is, but it may be worth a look.

If you’re using in-process (DLL) COM servers, be aware of 32-bit vs 64-bit issues. For web  applications, take a look a Rick Strahl’s post on STA components. I don’t know if these techniques are available in .NET Core.  In my experience, these issues do not apply with out-of-process (EXE) COM servers, but your mileage may vary.

Lastly, keep in mind that ASP.NET Core 2.0 continues to run on .NET Framework 4.x, in addition to .NET Core.  If you’re already restricted to Windows, there aren’t many reasons to prefer .NET Core over the full framework (yet), so it remains the best option for COM Interop.  That said, it’s good to know these possibilities exist with .NET Core.

Microsoft has been choosy about what they bring over to .NET Core.  Over time, they have been finding their way towards more parity with .NET Framework. It was recently announced that WinForms/WPF will be coming to .NET Core 3.0. They may find that a lot of existing code relies on late binding.  I would not be surprised if IDispatch makes a comeback.

Welcome to!

Nearly a decade ago, I started this blog on the Community Weblog, a free service made available to the FoxPro community by Eric den Doop.  I wanted more control on the admin side — especially for dealing with spam – so I have moved the blog to my own site:

All posts/comments have been retained, and links to the old site should automatically redirect to the new site.  Please update your RSS readers to point to the new feed.

Special thanks to Eric for making this service available to the community and for hosting my blog all these years.