Search code examples
c#.netcpinvoke

PInvoke marshaling a struct pointer from ANSI C as an IntPtr in C#


So I'm trying to PInvoke an unmanaged DLL in C# from the iniParser library. I'm currently stumbling over the correct way to marshal the struct pointers returned and taken by functions in the unmanaged library.

In C:

__declspec(dllexport) dictionary * iniparser_load(const char * ininame);

In C#:

[DllImport("iniParser.dll")]
private static extern IntPtr iniparser_load(string filename);

The dictionary structure in C:

typedef struct _dictionary_ {
    int             n ;     /** Number of entries in dictionary */
    int             size ;  /** Storage size */
    char        **  val ;   /** List of string values */
    char        **  key ;   /** List of string keys */
    unsigned     *  hash ;  /** List of hash values for keys */
} dictionary ;

I understand that to actually access the structure in C# I need to create a counterpart for the C structure, but I don't need to access the struct in C#.

When the function is called in C#, I get the following error:

A call to PInvoke function 'CacheExplorer!CacheExplorer.iniParser::iniparser_load'
has unbalanced the stack. This is likely because the managed PInvoke signature 
does not match the unmanaged target signature. Check that the calling convention 
and parameters of the PInvoke signature match the target unmanaged signature.

But how does the managed signature not match the unmanaged signature? Does PInvoke require that I make a C# counterpart for the C structure? All I need is essentially a handle to the dictionary in C#, accessing members is totally unnecessary and I'd rather not convert the structure to C#


Solution

  • The calling convention of the iniParser library is probably cdecl, which means you need update your [DllImport] attribute usage:

    [DllImport("iniParser.dll", CallingConvention = CallingConvention.Cdecl)]