Windows Mobile多媒体开发总结之Media Player Plugins(续)
2009-05-01 21:58 王克伟 阅读(3190) 评论(13) 编辑 收藏 举报在文章“Windows Mobile多媒体开发总结之Media Player Plugins ”中总结了在WM(Windows Mobile)中扩展WMP(Windows Media Player)的几种方法。发布之后有很多朋友询问具体做法,所以我乘机也总结下相关知识,刚好也补一下我这方面的差缺。
需求
在WM开发中如果不是单独开发自己的播放器或者使用第三方播放器,你就只能使用WMP,但是你可能需要在别的应用程序或者驱动中控制WMP,或者需要获得WMP的播放状态,那么怎样做呢?你可能会想到向WMP对应的按键发送消息,或者模拟键盘消息。实际上这些都不是好的解决方案。解决方法就是使用User Interface Background Plug-ins,这在上一篇文章中提到过了。
涉及到的知识
User Interface Background Plug-ins需要实现的接口和操作WMP的方法,COM进程内服务器的编写(在Windows下扩展微软本身软件,比如扩展IE,基本都以COM的形式),Today Plug-ins的编写等。(当然你使用ATL会更方便,就不需要自己这样一步步的实现COM了。这里只是为了深入的了解下COM内部原理。)
动手做
第一步
在Windows Mobile中开发WMP相关头文件在AKU中的位置如下图(比如AKU 6.15):
在你的项目中需要使用wmp.h和wmpplug.h头文件。
第二步
实现作为COM进程内服务器需要的方法,这也是需要在DLL中导出的方法:
DllGetClassObject
DllCanUnloadNow
DllRegisterServer
先简单了解下COM服务器在创建过程中的位置,为了偷懒,图就直接引用VC知识库的,组件DLL即是所要编写的COM服务器端,客户端就是WMP:
关于更多COM的原理知识和使用可以参考《COM本质论》、《深入解析ATL》(我对ATL/WTL还是知之甚少,这本书已经放我枕头边很久了,一直在学习Windows操作系统而耽误了学习ATL)或VC知识库等。
对上面的图再解释一下,当客户端调用CoCreateInstance方法(这是WMP去做的,我们不管)时,CoCreateInstance实际上完成了下列三步:
1 2 3 | CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, ( void **)&pCF); //此方法调用我们要实现的DllGetClassObject方法,获得工厂对象的指针 pCF->CreateInstance(pUnkOuter, riid, ppvObject); //CMediaPlayerPluginClassFactory::CreateInstance方法此时被调用 pCF->Release(); |
看一下我们要实现的这3个方法代码是怎样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, VOID ** ppv) { HRESULT hr; CMediaPlayerPluginClassFactory * pcf; *ppv = NULL; if ((pcf = new CMediaPlayerPluginClassFactory()) == NULL) return E_OUTOFMEMORY; if (FAILED(hr = pcf->QueryInterface(riid, ppv))) //把插件工厂对象的指针传递给WMP { delete pcf; return hr; } return S_OK; } STDAPI DllCanUnloadNow() { if (g_pServer->CanUnload()) return S_OK; else return S_FALSE; } STDAPI DllRegisterServer() //当你安装插件时系统调用这个方法,在这里你把你的COM服务器注册到注册表的CLSID键上。 { TCHAR szModulePath[MAX_PATH]; // Get our module path. if (!GetModuleFileName(GetModuleHandle(s_szModuleName), szModulePath, MAX_PATH)) return E_FAIL; szModulePath[MAX_PATH - 1] = _T( '\0' ); // register this COM object. // // IMPORTANT: // be sure to update this GUID with another if you create another plug-in. Each plug-in must have a unique GUID. return DllRegisterServerImplementation(_T( "{009B9B8A-5080-4d09-8F74-9BD96A3558D4}" ), s_szRegDescription, szModulePath, _T( "Free" )); } |
来看看CMediaPlayerPluginClassFactory相关的实现,这个类实现IClassFactory接口,我们看下它最关键的一个方法是怎样实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | HRESULT CMediaPlayerPluginClassFactory::CreateInstance(IUnknown * pUnkOuter, REFIID riid, VOID ** ppvObject) { HRESULT hr; CMediaPlayerPlugin * pPlugin; *ppvObject = NULL; if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION; // 创建插件对象 if ((pPlugin = new CMediaPlayerPlugin()) == NULL) return E_OUTOFMEMORY; pPlugin->InternalAddRef(); hr = pPlugin->FinalConstruct(); //在此注册和创建插件窗口,实际上这个窗口是不可见的,仅仅是实现一个消息循环,用于其它应用程序向它发送消息。 pPlugin->InternalRelease(); if (FAILED(hr)) { delete pPlugin; return hr; } if (FAILED(hr = pPlugin->QueryInterface(riid, ppvObject))) //传递插件对象的指针 { delete pPlugin; return hr; } return S_OK; } |
另外还有像CServer类的实现,具体见附件的项目。
第三步
实现IWMPPluginUI等接口
1 2 | class CMediaPlayerPlugin: public IWMPPluginUI |
在上一篇文章中我列出了这个接口下的方法:
1 2 3 4 5 6 7 | STDMETHODIMP Create( HWND hwndParent, HWND * phwndWindow); STDMETHODIMP Destroy(); STDMETHODIMP DisplayPropertyPage( HWND hwndParent); STDMETHODIMP GetProperty( LPCWSTR wszName, VARIANT * pvarProperty); STDMETHODIMP SetCore(IWMPCore * pCore); STDMETHODIMP SetProperty( LPCWSTR wszName, const VARIANT * pvarProperty); STDMETHODIMP TranslateAccelerator(MSG * pMsg); |
对于这些方法,实现你需要的,不感兴趣的仅仅让它为空即可,比如:
1 2 3 4 5 6 7 8 | HRESULT CMediaPlayerPlugin::Create( HWND hwndParent, HWND * phwndWindow) { // As per the IWMPPluginUI documentation, this method will never be called // because we're a background plugin (our registry Capabilities flags include // PLUGIN_TYPE_BACKGROUND = 0x00000001). return E_NOTIMPL; } |
SetCore是个关键方法,因为我们需要通过它获得操作WMP的接口指针,这里我们把获得的指针存放在m_pCore中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | HRESULT CMediaPlayerPlugin::SetCore(IWMPCore * pCore) { // This method is called shortly after this instance is created, and allows // us to hook up to Windows Media Player. Save the interface pointer. // // When WMP is shutting down, it calls SetCore(NULL) so we have to handle that // as well. if (m_pCore != NULL) { m_pCore->Release(); } m_pCore = pCore; if (m_pCore != NULL) { m_pCore->AddRef(); } return S_OK; } |
然后我们可以像这样进一步通过m_pCore获得其它接口指针,类似这里的get_contronls方法的还有get_settings等,更详细的可以查看附件的项目。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | VOID CMediaPlayerPlugin::ControlPlayer( UINT uMsg) { IWMPControls * pControls; // Get the 'IWMPControls' interface. if (SUCCEEDED(m_pCore->get_controls(&pControls))) { switch (uMsg) { // for the toggle message case WM_WMPTOGGLE: WMPPlayState wmpps; // get the current state if (SUCCEEDED(m_pCore->get_playState(&wmpps))) { // if it playing a track, pause it if (wmpps == wmppsPlaying) { pControls->pause(); } // otherwise try to play the track else { pControls->play(); } } break ; case WM_WMPPREVIOUS: pControls->previous(); break ; case WM_WMPNEXT: pControls->next(); break ; default : break ; } pControls->Release(); } } |
文章上个星期就写的差不多了,一直拖到现在才发布,实在抱歉。下一篇文章我总结下Today Plugin的开发。随便介绍下通过Today Plugin控制WMP。希望对你有所帮助。
项目的环境是:
Win32/Windows Mobile 6 Professional(CHS)/Visual Studio 2008(CHS)
/Files/wangkewei/WMPlayerPlugin.rar
出处: http://wangkewei.cnblogs.com/
版权声明: 本文的版权归作者与博客园共有。转载时须注明本文的详细链接,否则作者将保留追究其法律责任的权利。
您可以从这里更方便的找到我的文章。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架