Puppy
Puppy

Reputation: 146930

P/Invoke method type signature error

I've got an unmanaged function (which takes three other functions as arguments, making this extra confusing since VS does not say which function was the problem). The .NET Runtime claims that at least one of their signatures is not P/Invoke compatible (although I'm pretty sure that I marshalled everything non-trivial).

Here's my code (where TokenType is a giant enum and Failure is a small enum):

public enum Failure {
    UnterminatedStringLiteral,
    UnlexableCharacter,
    UnterminatedComment
};
public enum TokenType {
    OpenBracket,
    CloseBracket,
    Dot,
    Semicolon,
    Identifier,
    String,
    LeftShift,
    RightShift,
    OpenCurlyBracket,
    CloseCurlyBracket,
    Return,
    Assignment,
    VarCreate,
    Comma,
    Integer,
    Using,
    Prolog,
    Module,
    If,
    Else,
    EqCmp,
    Exclaim,
    While,
    NotEqCmp,
    This,
    Type,
    Operator,
    Function,
    OpenSquareBracket,
    CloseSquareBracket,
    Colon,
    Dereference,
    PointerAccess,
    Negate,
    Plus,
    Increment,
    Decrement,
    Minus,

    LT,
    LTE,
    GT,
    GTE,
    Or,
    And,
    Xor
}

[StructLayout(LayoutKind.Sequential)]
private struct MaybeByte {
    public byte asciichar;
    [MarshalAs(UnmanagedType.I1)]
    public bool present;
}

[StructLayout(LayoutKind.Sequential)]
public struct Position {
    public UInt32 column;
    public UInt32 line;
    public UInt32 offset;
}

[StructLayout(LayoutKind.Sequential)]
public struct Range {
    public Position begin;
    public Position end;
}

[StructLayout(LayoutKind.Sequential)]
public struct Token {
    public Range location;
    public TokenType type;
    [MarshalAs(UnmanagedType.LPStr)]
    public string value;
}

private delegate MaybeByte LexerCallback(System.IntPtr arg);
public delegate void CommentCallback(Range arg);
private delegate Token ErrorCallback(Position p, Failure f);

[DllImport("CAPI.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern System.IntPtr CreateLexer(
    [MarshalAs(UnmanagedType.FunctionPtr)]LexerCallback callback,
    System.IntPtr context,
    [MarshalAs(UnmanagedType.FunctionPtr)]CommentCallback comment,
    [MarshalAs(UnmanagedType.FunctionPtr)]ErrorCallback error
);

As soon as I call CreateLexer with some delegates, the runtime errors. The other answers I've seen were all about fixed-size arrays in the structs, of which I have none.

Any suggestions?

Upvotes: 3

Views: 131

Answers (1)

Puppy
Puppy

Reputation: 146930

Alright. Turns out that the marshaller was rejecting

[StructLayout(LayoutKind.Sequential)]
public struct Token {
    public Range location;
    public TokenType type;
    [MarshalAs(UnmanagedType.LPStr)]
    public string value;
}

Apparently, you have to explicitly specify the CharSet on the struct, even though the LPStr documentation clearly states what encoding is expected. Once I set CharSet = CharSet.Ansi on the struct, the marshaller rejected something else.

Upvotes: 1

Related Questions