0

我有一个非托管函数调用,当我尝试将路径传递给文件名时抛出此异常。

我读过这很可能是由 DLL 本身引起的,但我认为情况并非如此,因为 DLL 用于另一个应用程序,所以问题可能出在我调用该函数的方法中。

规格:

libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)

描述:

p_instance  the instance
path    local filesystem path

还有我的方法:

[DllImport("libvlc", EntryPoint = "libvlc_media_new_path")]
public static extern IntPtr NewMedia(IntPtr instance,
                            [MarshalAs(UnmanagedType.LPStr)] string path);

我想我错过了会议电话,但这可能是什么?还是会导致此异常的其他原因?

编辑:根据一些评论,我做了一些探索,发现......好吧,什么都没有。该实例的结构是不透明的,这意味着我不知道用外行术语。我的猜测是这意味着您不需要在使用它的应用程序中重建它?

在基于long的盲目猜测中,我用负责将 *p_instance 值设置为 a而不是a 的函数替换了我一直使用的返回值,IntPtr因为当它IntPtr返回 0 时,我看到了 long一个值。再说一次,IntPtr我真的不知道是什么。我很高兴在实例变量中看到不是 0 的东西,但是当我运行它时,它又出错了。

编辑:我已将问题扩展到此处

4

2 回答 2

1

根据您看到的异常和您为本机函数提供的声明,

libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)

您的 p/invoke 声明不正确。您与调用约定不匹配。.NET p/invoke 系统的默认值为 stdcall(以匹配 Windows API 函数),但 C 和 C++ 代码的默认值为 cdecl。您必须明确告诉 .NET 您的函数使用 cdecl 调用约定。

所以把它改成这样:

[DllImport("libvlc", EntryPoint = "libvlc_media_new_path", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewMedia(IntPtr instance,
                                     [MarshalAs(UnmanagedType.LPStr)] string path);

当然,我猜你对返回值是一个指针是正确的。您显示的本机函数声明缺少返回类型。

至于您关于instance参数的问题,以及您是否正确使用IntPtr类型:参数是指向 a 的指针libvlc_instance_t,因此您有两种使用 p/invoke 使其工作的基本方法。首先是将参数声明为 an IntPtr,这会将其编组为原始指针值。这对于指针需要不透明的情况(即从一个本机函数检索、存储,然后传递给另一个本机函数)的情况并不是特别有用。其次是声明一个镜像本机结构的托管结构,然后编写 p/invoke 声明以使用此结构,以便编组器自动处理事情。如果您确实需要与存储在指针指向的结构中的值进行交互,这将非常有用。

在这种情况下,在 Google 搜索之后,您似乎正在使用其中一个 VLC API。具体是这一项。这也告诉我们anlibvlc_instance_t是什么:它是一个表示 libvlc 实例的不透明结构。所以在这里声明一个托管结构不是一个选项,因为即使本机代码也将结构视为不透明的。你真正需要的只是指针,来回传递;我上面谈到的第一种方法的完美案例。所以上面显示的声明是你的赢家。

现在唯一的战斗是获取一个指向 libvlc 实例的有效指针,您可以在调用它时将其传递给函数。很有可能来自先前调用类似 的函数libvlc_new,该函数被记录为创建和初始化一个新的 libvlc 实例。它的返回值正是您在这里所需要的。所以除非你已经创建了一个 libvlc 实例(在这种情况下,使用那个指针),你还需要调用这个函数并存储它的结果。

如果文档关于函数参数所需的值是正确libvlc_new的,您可以非常简单地声明它:

[DllImport("libvlc", EntryPoint = "libvlc_new", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewCore(int argc, IntPtr argv);

并这样称呼它:

IntPtr pLibVlc = NewCore(0, IntPtr.Zero);
// now pLibVlc should be non-zero

当然,我对 VLC API 一无所知,但我对 API 设计的一般知识告诉我,libvlc_release一旦完成,您可能需要使用指向实例的相同指针调用函数。

于 2013-08-13T15:20:38.807 回答
0

尝试不使用 [MarshalAs(UnmanagedType.LPStr)],通常对我有用。

于 2013-08-13T13:19:32.817 回答