首页 > 代码库 > 用JNI实现调节win7系统音量

用JNI实现调节win7系统音量

   前言

   这是我大三时写的,现在把它传到博客园给大家分享.

   github地址:https://github.com/silicon621600/SiliconJNIProject/tree/master/JavaControlVolumeOfWin7

一编写包含native方法的Java类文件:

使用了异常处理机制

com.guwei,volume.VolumeControl.java文件

  1. package com.guwei.volume;
  2. /**
  3. * 该类设计为单例模式
  4. * 提供控制win7系统音量的方法
  5. * @author guwei
  6. *
  7. */
  8. public class VolumeControl {
  9.      static
  10.      {
  11.          System.out.println(System.getProperty("java.library.path"));
  12.      System.loadLibrary("VolumeControlDLL");
  13.      }
  14.         private static VolumeControl uniqueInstance = null;
  15.  
  16.         private VolumeControl() throws OperationFailedException
  17.         {            
  18.             init();
  19.         }            
  20.         /**
  21.          * 单例模式
  22.          * @return 唯一的VolumeControl 有可能为null
  23.          */
  24.         public static VolumeControl getInstance() {
  25.             if (uniqueInstance == null) {
  26.                 try {
  27.                     uniqueInstance = new VolumeControl();
  28.                 }catch (OperationFailedException e)
  29.                 {
  30.                     e.printStackTrace();
  31.                     return null;
  32.                 }
  33.             }
  34.             return uniqueInstance;
  35.         }             
  36.         /**
  37.          * cpp本地一些初始化
  38.          * @return
  39.          */
  40.         private native void init() throws OperationFailedException;
  41.         /**
  42.          * 设置音量大小0~100
  43.          * @param num
  44.          * @return 操作是否成功
  45.          */
  46.      public native void setMasterVolume(int num) throws OperationFailedException;
  47.      /**
  48.      *
  49.      * @return 当前音量大小1-100
  50.      */
  51.         public native int getMasterVolume() throws OperationFailedException;
  52.         /**
  53.          * 设置是否静音 true-是 false-否
  54.          * @param bMute
  55.          * @return
  56.          */
  57.         public native void setMute(boolean bMute) throws OperationFailedException;
  58.         /**
  59.          * 得到当前静音状态 true-是 false-否
  60.          * @return
  61.          */
  62.         public native boolean getMute() throws OperationFailedException;
  63.         /**
  64.          * cpp本地释放指针等操作
  65.          * @return
  66.          */
  67.         private native void finished();        
  68.         @Override
  69.         public void finalize()
  70.         {
  71.             finished();
  72.         }
  73. }

com.guwei,volume.OperationFailedException.java文件

  1. package com.guwei.volume;
  2. public class OperationFailedException extends Exception
  3. {
  4.     public OperationFailedException()
  5.     {}
  6.     public OperationFailedException(String message)
  7.     {
  8.         super(message);
  9.     }
  10. }

 

一.编译,然后用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;

 

staticIAudioEndpointVolume *g_pEndptVol = NULL;

 

IMMDeviceEnumerator *pEnumerator = NULL;

IMMDevice *pDevice = NULL;

 

JNIEXPORTvoidJNICALL Java_com_guwei_volume_VolumeControl_init(JNIEnv *env,

    jobjectobj)

{

    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");

    }

}

JNIEXPORTvoidJNICALL Java_com_guwei_volume_VolumeControl_setMasterVolume(JNIEnv *env,

    jobjectobj,

    jintnVolume)

{

    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");

    }    

}

JNIEXPORTjintJNICALL Java_com_guwei_volume_VolumeControl_getMasterVolume(JNIEnv *env,

    jobjectobj)

{

    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;

}

JNIEXPORTvoidJNICALL Java_com_guwei_volume_VolumeControl_setMute(JNIEnv *env,

    jobjectobj,

    jbooleanbMute)

{

    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");

    }

}

 

JNIEXPORTjbooleanJNICALL Java_com_guwei_volume_VolumeControl_getMute(JNIEnv *env,

    jobjectobj)

{

    jclass cls;

    cls = env->FindClass("com/guwei/volume/OperationFailedException");

    if (cls == NULL){

        returnfalse;

    }

 

    BOOL bMute;//是否静音

    HRESULT hr = g_pEndptVol->GetMute(&bMute);//得到静音状态

    if (FAILED(hr)) {

        env->ThrowNew(cls, "getMute error");

    }

    return bMute;

}

JNIEXPORTvoidJNICALL Java_com_guwei_volume_VolumeControl_finished(JNIEnv *env,

    jobjectobj)

{

    //释放指针

    SAFE_RELEASE(pEnumerator)

    SAFE_RELEASE(pDevice)

    SAFE_RELEASE(g_pEndptVol)        

}

  1. 配置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 = http://www.mamicode.com/-1;>

                    try {

                        value = http://www.mamicode.com/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 ;

                        }

                    }

                }

            }

        }

    }

用JNI实现调节win7系统音量