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.

COM Interop with .NET Core


UPDATE: COM Interop with .NET Core 2.0

The short story is that COM interop does not function in .NET Core 1.0. .NET Core is Microsoft’s open-source, cross-platform implementation of the core libraries in the .NET Framework.  With its cross-platform focus, the exclusion of COM interop is intentional.

ASP.NET Core is Microsoft’s open-source web framework that sits on top of the base .NET framework.  If you require COM interop and want to take advantage of new features in ASP.NET Core 1.0, you are in luck. Scott Hanselman reminds us that ASP.NET Core runs not only on .NET Core, but also on the full .NET Framework 4.6.

Here is some typical code for instantiating a COM object in C#:

dynamic myObject = Activator.CreateInstance(Type.GetTypeFromProgID("My.COMObject", true));

If you try to compile this code with .NET Core 1.0, it simply won’t work because Type.GetTypeFromProgID() is not available in the API.

That describes the current situation, but what about the future?  A while back, there was actually talk about bringing pieces of COM to Mac and Linux.  I think those plans have been scrapped or would only have limited use.

.NET Standard is an effort to bring a minimum common API set to all .NET platforms, present (Full Framework 4.6, .NET Core, Xamarin, Mono) and future.  .NET Standard 2.0 will be implemented in .NET Core 1.1, and it brings in a lot of missing APIs from the full framework. (UPDATE: .NET Core 1.1 has been released since this was written. It includes many new APIs, but not full support for .NET Standard 2.0. That will show up in a future release of .NET Core.)   It should make porting existing code to .NET Core much easier.  One of the APIs slated for 2.0 (as of this writing) is Type.GetTypeFromProgID().  That means that COM interop will work on .NET Core 1.1, right? Wrong. Calling this method will throw a “Not Implemented” or “Platform Not Supported” error.  As I was told by a .NET Foundation member:

There is often incorrect assumption made that “included in .NET Standard” == “works in .NET Core”. There are going to be some APIs that will throw PlaformNotSupportedException on .NET Core, also this set be different between Windows and Unix.

That’s a bit counter-intuitive to me. First of all, it seems like .NET Core should be the “reference implementation” of .NET Standard.  Beyond that, the availability of APIs on unsupported platforms may lead a developer to believe an API is fully functional when it is not. To solve that issue, tooling is coming that will identify APIs that are not supported on certain platforms/runtimes (hopefully before a developer has gone through a porting effort). Also, keep in mind that a least-common-denominator approach has already been tried with Portable Class Libraries, and the .NET team is going for something better. The .NET Standard team is currently accepting feedback on GitHub, so feel free to post your thoughts and questions.

Looking beyond .NET Standard 2.0 and .NET Core 1.1, several COM/native interop pieces have already been segregated for a possible future extension. Also, the source code for the underlying functionality is readily available.  I think it is only a matter of time before COM interop will be available for use with .NET Core.


Debugging in ParallelFox

ParallelFox 0.6 Beta was released today.  Earlier this week, I posted a couple of new training videos about Worker Events on VFPX.  When I started, I figured the training video would be 30-45 minutes to cover all the features in ParallelFox.  I’m now up to 4 videos clocking in at almost two hours.  Part of that is my slow presentation (sorry for that, I was doing most of it off the cuff), but if you’ve ever put together videos like this, then you know how time consuming they are.  I feel like it was important to actually demonstrate those concepts in action, but for the rest of the topics, that is not a requirement.  It will be quicker for you and me if I present the remaining topics in written form, and this is the first entry in that series.  I will link to all entries from the main ParallelFox page on VFPX.  Occasionally, a video may be called for, in which case I will create a short video and link to it from the associated blog entry.  These entries may someday make their way into a Help file.  Ok, let’s get started with the first topic…

FoxPro does not allow you to debug into COM servers.  To spell that out, suppose you created a COM server in VFP, and then instantiated that object in VFP as well.  The code would look something like this:

Local loMyCOMObject as MyCOMServer.MyObject
loMyCOMObject = CreateObject(“MyCOMServer.MyObject”)

Set Step On


In the code above, Set Step On would open the debugger, but if you tried to step into the DoSomething() method, you would not be able to see the code inside the COM object.  VFP would execute the method then return to the calling program.  Calling Set Step On (or setting a breakpoint) inside the COM object doesn’t work either.  To work around this, you have to instantiate your objects as regular FoxPro objects and fully debug them before building them into a separate COM server.

Aside: Years ago, Robert Green and Calvin Hsia demonstrated debugging FoxPro COM objects from Visual Studio. This was around the time Microsoft introduced .NET, and even though they had already decided there would be no VFP.NET, VFP still needed a good integration “story” if it were to remain part of Visual Studio.  You know the rest of the story.  The Fox was taken “out of the box” before the release of VFP 7.0, so it no longer needed that story, and the feature was dropped.

This limitation could pose some problems for ParallelFox, because code is run in parallel by means of COM servers.  It is not convenient to simply instantiate an object in the main process, and the code you are running in parallel may not be inside a class anyway.  Even if it were convenient, the code would be not be running in parallel, only in the main process, so it’s not exactly an ideal situation.

Fortunately, ParallelFox makes it easy to debug your code by providing a debug mode.  To turn on debug mode, simply pass .T. as the third parameter to the StartWorkers() method:

Local Parallel as Parallel of ParallelFox.vcx
Parallel = NewObject(“Parallel”, “ParallelFox.vcx”)


This tells ParallelFox to start the workers in full instances of VFP, rather than as standard COM objects.  Simply SET STEP ON in your worker code (breakpoints may not transfer to worker instances), and the debugger will open in the worker instance.

To use debug mode, the main process needs to know where ParallelFox.vcx and WorkerMgr.vcx are, so make sure they are in your path.  If you’re going to use the Worker object, the worker processes need to know where ParallelFox.vcx is as well, so make sure your workers can find it before you instantiate the Worker object.


As I mentioned previously, I have been experimenting with integrating our application with Maximizer CRM.  Working with their SDK, it doesn’t take long to figure out that the com interfaces were designed with VB and C++ programmers in mind.  Most of it works with VFP, but there are a few exceptions.  I ran into a problem with an interface that accepts a variant variable by reference.  I was surprised to find out that Fox can’t create a variant.

Shirley I can’t be serious?  Everyone knows that all variables in Fox are variants.  While that may be true, Fox can’t create a variable of type variant that can be passed to com components.  Fox always assigns a type to a variable.  Even a simple local myvariable statement creates a logical variable.  Attempting to pass the variable by reference to a com component may result in a “type mismatch” error.

This isn’t entirely Fox’s fault.  After all, should a COM component assume that the calling environment can create a variant?  Microsoft concedes this is a problem in C++ with MFC components and recommends using ATL instead (see link below).

So, what can you do if you run into this situation?  Ideally, the COM interface would be changed not to use variants, but I doubt Maximizer will change their interfaces, in place for years, just so I can use VFP.  VB does allow you to create variables of type variant, so I created a VB wrapper component.  VFP passes a string to the VB component, the VB component converts that to a variant and passes it to the Maximizer component.  It’s not an ideal solution, but it works.

Prb: ActiveX controls passing variant* back to VFP cause error