3

我的目标

我正在尝试为Plex Media Server (PMS)创建一个插件,该插件将与 WMP (Windows Media Player) 交互,以获取有关 Windows 媒体库项目的元数据。

设置

  • PMS 使用 Python 2.7 作为其主要脚本宿主。Plex 插件是用 Python 编写的,尽管它们以沙盒容量运行。不幸的是,关于这个沙盒功能的边界究竟是什么,很少有文档可悲。
  • 我决定使用 Python for .NET 来访问 Windows SDK 以与 WMPLib 交互。Python for .NET ( http://pythonnet.github.io/ ) 是一个 Python 库,用于从 Python 运行时访问 .NET 程序集的功能。
  • 我创建了一个 .NET 程序集来访问 WMPLib,它是 Windows SDK 的一部分,旨在以编程方式访问 WMP 的功能。WMPLib 基本上是针对 wmp.dll 的 .NET 的 COM 互操作包装器。

什么工作?

从 Python 到基于 COM 的 WMP 访问的整个链都在工作。如果我启动 Plex 媒体服务器(Python 2.7 版本)附带的嵌入式 Plex 脚本主机,我可以轻松地从 WMP 访问数据。这意味着链中的以下链接都在工作:

  • Python正在为 .NET 加载 Python
  • .NET 的Python正在加载我的 .NET 程序集
  • 我的 .NET 程序集正在加载 WMPLib(Interop.WMPLib.dll,COM 互操作的 .NET 程序集)
  • WMPLib正在成功打开和使用 wmp.dll(从 C:\Windows\System32 访问)

什么不工作?

在沙盒 Plex 插件中无法激活此链的 COM 互操作部分。同样,这个插件是用标准 Python 编写的,但是一旦沙盒代码运行,Python 执行环境就会有一些微妙的不同。从插件中运行 WMP 访问代码时出现以下异常:

COMException: Exception from HRESULT: 0xC00D1327
   at WMPLib.IWMPPlayer4.get_mediaCollection()
  • 在这种情况下,我知道 Python for .NET 正在工作,因为此时我已经从我的 .NET 程序集中加载并访问了其他内容。
  • C:\Windows\System32位于 PATH 变量的前面。我假设 COM dll 应该通过 PATH 环境变量定位(似乎是这样说的),但我并不完全确定这一点。 在这种独特的场景中(Python 访问 .NET 访问 COM)应该如何定位 COM 程序集是我最大的未知数之一

问题

  1. Plex 插件沙箱如何更改 Python 执行环境,从而无法访问 COM 程序集?
  2. 在这种情况下,环境应该如何定位和访问 COM 程序集?
  3. 它是否需要 Plex 沙盒可能已锁定的特定权限?

也许我至少应该赢得某种奖品,因为我以一种独特的混乱方式解决了一个与众多不同技术相交的问题……

编辑 1

感谢@Paulo 下面的建议,我已经完全排除了任何与 .NET 相关的问题。我现在正在WMPLib通过comtypesPython 库进行所有互操作。现在我收到以下错误:

COMError: (-1072884953, None, (None, None, None, 0, None))

虽然-1072884953是一个不同的错误代码,但稍微挖掘一下就会发现这个错误与(可能等同于?)我通过 .NET 互操作遇到的相同错误相关联(这篇文章使它看起来如此)。

所以现在我坚持的事实是:

  1. wmp.dll在所有情况下都在加载(@Paulo 帮助我在下面弄清楚)。
  2. 当访问 WMP 的代码在 Plex 沙箱环境之外运行时,可以从 WMP 访问库项目。
  3. 当访问 WMP 的代码在 Plex 沙箱环境中运行时,无法从 WMP 访问库项目。
  4. 我得到的错误代码(无论是来自 .NET 还是基于 Python 的 COM 互操作)NS_E_CURL_INVALIDPATH: The URL contains a path that is not valid.在大多数情况下,此错误似乎与尝试播放有关。
  5. 这很奇怪,因为我从来没有在我的场景中播放过……我只是想打电话wmp.mediaCollection

因此,Plex 沙盒在这种情况下似乎确实是关键。还有什么想法吗?

编辑 2

最低限度,这是失败的代码:

from comtypes.client import CreateObject

wmp = CreateObject("{6BF52A52-394A-11d3-B153-00C04F79FAA6}")
collection = wmp.mediaCollection

collection = wmp.mediaCollection就是发生错误的地方。

所以实际上没有任何可能导致失败的参数传入。重申一下,此代码在一般 Python 2.7 上下文中运行良好。它仅在 Plex 插件沙箱中失败。我不知道如何获取有关 Plex 沙盒如何更改执行环境的详细信息。我想我的答案就在那个方向。

4

1 回答 1

0

让我直截了当,如果我错了,请纠正我:

  • 您有一个正在运行的 Python 2.7 实例,即 Plex 媒体服务器

  • 您正在使用 Python for .NET 库将 .NET 加载到您的进程中

  • 您正在 .NET 中加载 WMPLib,这是一个导入的 COM 互操作程序集,以通过 Python for .NET 使用 Windows Media Player 库

让我们澄清一下:

  • 0xC00D1327NS_E_CURL_INVALIDPATH

    URL 包含无效的路径。

    这似乎是一个合法的对象错误,而不是 COM 错误。

  • DLL 搜索顺序与它几乎没有关系,因为 wmp.dll 在InProcServer32注册表项下为每个提供的类注册了完整路径,这才是最重要的。

    事实上,正如您所说,如果您已经达到了这一点,那么加载 .NET 程序集或 COM 找不到 DLL 显然不是问题。

现在,对于问题:

  1. 由于错误似乎是合法的,您可能无法访问媒体集合(Internet 区域?),或者 WMP 未正确注册/安装,或者某些编解码器丢失或未正确注册/安装等。

    你在 WMP 中加载什么?尝试基本的东西,例如本地 .WAV、.MP3、.AVI 和 .MPG 文件,然后尝试更高级的格式,例如 MPEG4 编码的视频,或者可能是远程位置。

  2. 您应该尝试一种更直接的方法,尽管我不能真正保证哪个更好:win32com (pywin32 的一部分)comtypes

    自从我看过它们以来是很久以前的事了,所以对此持保留态度:使用 comtypes,您可以像使用具有属性和方法的常规 Python 对象一样使用 COM 对象,而 win32com 似乎更倾向于通过运行时名称调度来做事。

    至少你会打一些你真的必须忍受的东西(Python),而不是为甚至不需要它的东西(WMP)加载.NET。

  3. 我不知道沙盒是什么,但我猜它是一个纯 Python 沙盒,而不是限制操作系统使用的东西。


编辑:您是否提供了预期 URL 的文件名(例如 C:\path\to\file.mp4)(file:///C:/path/to/file.mp4),反之亦然?我想您必须显示失败的代码以及提供的值。

于 2014-07-17T16:20:44.333 回答