P/Invoke方法类型签名错误

3
我有一个未受管理的函数(它接受三个其他函数作为参数,使得这更加令人困惑,因为VS没有说出哪个函数是问题所在)。 .NET Runtime声称他们中至少有一个签名不兼容P/Invoke(尽管我非常确定我已经处理了所有复杂的东西)。
以下是我的代码(其中TokenType是一个巨大的枚举,而Failure是一个小枚举):
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
);

当我使用一些代理调用CreateLexer时,运行时出现错误。我看到的其他答案都与结构体中的固定大小数组有关,但我没有这样的数组。
有什么建议吗?

Failure 定义在哪里? - Damien_The_Unbeliever
@Damien:哦,这是一个枚举。如果你想的话,我可以发布其中的内容。 - Puppy
it和“TokenType”是你展示的内容中不明显存在的两个项目(至少在我看来是这样的) - Damien_The_Unbeliever
1
提供的源代码没有问题。但是这里有很多麻烦,IntPtr太多了,委托类型看起来太可疑了,没有声明它们为cdecl的属性,还有返回结构体的函数。不要试图一次性解决所有问题,从小处着手。 - Hans Passant
@HansPassant:如果 C 函数曾经被调用,没有声明 cdecl 可能会成为一个问题。不幸的是,我添加了这样的属性,但它似乎不是问题的原因。我可以发布更多的示例代码,但其他交互操作还未到达。委托的值是否可能是问题?我假设与类型签名匹配的每个委托都会以相同的方式运行,但如果某些委托在这里具有特殊行为(我使用 lambda),那就可以解释为什么您找不到重现。 - Puppy
1个回答

1

好的。事实证明,编组程序拒绝了

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

显然,您必须在结构体上明确指定 CharSet,即使 LPStr 文档清楚地说明了所期望的编码方式。一旦我在结构体上设置了 CharSet = CharSet.Ansi,编组程序就会拒绝其他内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接