2

从我关于 SO 的另一个问题中,我询问了如何从 Windows Media Player 和 Zune 中检索当前正在播放的歌曲,我得到了一个 c++ 开发人员的回答,他解释了我将如何为 WMP 执行此操作。

但是,我不是 C++ 开发人员,对 pywin32 库也不是很有经验。最重要的是,所有这些(尤其是关于 WMP)的文档非常糟糕

因此,我需要您的帮助来了解我将如何在 Python 中执行以下操作。

来源

我在 C++ 中有工作代码来打印当前在 WMP 中播放的媒体的名称。这是一个简单的控制台应用程序(78 行代码)。

脚步:

1)实现一个基本的 COM 对象,实现 IUnknown、IOleClientSite、IServiceProvider 和 IWMPRemoteMediaServices。使用 ATL 模板 CComObjectRootEx 很简单(有点,您的里程可能会有所不同)。唯一需要(简单)代码的方法是 IServiceProvider::QueryService 和 IWMPRemoteMediaServices::GetServiceType。所有其他方法都可能返回 E_NOTIMPL

2)实例化“WMPlayer.OCX”COM对象(在我的例子中,通过CoCreateInstance)

3)通过 QueryInterface 从对象中检索一个 IOleObject 接口指针

4)从 1) 中看到的类中实例化一个对象(我使用 CComObject<>::CreateInstance 模板)

5)使用您在 3) 中获得的接口中的 SetClientSite 方法,将指针传递给您的 OleClientSite 实现。

6)在SetClientSite调用过程中,WMP会回调你:首先要求IServiceProvider接口指针,其次调用QueryService方法,要求IWMPRemoteMediaServices接口指针。返回您的 IWMPRemoteMediaServices 实现,第三,您将通过 GetServiceType 再次调用。然后您必须返回“远程”。您现在已连接到 WMP 运行实例

7)在 COM 对象中查询 IWMPMedia 接口指针

8)如果 7) 没有给出 NULL,请阅读 IWMPMedia::name 属性。

9)完成

以上所有内容均使用 VS2010 / Windows 7 进行了测试,并且运行了 WMP(如果没有运行媒体播放器进程,则什么也不做)。

我不知道你是否可以/想要在 Python 中实现 COM 接口和对象。如果您对我的 C++ 代码感兴趣,请告诉我。您可以在 C++ DLL 中使用该代码,然后从 python 调用它。

我对win32api有点了解。

第一步,我真的不知道该怎么办,谷歌搜索 IOleClientSite 结果在 msdn 文档中,它是一个接口。但是,这就是我已经陷入困境的地方。在 Python 中使用这些东西时,我找不到任何东西(可能只是我可怕的谷歌搜索技能)。

第二步:

WMP = win32com.client.Dispatch("WMPlayer.OCX")

好吧,这是可行的。

进入第三步。查询接口 -

“不管你有什么对象,你总是可以调用它的QueryInterface()方法来获取一个新的接口,比如IStream。”

来源

然而,不适合我。据我理解他的解释,我认为这意味着每个 com 对象都从 IUnknown“继承”了三个方法,其中之一是 QueryInterface,但情况似乎并非如此,因为在我的WMP对象上调用 QueryInterface 失败得很惨。(Object has no attribute 'QueryInterface')

我可以继续说下去,但我相信你明白了,我不知道如何处理这个问题。谁能帮我解决这个问题?最好使用代码示例,但也欢迎资源/文档。

4

1 回答 1

2

几乎是最终答案,但无法完成。如果没有 C++ 模块的帮助,我似乎无法使用 pythoncom 来实现自定义接口。这是 Mark Hammon 的回答(2003 年 1 月 13 日,星期一):How to create COM Servers with IID_IDTExtensibility2 interface

对不起 - 你是 SOL。要支持任意接口,您需要以扩展模块的形式支持 C++。有一个新的“Univgw”可以帮助你,但我对此了解不多

我找不到任何关于“Univgw”的东西......

comtypes python 模块旨在解决这个问题,我发现链接说它确实如此,但我无法让它与我全新的 Python 3.3 一起使用。这是 Python 2.x 代码。comtypes 似乎已过时且未维护。

第 1 步 OK 用于 IOleClientSite 和 IServiceProvider,KO 用于 IWMPRemoteMediaServices

步骤 2、3、4 和 5 确定

没有 IWMPRemoteMediaServices 就无法实现步骤 6、7 和 8 :-(

免责声明:完全是Python新手,请不要大喊大叫

import pythoncom
import win32com.client as wc
from win32com.axcontrol import axcontrol
import win32com.server as ws
from win32com.server import util
from win32com.server.exception import COMException
import winerror
import pywintypes

# Windows Media Player Custom Interface IWMPRemoteMediaServices
IWMPRemoteMediaServices = pywintypes.IID("{CBB92747-741F-44FE-AB5B-F1A48F3B2A59}")

class OleClientSite:
    _public_methods_ = [ 'SaveObject', 'GetMoniker', 'GetContainer', 'ShowObject', 'OnShowWindow', 'RequestNewObjectLayout', 'QueryService' ]
    _com_interfaces_ = [ axcontrol.IID_IOleClientSite, pythoncom.IID_IServiceProvider ]

    def SaveObject(self):
        print("SaveObject")
        raise COMException(hresult=winerror.E_NOTIMPL)

    def GetMoniker(self, dwAssign, dwWhichMoniker):
        print("GetMoniker ")
        raise COMException(hresult=winerror.E_NOTIMPL)

    def GetContainer(self):
        print("GetContainer")
        raise COMException(hresult=winerror.E_NOTIMPL)

    def ShowObject(self):
        print("ShowObject")
        raise COMException(hresult=winerror.E_NOTIMPL)

    def OnShowWindow(self, fShow):
        print("ShowObject" + str(fShow))
        raise COMException(hresult=winerror.E_NOTIMPL)

    def RequestNewObjectLayout(self):
        print("RequestNewObjectLayout")
        raise COMException(hresult=winerror.E_NOTIMPL)

    def QueryService(self, guidService, riid):
        print("QueryService",guidService,riid)
        if riid == IWMPRemoteMediaServices:
            print("Known Requested IID, but can't implement!")
            raise COMException(hresult=winerror.E_NOINTERFACE)
        else:
            print("Requested IID is not IWMPRemoteMediaServices" )
            raise COMException(hresult=winerror.E_NOINTERFACE)


if __name__=='__main__':
    wmp = wc.Dispatch("WMPlayer.OCX")
    IOO = wmp._oleobj_.QueryInterface(axcontrol.IID_IOleObject)
    pyOCS = OleClientSite()
    comOCS = ws.util.wrap(pyOCS, axcontrol.IID_IOleClientSite)
    IOO.SetClientSite(comOCS)
于 2013-10-28T20:01:03.140 回答