Error with a COM project containing WPF/WinForms
bclothier opened this issue · 6 comments
It appears that if a solution contains WPF & WinForms, there are errors within the library that prevents it from exporting correctly where the same DLL will export fine with the System.Runtime.InteropServices
.
To reproduce, use the Rubberduck.dll
which can be obtained from here and run the command line tool:
dscom tlbexport .\Rubberduck.Deployment\bin\Rubberduck.dll --out .\Rubberduck.Deployment\bin\Test.tlb
I get the following output:
dscom : warning TX00000000 : Type library exporter encountered an error while processing 'Rubberduck'. Error: Could not load file or assembly 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.
dscom : warning TX00000000 : Type library exporter encountered an error while processing 'Microsoft.VisualStudio.Interop'. Error: Could not load file or assembly 'Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
Failed to export type library. Failed to set GUID for DOMDocument. Duplicate ID in inheritance hierarchy. (0x800288C6 (TYPE_E_DUPLICATEID))
Hello bclothier,
the problem here is that dscom does not use the GAC.
To create a TLB from a .NET 4.x project, you need to specify the dependent DLLs.
This is how it should work:
dscom tlbexport C:\ProgramData\Rubberduck\Rubberduck.dll --asmpath C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089
Thanks for the guidance. Adding the reference assemblies (it appears that I needed 2), I still get the duplicate GUID error:
dscom tlbexport .\Rubberduck.Deployment\bin\Rubberduck.dll --out .\Rubberduck.Deployment\bin\Test.tlb --asmpath 'C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089' --asmpath 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\PublicAssemblies'
Failed to export type library. Failed to set GUID for DOMDocument. Duplicate ID in inheritance hierarchy. (0x800288C6 (TYPE_E_DUPLICATEID))
We have several GUIDs defined so it's hard to tell which one is causing the problem.
FWIW, this seems to work:
dscom.exe tlbexport .\Rubberduck.Deployment\bin\Rubberduck.dll --out .\Rubberduck.Deployment\bin\Test.tlb --asmpath 'C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089' --tlbreference 'C:\Program Files (x86)\Common Files\Designer\MSADDNDR.dll' --verbose
The duplicate ID is from the Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime
assembly. It looks like error is with GUID {2933bf81-7b36-11d2-b20e-00c04f983e60}
for the type named DOMDocument
. This was not a type we wanted to export, and apparently was not a problem with the System
version. The above tlbreference
allows us to bypass the exports of the types defined in the interop assembly. Oddly, trying it without the assembly references to System.Windows.Forms
still fails even after removing any actual references. The original type library was leaking a UserControl
type from the System.Windows.Forms
assembly. I edited the interface to use object
rather than the actual type. After the changes, I verified via the OLEVIEW that it now has the following importlib
:
// TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// TLib : Microsoft Add-In Designer : {AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}
importlib("MSADDNDR.dll");
Using the working example, I get only the last two importlib
s. I'm not yet sure if it'll work without the importlib
to the mscorlib.lib
and will have to test this out. I think it's because the System
version decorate the exports with _Object
interfaces which requires the reference. The dSPACE
version does not decorate the exports.
Now that I have a working command-line example, I will need to translate it to the C# code accessing the TypeLibConverter
object rather than via the command line.
Good to hear that you were able to generate a tlb.
In case you migrate to .NET 5+, then note that you will have problems with mscorelib types anyway.
See: https://github.com/dspace-group/dscom#migration-notes-mscorelib-vs-systemprivatecorelib
When I perform an export, the result looks like this:
dscom tlbexport C:\ProgramData\Rubberduck\Rubberduck.dll --asmpath C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0__b77a5c561934e089
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: Rubberduck.x32.tlb
[
uuid(E07C841C-43F0-3B33-B105-9B8188A6F040),
version(2.5),
helpstring("Rubberduck AddIn"),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "Rubberduck, Version=2.5.2.5906, Culture=neutral, PublicKeyToken=null")
]
library Rubberduck
{
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface IDockableWindowHost;
interface IAssert;
interface IFake;
interface IFakesProvider;
interface IStub;
interface IVerify;
System.Windows.Forms
is only needed because Rubberduck.dll
references it and dscom needs it for Reflection.
Hi @bclothier,
can I close the issue?
Apologies. I meant to circle back because I did have a follow up question.
I worked out the logic for using the TypeLibConverter
by using the sink's ResolveRef
to mirror the argument line commands for the command-line tools. However, I did want to use the build task instead of running code. The documentation implies that the equivalent should be:
<DsComTlbExportTlbReferences>C:\Program Files\Common Files\DESIGNER\MSADDNDR.OLB</DsComTlbExportTlbReferences>
As a property in my .csproj
. However, it does not appear that it get passed as an input to the command line tool during the build. I tried with DsComTlbExportAssemblyPaths
but got the same result; no changes to the command line generated by the build task.
In both cases, the error is as following:
The command "C:\Users\User\.nuget\packages\dspace.runtime.interopservices.buildtasks\0.18.0\build\..\tools\x64\dscom.exe tlbexport C:\GitHub\Rubberduck\Rubberduck.Main\bin\Debug\net48\Rubberduck.dll --out C:\GitHub\Rubberduck\Rubberduck.Main\bin\Debug\net48\\Rubberduck.tlb" exited with code 1.
with additional warnings:
TX00000000 Type library exporter encountered an error while processing 'Microsoft.VisualStudio.Interop'. Error: Could not load file or assembly 'Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
TX00000000 Type library exporter encountered an error while processing 'Rubberduck'. Error: Could not load file or assembly 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.
I should note that in the TypeLibConverter
+ sink's ResolveRef
approach, I basically check if it's trying to resolve the Microsoft.VisualStudio.Interop
in which case I pass back C:\Program Files\Common Files\DESIGNER\MSADDNDR.OLB
which has the needed type information without all the junk. This works correctly but not sure how to replicate this as a build task.