2

Initial situation

I made use of the Component Object Model (COM) in the .NET Framework before in order to use my C# class library in Delphi as shown in this YouTube tutorial, which worked surprisingly well. However, I now want to use .NET Core 6 instead.

Following the official tutorial from Microsoft "Expose .NET Core components to COM", I created this interface

using System.Runtime.InteropServices;

[ComVisible(true)]
[Guid(6775d93d-cf14-42b9-83db-425bac0acf4d)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServer
{
    public string getHelloWorld();
}

and this class.

using System.Runtime.InteropServices;

[ComVisible(true)]
[Guid(d62bf794-d29e-4fcd-8637-994490264a93)]
public class Server : IServer
{
    public string getHelloWorld()
    {
        return "Hello World";
    }
}

After building the project, I executed this command to register all of my exposed .NET objects with COM.

regsvr32 MyProjectName.comhost.dll

The command executed successfully. I now tried to import the created .dll file in Delphi, like I did before with the class libraries written in .NET Framework (See timestamp of YouTube tutorial). However, Delphi runs into an error because it can't load the type library.


Edit 1: Godzilla-type breaking change

According to the official documentation...

Unlike in .NET Framework, there is no support in .NET Core or .NET 5+ for generating a COM Type Library (TLB) from a .NET assembly. The guidance is to either manually write an IDL file or a C/C++ header for the native declarations of the COM interfaces. If you decide to write an IDL file, you can compile it with the Visual C++ SDK's MIDL compiler to produce a TLB.

... there is no support in .NET Core for generating a typelib.


Edit 2: MIDL compiler

However, there is still a way to manually produce a TBL file by using the MIDL compiler. As you can read up in the official documentation, the MIDL compiler processes an IDL file to generate a type library. With that beeing said, I created this IDL file by using this guide.

[
    uuid(a93d03e0-9adf-4a2d-93e3-0ccfc2d8e1a6),
    lcid(0x0409),
    version(1.0),
]
library MyProjectName
{
    importlib("stdole.tlb"); 
    [
        uuid(16292ce5-ccd1-405d-9a70-ace42152bb15),
        oleautomation,
        dual
    ]
    interface IServer: IUnknown {
        HRESULT getHelloWorld([out, string] IServer** string);
    };
};

However, I get an error when I execute the following command to generate the .tlb file.

midl myProjectName.idl /tlb myProjectName.tlb

> midl : command line error MIDL1005 : cannot find C preprocessor cl.exe

Issue: I searched for cl.exe on my Computer but couldn't find anything.

Q.: Does anybody have an idea on how I could solve my problem? I highly appreciate any kind of help, cheers!

Maik Hasler
  • 1,064
  • 6
  • 36
  • 1
    I don't know about how the Delphi side works, it seems to be looking for a typelib, but from .NET 5/6 side, you have no typelib generated (this is a godzilla-type breaking change from .NET Framework). With .NET 6 you can embed one but it's still up to you to built it: https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com#embedding-type-libraries-in-the-com-host (tip: you can use ole .NET Framework's tlbexp with your new code just to build one...) – Simon Mourier Mar 07 '22 at 10:12
  • Yes Delphi looks for a typelib - Seems like I skipped this part of the tutorial! - Thank you very much for giving me a hint! – Maik Hasler Mar 07 '22 at 11:08
  • Are you sure the string types are compatible? – Delphi Coder Mar 07 '22 at 11:49
  • @DelphiCoder Yes, I've used it before in the .NET Framework and it was working very well for me – Maik Hasler Mar 07 '22 at 11:54
  • You can't use tlbexp on .NET core3/5/6 files. Only on .NET Framework-produced ones. Or build a .TLB manually using MIDL compiler. – Simon Mourier Mar 07 '22 at 12:13
  • @SimonMourier I've tried it with the .NET Framework again and Delphi uses the produced `.dll` **not** a tbl. So it seems, that my `.dll` is wrong, but I don't know where since the exposing of the COM interop worked fine... Have you any idea? – Maik Hasler Mar 07 '22 at 12:18
  • The typelib is just used to generate the Delphi import unit. You can do that yourself although it would be a PITA. Ultimately at runtime it's the dll that is loaded, but how is your delphi code going to know how to call it without an import unit? – David Heffernan Mar 07 '22 at 13:39
  • @DavidHeffernan Maybe Delphi creates it? I actually don't know. But this approach only works for the .NET Framework and not .NET Core. So it's basically irrelevant for me since I am trying to do so with .NET Core – Maik Hasler Mar 07 '22 at 14:55
  • That's not what Simon said at all. You create your own type library which then is used by delphi to create the import unit. Have you ever imported a COM object before? – David Heffernan Mar 07 '22 at 15:32
  • Given the simplicity of the code shown, you could just define the COM interface manually in your Delphi code, and then call CoCreateInstance() at runtime. You don't need a typelib to generate an import unit. But, if you need to import more complex objects in the future, the auto-gen becomes more important. – Remy Lebeau Mar 07 '22 at 15:54
  • @SimonMourier Can you give me any reference on how to use MIDL compiler or OLE .NET tlbexp? – Maik Hasler Mar 08 '22 at 09:06
  • @DavidHeffernan I'm sorry for the misunderstanding - I've made some more research and I think I understand the problem now. I am not sure what you mean by "imported a COM object before". I would say no - It's the first time I have to do it manually since I am using .NET Core. Haven't got much experience with COM at all, that's why I appreciate any kind of help :) – Maik Hasler Mar 08 '22 at 09:09
  • @RemyLebeau That would be a possible solution - Nevertheless I'll need more complex objects in the future. Anyways could you give me a refernece on how to do so? :) – Maik Hasler Mar 08 '22 at 09:10
  • @MaikHasler - It was "old" tlbexp :-) https://www.codeproject.com/Articles/12741/Tlbexp-exe-and-Regasm-exe-NET-FrameWork-Tools-Seri for MIDL https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/creating-a-type-library but it's easier to to "reverse engineer" existing ones using Windows SDK OleView https://learn.microsoft.com/en-us/windows/win32/com/ole-com-object-viewer change code and rebuild it using midl. – Simon Mourier Mar 08 '22 at 10:16
  • @SimonMourier Thanks for your **huge** help already, I highly appreciate it. Could you give me some more details about the "reverse engineer" way? Basically I build a `.tlb` first and go all steps backwards or how can I imagine it? – Maik Hasler Mar 08 '22 at 10:24
  • This procedure does not require registration: [https://stackoverflow.com/questions/69306050/create-c-sharp-dll-and-call-from-delphi/69348408#69348408](https://stackoverflow.com/questions/69306050/create-c-sharp-dll-and-call-from-delphi/69348408#69348408) – USauter Mar 08 '22 at 13:26
  • @USauter This looks promising - Anyways you are using .NET Framework in the answer. Might work with .NET Core aswell, I actually don't know. Can you give me an example on how to do so with my example? – Maik Hasler Mar 08 '22 at 13:31
  • 1
    That @USauter method seems like it adds another layer. I wouldn't do that. Personally I'd start by trying to understand COM. Or I'd just go straight to UnmanagedExports which is https://github.com/3F/DllExport on .net core. – David Heffernan Mar 08 '22 at 16:12
  • @DavidHeffernan Thanks for the advice - I've tried using DllExport, but I am unable to use my static method in Delphi. Could you give me an example on how to load the method in Delphi? – Maik Hasler Mar 08 '22 at 17:10
  • 2
    You keep asking people to give you examples. That's not how this site works. There are plenty of `DllExport` examples available. Just do the research to find them. Don't start with returning a string as your first example though. – David Heffernan Mar 08 '22 at 17:24

3 Answers3

1

If you do not mind switching to a different approach, you can compile a native library from .Net using NativeAOT. You can find an example here

It seems to be planned to be available in .Net 7 but you can already start using it with .Net 6.

Fabian
  • 1,100
  • 11
  • 14
1

Wouldn't it be easier to create an API using MVC and call that from the Delphi appication. That way you can avoid all the problems with DLL's.

Paul Sinnema
  • 2,534
  • 2
  • 20
  • 33
1

Maybe this tool will help you:
https://github.com/dspace-group/dscom

 C:\> dotnet tool install dscom -g

 C:\> dscom tlbexport myassembly.dll
MarkL
  • 76
  • 3