我是前阵子来这里询问通过 Java 控制 Windows Media Player 的人。 我已经取得了进展,但我遇到了一个令人烦恼的问题,所以我回来寻求帮助。
我按照上次得到的建议安装了 Jacob。我从测试脚本中执行这些行:
ActiveXComponent wmp = new ActiveXComponent("WMPlayer.OCX");
wmp.invoke("openPlayer", "http://somafm.com/wma128/groovesalad.asx");
...然后 WMP 弹出,播放 SomaFM。“哇!” 我认为。“我已经解决了这个问题!”
除了当我在创建该对象后与它进行交互时,它似乎与播放的 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"));
...我得到以下输出:
音量:50 音量:0
这似乎无伤大雅,除了
- “50”的音量与实际设置的播放器音量无关,
- 在 setProperty 调用之后,播放器的音量实际上并没有改变。
我也尝试过其他属性,但都是一样的:属性的值似乎与玩家实际在做什么无关,而更改它们似乎会改变被操纵对象的状态,它对实际播放器没有影响。 (每次运行脚本时我都会得到完全相同的输出,所以无论我在旋转“音量”时更改的是什么,它在代码之外都没有任何持久性。)
显然我做错了什么,但我盲目地摸索着想弄清楚是什么。任何人都可以向我提供任何关于出了什么问题的见解,或者我接下来应该尝试什么?
(注意:我什至不确定“WMPlayer.OCX”是正确的输入参数。我在注册表中的 HKEY_CLASSES_ROOT 中尝试了看起来很可能的条目,直到找到这个。)
我提前感谢任何人可以提供的任何帮助。
编辑,2009 年 4 月 15 日: 我在一家名为 EZ JCom 的公司的产品中发现了一个特定于 WMP 的软件包。它的失败方式与我之前看到的完全相同,要么它只是 Jacob 的包装器,要么 WMP ActiveX/COM 接口完全损坏。(等等,我为什么说“要么”?)
我与客户服务聊天,他们最终展示了您如何在没有实际用处的情况下提供帮助。他们帮助我更正了他们提供的非编译示例代码,作为他们的 WMP 代码运行示例,但是当我纠缠他们以了解 get/set volume 方法应该如何工作时,我得到了这个:
“抱歉,这里没有 WMP 深入的专业知识 - EZ JCom 只是 Java 和 WMP 等其他程序之间的桥梁建设者。”
请记住,我正在评估的他们的软件包实际上称为“wmp.WindowsMediaPlayer”。如果我让它发挥作用,我将不得不说服我的老板花 600 美元购买许可证。有人想知道如果他们真的对自己的产品有一些专业知识,他们会收取什么费用。
所以,没有真正的进展。只是想我会分享。
编辑,2009 年 4 月 20 日: 是的,我还在纠结这个。我目前的操作理论是,为了获得音量设置,我需要远程访问 WMP。我见过提到 IWMPRemoteMediaServices 和 IServiceProvider 接口,后者的 QueryService 方法提供了指向前者的指针。不幸的是,我没有任何运气弄清楚如何获得 IServiceProvider。我已经看到提到它可以从 Windows“系统”对象访问,但我不知道如何获取该对象。(而且由于“系统”这个词在 Java 中占有很大比重,谷歌给了我一个可怕的噪音:信号比。)如果有人对我如何处理表示 System.dll 的 COM 对象有任何建议,我很乐意听到。
编辑,2009 年 4 月 21 日: 澄清:这是在 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());
这给了我一个结果:
wmpHandle: 1640048 查找窗口错误?空值 播放结果:-1 播放错误?空值 暂停结果:-1 暂停错误?空值
...但实际上并不影响媒体播放器。
我也用 APPCOMMAND_MEDIA_PLAY_PAUSE (14) 进行了尝试,它给出了不同的返回值 (20),但也没有做任何事情。
FWIW,我真的需要让单独的 PLAY/PAUSE 命令来工作,这是一个可行的选择;只是盲目地切换状态对我没有帮助,因为我不知道当我开始时玩家处于什么状态。
有没有人对我做错了什么或我可以尝试什么有任何建议?