非托管 DLL 函数的正确调用约定
Posted
技术标签:
【中文标题】非托管 DLL 函数的正确调用约定【英文标题】:Proper calling convention of unmanaged DLL function 【发布时间】:2013-08-13 11:38:03 【问题描述】:我正在尝试为 LibVLC DLL 库编写一个简单的超简单轻量级包装器。我不需要访问太多,只需要播放暂停和停止媒体文件的能力。我正在查看文档和我发现的其他链接,它解释了旧版本的 LibVLC,但对于最新版本来说它已经过时了。我也尝试了 LibVLC.Net,但它也已过时,我无法在源代码中找到我要查找的内容以将其与我尝试导出的函数相匹配。
我正在尝试导出以下签名:
libvlc_new (int argc, const char *const *argv)
描述:
argc the number of arguments (should be 0)
argv list of arguments (should be NULL)
这就是我正在尝试的方法。
[DllImport("libvlc", EntryPoint = "libvlc_new")]
public static extern IntPtr New(Int32 argc, String[] argv);
描述表明它应该是一个数组,我认为问题出在第二个参数上。我试过了:
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] String[] argv
根据here,还有一些其他选项,例如here 建议的 String 和 StringBuilder,但仍然会发生每次调用该函数时都会得到一个不平衡的 PInvoke 堆栈。
我需要知道这个函数以及其他几个函数的正确调用约定是什么。 “PInvoke For Dummies”在线参考会非常好。
【问题讨论】:
感谢您的快速回复。我试过你的建议。虽然同样的问题。此外,它不会接受 IntPtr.Zero。 【参考方案1】:如果只允许 NULL,则声明参数类型没有多大意义。只需将其声明为 IntPtr 并传递 IntPtr.Zero。
调试器指出您忘记声明 CallingConvention。它不是 .NET 的默认值,这是一个 __cdecl 函数。所以正确的声明应该是:
[DllImport("libvlc", EntryPoint = "libvlc_new",
CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr New(int argc, IntPtr argv);
称为:
New(0, IntPtr.Zero);
请尝试选择一个更好的名字...
【讨论】:
那行得通。我知道传递零和空,但你添加的 CallingConvention 是什么? 你可以在this answer找到调用约定的详细描述以上是关于非托管 DLL 函数的正确调用约定的主要内容,如果未能解决你的问题,请参考以下文章
C# DllImport“调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配 ”