admin管理员组

文章数量:1122832

I'm trying to come up with a simple "poke" .NET 9 class library project that I could call from a COM client (Classic ASP) without registering it.

When I build the project though, I'm not getting the .manifest file output. According to Microsoft Docs I should get a ProjectName.X.manifest file on build.

I must be skipping a simple step but I'm confused with the new ComWrappers Code Generation feature introduced in .NET 8.

So then I built a simple ASP.NET 9 project following the guidelines at:

  • initial project setup: Expose .NET Core components to COM
  • .NET 8 source generation feature: What's new in .NET 8 - Source-generated COM interop
  • more on .NET 8 source generation: Source generation for ComWrappers

In an attempt to clean up most of the clutter (attributes) from the first article, I mixed-up the steps until I got a working project:

  1. create a new Class Library project:
mkdir testComLib
chdir testComLib
dotnet new classlib
  1. adjust Class1.cs with the minimal code (and interface in the same file for now)

Class1.cs

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace testComLib;

[GeneratedComInterface]
[Guid("e9cbe871-533e-48b5-b33f-a296a98a51cc")] // generated with 'dotnet guid' (dotnet tool install -g dotnet-guid)
partial interface IClass1
{
  int Poke(int count);
}

[GeneratedComClass]
public partial class Class1 : IClass1
{
  public int Poke(int count) => count + 2;
}
  1. set up the project to allow Unsafe blocks (build required it) and also enable RegFreeCom:

testComLib.csproj

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

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <EnableRegFreeCom>true</EnableRegFreeCom>
  </PropertyGroup>

</Project>

The actual change here is just the two last lines in the PropertyGroup block:

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRegFreeCom>true</EnableRegFreeCom>
  1. Build

    dotnet build

The project is built and reported success

Restore complete (0.3s)
  testComLib succeeded (1.9s) → bin\Debug\net9.0\testComLib.dll

Build succeeded in 2.7s

But when I look up bin/Debug/net9.0/ I only see:

testComLib.deps.json  testComLib.dll  testComLib.pdb

And of course, trying to reference this from VBScript (Classic ASP) with GetObject("c:\...\bin\Debug\net9.0\testComLib.dll", "Class1") gives me a big ActiveX component can't create object: 'GetObject' error.

I wanted to be able to use the RegFreeCom feature to allow for easier deployment of new and production versions of the driver in the host system and also development endpoints without the need to register the DLL in the whole system.

I might be a bit rusted off with the dotnet tool but dotnet build --verbosity diag says it's passing -verbosity:diag to msbuild but I get no verbose output at all. This might help me identify why the EnableRegFreeCom target is not triggering

EDIT

In following three guidelines:

  • @pfx's comment
  • somebody's answer suggestion (which they deleted as it was not complete)
  • the COMServerDemo project

I shall drop the [GeneratedComInterface] and [GeneratedComClass] attributes in favor of provinding two guids (one for interface and another for implementation), and [ComVisible(true)]. And add <EnableComHosting>true</EnableComHosting> to the project.

With this I get to the same foot of the mentioned COMServerDemo (a working build with manifest). Then all that's left is being able to call it from a VBScript environment -- which is probably being cracked by @pfx's advice.

I'm trying to come up with a simple "poke" .NET 9 class library project that I could call from a COM client (Classic ASP) without registering it.

When I build the project though, I'm not getting the .manifest file output. According to Microsoft Docs I should get a ProjectName.X.manifest file on build.

I must be skipping a simple step but I'm confused with the new ComWrappers Code Generation feature introduced in .NET 8.

So then I built a simple ASP.NET 9 project following the guidelines at:

  • initial project setup: Expose .NET Core components to COM
  • .NET 8 source generation feature: What's new in .NET 8 - Source-generated COM interop
  • more on .NET 8 source generation: Source generation for ComWrappers

In an attempt to clean up most of the clutter (attributes) from the first article, I mixed-up the steps until I got a working project:

  1. create a new Class Library project:
mkdir testComLib
chdir testComLib
dotnet new classlib
  1. adjust Class1.cs with the minimal code (and interface in the same file for now)

Class1.cs

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace testComLib;

[GeneratedComInterface]
[Guid("e9cbe871-533e-48b5-b33f-a296a98a51cc")] // generated with 'dotnet guid' (dotnet tool install -g dotnet-guid)
partial interface IClass1
{
  int Poke(int count);
}

[GeneratedComClass]
public partial class Class1 : IClass1
{
  public int Poke(int count) => count + 2;
}
  1. set up the project to allow Unsafe blocks (build required it) and also enable RegFreeCom:

testComLib.csproj

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

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <EnableRegFreeCom>true</EnableRegFreeCom>
  </PropertyGroup>

</Project>

The actual change here is just the two last lines in the PropertyGroup block:

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRegFreeCom>true</EnableRegFreeCom>
  1. Build

    dotnet build

The project is built and reported success

Restore complete (0.3s)
  testComLib succeeded (1.9s) → bin\Debug\net9.0\testComLib.dll

Build succeeded in 2.7s

But when I look up bin/Debug/net9.0/ I only see:

testComLib.deps.json  testComLib.dll  testComLib.pdb

And of course, trying to reference this from VBScript (Classic ASP) with GetObject("c:\...\bin\Debug\net9.0\testComLib.dll", "Class1") gives me a big ActiveX component can't create object: 'GetObject' error.

I wanted to be able to use the RegFreeCom feature to allow for easier deployment of new and production versions of the driver in the host system and also development endpoints without the need to register the DLL in the whole system.

I might be a bit rusted off with the dotnet tool but dotnet build --verbosity diag says it's passing -verbosity:diag to msbuild but I get no verbose output at all. This might help me identify why the EnableRegFreeCom target is not triggering

EDIT

In following three guidelines:

  • @pfx's comment
  • somebody's answer suggestion (which they deleted as it was not complete)
  • the COMServerDemo project

I shall drop the [GeneratedComInterface] and [GeneratedComClass] attributes in favor of provinding two guids (one for interface and another for implementation), and [ComVisible(true)]. And add <EnableComHosting>true</EnableComHosting> to the project.

With this I get to the same foot of the mentioned COMServerDemo (a working build with manifest). Then all that's left is being able to call it from a VBScript environment -- which is probably being cracked by @pfx's advice.

Share Improve this question edited Nov 22, 2024 at 22:15 Avenger asked Nov 22, 2024 at 20:51 AvengerAvenger 3652 silver badges11 bronze badges 4
  • 1 Notice the IUnknown only section; which limits source-generated COM to only early binding, not allowing vbscripts late binding. In case late binding is your goal, this source generation is not an option. – pfx Commented Nov 22, 2024 at 22:00
  • I see, I saw this section but no clue VBScript would fall in it. So it seems I should mimic what the COMServerDemo project does and drop all .NET 8 source generating steps... Although I couldn't query that project from VBScript either. – Avenger Commented Nov 22, 2024 at 22:07
  • Make sure to have a [InterfaceType(ComInterfaceType.InterfaceIsDual)] or InterfaceIsIDispatch for late binding. – pfx Commented Nov 22, 2024 at 22:12
  • Tried all these (IsIUnknown, IsDual and IsIDispatch) and still not callable from VBS; I'm not sure what I use in GetObject(path, name). There's the testComLib.dll, testComLib.comhost.dll and testComLib.X.manifest containing `ProgID="testComLib.Class1". – Avenger Commented Nov 22, 2024 at 22:22
Add a comment  | 

1 Answer 1

Reset to default 0

In order to effectively output the manifest file what I needed was, in summary:

  • drop the .NET 8 source generation attributes ([GeneratedComInterface] and [GeneratedComClass] in Class1.cs)
  • add <EnableComHosting>true</EnableComHosting> to the testComLib.csproj project file
  • add the [ComVisible(true)] attribute to both class and interface
  • Create a new guid and add it to the Class1 class as well.

Thus, from my original question, the changes are:

Class1.cs

using System.Runtime.InteropServices;

namespace testComLib;

[ComVisible(true)]
// One of these InterfaceTypeAttributes:
//[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
//[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("e9cbe871-533e-48b5-b33f-a296a98a51cc")]
partial interface IClass1
{
  int Poke(int count);
}

[ComVisible(true)]
[Guid("c15579a1-f57c-4a30-a6a6-629786cb1ee2")]
public partial class Class1 : IClass1
{
  public int Poke(int count) => count + 2;
}

testComLib.csproj

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

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <EnableComHosting>true</EnableComHosting>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <EnableRegFreeCom>true</EnableRegFreeCom>
  </PropertyGroup>

</Project>

And I can get the output I wanted, at least: the build process outputs more files, including the Manifest one:

testComLib.comhost.dll
testComLib.dll
testComLib.runtimeconfig.json
testComLib.deps.json
testComLib.pdb
testComLib.X.manifest

Now, getting the COM Server to talk to ol' ASP is another story. :`(

For the record, the output manifest is (formatted by me; it is output as a single line file)

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity
    type="win32"
    name="testComLib.X"
    version="1.0.0.0"
  />
  <file name="testComLib.comhost.dll">
    <comClass
      clsid="{c15579a1-f57c-4a30-a6a6-629786cb1ee2}"
      threadingModel="Both"
      progid="testComLib.Class1"
    />
  </file>
</assembly>

I would still gladly mark as the chosen answer a solution using the .NET 8 source generation approach even though it could not be the one I use (for the IUknown limitation pointed by @pfx).

本文标签: cNET 9 RegFree COM Class Library no manifestStack Overflow