Windows Media Player忽略我

Bla*_*ppo 7 activex windows-media-player

我曾经在这里问过有关通过Java控制Windows Media Player的问题. 我已经取得了进步,但我遇到了一个棘手的问题,所以我回来寻求帮助.

我按照上次给出的建议,安装雅各布.我从测试脚本中执行这些行:

ActiveXComponent wmp = new ActiveXComponent("WMPlayer.OCX");
wmp.invoke("openPlayer", "http://somafm.com/wma128/groovesalad.asx");
Run Code Online (Sandbox Code Playgroud)

...和WMP弹出,玩SomaFM."W00t!" 我认为."我已经解决了这个问题!"

除了当我在创建它之后与该对象交互时,它似乎与WMP实例播放没有任何关系.当我执行此代码时:

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"));
Run Code Online (Sandbox Code Playgroud)

...我得到的输出:

VOLUME: 50
VOLUME: 0

这似乎无害,除此之外

  1. "50"的音量与实际设定的播放器音量无关
  2. setProperty调用后,播放器的音量实际上没有变化.

我也尝试了其他属性,但它是一样的:属性的值似乎与玩家实际做的事情没有关系,而改变它们似乎改变了被操纵对象的状态,它对实际玩家没有影响. (每次运行脚本时,我都得到完全相同的输出,所以无论是什么,当我转动"音量"时我都会改变它,它在代码之外没有任何持久性.)

显然我做错了什么,但我一直摸索着试图找出什么.任何人都可以向我提供任何有关出错的信息,或者我接下来应该尝试的内容吗?

(注意:我甚至不确定"WMPlayer.OCX"是正确的输入参数.我在注册表中的HKEY_CLASSES_ROOT中试验了看起来很可能的条目,直到找到这个.)

我提前感谢任何人提供的任何帮助.


编辑,4/15/2009: 我在一家名为EZ JCom的公司的产品中找到了一个特定于WMP的软件包.它失败的方式与我之前看到的完全相同,要么它只是Jacob的包装器,要么是WMP ActiveX/COM接口完全坏了.(等等,为什么我说"要么"?)

我与客户服务人员聊天,他们最终展示了如何在没有实际用处的情况下提供帮助.他们帮助我纠正了他们提供的非编译示例代码作为他们的WMP代码的实例,但是当我纠缠他们以了解get/set卷方法应该如何工作时,我得到了这个:

"对不起,但这里没有WMP深度专业知识--EZ JCom只是Java与WMP等其他程序之间的桥梁建设者."

请记住,我评估的他们的包实际上被称为"wmp.WindowsMediaPlayer".如果我得到它的工作,我将不得不与我的老板谈论花费600美元的许可证.人们想知道如果他们真正拥有自己产品的专业知识,他们会收取什么费用.

所以,没有真正的进步.只是想我会分享.


编辑,2009年4月20日: 是的,我仍然在嘲笑这个.我目前的操作理论是,为了获得音量设置,我需要远程访问WMP.我已经看到了IWMPRemoteMediaServices和IServiceProvider接口的提及,后者的QueryService方法提供了指向前者的指针.不幸的是,我没有任何关于如何获得IServiceProvider的运气.我已经看到提到它可以从Windows"系统"对象访问,但我无法弄清楚如何获取该对象.(而且由于"系统"这个词在Java中非常重要,谷歌给了我一个喧闹的声音:信号比率.)如果有人对如何把手放在代表System.dll的COM对象上有任何建议,我很乐意听到.


编辑,4/21/2009: 澄清:这是在XP系统上.

另外:我的研究表明仅仅谈论WMP对象是不够的; 你需要把它包裹得更紧,所以它可以回复.有一个包含大量C++内容的WMP SDK,但它似乎依赖于Microsoft Visual C++对我没有的代码的扩展,并且它们不是免费赠送的.(此外,我在12年内没有完成C++.)我知道C#可以实现,但如果我不在Java之外,我需要将解决方案作为独立的可执行文件并且不安装.NET相关的机器.


编辑,2009年4月22日: 根据Mark的答案,我从WinUser.h中挖出了APPCOMMAND_MEDIA_*常量并尝试了以下代码,它使用了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());
Run Code Online (Sandbox Code Playgroud)

这给了我一个结果:

wmpHandle: 1640048
Find Window Error? null
Play Result: -1
Play Error? null
Pause Result: -1
PauseError? null

...但实际上并不影响媒体播放器.

我也尝试过APPCOMMAND_MEDIA_PLAY_PAUSE(14),它给出了不同的返回值(20),但也没有做任何事情.

FWIW,我真的需要让单独的PLAY/PAUSE命令工作才能成为一个可行的选择; 盲目地简单地切换状态对我没有帮助,因为当我开始时我不知道玩家处于什么状态.

有没有人对我做错了什么或者我可能会尝试什么有任何建议?

Mar*_*ark 2

那么这些都不起作用吗?

wmp.getProperty("settings").toDispatch().setProperty("mute", 1);
wmp.getProperty("controls").toDispatch().invoke("pause");
Run Code Online (Sandbox Code Playgroud)

(对错误代码表示歉意;我以前从未使用过 Jacob)


在这种情况下,创建/查找任何窗口并发送APPCOMMAND_MEDIA_PLAY_PAUSE。默认的消息处理会使其影响WMP。(发送静音是不好的,因为这会使整个系统静音。)

为了可移植性,我建议创建一个 C++ 命令行实用程序或使用 JNI,但NativeCall目前可能就足够了。


您的代码看起来不错,但我认为您只需要更改 SendMessage 的参数即可。尝试:

final int WM_APPCOMMAND = 0x0319;
int playResult = sendMessage.executeCall(new Object[] {
        wmpHandle,
        WM_APPCOMMAND,
        wmpHandle,
        APPCOMMAND_MEDIA_PLAY << 16});
Run Code Online (Sandbox Code Playgroud)

APPCOMMAND_MEDIA_PLAY需要 XP SP1,但我假设您已经部署了。