Search code examples
c#c++enumspinvokemarshalling

c# P/Invoke : Pass Enum value with IntPtr to Function; AccessViolationException


I'm implementing C# wrapper to link C-library and having trouble passing Enum value as parameter to Unmanaged function call which takes pointer as input. that is throwing this exception. The code looks like this :

Function from library :

int function(infoField Field, void const *value); 

Marshal in C#:

[DllImport("CLibrary.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern int function(infoField Field, IntPtr value);

infoField structure :

public enum infoField {section, options, orientation};

One Enum type 'Options' has 4 values to choose from :

public enum Options { var1, var2, var3, var4};

I want to pass one of the 4 choices as value for EnumField = Options, something like this:

IntPtr value = (Intptr)Options.var1;
function (infoField.options,  value);

I think I am missing correct cast convention for pointer to point to Enum type. What should be correct format to pass enum value with IntPtr to function? So far, I have tried few options but get AccessViolationException on function call, Which either means memory allocation failed or did not match what what library is expects the type.

PS : Function marshaling is successful for Other EnumFields. That's also because value passing is string value for them. But Particularly for 'options' it has to be one of 4 Enum options.


Solution

  • Normally, C++ enumerators are defined as follows:

    enum class ENUM_FIELD
    { 
        VAR1, 
        VAR2,
        VAR3,
        VAR4
    };
    

    By default, enum class types are int sized, which means that you can translate them to C# as follows:

    public enum EnumField
    { 
        VAR1, 
        VAR2,
        VAR3,
        VAR4
    }
    

    In such case, both enums will be mapped without problem within the interop environment. But if the C++ enum is defined in a different way, or if the unmanaged method requires a different type, you may need to change the underlying type in your C# declaration in order to map the values correctly. For example:

    public enum EnumField : short
    { 
        VAR1, 
        VAR2,
        VAR3,
        VAR4
    }
    

    Anyway, I think the problem is not caused by the enum, but rather by what you pass as the const void* parameter. Casting an enum value to IntPtr doesn't look right to me:

    UInt32 field = (UInt32)EnumField.VAR1;
    GCHandle handle = GCHandle.Alloc(field, GCHandleType.Pinned);
    IntPtr ptr = handle.AddrOfPinnedObject();
    
    // pass the ptr variable to the unmanaged function
    // and don't forget to handle.Free() when you are done