编写一个轻量级的libVLC包装器.需要帮助(P/Invoke新手)

本文关键字:帮助 新手 Invoke libVLC 一个 轻量级 包装 | 更新日期: 2023-09-27 18:27:35

我正在为LibVLC媒体库编写一个超简单的超轻量级.Net包装器,因为我只需要访问播放、暂停和停止媒体文件的功能。我已经发布了几个问题,并得到了一些答案,但不幸的是,我只剩下更多的问题。

我们将从顶部开始,向下工作。

文档首先指出,我必须通过调用以下规范的函数来初始化VLC:

libvlc_instance_t* libvlc_new (int argc, const char *const *argv)

为此,我定义了以下方法:

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

我调用的函数是这样的:

private IntPtr Instance;
this.Instance = DGLibVLC.NewCore(0, IntPtr.Zero);

我试过几种不同的方法。起初,我不知道CallingConvention,它导致了一个不平衡的堆栈,这让我来到了这里。这个问题得到了解决,该方法已经经历了几次迭代,没有一次被证明是成功的,我的意思是IntPtr在方法调用后总是0。我已经像上面一样尝试过了,第二个参数是String[] argc[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[],我试过让它返回到Long(这实际上导致Long中有一个值),但到目前为止没有任何正确的方法。

有人知道从LibVLC DLL库调用此函数的正确方法吗?

编辑:根据一个建议,我尝试调用库的错误消息函数:

规格:

const char* libvlc_errmsg (void)

实施:

[DllImport("libvlc", EntryPoint = "libvlc_errmsg", 
CallingConvention = CallingConvention.Cdcel)]
public static extern string GetLastError();

呼叫:

Console.WriteLine(DGLibVLC.GetLastError());

结果:

Null

文档指出,如果没有错误,它将返回Null。这一定表明最初的函数调用NewCore工作正常,但仍有问题。

为了涵盖所有基础,我检查了DLL是否与文档匹配,它们确实匹配。2.0.6.0。我引用的文档在这里。

编辑:我可以确认没有错误。当使用一个初始化为零的长变量来存储NewCore的结果时,我可以看到它返回了一些东西。我在这里做错的是,我试图将返回对象指针的非托管函数返回的指针存储在哪里。如何存储指向传递回的不透明结构引用的指针?

编写一个轻量级的libVLC包装器.需要帮助(P/Invoke新手)

它与调用函数的方式无关。当您从libvlc_new()返回IntPtr.Zero时,您将无法获得任何位置。意思是"出现错误"。您需要首先关注错误报告,调用libvlc_errmsg()尝试获取问题的描述。

所以,经过多次环顾四周并提出问题,我已经绕了一圈。我深入研究了LibVLC.Net,发现他们是如何导入DLL函数的,并将它们的功能调整到我自己的包装器中,结果就成功了。

总结:

在开始时的代码中声明了一些Win32 API函数:

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetDllDirectory(string lpPathName);
    [DllImport("kernel32", SetLastError = true)]
    private static extern IntPtr LoadLibrary(string lpFileName);
    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool FreeLibrary(IntPtr hModule);

该句柄提供dll的句柄并设置目录搜索路径。

我不知道这一切到底意味着什么,但当你初始化LibVLC.Net库(主要对象)时,它会加载几乎所有的函数,如下所示:

m_libvlc_media_player_new = (libvlc_media_player_new_signature)LoadDelegate<libvlc_media_player_new_signature>("libvlc_media_player_new");

该委托的定义如下:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr libvlc_media_player_new_signature(IntPtr p_instance);
//==========================================================================
private readonly libvlc_media_player_new_signature m_libvlc_media_player_new;
//==========================================================================
public IntPtr libvlc_media_player_new(IntPtr p_instance)
{
  VerifyAccess();
  return m_libvlc_media_player_new(p_instance);
}

并且它有一个公共函数,一旦定义就调用委托。

我只是简单地去掉了定义库实例的函数,只导入了我需要的功能。

非常感谢所有耐心帮助我的人。如果没有你的帮助,我可能无法找到解决方案。

编辑:好吧,原来不是这样。这是LibVLC插件目录的位置。所以这是一件愚蠢的事;