用JNI实现调节win7系统音量
前言
这是我大三时写的,现在把它传到博客园给大家分享.
github地址:https://github.com/silicon621600/SiliconJNIProject/tree/master/JavaControlVolumeOfWin7
一编写包含native方法的Java类文件:
使用了异常处理机制
com.guwei,volume.VolumeControl.java文件
-
package com.guwei.volume;
-
/**
-
* 该类设计为单例模式
-
* 提供控制win7系统音量的方法
-
* @author guwei
-
*
-
*/
-
public class VolumeControl {
-
static
-
{
-
System.out.println(System.getProperty("java.library.path"));
-
System.loadLibrary("VolumeControlDLL");
-
}
-
private static VolumeControl uniqueInstance = null;
-
-
private VolumeControl() throws OperationFailedException
-
{
-
init();
-
}
-
/**
-
* 单例模式
-
* @return 唯一的VolumeControl 有可能为null
-
*/
-
public static VolumeControl getInstance() {
-
if (uniqueInstance == null) {
-
try {
-
uniqueInstance = new VolumeControl();
-
}catch (OperationFailedException e)
-
{
-
e.printStackTrace();
-
return null;
-
}
-
}
-
return uniqueInstance;
-
}
-
/**
-
* cpp本地一些初始化
-
* @return
-
*/
-
private native void init() throws OperationFailedException;
-
/**
-
* 设置音量大小0~100
-
* @param num
-
* @return 操作是否成功
-
*/
-
public native void setMasterVolume(int num) throws OperationFailedException;
-
/**
-
*
-
* @return 当前音量大小1-100
-
*/
-
public native int getMasterVolume() throws OperationFailedException;
-
/**
-
* 设置是否静音 true-是 false-否
-
* @param bMute
-
* @return
-
*/
-
public native void setMute(boolean bMute) throws OperationFailedException;
-
/**
-
* 得到当前静音状态 true-是 false-否
-
* @return
-
*/
-
public native boolean getMute() throws OperationFailedException;
-
/**
-
* cpp本地释放指针等操作
-
* @return
-
*/
-
private native void finished();
-
@Override
-
public void finalize()
-
{
-
finished();
-
}
-
}
com.guwei,volume.OperationFailedException.java文件
-
package com.guwei.volume;
-
public class OperationFailedException extends Exception
-
{
-
public OperationFailedException()
-
{}
-
public OperationFailedException(String message)
-
{
-
super(message);
-
}
-
}
一.编译,然后用javah命令生成相应cpp头文件
编译可用命令行javac或eclipse自动编译(javac 注意用-encoding utf8参数)
在完整.class文件位置(不是class文件的存放目录,考虑包名)使用javah命令
javah -jni com.guwei.volume.VolumeControl
也可以用-classpath指明类路径
注意要输入完整的类名,更多参数输入javah查看
命令运行完成后,会出现一个com_guwei_volume_VolumeControl.h文件
生成的头文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_guwei_volume_VolumeControl */
#ifndef _Included_com_guwei_volume_VolumeControl
#define _Included_com_guwei_volume_VolumeControl
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_guwei_volume_VolumeControl
* Method: init
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_init
(JNIEnv *, jobject);
/*
* Class: com_guwei_volume_VolumeControl
* Method: setMasterVolume
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_setMasterVolume
(JNIEnv *, jobject, jint);
/*
* Class: com_guwei_volume_VolumeControl
* Method: getMasterVolume
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_guwei_volume_VolumeControl_getMasterVolume
(JNIEnv *, jobject);
/*
* Class: com_guwei_volume_VolumeControl
* Method: setMute
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_setMute
(JNIEnv *, jobject, jboolean);
/*
* Class: com_guwei_volume_VolumeControl
* Method: getMute
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_guwei_volume_VolumeControl_getMute
(JNIEnv *, jobject);
/*
* Class: com_guwei_volume_VolumeControl
* Method: finished
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_finished
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
二.查询MSDN中调节wen7系统音量的方法
https://msdn.microsoft.com/zh-cn/library/windows/desktop/dd370839(v=vs.85).aspx
该网址提供一个样例VC++的win32工程显示调节系统音量,
将网页文档读懂即可编写自己的dll,其中用到了COM组件相关知识
该工程运行效果如下:
三.编写dll文件(用到了COM相关)
使用VS2010建立名为VolumeControlDLL的win32控制台工程
点下一步后 选择dll 和空项目
将jni.h和之前生成的com_guwei_volume_VolumeControl.h加入工程
jni.h在jdk目录的include目录下:
可以在VS的环境变量中加入该目录
此处我用的是直接把文件拷到当前工程,所以相应com_guwei_volume_VolumeControl.h文件中的 include <jni.h> 改为 include "jni.h"
注意头文件中的extern C 是必要的,否则会报找不到的错,这是因为CPP支持函数重载,会将函数名XX映射
另外,jdk1.7只需jni.h文件,jdk1.8还需要jni_md.h文件(include/win32目录下)根据编译信息来即可
Epvolume.cpp文件实现com_guwei_volume_VolumeControl.h的方法(根据MSDN工程中的改写)
// Epvolume.cpp -- WinMain and dialog box functions
#include "Epvolume.h"
#include "com_guwei_volume_VolumeControl.h"
GUID g_guidMyContext = GUID_NULL;
static IAudioEndpointVolume *g_pEndptVol = NULL;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_init(JNIEnv *env,
jobject obj)
{
jclass cls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if (cls == NULL){
return;
}
HRESULT hr = S_OK;
//CAudioEndpointVolumeCallback EPVolEvents;
//得到g_guidMyContext hr只是结果
hr = CoCreateGuid(&g_guidMyContext);
if (FAILED(hr)) {
env->ThrowNew(cls, "CoCreateGuid error");
}
// Get enumerator for audio endpoint devices. pEnumerator中
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(void**)&pEnumerator);
if (FAILED(hr)) {
env->ThrowNew(cls, "CoCreateInstance error");
}
// Get default audio-rendering device. pDevice中
hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
if (FAILED(hr)) {
env->ThrowNew(cls, "pEnumerator->GetDefaultAudioEndpoint error");
}
hr = pDevice->Activate(__uuidof(IAudioEndpointVolume),
CLSCTX_ALL, NULL, (void**)&g_pEndptVol);
if (FAILED(hr)) {
env->ThrowNew(cls, "pDevice->Activate error");
}
}
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_setMasterVolume(JNIEnv *env,
jobject obj,
jint nVolume)
{
jclass cls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if (cls == NULL){
return;
}
float fVolume = (float)nVolume / MAX_VOL;//设置音量
HRESULT hr = g_pEndptVol->SetMasterVolumeLevelScalar(fVolume, &g_guidMyContext);
if (FAILED(hr)) {
env->ThrowNew(cls, "setMasterVolume error");
}
}
JNIEXPORT jint JNICALL Java_com_guwei_volume_VolumeControl_getMasterVolume(JNIEnv *env,
jobject obj)
{
jclass cls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if (cls == NULL){
return -1;
}
int ret;
float fVolume;
HRESULT hr = g_pEndptVol->GetMasterVolumeLevelScalar(&fVolume);//得到主音量的大小浮点数(0.0~1.0)
if (FAILED(hr)) {
env->ThrowNew(cls, "getMasterVolume error");
}
ret = (int)(MAX_VOL*fVolume + 0.5);//将音量转化为整数(0到100) MAX_VOL为100
return ret;
}
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_setMute(JNIEnv *env,
jobject obj,
jboolean bMute)
{
jclass cls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if (cls == NULL){
return;
}
HRESULT hr = g_pEndptVol->SetMute(bMute, &g_guidMyContext);//设置静音
if (FAILED(hr)) {
env->ThrowNew(cls, "setMute error");
}
}
JNIEXPORT jboolean JNICALL Java_com_guwei_volume_VolumeControl_getMute(JNIEnv *env,
jobject obj)
{
jclass cls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if (cls == NULL){
return false;
}
BOOL bMute;//是否静音
HRESULT hr = g_pEndptVol->GetMute(&bMute);//得到静音状态
if (FAILED(hr)) {
env->ThrowNew(cls, "getMute error");
}
return bMute;
}
JNIEXPORT void JNICALL Java_com_guwei_volume_VolumeControl_finished(JNIEnv *env,
jobject obj)
{
//释放指针
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pDevice)
SAFE_RELEASE(g_pEndptVol)
}
-
配置dll
注意32位和64位系统问题,
错误:Can't load IA 32-bit .dll on a AMD 64-bit platform
由于VS生成32位的,但系统使用64位
然后多了x64文件夹
VC项目生成的dll在工程目录的debug(32位) 或 x64/debug(64位)目录里
将该dll加入java工程的类路径(System.getProperty("java.library.path");只要在这里面都行)即可(可以设定参数-Djava.library.path=)
编写测试类Test.java
import com.guwei.volume.*;
import java.lang.Integer;
public class Test{
public static void main(String[] args)
{
VolumeControl vc = null;
try{
vc = VolumeControl.getInstance();
int val = vc.getMasterVolume();
boolean mute = vc.getMute();
System.out.println("current volume is"+val+". Is Muted?:"+mute);
}catch (OperationFailedException e)
{
System.out.println("can not read volume info: Exception:"+e);
return ;
}
if (args.length>1)
{
String s1=args[0];
String s2=args[1];
if (s1.equals("setmute"))
{
if (s2.equals("on"))
{
try{
vc.setMute(true);
System.out.println("Operation succeed!!!");
}catch (OperationFailedException e)
{
System.out.println("operation failed: Exception:"+e);
return ;
}
}
else if (s2.equals("off"))
{
try{
vc.setMute(false);
System.out.println("Operation succeed!!!");
}catch (OperationFailedException e)
{
System.out.println("operation failed: Exception:"+e);
return ;
}
}
}else if (s1.equals("setvolume"))
{
int value = -1;
try {
value = Integer.parseInt(s2);
}catch(NumberFormatException e)
{
System.out.println("operation failed: Exception:"+e);
return ;
}
if (value>=0 && value<=100)
{
try{
vc.setMasterVolume(value);
System.out.println("Operation succeed!!!");
}catch (OperationFailedException e)
{
System.out.println("operation failed: Exception:"+e);
return ;
}
}
}
}
}
}
浙公网安备 33010602011771号