An Application of mine retrieves the current playing song from a multitude of music players. However, I'm having great trouble implementing Zune and Windows Media Player.
我的一个应用程序从众多的音乐播放器中检索当前播放的歌曲。然而,我在实现Zune和Windows媒体播放器时遇到了很大的麻烦。
I've done a lot of googling on the subject, unfortunately it's only confusing me more and more.
我在谷歌上搜索了很多关于这个话题的信息,不幸的是,这让我越来越困惑。
What I would normally do for my other applications:
我通常会为我的其他应用程序做些什么:
- Iterate over all open windows every 4 seconds
- 每4秒遍历所有打开的窗口
- Get the title of all windows
- 获取所有窗口的标题
- Check title for a pattern (Ie,
" - Spotify "
) - 查看模式的标题(例如,“- Spotify”)
- If it's there, adjust the title for output.
- 如果它在那里,调整输出的标题。
WMP Does not have the current playing song in the title.
WMP在标题中没有当前播放的歌曲。
Zune does, but it's rotating every few seconds between title, album and artist. Which is heavily unreliable to track with my current method, albeit possible.
Zune有,但是它每隔几秒钟就会在标题、专辑和艺术家之间旋转。用我目前的方法跟踪它是非常不可靠的,尽管可能。
Windows Media Player
Windows媒体播放器
I've also tried using the COM component for windows media player.
我还尝试过在windows媒体播放器中使用COM组件。
import win32com.client
wmp = win32com.client.gencache.EnsureDispatch('WMPlayer.OCX')
# some function I don't have here, it retrieves the current playing song
# and other data
The big problem with that it requires you to start WMP programmatically, which would be extremely user unfriendly
这样做的最大问题是需要您以编程方式启动WMP,这将是非常不友好的用户
So, what have I found? This SO post redirects to WMP.dll. But as far as I've read, it has the same problem as the COM, you have to start it programmatically. If not, I would really like some directions on how to work with that dll in python.
那么,我找到了什么?这个SO post重定向到WMP.dll。但据我所知,它与COM有相同的问题,你必须以编程的方式启动它。如果没有,我真的想要一些关于如何使用python中的dll的说明。
There would be another a little less hacky solution, which is to write a plugin for WMP, let my users download that plugin and retrieve the data from that plugin. I'd rather not go there, since I have no experience with any of the C languages, nor do I feel like digging into plugin documentations for this.
还有一种不那么陈腐的解决方案,那就是为WMP编写一个插件,让我的用户下载那个插件并从那个插件中检索数据。我宁愿不去那里,因为我没有使用任何C语言的经验,我也不想为此深入研究插件文档。
Zune
Zune
A method would be to cycle through the three title states, determine which state it's currently at and find the position of the other two.
方法是循环遍历三个标题状态,确定当前的状态,并找到其他两个的位置。
IE: First 5 seconds the title is: Super_song Next 5 seconds the title is: By Power_artist Next 5 seconds the title is: Good_album (date)
IE:前5秒标题是:Super_song接下来5秒标题是:由Power_artist接下来5秒标题是:Good_album(日期)
So I could determine when the album title is by making a regex for the date (which is always there) and then find the title and artist by waiting a few seconds.
因此,我可以通过为日期(总是在那里)创建一个regex来确定专辑标题的时间,然后通过等待几秒钟找到标题和艺术家。
This is obviously not a great solution, since it'll take a while and it's not very reliable either, (what if the song name contains a date for example)
这显然不是一个很好的解决方案,因为这需要一段时间,而且也不是很可靠(例如,如果歌曲名称包含日期)
The next problem is that it's not consistent either, sometimes the title just stays Zune for minutes long. No idea why.
下一个问题是,它也不一致,有时标题只会持续几分钟。不知道为什么。
So, move on to the next method.
那么,继续下一个方法。
There's this application called ZuneNowPlaying. This "somehow" gets the current playing song from Zune and puts it in the registry, this thing does not work with my sloppy title method, since it changes the registry the instant the song changes. Immediately.
有一个应用程序叫做ZuneNowPlaying。这个“以某种方式”获取Zune当前播放的歌曲并将其放入注册表中,这个东西不能使用我草率的标题方法,因为它会在歌曲更改时更改注册表。立即。
This is the solution I had used in the working version of my program, but many users reported that it simply didn't work, nothing happened. And I checked the program and it doesn't reliably change the registry all the time. I don't know why, I don't know how to fix it. Therefor, this solution is also -scrapped-.
这是我在程序的工作版本中使用的解决方案,但是许多用户报告说它根本不起作用,什么也没有发生。我检查了程序,它并不总是可靠地改变注册表。我不知道为什么,我不知道怎么修复它。因此,这个解决方案也被废弃了。
Is the fact that it is using the name "MsnMsgrUIManager"#000000"> causing the zune software to send it information about which song is playing? Is there a way to get this information without this kind of hack?
事实是,它使用的是“MsnMsgrUIManager”#000000“>”,导致zune软件发送它所播放的歌曲的信息吗?有没有一种不用这种方法就能得到这些信息的方法?
That is found in the discussion of the Zune Now Playing application. The source is not available unfortunately, at least I can't find it. Anyone got more on this?
这是在Zune现在的应用程序的讨论中发现的。不幸的是,源文件不可用,至少我找不到它。有人知道更多吗?
Third method I had heard of was once again, a dll. ZuneShell.dll it's called. I don't remember where I read about it, nor can I find it via google, since all results are "Is ZuneShell.dll a virus?".
我听说过的第三个方法是dll。ZuneShell。dll叫做。我不记得我在哪里读到过它,也没有通过谷歌找到它,因为所有的结果都是“ZuneShell”。dll病毒?”
Once again, I run into the problem that I wouldn't know how to work with this even IF I had documentation on it, heck, if it's even what I have been looking for.
再一次,我遇到了一个问题我不知道如何处理这个问题即使我有关于它的文档,如果它是我一直在寻找的。
Alternate directions to maybe look into
可能要研究的另一个方向
While browsing about this subject, I've seen people talking about retrieving data directly from GUI's. I'm not sure how legit, possible or even how correct my memory of it is, but if it's possible could someone redirect me to more on this?
在浏览这个主题时,我看到人们直接从GUI中检索数据。我不知道我的记忆有多正确,有多合理,甚至有多正确,但如果有可能,有人能让我在这方面做得更多吗?
Anything else, really.
什么,真的。
2 个解决方案
#1
3
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).
我有c++的工作代码来打印当前在WMP中播放的媒体名称。这是一个简单的控制台应用程序(78行代码)。
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
1)实现一个基本的COM对象,实现IUnknown、IOleClientSite、IServiceProvider和IWMPRemoteMediaServices。使用ATL模板CComObjectRootEx,这很简单(您的里数可能不同)。唯一需要(简单)代码的方法是IServiceProvider::QueryService和IWMPRemoteMediaServices:::GetServiceType。所有其他方法都可能返回E_NOTIMPL
2) Instantiate the "WMPlayer.OCX" COM object (in my case, via CoCreateInstance)
2)WMPlayer实例化”。OCX" COM对象(在我的例子中,通过CoCreateInstance)
3) Retrieve from the object an IOleObject interface pointer via QueryInterface
3)通过QueryInterface从对象中检索IOleObject接口指针
4) Instanciate an object from the class seen in 1) (I use the CComObject<>::CreateInstance template)
4)从类中实例化一个对象(我使用CComObject<>::CreateInstance模板)
5) Use the SetClientSite method from the interface you got at 3), passing a pointer to your OleClientSite implementation.
5)使用来自3)接口的SetClientSite方法,传递一个指向OleClientSite实现的指针。
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
6)在SetClientSite调用期间,WMP将回调您:fisrt请求IServiceProvider接口指针,然后调用QueryService方法,请求IWMPRemoteMediaServices接口指针。返回您的IWMPRemoteMediaServices实现,第三,您将通过GetServiceType再次调用。然后必须返回“Remote”。您现在连接到WMP运行实例
7) Query the COM object for an IWMPMedia interface pointer
7)为IWMPMedia接口指针查询COM对象
8) If 7) didn't gave NULL, read the the IWMPMedia::name property.
8)如果没有给出空值,请阅读IWMPMedia::name属性。
9) DONE
9)做
All the above was tested with VS2010 / Windows Seven, and with WMP running (if there is no Media Player process running, just do nothing).
所有这些都在VS2010 / Windows 7和WMP中进行了测试(如果没有媒体播放器进程运行,什么都不做)。
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.
我不知道yoy是否可以在Python中实现COM接口和对象。如果您对我的c++代码感兴趣,请告诉我。您可以在c++ DLL中使用该代码,然后从python中调用它。
#2
1
I just found a cool Python tool which can query all the controls of any program. Simple, straightforward, and easy to read. It's here:
我刚刚找到了一个很酷的Python工具,它可以查询任何程序的所有控件。简单、直接、易读。在这里:
http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html
http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html
With that you can get the info from the GUI.
这样,您就可以从GUI中获取信息。
You can also grab the loaded file list. It works for most media player. You can get this information programmatically like this:
您还可以获取已加载的文件列表。它适用于大多数媒体播放器。您可以通过编程方式获取这些信息:
http://www.codeproject.com/Articles/18975/Listing-Used-Files
http://www.codeproject.com/Articles/18975/Listing-Used-Files
This is C++, but at that point you can wrap the native code. This way you have to extract the ID3 tags yourself. Might worth the shot as it would be an universal solution.
这是c++,但此时可以封装本机代码。这样,您必须自己提取ID3标记。也许值得一试,因为这将是一个普遍的解决方案。
#1
3
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).
我有c++的工作代码来打印当前在WMP中播放的媒体名称。这是一个简单的控制台应用程序(78行代码)。
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
1)实现一个基本的COM对象,实现IUnknown、IOleClientSite、IServiceProvider和IWMPRemoteMediaServices。使用ATL模板CComObjectRootEx,这很简单(您的里数可能不同)。唯一需要(简单)代码的方法是IServiceProvider::QueryService和IWMPRemoteMediaServices:::GetServiceType。所有其他方法都可能返回E_NOTIMPL
2) Instantiate the "WMPlayer.OCX" COM object (in my case, via CoCreateInstance)
2)WMPlayer实例化”。OCX" COM对象(在我的例子中,通过CoCreateInstance)
3) Retrieve from the object an IOleObject interface pointer via QueryInterface
3)通过QueryInterface从对象中检索IOleObject接口指针
4) Instanciate an object from the class seen in 1) (I use the CComObject<>::CreateInstance template)
4)从类中实例化一个对象(我使用CComObject<>::CreateInstance模板)
5) Use the SetClientSite method from the interface you got at 3), passing a pointer to your OleClientSite implementation.
5)使用来自3)接口的SetClientSite方法,传递一个指向OleClientSite实现的指针。
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
6)在SetClientSite调用期间,WMP将回调您:fisrt请求IServiceProvider接口指针,然后调用QueryService方法,请求IWMPRemoteMediaServices接口指针。返回您的IWMPRemoteMediaServices实现,第三,您将通过GetServiceType再次调用。然后必须返回“Remote”。您现在连接到WMP运行实例
7) Query the COM object for an IWMPMedia interface pointer
7)为IWMPMedia接口指针查询COM对象
8) If 7) didn't gave NULL, read the the IWMPMedia::name property.
8)如果没有给出空值,请阅读IWMPMedia::name属性。
9) DONE
9)做
All the above was tested with VS2010 / Windows Seven, and with WMP running (if there is no Media Player process running, just do nothing).
所有这些都在VS2010 / Windows 7和WMP中进行了测试(如果没有媒体播放器进程运行,什么都不做)。
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.
我不知道yoy是否可以在Python中实现COM接口和对象。如果您对我的c++代码感兴趣,请告诉我。您可以在c++ DLL中使用该代码,然后从python中调用它。
#2
1
I just found a cool Python tool which can query all the controls of any program. Simple, straightforward, and easy to read. It's here:
我刚刚找到了一个很酷的Python工具,它可以查询任何程序的所有控件。简单、直接、易读。在这里:
http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html
http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html
With that you can get the info from the GUI.
这样,您就可以从GUI中获取信息。
You can also grab the loaded file list. It works for most media player. You can get this information programmatically like this:
您还可以获取已加载的文件列表。它适用于大多数媒体播放器。您可以通过编程方式获取这些信息:
http://www.codeproject.com/Articles/18975/Listing-Used-Files
http://www.codeproject.com/Articles/18975/Listing-Used-Files
This is C++, but at that point you can wrap the native code. This way you have to extract the ID3 tags yourself. Might worth the shot as it would be an universal solution.
这是c++,但此时可以封装本机代码。这样,您必须自己提取ID3标记。也许值得一试,因为这将是一个普遍的解决方案。