I'm the guy who was here a short while ago asking how to control Windows Media Player through Java. I made progress, but I was struck by the annoyance of the problem, so I'm looking for help again.
I followed the advice I received the last time and installed Jacob. I am executing these lines from a test script:
ActiveXComponent wmp = new ActiveXComponent("WMPlayer.OCX"); wmp.invoke("openPlayer", "http://somafm.com/wma128/groovesalad.asx");
... and WMP pops up playing SomaFM. "W00t!" I think. "I decided to solve it!"
Except that when I interact with this object after its creation, it does not seem to have anything to do with playing a WMP instance. When I execute this code:
ActiveXComponent wmpSettings = new ActiveXComponent(wmp.getProperty("settings").toDispatch()); System.out.println("VOLUME: " + wmpSettings.getProperty("volume")); wmpSettings.setProperty("volume", 0); System.out.println("VOLUME: " + wmpSettings.getProperty("volume"));
... I get the output:
VOLUME: 50
VOLUME: 0
It seems harmless enough, except that
- volume "50" has nothing to do where the volume of the player is actually set and
- Player volume does not actually change after setProperty call.
I also tried other properties, but this is the same thing: the value of the properties does not seem to be related to what the player actually does, and when they change, the state of the object seems to change, it does not affect the actual player . (I get the same output every time I run the script, so no matter what I change when I twist the "volume", it has no persistence outside the code.)
Obviously, I am doing something wrong, but I am stumbling blindly, trying to understand that. Can someone offer me any idea of what is going on, or what should I do next?
(Note: I'm not even sure that “WMPlayer.OCX” is the correct input parameter. I experimented with probabilistic entries in HKEY_CLASSES_ROOT in the registry until I found this one.)
Thanks for any help anyone can offer.
Edit, 4/15/2009: I found the WMP package in offers from EZ JCom. This failed just like what I saw before, either it's just a shell for Jacob, or the WMP ActiveX / COM interface is just broken. (Wait, why did I say "or"?)
I talked to customer service and they ended up demonstrating how you can be helpful without even being helpful. They helped me fix the non-compiling code sample that they provided as an example of their WMP code in action, but when I pestered them to understand how the get / set volume methods should work, I got the following:
"Sorry, there is no extensive WMP expert knowledge here. EZ JCom is just a bridge builder between Java and other programs such as WMP."
Remember that their package, which I evaluated, is actually called "wmp.WindowsMediaPlayer". If I got him to work, I would have to talk to my boss about shelling $ 600 per license. Everyone wonders what they charge if they really have experience in their own product.
So, no real progress. Just thought I'd share.
Edit, 4/20/2009: Yes, I still hold onto this. My current theory of work is that in order to get volume settings, I need to access WMP remotely. I saw mention of the IWMPRemoteMediaServices and IServiceProvider interfaces, with the QueryService method of the latter providing a pointer to the former. Unfortunately, I will not be able to figure out how to get hold of IServiceProvider. I noticed that it is accessible from the "System" object window, but I cannot figure out how to get this object. (And since the word "System" appears very strongly in Java, Google gives me a hellish noise level: a signal.) If anyone has any advice on how I lay my hands on the COM object representing System.dll, I would love to listen to him.
Edit, 4/21/2009: Specification: this is on an XP system.
Also: my research shows that just talking to a WMP object is not enough; you need to wrap him more tightly than this so that he can talk. There's a WMP SDK with lots of C ++ stuff, but it looks like it relies on Microsoft Visual C ++ extensions for code that I don't have, and they don’t give away for free. (In addition, I have not done C ++ for twelve years.) I know that this is possible with C #, but if I go beyond Java, I need the solution to be a standalone executable, and .NET not installed on appropriate cars.
Edit, 4/22/2009: In the answer below, I dug the APPCOMMAND_MEDIA_ * constants from WinUser.h and tried the following code that uses the NativeCall api:
final int APPCOMMAND_MEDIA_PLAY = 46; final int APPCOMMAND_MEDIA_PAUSE = 47; NativeCall.init(); IntCall findWindow = new IntCall("user32", "FindWindowA"); int wmpHandle = findWindow.executeCall(new Object[] { null, "Windows Media Player" }); System.out.println("wmpHandle: " + wmpHandle); System.out.println("Find Window Error? " + findWindow.getLastError()); IntCall sendMessage = new IntCall("user32", "SendMessageA"); int playResult = sendMessage.executeCall(new Object[] { wmpHandle, APPCOMMAND_MEDIA_PLAY, 0, 0 }); System.out.println("Play Result: " + playResult); System.out.println("Play Error? " + sendMessage.getLastError()); try { Thread.sleep(5000); } catch (Exception e) {} int pauseResult = sendMessage.executeCall(new Object[] { wmpHandle, APPCOMMAND_MEDIA_PAUSE, 0, 0 }); System.out.println("Pause Result: " + pauseResult); System.out.println("PauseError? " + sendMessage.getLastError());
This gives me the result:
wmpHandle: 1640048
Find Window Error? null
Play Result: -1
Play error? null
Pause Result: -1
PauseError? null
... but doesn’t really affect the media player.
I also tried it with APPCOMMAND_MEDIA_PLAY_PAUSE (14), which gives different return values (20), but does nothing.
FWIW, I really need to get individual PLAY / PAUSE commands to work, so that is a viable option; just switching the state blindly doesn’t help, since I don’t know what state the player is in when I start.
Does anyone have any tips on what I'm doing wrong or what else can I try?