很惊讶win32api + COM和来自SO的回答

时间:2013-10-27 01:34:27

标签: python windows com pywin32

从我在SO上的另一个问题,我问如何从Windows Media Player和Zune中检索当前播放的歌曲,我得到了一个c ++开发人员的回答,他给了我一个如何为WMP做这个的解释。 / p>

但是,我不是C ++ dev,我对pywin32库也没有经验。最重要的是,所有这些(特别是关于WMP)的文档都是可怕的

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

Source

  

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

     

步骤:

     

1)实现了一个实现IUnknown,IOleClientSite,IServiceProvider和IWMPRemoteMediaServices的基本COM对象。这是   使用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将回调您:fisrt要求提供IServiceProvider接口指针,第二次调用   QueryService方法,要求IWMPRemoteMediaServices接口   指针。返回IWMPRemoteMediaServices的实现,   第三,您将通过GetServiceType再次调用。那你必须   返回“远程”。您现在已连接到WMP运行实例

     

7)查询COM对象以获取IWMPMedia接口指针

     

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

     

9)完成

     

以上所有测试均使用VS2010 / Windows Seven和WMP进行测试   正在运行(如果没有运行Media Player进程,那就行了   没有)。

     

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

我对win32api有点了解。

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

第二步:

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

好的,那是可行的。

到第三步。 QueryInterface -

  

“无论您拥有什么对象,您都可以调用其QueryInterface()方法来获取新的接口,例如IStream。”

source

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

我可以漫步,但我相信你明白了,我不知道如何使用它。任何人都可以帮我解决这个问题吗?最好使用代码示例,但也欢迎资源/文档。

1 个答案:

答案 0 :(得分: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确定IOleClientSite和IServiceProvider,KO for 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)