严重困惑的win32api + COM和答案从SO [英] Heavily confused by win32api + COM and an answer from SO

查看:256
本文介绍了严重困惑的win32api + COM和答案从SO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从我在这里的其他问题SO,我问如何从Windows Media Player和Zune检索当前播放的歌曲,我得到了一个C ++开发人员的答案,给我一个解释如何我会这样做WMP。 / p>

但是,我不是C ++开发,也不是我非常有经验的pywin32库。最重要的是,所有这一切(特别是关于WMP)的文档是可怕的。



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



来源


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



步骤:



1) / strong>实现实现IUnknown,IOleClientSite,IServiceProvider和IWMPRemoteMediaServices的基本COM对象。这是
直接(类型,你的里程可能会变化)使用ATL
模板CComObjectRootEx。唯一需要(简单)代码的方法是
IServiceProvider :: QueryService和
IWMPRemoteMediaServices :: GetServiceType。所有其他方法可能返回
E_NOTIMPL



2)实例化WMPlayer.OCXCOM对象(在我的case,通过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属性。



strong> 9)已完成



以上所有都是使用VS2010 / Windows 7测试,并且运行WMP
(如果没有媒体播放器



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


我知道一点win32api。



在第一步,我真的不知道该怎么做,googling的IOleClientSite结果在msdn文档中,它是一个接口。然而,这是我陷入了。



第二步:

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

好的,这是可行的。



到第三步。 QueryInterface -


无论你有什么对象,你总是可以调用它的QueryInterface()方法来获得一个新的接口,如IStream 。


来源



但是,不是为我。根据我的理解他的解释,我认为这意味着每个com对象类型继承从IUnknown的三个方法,其中之一是QueryInterface,但是这似乎不是这样的,因为调用QueryInterface在我的 WMP 对象失败。 (对象没有属性'QueryInterface')



我可以跳过,但我相信你得到了点,我不知道如何使用这个。任何人可以帮助我这个吗?

解决方案

几乎最后的回答,但不能完成。
我似乎pythoncom不能用于实现自定义接口没有C ++模块的帮助。
以下是Mark Hammon的回答(2003年1月13日星期一):如何使用IID_IDTExtensibility2接口创建COM服务器


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


能够找到任何关于Univgw的东西...



comtypes python模块旨在解决这个问题,我发现链接说它,但我可以不能使它与我新鲜的新的Python 3.3。它是Python 2.x代码。



步骤1对于IOleClientSite和IServiceProvider,KO为IWMPRemoteMediaServices



步骤2, 3,4和5 OK



无法在没有IWMPRemoteMediaServices的情况下实现步骤6,7和8: - (



免责声明:在Python中完成新手,请不要叫喊

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

#Windows Media Player自定义界面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 guidService,riid):
print(QueryService,guidService,riid)
如果riid == IWMPRemoteMediaServices:
print(已知请求的IID,但不能实现! $ b raise COMException(hresult = winerror.E_NOINTERFACE)
else:
print(请求的IID不是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)


From my other question here on SO, I asked how to retrieve the current playing song from Windows Media Player and Zune, I got an answer from a c++ dev who gave me an explanation of how I would do this for WMP.

However, I am no C++ dev, nor am I very experienced with the pywin32 library. And on-top of all that, the documentation on all this (especially concerning WMP) is horrible.

Therefor, I need your help understanding how I would do the following in 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.

I know a little bit about the win32api.

At the first step, I really don't know what to do, googling IOleClientSite results in the msdn documentation, it's an interface. However, that's where I get stuck already. I can't find anything (might just be my horrendous googling skills) on working with these things in Python.

The second step:

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

Alright, that's doable.

On to the third step. QueryInterface -

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

source

However, not for me. As I understand his explanation, I think it means that every com object sort of "inherits" three methods from IUnknown, one of which is QueryInterface, however this does not seem the case since calling QueryInterface on my WMP object fails miserably. (Object has no attribute 'QueryInterface')

I could ramble on, but I believe you got the point, I have no idea how to work with this. Can anyone help me out with this one? Preferably with code examples, but resources/documentation is welcome too.

解决方案

Almost final answser but CAN'T finish. I seems that pythoncom can't be used to implement custom Interface without the help of a C++ module. Here is an answser from Mark Hammon (Mon, 13 Jan 2003): 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

I am not able to find anything about that "Univgw" thing...

The comtypes python module is intended to resolve the problem, and I found links saying it does, but I can't make it works with my fresh new Python 3.3. It's Python 2.x code. comtypes seems outdated and unmaintained.

Step 1 OK for IOleClientSite and IServiceProvider, KO for IWMPRemoteMediaServices

Step 2, 3, 4 and 5 OK

Step 6, 7 and 8 can't be implemented without IWMPRemoteMediaServices :-(

disclaimer: complete newbie in Python, please don't yell

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)

这篇关于严重困惑的win32api + COM和答案从SO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆