C++/CLI->C# error C2526: C linkage function cannot return C++ class
Asked Answered
B

1

11

I have a simple .NET dll built with VS2010 C# that exposes 2 static members of a class

public class Polygon
{
    public static void Test(int test) {}
    public static void Test(List<int> test) {}
}

I then created a Console app from VS2010 C++ and added this function above _tmain

extern "C" void TestMe()
{
    Polygon::Test(3);
}

Adding the reference and compiling gives me this error

1>WierdError.cpp(9): error C2526: 'System::Collections::Generic::List<T>::GetEnumerator' : C linkage function cannot return C++ class 'System::Collections::Generic::List<T>::Enumerator'
1>          with
1>          [
1>              T=int
1>          ]
1>          WierdError.cpp(9) : see declaration of 'System::Collections::Generic::List<T>::Enumerator'
1>          with
1>          [
1>              T=int
1>          ]
1>          WierdError.cpp(9) : see reference to class generic instantiation 'System::Collections::Generic::List<T>' being compiled
1>          with
1>          [
1>              T=int
1>          ]

Some of my observations:

  • It compiles successfully if I remove extern "C"
  • It compiles successfully if I rename Test(List<int> test) to Test2(List<int> test)

My question is, what is going wrong and how to fix it from the C++ side.

My current workaround is to rename the method in C#, but I would rather not have to do this, I have a feeling there is a setting I might be missing in my C++ project.

Edit:

I found a better workaround in the C++, it looks like I can wrap the .NET calls in another function.

void wrapper()
{
    Polygon::Test(3);
}

extern "C" void TestMe()
{
    wrapper();
}

It seems silly to have to do this, I'm wondering if it's a compiler bug? What scares me is using such methods and having to worry that the C# developer may at a later point add such a static method and break the C++ builds.

Bane answered 16/6, 2011 at 17:12 Comment(5)
I can't repro this error. What project template did you use to create the C++/CLI project? I suspect you chose the wrong one, since none of the CLR project templates define a _tmain entry-point.Inexplicit
I think it was the Win32 Console, I then went into the settings and added /clr support, I'll verify tomorrow.Bane
youtube.com/watch?v=QUuQ-BdHflk - fast forward to 2:08 is what I did.Bane
Well, FWIW, it works for me when using the CLR Console Application template. Give that a shot.Inexplicit
A CLR Console project also gave me the same compile errorBane
F
6

I am just going to take a wild shot here, with the following reasoning:

During compilation MSVC's C++ compiler sees the extern "C" function TestMe() is calling an function Test() inside a class Polygon. Polygon is an incomplete type for the compiler. I guess the compiler cannot see whether the function Polygon::Test(3) is returning an incomplete type or returning anything at all, it decides that it needs to return an error at that point in case the type turns out to not be a plain C-style POD type.

The above seems a reasonable assumption on part of MSVC as in (7.5/9 "Linkage specifications") the C++ standard says:

"Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved."

That would explain the error vanishing once you remove the extern C linkage specification or replace the call to a Cstyle function.

Fortuitous answered 16/6, 2011 at 17:50 Comment(2)
yes, and the vanishing when I wrap Polygon::Test inside of it's own function without the extern "C". I'm so used to header files, and it's unclear to me how it all work now in the world of adding .NET assembly referencesBane
Polygon is not an incomplete type; in C++/CLI, when an assembly reference is added, all types in that assembly are complete.Inexplicit

© 2022 - 2024 — McMap. All rights reserved.