技术开发 频道

Windows Mobile多媒体开发总结之Media Player Plugins(续)

 【IT168技术文档】

 在文章“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实际上完成了下列三步:

 

  CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, (void **)&pCF); //此方法调用我们要实现的DllGetClassObject方法,获得工厂对象的指针

 pCF->CreateInstance(pUnkOuter, riid, ppvObject);//CMediaPlayerPluginClassFactory::CreateInstance方法此时被调用

 pCF->Release();

 看一下我们要实现的这3个方法代码是怎样的

 

  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接口,我们看下它最关键的一个方法是怎样实现的:

 

  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类的实现,具体见附件的项目。

0
相关文章