0

我正在尝试从 GitHub 的 CMark 分支 PInvoke 以下函数

char *cmark_markdown_to_html(const char *text, size_t len, int options)

这是我的 PInvoke 签名:

[DllImport("cmark.dll")]
    public static extern IntPtr cmark_markdown_to_html(
        [In()] [MarshalAs(UnmanagedType.LPStr)] string text, 
        [MarshalAs(UnmanagedType.SysUInt)] uint len,
        [MarshalAs(UnmanagedType.SysInt)] int options);

我这样称呼它:

var retValue = cmark_markdown_to_html(markdown, 0, 0);

但是,它会抛出一个 Marshaling 异常,并带有以下消息:

Cannot marshal 'parameter #2': 
  Invalid managed/unmanaged type combination 
  (Int32/UInt32 must be paired with I4, U4, or Error). 

好的,所以我将签名更改为:

[DllImport("cmark.dll")]
    public static extern IntPtr cmark_markdown_to_html(
        [In, MarshalAs(UnmanagedType.LPStr)] string text, 
        [MarshalAs(UnmanagedType.U4)] uint len,
        [MarshalAs(UnmanagedType.I4)] int options); 

现在它抛出一个PInvokeStackImbalance错误

The name '$exception' does not exist in the current context

本土的东西对我来说是个谜。有人可以帮忙吗?

4

2 回答 2

2

堆栈不平衡

为什么 Cdecl 调用在“标准”P/Invoke 约定中经常不匹配中描述了堆栈不平衡的原因?.

基本上,您需要在其中指定正确的调用约定,DllImport这可能是cdecl

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

编组尺寸_t

那个是在等于 c# 中的 c++ size_t 中讨论的。

  • 假设 CMark 始终是原生的(x86 上为 32 位,x64 上为 64 位),您应该使用(U)IntPtr.
  • 如果它总是 32 位,那么Int32应该使用。
于 2017-01-07T20:32:22.317 回答
1

PInvokeStackImbalance

大概 CMark 正在使用默认的调用约定。C 代码的默认调用约定是“Cdecl”,而用于 P/invoke 调用的默认调用约定是“StdCall”。调用约定指定如何将参数和返回值放在调用堆栈上。使用的调用约定之间的不匹配会导致堆栈变得不平衡。

DllImport您可以从属性中的 C# 代码指定要使用的调用约定。

[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cmark_markdown_to_html(
    [In, MarshalAs(UnmanagedType.LPStr)] string text, 
    [MarshalAs(UnmanagedType.U4)] uint len,
    [MarshalAs(UnmanagedType.I4)] int options); 

编组

如果您希望您的代码与 32 位以外的体系结构兼容,您可能希望size_t使用UIntPtr. (阅读@Eugene Podskal 的回答)

[DllImport("cmark.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cmark_markdown_to_html(
    [In, MarshalAs(UnmanagedType.LPStr)] string text, 
    [MarshalAs(UnmanagedType.U4)] UIntPtr len,
    [MarshalAs(UnmanagedType.I4)] int options);

然后你可以像这样调用该方法

var retValue = cmark_markdown_to_html(markdown, UIntPtr.Zero, 0);
于 2017-01-07T20:35:08.693 回答