Question

I have the following struct defined in C++:

struct GraphicsAdapterDesc {
    // ... Just some constructors / operators / destructor here
    DEFINE_DEFAULT_CONSTRUCTOR(GraphicsAdapterDesc);
    DEFINE_DEFAULT_DESTRUCTOR(GraphicsAdapterDesc);
    ALLOW_COPY_ASSIGN_MOVE(GraphicsAdapterDesc);

    std::wstring AdapterName;
    int32_t AdapterNum;
    std::wstring HardwareHash;

    int64_t DedicatedVMEM;
    int64_t DedicatedSMEM;
    int64_t SharedSMEM;

    int32_t NumOutputs;
};

In C#, I have a 'mirror' struct declared thusly:

[StructLayout(LayoutKind.Sequential)]
public struct GraphicsAdapterDesc {
    string AdapterName;
    int AdapterNum;
    string HardwareHash;

    long DedicatedVMEM;
    long DedicatedSMEM;
    long SharedSMEM;

    int NumOutputs;
};

I've tried to be really careful about matching up the widths of the variables (although I'm a bit unsure on what to do with the strings exactly).

Anyway, I have the following exported C method:

extern "C" __declspec(dllexport) bool GetGraphicsAdapter(int32_t adapterIndex, GraphicsAdapterDesc& outAdapterDesc) {
    outAdapterDesc = RENDER_COMPONENT.GetGraphicsAdapter(adapterIndex);
    return true;
}

And, the following extern method in my C# app:

[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);

However, this doesn't work right when I call it. I get a different result depending on whether or not I'm compiling in x64 or x86 mode (both the C++ DLL and the C# app are compiled as x86 or x64):

  • In x86 mode, the call returns, but the struct has 'nonsense' values in, and the strings are all null,
  • In x64 mode, the call throws a NullPointerException.

My expectation is that I'm doing something wrong marshalling the strings, and that I need to specify 'wide-mode' for the characters, but I don't know how (or if that's even the right option).

Thank you in advance.

Was it helpful?

Solution

C++ types are not compatible with C# unless they're wrapped in managed C++. and you're using std::wstring which cannot be marshaled into .NET.

To interop successfully you'll either need to use a wchar_t[] or a whar_t* and tell C# now to marshal it.

OTHER TIPS

I don't know what your macros are doing but this will only work if your c++ type is POD. c++11 Has an expanded sense of POD but I don't think you meet the expanded criteria anyway. Otherwise you can't guarantee layout. If you want to export your c++ classes to C# I would suggest you use c++\cli. Also you have wstring defined in your stuct which are definitely not POD. When you use DLLImport think C constructs only or you are going to have a bad time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top