3

I am working on porting some C++ code to managed .NET. I will need to retain some C++ code in native form and am trying to use an IJW approach to it. I know it's possible to declare an unmanaged struct so that it will get correctly marshaled to .NET code, but the C++ compiler doesn't seem to do it.

For example, I have this code (managed):

struct MyStruct
{
     int some_int;
     long some_long;
};

public ref class Class1
{
    static MyStruct GetMyStruct()
    {
        MyStruct x = { 1, 1 };
        return x;
    }
};

It compiles, but when I look at it using Reflector, the code looks like this:

public class Class1
{
    // Methods
    private static unsafe MyStruct GetMyStruct()
    {
        MyStruct x;
        *((int*) &x) = 1;
        *((int*) (&x + 4)) = 1;
        return x;
    }
}

[StructLayout(LayoutKind.Sequential, Size=8), NativeCppClass,
                      MiscellaneousBits(0x41), DebugInfoInPDB]
internal struct
{
}

Basically, no fields in MyStruct are visible to .NET. Is there a way to tell the C++ compiler to generate ones?

When answering, please consider this: I know how to create a managed class which could be visible to .NET framework. I am not interested in doing this. I want for the C++ compiler to declare an unmanaged struct in a way that .NET will understand it. Something like:

[StructLayout(LayoutKind::Sequential, blablabla ... )]
struct MyStruct
{
    [MarshalAs ....... ]
    System::Int32 some_int;
    [MarshalAs ....... ]
    System::Int32 some_long;
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
galets
  • 17,802
  • 19
  • 72
  • 101

2 Answers2

1

If you want to define a public struct visible to .NET applications, from C++ managed code, here is a way to do it (note the 'public' and 'value' keywords):

[StructLayout(LayoutKind::Sequential)]
public value struct MyStruct
{
    int some_int;
    long some_long;
};

If you want an unmanaged struct to be moved between C# and C/C++, you'll have to declare it on both sides. Like this in C:

struct MyUnmanagedStruct
{
    int some_int;
    long some_long;
};

And like this, say, in C#, for example:

[StructLayout(LayoutKind.Sequential)]
struct MyUnmanagedStruct
{
    public int some_int;
    public long some_long; // Or as int (depends on 32/64 bitness)
};

You'll have to ensure the fields in .NET match the fields from C. You may want to use StructLayout attributes (notably Pack). See the two tutorials Structs Tutorial and How to: Marshal Structures Using PInvoke.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • Yes but this makes the struct managed. The question is specifically about accessing members of native structs in C#. – Derrick Jan 09 '12 at 14:54
  • @Derrick - Hmmm... it was not that clear to me, anyway I have updated my answer. – Simon Mourier Jan 09 '12 at 15:33
  • Thanks. This is the way i'm doing it now. Using a pack of 1 on both sides yields identical memory layouts this allows me to recive a pointer to the C++/CLI unmanged struct, and cast it to the C# struct. The shame here, and i think what the question author was trying to get at is that there's code duplication, leading to maintainability issues. You could also declare the struct twice in C++ as a managed and unmanaged version and do the casting there which at least gets you away from unsafe blocks in C#. I guess some form of code generation may be the only solution. – Derrick Jan 09 '12 at 17:04
  • 1
    @Derrick - if duplication is your issue, there are some ways to automate the interop, see this here on SO: http://stackoverflow.com/questions/6319650/is-there-a-tool-that-generates-p-invoke-signatures-for-arbitrary-unmanaged-dll – Simon Mourier Jan 09 '12 at 19:48
1

This question was viewed 194 times in the past two years and has no lack of attention. Take the lack of answers as sufficient proof that this just is not possible.

An unmanaged struct has to be marshaled, and the .NET layout rules for structs are fundamentally incompatible with those for a C or C++ compiler. This answer provides some background information on why .NET works this way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • But I can define a struct in c# with the exact same layout and cast the pointer. It just seems a shame to have to make two identical definitions for the same structure. Thanks for link! – Derrick Jan 09 '12 at 14:53
  • That was the point of the link, you cannot in fact define a struct in C# with the exact same layout. You can only specify a layout that's valid *after marshaling*. The actual layout is completely undiscoverable. – Hans Passant Jan 09 '12 at 14:59