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

Unable to use ICustomTypeDescriptor in C++/CLI #109950

Closed
hmisaki opened this issue Nov 19, 2024 · 8 comments
Closed

Unable to use ICustomTypeDescriptor in C++/CLI #109950

hmisaki opened this issue Nov 19, 2024 · 8 comments
Labels
area-System.ComponentModel tracking-external-issue The issue is caused by external problem (e.g. OS) - nothing we can do to fix it directly

Comments

@hmisaki
Copy link

hmisaki commented Nov 19, 2024

Description

I am working on the dotnet 9 migration in our repo.
When I tried to build a managed C++ project, it failed. The error log shows :

1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18): error C3766: 'test' must provide an implementation for the interface method 'System::Nullable<bool> System::ComponentModel::ICustomTypeDescriptor::RequireRegisteredTypes::get(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18): error C3766: 'test' must provide an implementation for the interface method 'System::ComponentModel::TypeConverter ^System::ComponentModel::ICustomTypeDescriptor::GetConverterFromRegisteredType(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18): error C3766: 'test' must provide an implementation for the interface method 'System::ComponentModel::EventDescriptorCollection ^System::ComponentModel::ICustomTypeDescriptor::GetEventsFromRegisteredType(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18): error C3766: 'test' must provide an implementation for the interface method 'System::ComponentModel::PropertyDescriptorCollection ^System::ComponentModel::ICustomTypeDescriptor::GetPropertiesFromRegisteredType(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18): warning C4570: 'test': is not explicitly declared as abstract but has abstract functions
1>.NETCoreApp,Version=v9.0.AssemblyAttributes.cpp
1>    E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18):
1>    'System::Nullable<bool> System::ComponentModel::ICustomTypeDescriptor::RequireRegisteredTypes::get(void)': is abstract
1>    E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18):
1>    'System::ComponentModel::TypeConverter ^System::ComponentModel::ICustomTypeDescriptor::GetConverterFromRegisteredType(void)': is abstract
1>    E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18):
1>    'System::ComponentModel::EventDescriptorCollection ^System::ComponentModel::ICustomTypeDescriptor::GetEventsFromRegisteredType(void)': is abstract
1>    E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(4,18):
1>    'System::ComponentModel::PropertyDescriptorCollection ^System::ComponentModel::ICustomTypeDescriptor::GetPropertiesFromRegisteredType(void)': is abstract
1>Generating Code...
1>Done building project "managed2.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

It seems it's related to C++/CLI doesn't support the default interface method.

Reproduction Steps

Create a managed C++ project in Visual Studio and fill it with the following codes:

using namespace System::ComponentModel;
using namespace System;
public ref class test : ICustomTypeDescriptor
{
public:
    virtual Object^ GetPropertyOwner(PropertyDescriptor^ pd) { return nullptr; }
    virtual AttributeCollection^ GetAttributes(void) { return nullptr; }
    virtual String^ GetClassName(void) { return nullptr; }
    virtual String^ GetComponentName(void) { return nullptr; }
    virtual TypeConverter^ GetConverter(void) { return nullptr; }
    virtual EventDescriptor^ GetDefaultEvent(void) { return nullptr; }
    virtual PropertyDescriptor^ GetDefaultProperty(void) { return nullptr; }
    virtual Object^ GetEditor(Type^ editorBaseType) { return nullptr; }
    virtual EventDescriptorCollection^ GetEvents(cli::array<Attribute^>^ attributes) { return nullptr; }
    virtual EventDescriptorCollection^ GetEvents(void) { return nullptr; }
    virtual System::ComponentModel::PropertyDescriptorCollection^ GetProperties(void) { return nullptr; }
    virtual System::ComponentModel::PropertyDescriptorCollection^ GetProperties(cli::array<Attribute^>^ attributes) { return nullptr; }
};

Then, compile the project.

Expected behavior

Build success.

Actual behavior

Build fail.

Regression?

Yes, I can build these code on .net 8

Known Workarounds

No

Configuration

No response

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Nov 19, 2024
@huoyaoyuan
Copy link
Member

C++/CLI compiler doesn't handle default interface method in this case.

@hmisaki
Copy link
Author

hmisaki commented Nov 19, 2024

Is there any solution or workaround to fix in my scenario? We have too much usage like this.

@huoyaoyuan
Copy link
Member

What version of MSVC compiler are you using? There are several updates for type system recently.

@JavaScript-Py
Copy link

JavaScript-Py commented Nov 19, 2024

Hello!

In .NET 9, ICustomTypeDescriptor includes new members with default implementations, such as:

RequireRegisteredTypes
GetConverterFromRegisteredType
GetEventsFromRegisteredType
GetPropertiesFromRegisteredType
These default interface methods are abstract in managed C++/CLI because it does not yet fully support DIMs, requiring explicit implementation.

Managed C++ does not seamlessly support default interface methods added in newer .NET versions, necessitating the explicit implementation of all interface members, even those with default implementations in .NET languages like C#.



  #include "pch.h"
  
  using namespace System;
  using namespace System::ComponentModel;
  
  public ref class MyCustomTypeDescriptor : public ICustomTypeDescriptor
  {
  
  public:
      virtual Object^ GetPropertyOwner(PropertyDescriptor^ pd) override { return nullptr; }
      virtual AttributeCollection^ GetAttributes(void) override { return AttributeCollection::Empty; }
      virtual String^ GetClassName(void) override { return "MyCustomTypeDescriptor"; }
      virtual String^ GetComponentName(void) override { return nullptr; }
      virtual TypeConverter^ GetConverter(void) override { return gcnew TypeConverter(); }
      virtual EventDescriptor^ GetDefaultEvent(void) override { return nullptr; }
      virtual PropertyDescriptor^ GetDefaultProperty(void) override { return nullptr; }
      virtual Object^ GetEditor(Type^ editorBaseType) override { return nullptr; }
  
      virtual EventDescriptorCollection^ GetEvents(void) override { return EventDescriptorCollection::Empty; }
  
      virtual EventDescriptorCollection^ GetEvents(cli::array<Attribute^>^ attributes) override
      {
          return EventDescriptorCollection::Empty;
      }
  
      virtual PropertyDescriptorCollection^ GetProperties(void) override { return PropertyDescriptorCollection::Empty; }
  
      virtual PropertyDescriptorCollection^ GetProperties(cli::array<Attribute^>^ attributes) override
      {
          return PropertyDescriptorCollection::Empty;
      }
  };


I tried here and worked fine, I hope it helps you.

I used C++/CLI support for v143 build tools (Latest).

To execute: Do not forget the Main() from cpp

@hmisaki
Copy link
Author

hmisaki commented Nov 20, 2024

Hi, @huoyaoyuan The MSVC version is 14.40.33807.

@hmisaki
Copy link
Author

hmisaki commented Nov 20, 2024

Hi @JavaScript-Py , I am glad to get a workaround from you. I copied the code and tried to compile my test project, but there are still the same issues:

1>    Matching base method 'System::ComponentModel::ICustomTypeDescriptor::GetProperties' is from an interface class (not a ref class)
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(27,18): error C3766: 'MyCustomTypeDescriptor' must provide an implementation for the interface method 'System::Nullable<bool> System::ComponentModel::ICustomTypeDescriptor::RequireRegisteredTypes::get(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(27,18): error C3766: 'MyCustomTypeDescriptor' must provide an implementation for the interface method 'System::ComponentModel::TypeConverter ^System::ComponentModel::ICustomTypeDescriptor::GetConverterFromRegisteredType(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(27,18): error C3766: 'MyCustomTypeDescriptor' must provide an implementation for the interface method 'System::ComponentModel::EventDescriptorCollection ^System::ComponentModel::ICustomTypeDescriptor::GetEventsFromRegisteredType(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(27,18): error C3766: 'MyCustomTypeDescriptor' must provide an implementation for the interface method 'System::ComponentModel::PropertyDescriptorCollection ^System::ComponentModel::ICustomTypeDescriptor::GetPropertiesFromRegisteredType(void)'
1>E:\MySpace\TestDefaultMethonInterface\Library1\managed2\test.cpp(27,18): warning C4570: 'MyCustomTypeDescriptor': is not explicitly declared as abstract but has abstract functions

I have tried to fix it by adding implementations in the C++/CLI class :

    virtual TypeConverter^ GetConverterFromRegisteredType()
    {
        return nullptr;
    }
    virtual EventDescriptorCollection^ GetEventsFromRegisteredType()
    {
        return nullptr;
    }
    virtual System::ComponentModel::PropertyDescriptorCollection^ GetPropertiesFromRegisteredType()
    {
        return nullptr;
    }
    property virtual System::Nullable<bool> RequireRegisteredTypes {
        System::Nullable<bool> get() { return false; }
    }

That will make the build pass, but I am worried that it might cause the runtime to fail.

@huoyaoyuan
Copy link
Member

Seems that the latest version of msvc hasn't provide support for default interface method, and you have to provide implementation of the methods.

That will make the build pass, but I am worried that it might cause the runtime to fail.

It should run fine. You can copy the default implementation of the methods from C# source at https://github.com/dotnet/runtime/blob/main/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ICustomTypeDescriptor.cs .

@jkotas jkotas added the tracking-external-issue The issue is caused by external problem (e.g. OS) - nothing we can do to fix it directly label Nov 20, 2024
@steveharter
Copy link
Member

Closing; please report back if the work-around of adding the default implementation works.

@steveharter steveharter closed this as not planned Won't fix, can't repro, duplicate, stale Nov 22, 2024
@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.ComponentModel tracking-external-issue The issue is caused by external problem (e.g. OS) - nothing we can do to fix it directly
Projects
None yet
Development

No branches or pull requests

5 participants