Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error with a COM project containing WPF/WinForms #120

Closed
bclothier opened this issue Jan 11, 2023 · 6 comments
Closed

Error with a COM project containing WPF/WinForms #120

bclothier opened this issue Jan 11, 2023 · 6 comments
Assignees
Labels
limitation This is a known limitation

Comments

@bclothier
Copy link
Contributor

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))
@marklechtermann marklechtermann self-assigned this Jan 11, 2023
@marklechtermann
Copy link
Member

marklechtermann commented Jan 11, 2023

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

@marklechtermann marklechtermann added the limitation This is a known limitation label Jan 11, 2023
@bclothier
Copy link
Contributor Author

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.

@bclothier
Copy link
Contributor Author

bclothier commented Jan 11, 2023

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 importlibs. 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.

@marklechtermann
Copy link
Member

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.

@marklechtermann
Copy link
Member

Hi @bclothier,
can I close the issue?

@bclothier
Copy link
Contributor Author

bclothier commented Jan 23, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
limitation This is a known limitation
Projects
None yet
Development

No branches or pull requests

2 participants