前言
这是我大三时写的,现在把它传到博客园给大家分享.
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
/* 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系统音量的方法
该网址提供一个样例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 改为 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"
GUIDg_guidMyContext = GUID_NULL;
staticIAudioEndpointVolume*g_pEndptVol = NULL;
IMMDeviceEnumerator*pEnumerator = NULL;
IMMDevice*pDevice = NULL;
JNIEXPORTvoidJNICALLJava_com_guwei_volume_VolumeControl_init(JNIEnv*env,
jobjectobj)
{
jclasscls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if(cls == NULL){
return;
}
HRESULThr = 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");
}
}
JNIEXPORTvoidJNICALLJava_com_guwei_volume_VolumeControl_setMasterVolume(JNIEnv*env,
jobjectobj,
jintnVolume)
{
jclasscls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if(cls == NULL){
return;
}
floatfVolume = (float)nVolume/ MAX_VOL;//设置音量
HRESULThr = g_pEndptVol->SetMasterVolumeLevelScalar(fVolume, &g_guidMyContext);
if(FAILED(hr)) {
env->ThrowNew(cls, "setMasterVolume error");
}
}
JNIEXPORTjintJNICALLJava_com_guwei_volume_VolumeControl_getMasterVolume(JNIEnv*env,
jobjectobj)
{
jclasscls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if(cls == NULL){
return-1;
}
intret;
floatfVolume;
HRESULThr = 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
returnret;
}
JNIEXPORTvoidJNICALLJava_com_guwei_volume_VolumeControl_setMute(JNIEnv*env,
jobjectobj,
jbooleanbMute)
{
jclasscls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if(cls == NULL){
return;
}
HRESULThr = g_pEndptVol->SetMute(bMute, &g_guidMyContext);//设置静音
if(FAILED(hr)) {
env->ThrowNew(cls, "setMute error");
}
}
JNIEXPORTjbooleanJNICALLJava_com_guwei_volume_VolumeControl_getMute(JNIEnv*env,
jobjectobj)
{
jclasscls;
cls = env->FindClass("com/guwei/volume/OperationFailedException");
if(cls == NULL){
returnfalse;
}
BOOLbMute;//是否静音
HRESULThr = g_pEndptVol->GetMute(&bMute);//得到静音状态
if(FAILED(hr)) {
env->ThrowNew(cls, "getMute error");
}
returnbMute;
}
JNIEXPORTvoidJNICALLJava_com_guwei_volume_VolumeControl_finished(JNIEnv*env,
jobjectobj)
{
//释放指针
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 ;
}
}
}
}
}
}