Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

COM Object Access and dynamic in .NET Core 2.x


:P
On this page:

I've been playing around with some old legacy code that uses an ASP.NET front end to some really old FoxPro COM servers. Yup - very Old Skool! It's part of an old framework that works well on full .NET.

Recently I've been toying with the idea moving this to .NET Core to make the local development experience a lot smoother. With easy Kestrel self-hosting the need to use IIS or local IIS Express goes away and even for this old monolith that would be a huge win.

The old framework is implemented in .NET HttpModule/Handler and moving this to .NET Core wouldn't be a big effort which is even more of an incentive. The upside would be that it still works in IIS especially now in .NET Core 2.2 with the new and improved InProcess .NET Core hosting capability.

COM in .NET Core

COM of course is old tech and totally Windows specific, which is fine in this case. But in my case it's the only way to interop with the old legacy FoxPro COM server/applications.

Surprisingly .NET Core - when running on Windows at least - supports COM access, which means you can instantiate and call COM objects from .NET Core in the same way as full framework. Well almost...

Although .NET Core is cross-platform, COM Interop is a purely Windows specific feature. Incidentally even .NET Standard includes support for the COM related Reflection and Interop functions with the same Windows specific caveat.

Not so Dynamic

The good news is that COM Interop works in .NET Core. The bad news is that COM Interop using the C# dynamic keyword and the Dynamic Language Runtime in .NET does not.

Here's a silly example that's easy to try out using InternetExplorer.Application to automate that crazy Web Browser. Not very useful but an easy to play with COM Server that's generically available on Windows.

The following code uses raw Reflection in .NET Core to access a COM object and this works just fine in both full .NET 4.5+ or .NET Core 2.x:

[TestMethod]
public void ComAccessReflectionCoreAnd45Test()
{
    // this works with both .NET 4.5+ and .NET Core 2.0+

    string progId = "InternetExplorer.Application";
    Type type = Type.GetTypeFromProgID(progId);
    object inst = Activator.CreateInstance(type);


    inst.GetType().InvokeMember("Visible", ReflectionUtils.MemberAccess | BindingFlags.SetProperty, null, inst,
        new object[1]
        {
            true
        });

    inst.GetType().InvokeMember("Navigate", ReflectionUtils.MemberAccess | BindingFlags.InvokeMethod, null,
        inst, new object[]
        {
            "https://markdownmonster.west-wind.com",
        });

    //result = ReflectionUtils.GetPropertyCom(inst, "cAppStartPath");
    bool result = (bool)inst.GetType().InvokeMember("Visible",
        ReflectionUtils.MemberAccess | BindingFlags.GetProperty, null, inst, null);
    Console.WriteLine(result); // path             
}

I used this in a multi-targeted project targeting net46 and netcore2.1. The above code works against either target.

Using the much simpler dynamic code however, works only in .NET 4.5 but not in .NET Core 2.x:

[TestMethod]
public void ComAccessDynamicCoreAnd45Test()
{
    // this does not work with .NET Core 2.0

    string progId = "InternetExplorer.Application";
    Type type = Type.GetTypeFromProgID(progId);
    dynamic inst = Activator.CreateInstance(type);

    // dynamic inst is set, but all prop/metho access on dynamic fails
    inst.Visible = true;
    inst.Navigate("https://markdownmonster.west-wind.com");

    bool result = inst.Visible;
    Assert.IsTrue(result);
}

This is a bummer, but it looks like this will get fixed in .NET Core 3.0. I was just about to post an issue on the CoreFx Github repo, when I saw this:

and it looks it's been added to be fixed for .NET Core 3.0.

I'm glad to see that COM at least works. In this particlar case, I'm only dealing with a handful of Interop calls so I don't mind too much using my ReflectionUtils in Westwind.Utilties to do it.

But for more complex use cases it sure is a lot easier to use dynamic to automatically handle the type casting and more natural member syntax. Hopefully this will get addressed before 3.0 ships later this year - chances are good seeing that a lot of focus in 3.0 is around making old Windows related frameworks like WinForms and WPF work in .NET Core. COM is just one more step removed back from that 😂.

this post created and published with Markdown Monster
Posted in .NET  .NET  COM  

The Voices of Reason


 

Matthew
April 14, 2019

# re: COM Object Access and dynamic in .NET Core 2.x

Hi Rick,

Have recently started delving into .NET core and API's built on it, during this time have come across your site and blog posts and really enjoy reading your content. All was going well until I tried to reconstruct an old function that utilizes a DLL file that when referenced into a project typically creates the old traditional INTEROP.x.DLL file.

Although the project adds the reference correctly and creates the INTEROP file. It builds fine and runs until an endpoint hits the function that uses a function in the DLL library at which time it is throwing an exception in my catch section of the endpoint method.

I am getting the Could not find the file or assembly... Cannot find the file specified etc. The INTEROP file and the original DLL file are both in the Debug folder. I've done a bit of searching on this but haven't come up with anything concrete.

Hoping that since you have been able to get some of your COM objects working you might know if there is anything you can suggest or try. Or am I looking at going back to Standard .NET to properly support third party COM objects?

Thanks


BojanM
September 30, 2019

# re: COM Object Access and dynamic in .NET Core 2.x

@Mathew: Firstly, have you tried .NET Core 3?

I've been playing with the various COM libs and .NET Core 3 lately. Major problems for me were around the fact that not all libraries had x64 version and, just as in your example, all seemed to work well until the moment of method invocation at runtime.

Just make sure your process is running as a process in the same platform as the COM library is registered. The HRESULT errors range from NOT_REGISTERED to File not found...

Matching the platform is another story. Dotnet CLI runs by default 64bit on x64 machine. You'd need to create configuration for x86 (if your COM is 32bit one) and VS can be helpful in that case. Otherwise, call dotnet with parameters. Another problem is that dotnet msbuild does not work (regardless of the SDK platform you have, 32 or 64bit) since .NET Core 3 cannot resolve msbuild task ResolveComReference. This msbuild task is part of the .NET Framework version of msbuild, so it works if built from VS.


Raphael Basso
November 12, 2019

# re: COM Object Access and dynamic in .NET Core 2.x

Hello!

I implemented using DynamicObject: https://github.com/arabasso/ComObject


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024