python - 被 win32api + COM 和 SO 的答案严重困惑

标签 python windows com pywin32

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

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

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

Source

I have working code in C++ to print the name of media currently playing in WMP. It's a simple console application (78 lines of code).

Steps:

1) implements a basic COM object implementing IUnknown, IOleClientSite, IServiceProvider and IWMPRemoteMediaServices. This is straightforward (sort of, your mileage may vary) using the ATL template CComObjectRootEx. The only methods needing (simple) code are IServiceProvider::QueryService and IWMPRemoteMediaServices::GetServiceType. All other methods may return E_NOTIMPL

2) Instantiate the "WMPlayer.OCX" COM object (in my case, via CoCreateInstance)

3) Retrieve from the object an IOleObject interface pointer via QueryInterface

4) Instanciate an object from the class seen in 1) (I use the CComObject<>::CreateInstance template)

5) Use the SetClientSite method from the interface you got at 3), passing a pointer to your OleClientSite implementation.

6) During the SetClientSite call, WMP will callback you: fisrt asking for an IServiceProvider interface pointer, second calling the QueryService method, asking for an IWMPRemoteMediaServices interface pointer. Return your implementation of IWMPRemoteMediaServices and, third, you will be called again via GetServiceType. You must then return "Remote". You are now connected to the WMP running instance

7) Query the COM object for an IWMPMedia interface pointer

8) If 7) didn't gave NULL, read the the IWMPMedia::name property.

9) DONE

All the above was tested with VS2010 / Windows Seven, and with WMP running (if there is no Media Player process running, just do nothing).

I don't know if yoy can/want to implement COM interface and object in Python. If you are interested by my C++ code, let me know. You could use that code in a C++ DLL, and then call it from python.

我对 win32api 了解一点。

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

第二步:

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

好吧,这是可行的。

进入第三步。查询接口(interface)-

"regardless of the object you have, you can always call its QueryInterface() method to obtain a new interface, such as IStream."

source

但是,不适合我。据我理解他的解释,我认为这意味着每个 com 对象都从 IUnknown 中“继承”了三个方法,其中之一是 QueryInterface,但是自从在我的 WMP 上调用 QueryInterface 以来,情况似乎并非如此。对象惨遭失败。 (对象没有属性“QueryInterface”)

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

最佳答案

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

Sorry - you are SOL. To support arbitary interfaces, you need C++ support, in the form of an extension module. There is a new "Univgw" that may help you out, but I dont know much about this

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

comtypes python 模块旨在解决这个问题,我发现链接说它可以解决这个问题,但我无法让它与我的新 Python 3.3 一起工作。这是Python 2.x 代码。 comtypes 似乎已经过时且无人维护。

第 1 步对 IOleClientSite 和 IServiceProvider 确定,对 IWMPRemoteMediaServices KO

第 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)

关于python - 被 win32api + COM 和 SO 的答案严重困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19613750/

相关文章:

python - 如何使用 ast.NodeTransformer 将 List Comprehensions 转换为 For Loops?

python - PyDAQmx 或类似软件适用于 Mac 吗?

windows - 进程资源管理器 : What does the Commit History graph show?

.net - Windows 8 会支持 System.Device.Location 吗?

windows - 从网站启动可执行文件?

c# - 是否可以使用免注册 COM 的 COM 可见 .NET 类?

python - PyQt MainWindow 不显示小部件

python - 将 sqlalchemy 连接到 MS Access

c# - 隐藏打开的 Excel 文件

c++ - 如何在 Linux 中使用 COM ATL 项目?