2

I am currently trying to create a COM object in .NET Core 6. To achieve this I have made a class library and edited the project like this:

C#:

Project file (*.csproj):

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <EnableComHosting>true</EnableComHosting>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
    
</Project>

COM object (*.cs):

using System;
using System.Runtime.InteropServices;

namespace COMNetCore6
{
    [ComVisible(true)]
    [Guid("64D6F9F6-6163-401A-82E6-C941CAF01399")]
    [ProgId("HelloWorldCOMObject")]
    public class ComObject
    {
        public string SayHello() => "Hello world from .NET Core";
    }
}

After building the project I get a *.comhost.dll file which I can add to the registry by using the command 'regsvr32 *.comhost.dll'. The comhost.dll gets registered successfully and it is working for Visual Basic in Excel as intended.

When I try using this COM object in another programming language though it will not work. I have tried using Octave and Python. While Octave only tells me that it wasn't able to create a server, Python gives me this error at least:

Python:

>>> import win32com.client
>>> comobj = win32com.client.Dispatch("HelloWorldCOMObject")
Traceback (most recent call last):
  File "C:\*\AppData\Local\Programs\Python\Python39-32\lib\site-packages\win32com\client\dynamic.py", line 86, in _GetGoodDispatch
    IDispatch = pythoncom.connect(IDispatch)
pywintypes.com_error: (-2147221021, 'Operation unavailable', None, None)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\*\AppData\Local\Programs\Python\Python39-32\lib\site-packages\win32com\client\__init__.py", line 117, in Dispatch
    dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch, userName, clsctx)
  File "C:\*\AppData\Local\Programs\Python\Python39-32\lib\site-packages\win32com\client\dynamic.py", line 106, in _GetGoodDispatchAndUserName
    return (_GetGoodDispatch(IDispatch, clsctx), userName)
  File "C:\*\AppData\Local\Programs\Python\Python39-32\lib\site-packages\win32com\client\dynamic.py", line 88, in _GetGoodDispatch
    IDispatch = pythoncom.CoCreateInstance(
pywintypes.com_error: (-2147467262, 'No such interface supported', None, None)

I have tried to solve this problem by following the steps described in these links (especially the first one) and adapting them to what I needed:

Can I connect a .NET 5 COM interop object with VB6? https://github.com/GregReddick/ComTestLibrary/tree/master/ComTestLibrary1 https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com

Unfortunately none of the approaches I tried worked. I have tried to create an interface for the COM object and use the correct interoperability annotations in C# but the error was still there. As I have said though the basic approach with no interface and barely any annotation from above worked for Visual Basic.

In this case I am trying to use late binding without a TLB (type library) because I need this to work for both late binding (without TLB) and early binding (with TLB) and I decided to start with late binding.

There has been a similar question regarding the late binding approach which wasn't answered as of now: 'No such interface supported' when using .NET 6.0 COM object in python 3.9.

Since the COM object works fine for Visual Basic but doesn't work for other programming languages I am not sure what exactly causes this issue.

Spikxz
  • 35
  • 5
  • I would attempt to find the type of object excel. Try getting the type in excel which may give clue why it is not working in other cases. Put a break point where object get returned and see type. – jdweng Feb 09 '22 at 11:32

1 Answers1

2

The .NET Core wrapper doesn't support this type of call where you ask for IDispatch at the same time you create the COM object:

C / C++:

IDispatch* disp;
CoCreateInstance(YourCLSID, NULL, CLSCTX_ALL, IID_IDispatch, &disp); // fails

Python:

disp = pythoncom.CoCreateInstance(YourCLSID, None, pythoncom.CLSCTX_ALL, pythoncom.IID_IDispatch) // fails

You must first get an IUnknown reference and QI for IDispatch on it, like this in python (which is what Excel/VBA does):

import pythoncom
import pywintypes
from win32com.client import Dispatch

unk = pythoncom.CoCreateInstance(pywintypes.IID('{64D6F9F6-6163-401A-82E6-C941CAF01399}'), None, pythoncom.CLSCTX_ALL, pythoncom.IID_IUnknown)
disp = Dispatch(unk.QueryInterface(pythoncom.IID_IDispatch))
print disp.SayHello

IMHO, python COM support should be modified to do this always...

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • Do you have a link to a source that explains what exactly was changed for the COM wrapper from .NET Framework to .NET (Core) 6.0? I am interested in how this problem occurred. – Spikxz Apr 11 '22 at 06:15
  • Unfortunately, there's no single source for that... You have the old .NET Framework articles (and you must understand by your own they're old), the new .NET core article (and .NET Core 3.1 is different from .NET 5 and 6), and you have to figure out what really changed... or you can dive in the dotnet source code (good luck). One thing to remember is Microsoft removed COM support bits and pieces from the runtime wherever possible and added support as external packages instead (like C#/WinRT, etc.) for "better" cross-platform support. This caused lots of trouble and breaking changes... – Simon Mourier Apr 11 '22 at 07:47