前言
这是我大三时写的,现在把它传到博客园给大家分享.
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 ;
}
}
}
}
}
}