Using the Windows Media Player Control on Handheld Devices

Multimedia Support in Windows CE

Recently, facing up to the fact that Windows CE 5.0 is coming soon on real devices, it is wonderful to unserstand that PDAs already have their own history. Mobile technologies made unbelievable progress during the last 10 years. The very first Windows CE-powered devices were an adventure in terms of capabilities and programming. The only sign of multimedia features was an opportunity to play WAV files. The latest Windows CE handhelds come with Windows Media Player 10 Mobile, which has many wonderful features and is built on the same platform as its big desktop brother. Now, you may add rich multimedia support to your applications, including playing video and audio files, displaying pictures, and so forth. You will find additional information about available SDKs and other related topics in the "References" section at the end of this article.

This article doens't pretend to be a full guide for WMP SDK, far from this. My goal is to introduce WMP common techniques, so that you'll be able to use them eaily in your own code.

Windows Media Player Object Model Overview

WMSDK offers you a lot of different interfaces, but not all of them are supported on Windows Mobile platforms. Below, I've put together a short description of what you can use:

Interface Description
IWMPCore Root interface of WMP object model. You may retrieve pointers to other interfaces and accesses basic features of the control via this interface.
IWMPControls Allows an application to access to Windows Media Player controls; for example, it has Play, Stop, and Pause buttons.
IWMPError Provides error information.
IWMPEvents Exposes events that originate from the Windows Media Player control to which an embedding program can respond.
IWMPMedia and IWMPMediaCollection Manages the properties of media items.
IWMPNetwork Sets and retrieves the properties of the network connection used by Windows Media Player.
IWMPPlayer Controls the behavior of the Windows Media Player control user interface.
IWMPPlaylist, IWMPPlaylistArray, and IWMPPlaylistCollection Playlists manupulation.
IWMPSettings Sets or retrieves Windows Media Player settings.

As you can see, this is really only a small part of desktop definitions, but it is still useful anyway.

Creating a First Application

You will start with a simple ATL application, where you easily can create a control container window. The code snippet below uses a standard ATL technique to display the Windows Media Player control:

LRESULT CWMPHost::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,
                           BOOL& bHandled)
{
    AtlAxWinInit();
    CComPtr<IAxWinHostWindow>           spHost;
    CComPtr<IConnectionPointContainer>  spConnectionContainer;
    CComWMPEventDispatch                *pEventListener = NULL;
    CComPtr<IWMPEvents>                 spEventListener;
    HRESULT                             hr;
    RECT                                rcClient;

    m_dwAdviseCookie = 0;
    ...
    // create window
    GetClientRect(&rcClient);
    m_wndView.Create(m_hWnd, rcClient, NULL,
        WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    if (NULL == m_wndView.m_hWnd)
        goto FAILURE;

    // load OCX in window
    hr = m_wndView.QueryHost(&spHost);
    if (FAILMSG(hr))
        goto FAILURE;

    hr = spHost->CreateControl(CComBSTR(_T("WMPlayer.OCX")),
                               m_wndView, 0);
    if (FAILMSG(hr))
        goto FAILURE;

    hr = m_wndView.QueryControl(&m_spWMPPlayer);
    if (FAILMSG(hr))
        goto FAILURE;

    // start listening to events

    hr = CComWMPEventDispatch::CreateInstance(&pEventListener);
    spEventListener = pEventListener;
    if (FAILMSG(hr))
        goto FAILURE;

    hr = m_spWMPPlayer->QueryInterface(__uuidof(IConnectionPointContainer),
                                       (void**)&spConnectionContainer);
    if (FAILMSG(hr))
        goto FAILURE;

    // See whether OCX supports the IWMPEvents interface
    hr = spConnectionContainer->FindConnectionPoint(__uuidof(IWMPEvents),
                                                    &m_spConnectionPoint);
    if (FAILMSG(hr))
        goto FAILURE;

    hr = m_spConnectionPoint->Advise(spEventListener, &m_dwAdviseCookie);
    if (FAILMSG(hr))
        goto FAILURE;

    return 0;

FAILURE:
    ::PostQuitMessage(0);
    return 0;
}

All you need to to is to create the control's window, obtain an IWMPPlayer interface pointer, and sign up to WMP events. ATL is usually the easier way to perform such tasks than MFC; nevertheless, you may use MFC as well. As a result, your application will be able to play Windows Media files such as WMA and WMV.

The WMP control has a number of methods that allow you to control its behavior. For example, you can start playing a media file as follows:

LRESULT CWMPHost::OnFileOpen(WORD wNotifyCode, WORD wID,
                             HWND hWndCtl, BOOL& bHandled)
{
    CFileOpenDlg dlgOpen;
    HRESULT      hr;

    if (dlgOpen.DoModal(m_hWnd) == IDOK)
    {
        hr = m_spWMPPlayer->put_URL(dlgOpen.m_bstrName);
        if (FAILMSG(hr))
            return 0;
    }
    return 0;
}

Mobile samples for Windows Media Player 10 provide a full example the of controls' usage.

Using the Windows Media Player Control on Handheld Devices

Using WMP OCX from a Web Application

In case you are using a Web browser, hosting WMP is the easiest thing (this is a SDK sample):

<HTML>
<HEAD>
</HEAD>
<BODY>
   <OBJECT>
      ID=wmpocx
      WIDTH=200
      HEIGHT=150
      CLASSID="clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6"
      TYPE="application/x-oleobject"
      VIEWASTEXT>
      <PARAM name="uimode" value="none">
   </OBJECT>
<BR>

<script for="wmpocx" event="PlayStateChange(NewState)"
                     language="JScript">ClipPlayState(NewState);
</script>
<script for="wmpocx" event="Error()"
                     language="JScript">StopPlayer();
</script>

<p>
<a href=# OnClick='PlayClip("\\storage card\\webapp\\glass.wmv",
                            ImgVideoPlay, true)'>
   <IMG id="ImgVideoPlay" src="bt_play.gif" border="0"></a> Video
<br>
<a href=# OnClick='PlayClip("\\storage card\\webapp\\jeanne.wma",
                            ImgAudioPlay, false)'>
   <IMG id="ImgAudioPlay" src="bt_play.gif" border="0"></a> Audio
<br>
Play state sequence
<br>
<input type="text" id="PlayStateSequence" width=30>

<SCRIPT language="JScript">
<!--
var CurrentPlayImage = null;
var bVideo = null;
var bWasBuffering = false;

function StopPlayer()
{
   wmpocx.controls.stop();
   wmpocx.close();
   if (CurrentPlayImage != null)
   {
      CurrentPlayImage.src = "bt_play.gif";
   }
   bWasBufferring = false;
}

function ClipPlayState(NewState)
{
   PlayStateSequence.value = PlayStateSequence.value + NewState
                           + " ";

   switch(NewState)
   {
   case 1:    // stopped

   if (bWasBuffering)
   {
      bWasBufferring = false;
      if (CurrentPlayImage != null)
      {
         CurrentPlayImage.src = "bt_play.gif";
      }
   }
      break;

   case 6:    // buffering

      bWasBufferring = true;
      if (CurrentPlayImage != null)
      {
         CurrentPlayImage.src = "bt_load.gif";
      }
      break;

   case 9:     // transitioning
   case 11:    // reconnecting

      bWasBufferring = false;
      break;

   case 3:    // playing

      if (bWasBufferring)
      {
         if (CurrentPlayImage != null)
         {
            CurrentPlayImage.src = "bt_stop.gif";
         }

      if (bVideo)
         {
            wmpocx.fullScreen = true;
         }
      }
      break;

   default:
   }
}

function PlayClip(url, img, video)
{
   if (wmpocx.playState == 3 && bVideo != null && bVideo != video)
   {
      return;
   }

   bVideo = video;
   CurrentPlayImage = img;

   if (wmpocx.playState == 3)
   {
      StopPlayer();
   }
   else
   {
      PlayStateSequence.value = "";

      if (CurrentPlayImage != null)
      {
            CurrentPlayImage.src = "bt_load.gif";
      }
      wmpocx.URL = url;
   }
}
-->
</SCRIPT>
</BODY>
</HTML>
Obviously, you can decorate this HTML as you want to.

Working with Older Versions of the WMP Control

If you have a handheld device without WMP 10, this is yet not the end of the world. You still have an opportunity to use WMP OCX of version 8 for Pocket PC, which has much fewer amazing features, but can serve your needs as well. For exercise purposes, I've created a simple project to illustrate how it works in an MFC environment. The small code snippet below proves that it is pretty similar to the ATL way:

BOOL CWMP8SampleDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   // Set the icon for this dialog. The framework does this
   // automatically when the application's main window is not
   // a dialog
   SetIcon(m_hIcon, TRUE);     // Set big icon
   SetIcon(m_hIcon, FALSE);    // Set small icon

   CenterWindow(GetDesktopWindow());    // center to the hpc screen

   CRect rect;
   m_Panel.GetClientRect(&rect);

   if ( m_PlayerWnd.CreateControl(__uuidof(WMP),L"",
                                  WS_VISIBLE|WS_CHILD,rect,
                                  &m_Panel,AFX_IDW_PANE_FIRST) )
   {
      LPUNKNOWN lpUnk = m_PlayerWnd.GetControlUnknown();
      HRESULT hr = lpUnk->QueryInterface(__uuidof(IWMP),(void**)
                                         &m_spWMPPlayer);
   }
   else
   {
      AfxMessageBox(L"Failed to create WMP control");
      ::PostQuitMessage(0);
      return 0;
   }

   if ( m_spWMPPlayer )
   {
      m_WMPEvents.m_pMainDlg = (CWMP8SampleDlg*)this;
      CComPtr<IConnectionPointContainer> spConnectionContainer;
      HRESULT hr = m_spWMPPlayer->
                   QueryInterface( IID_IConnectionPointContainer,
                                  (void**)&spConnectionContainer );
      if (SUCCEEDED(hr))
      {
         hr = spConnectionContainer->
              FindConnectionPoint( __uuidof(_IWMPEvents),
                                  &m_spConnectionPoint );
      }
      if (SUCCEEDED(hr))
      {
         hr = m_spConnectionPoint->Advise((IDispatch*)&m_WMPEvents,
                                          &m_dwAdviseCookie );
      }
      else
      {
         AfxMessageBox(L"Failed to get WMP control events");
         ::PostQuitMessage(0);
         return 0;
      }

      if ( FAILED(SetupWMP()) )
      {
         AfxMessageBox(L"Failed to setup WMP control");
         ::PostQuitMessage(0);
         return 0;
      }
   }

   m_spWMPPlayer->Stop();

   return TRUE;    // return TRUE  unless you set the focus to a
                   // control
}

Conclusion

With WMP control handy, your application gets additional strength in an interaction with the end user. Such multimedia support may create new added value for any product. Windows CE 5.0 brings you long-awaited support for DirectShow API to render video, but this is a good topic for future articles.

Download

Download the accompanying code's zip file here

References

Microsoft Windows Media Player 10 SDK

Microsoft Windows Media Player 8.x for Pocket PC

Mobile WMP 10 samples

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.



Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • In support of their business continuity and disaster recovery plans, many midsized companies endeavor to avoid putting all their eggs in one basket. Understanding the critical role of last-mile connectivity and always available Internet access for their enterprises, savvy firms utilize redundant connections from multiple service providers. Despite the good intentions, their Internet connectivity risk may still be in a single basket. That is because internet service providers (ISPs) and competitive local …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds