5
votes

I've been trying to get a registration-free .NET based COM DLL to work, but without success.

  • In Visual Studio 2008 I added a new C# class library.
  • I enabled the 'make assembly COM-visible' and 'register for COM interop' options.
  • I added a public interface and class with some functions.
  • I added a manifest dependency to my C++ client application: #pragma comment(linker,"/manifestdependency ...

But when I start my application I get 'the application has failed to start because the application configuration is incorrect'.

I've used Microsoft's mt tool to extract the manifest files of both the C++ client application and the C# COM DLL and the information in both is the same (the dependentAssembly in the C++ manifest file contains the same name and version as the assemblyIdentity in the COM manifest file).

I've also tried the approach described on http://msdn.microsoft.com/en-us/library/eew13bza.aspx but with similar results.

Similarly I tried to add a reference to my COM project in 'Framework and References' of my C++ client application. The information on that property page looked promising (it shows options like 'copy local', 'copy dependencies', etc and properties like the 'assemblyIdentity'), but Visual Studio neither copies the DLLs nor adds a dependency to the manifest file automatically.

Note that the 'registered variant' works fine.

Anyone have any ideas of what I'm doing wrong?

Update:

  • When I create a simple C++ DLL and embed a manifest with the same name and version of my .NET COM DLL (same assemblyIdentity) my application starts up fine. So the problem lies with the manifest file of my .NET COM DLL.
  • I can successfully extract the manifest from the DLL with mt -managedassemblyname:... and then embed the same manifest with mt -outputresource:..., but this also doesn't cause Windows to successfully resolve the dependency.
2

2 Answers

4
votes

I found the steps needed to get registration-free .NET COM interop working myself :-)

  • Run: mt -managedassemblyname:"myDll.dll" -out:"myDll.manifest"
  • Clean manifest (see format at http://msdn.microsoft.com/en-us/library/eew13bza.aspx). Mainly I needed to remove all tags except for assemblyIdentity, clrClass and file (and specifically remove the runtime, mvid and dependency tags).
  • Run mt -outputresource:"myDll.dll" -manifest "myDll.manifest". Basically this adds the modified manifest as a resource to the DLL. Note that this is apparently not the same manifest (location)! If I reextract the manifest with the managedassemblyname option I still get the 'old' manifest. If I extract it with the inputresource option I get the new one.

I pretty much found this all thanks to Windows Vista. Unlike my Windows XP it contains a tool called sxstrace that gives rather detailed information about the problems with side-by-side execution.

-2
votes

When I did this, I started with a very simple, basic component to get the COM stuff sorted. Also I used a script client in the initial development.

I did not use Visual Studio, but instead a text editor for the .NET code. I inserted the GUIDs for the assembly and for the Interfaces, and marked the interfaces for AutoDispatch.

using System;
using Interop=System.Runtime.InteropServices;

namespace Whatever
{
    [Interop.Guid("xxxxxxxx-9120-4283-b972-changethis05")]
    [Interop.ComVisible(true)]
    [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
    public partial class MyClass :
    ...
}

I made sure my class had a default (no-arguments) constructor.

I ran regasm /codebase by hand, from the command line, specifying the .NET assembly.

I hand-coded the javascript to instantiate the object.

When things were confusing, I checked the ProgId with OleView.exe.

Once you have the very basic stuff working, add complexity gradually, until you get the working solution.


You can also use the approach from the other direction; from the client. .NET Assemblies like System.Random are marked for COM interop when you install .NET, so you can use them to verify that your approach in C++ is correct. Instantiating a System.Random ProgId is something like the "hello, World" of C++-to-.NET-via-COM. If that succeeds, then you know the basic approach in C++ is sound.