views:

522

answers:

2

I was trying to "just quickly integrate" the Windows Media Player via COM to play single files from the local file system or http sources - but due to the sparse documentation and online resources to its usage when not embedding into some kind of an Ole container, i couldn't get that supposedly trivial use-case to work.

Initialization etc. works fine, but actually playing some file always fails.

Example code, starting with initialization (error handling stripped, basically translated from the C# example at MSDN, executed on the main thread):

CComPtr<IWMPPlayer> player;
player.CoCreateInstance(__uuidof(WindowsMediaPlayer), 0, CLSCTX_INPROC_SERVER);
CComQIPtr<IWMPCore3> core(player);
CComPtr<IWMPControls> controls;
core->get_controls(&controls);
CComPtr<IWMPPlaylist> playlist;
core->get_currentPlaylist(&playlist);
CComBSTR path("c:\\bar.mp3"); // alternatively http://foo/bar.mp3

The first approach to play something gives "command not available":

core->put_url(path);
// ... waiting after that for WMP to load doesn't make a difference
controls->play(); // returns 0x000D1105 - NS_S_WMPCORE_COMMAND_NOT_AVAILABLE

The second approach only produces S_OKs, but nothing is actually played:

CComPtr<IWMPMedia> media;
core->newMedia(path, &media);
playlist->appendItem(media);
controls->playItem(media); // returns S_OK, but doesn't play

Another thing i noted is that core->get_playState() always returns wmposMediaOpening, no matter how long i wait.

I've stumbled upon one thread that suggests multi-threading might not work properly with WMP and this code runs in a multi-threaded apartment. Might that be the problem?
If not, what else could be preventing WMP from playing the files?

Notable background:
The WMP instance is created in a DLL with a browser as the host-process.

Update:
Trying plain DirectShow, which WMP should be using itself, exhibits a more specific problem - see the question for that.

+1  A: 

WMP supports two automation methods, embedded ActiveX or COM server. For embedded use, you add the ActiveX via an object tag (execute some scripts via IHTMLWindow2 from your BHO/Band) or a hidden form and automate from there. See Using the Windows Media Player Control in a Web Page and Hosting the Windows Media Player Control in a Windows Application for sample codes.

For COM server use, just create the player as COM server and automate from it. You can either make it a UI-less playback engine, or remote it so you have a full UI.

Windows Media Player plays asynchronously, for example, it could call IMediaControl::Run and return immediately when you call put_URL (another immediate call to play would fail because it is already playing). If you do not need the automatic playing, I guess you need IWMPSettings::put_autoStart.

WMP assumes itself to be in the main thread. If you are in a worker thread or a MTA thread, I suggest you span another process to automate it, or remote it as an out-of-proc server.

Sheng Jiang 蒋晟
Finally some feedback, thanks. I am trying to run it as an ui-less in-proc-COM-server. WMP gets created on the main thread and the put_URL() occurs there too. However, even waiting quite a while, querying the open state always results in `wmposMediaOpening` and it never starts to play (regardless wether i call `play()` or not). Any ideas on that?
Georg Fritzsche
I suggest you remote WMP and automate it in the same way to see if you get any message boxes.
Sheng Jiang 蒋晟
Good point, i'll try.
Georg Fritzsche
A: 

After further investigation, it turned out that this was actually caused by a VS2005 workaround for VS2008s AtlSetPerUserRegistration() which was always active - but should have been only for the contained COM servers registration/unregistration.

The workaround overrides HKEY_LOCAL_MACHINE with HKEY_CURRENT_USER, which obviously results in quite some components failing if they are created in-process.

Georg Fritzsche