0 Replies Latest reply: Oct 31, 2011 2:02 AM by 896842 RSS

    Invalid memory access Error - Speaker Volume for Vista & Windows 7 - JNA

    896842
      <font size="2"><p>
      To get speaker volume in Vista and Windows 7 computers I've written Java-JNA code using JNA 3.3.0 jar.
      While invoking winapi (windows API from winmm.dll) mixerGetLineControlsA(..) I got "Invalid memory access" error in both 32 bit Vista and 64 bit windows 7 machines.
      Somehow I feel I'm not allocating memory properly while defining the structures MIXERLINECONTROLS and MIXERLINECONTROL, but I'm not able to figure it out.

      Appreciate your help in resolving this.
      </font>

      package com.mytest.jna;
      
      import com.sun.jna.Native;
      import com.sun.jna.Structure;
      import com.sun.jna.Union;
      import com.sun.jna.ptr.IntByReference;
      import com.sun.jna.win32.StdCallLibrary;
      
      
      
      public class SystemSpeakerTest {
           private static Winmm winmmLib=Winmm.INSTANCE;
           private static final int STRUCTURE_ALLIGNMENT=Structure.ALIGN_NONE;
      
           static {
                Native.setProtected(true);
           }
           public static class MixerConstants{
                //Refer to ->  http://source.winehq.org/source/include/mmsystem.h
                public static int MMSYSERR_NOERROR = 0;
      
                public static int MAXPNAMELEN = 32;
                public static int MIXER_LONG_NAME_CHARS = 64;
                public static int MIXER_SHORT_NAME_CHARS = 16;
      
                public static int MIXER_OBJECTF_HANDLE=0x80000000;
                public static int MIXER_OBJECTF_MIXER=0x00000000; 
                public static int MIXER_OBJECTF_HMIXER=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIXER);
      
                public static int MIXER_GETLINECONTROLSF_ALL=0x00000000;
                public static int MIXER_GETLINECONTROLSF_ONEBYID=0x00000001;
                public static int MIXER_GETLINECONTROLSF_ONEBYTYPE=0x00000002;
                public static int MIXER_GETLINECONTROLSF_QUERYMASK=0x0000000F;
      
                //Possible values of MIXERLINE.fdwLine
                public static int MIXERLINE_LINEF_ACTIVE=0x00000001;
                public static int MIXERLINE_LINEF_DISCONNECTED=0x00008000;
                public static int MIXERLINE_LINEF_SOURCE=0x80000000;
      
      
                public static int MIXER_GETLINEINFOF_DESTINATION=0x00000000; 
                public static int MIXER_GETLINEINFOF_SOURCE=0x00000001;
                public static int MIXER_GETLINEINFOF_LINEID=0x00000002;
                public static int MIXER_GETLINEINFOF_COMPONENTTYPE =0x00000003;
                public static int MIXER_GETLINEINFOF_TARGETTYPE=0x00000004;
                public static int MIXER_GETLINEINFOF_QUERYMASK=0x0000000F;
      
                public static int MIXERCONTROL_CT_CLASS_SWITCH            =0x20000000;
                public static int MIXERCONTROL_CT_CLASS_FADER             =0x50000000;
                public static int MIXERCONTROL_CT_SC_SWITCH_BOOLEAN       =0x00000000;
                public static int MIXERCONTROL_CT_UNITS_BOOLEAN           =0x00010000;
                public static int MIXERCONTROL_CT_UNITS_UNSIGNED          =0x00030000;
      
                public static int MIXERCONTROL_CONTROLTYPE_BOOLEAN        =(MIXERCONTROL_CT_CLASS_SWITCH | MIXERCONTROL_CT_SC_SWITCH_BOOLEAN | MIXERCONTROL_CT_UNITS_BOOLEAN);
                public static int MIXERCONTROL_CONTROLTYPE_ONOFF          =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1);
                public static int MIXERCONTROL_CONTROLTYPE_MUTE           =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2);
                public static int MIXERCONTROL_CONTROLTYPE_MONO           =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3);
                public static int MIXERCONTROL_CONTROLTYPE_LOUDNESS       =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4);
                public static int MIXERCONTROL_CONTROLTYPE_STEREOENH      =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5);
                public static int MIXERCONTROL_CONTROLTYPE_BASS_BOOST     =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 0x00002277);
                public static int MIXERCONTROL_CONTROLTYPE_FADER = (MIXERCONTROL_CT_CLASS_FADER | MIXERCONTROL_CT_UNITS_UNSIGNED);
                public static int MIXERCONTROL_CONTROLTYPE_VOLUME = (MIXERCONTROL_CONTROLTYPE_FADER + 1);
                public static int MIXERCONTROL_CONTROLTYPE_BASS           =(MIXERCONTROL_CONTROLTYPE_FADER + 2);
                public static int MIXERCONTROL_CONTROLTYPE_TREBLE         =(MIXERCONTROL_CONTROLTYPE_FADER + 3);
                public static int MIXERCONTROL_CONTROLTYPE_EQUALIZER      =(MIXERCONTROL_CONTROLTYPE_FADER + 4);
      
           }
      
           public interface Winmm extends StdCallLibrary { 
                Winmm INSTANCE = (Winmm)Native.loadLibrary("winmm", Winmm.class);
      
                //Ref: http://msdn.microsoft.com/en-us/library/aa910078.aspx
                int mixerGetNumDevs();
      
                //Ref: http://msdn.microsoft.com/en-us/library/ms932053.aspx
                int mixerOpen(IntByReference phmx, int pMxId, int dwCallback, int dwInstance, int fdwOpen);
      
                //Ref: http://msdn.microsoft.com/en-us/library/ms932045.aspx
                int mixerGetDevCapsA(int uMxId, MIXERCAPS pmxcaps,int cbmxcaps);
      
                //Ref: http://msdn.microsoft.com/en-us/library/dd757303(VS.85).aspx
                int mixerGetLineInfoA(int hmxobj,MIXERLINE pmxl, int fdwInfo);
      
                //Ref: http://msdn.microsoft.com/en-us/library/aa909824.aspx
                int mixerGetLineControlsA(int hmxobj,MIXERLINECONTROLS pmxlc, int fdwControls );
      
                //Ref: http://msdn.microsoft.com/en-us/library/aa909818.aspx
                int mixerClose(int hmx);
           }
      
           public static class MIXERCAPS extends Structure{
                public short wMid; 
                public short wPid; 
                public int vDriverVersion; 
                public byte[] szPname=new byte[MixerConstants.MAXPNAMELEN]; 
                public int fdwSupport; 
                public int cDestinations; 
           }
      
           public static class MIXERLINE extends Structure  {
                public int cbStruct;
                public int dwDestination;
                public int dwSource;
                public int dwLineID;
                public int fdwLine;
                /**
                 * by http://msdn.microsoft.com/en-us/library/aa909791.aspx 
                 *                the field dwUser is int 
                 * by http://msdn.microsoft.com/en-us/library/dd757305(v=VS.85).aspx
                 *                the field dwUser is IntByReference
                 */
                public int dwUser; 
                public int dwComponentType;
                public int cChannels;
                public int cConnections;
                public int cControls;
                public byte[] szShortName=new byte [MixerConstants.MIXER_SHORT_NAME_CHARS];
                public byte[] szName=new byte[MixerConstants.MIXER_LONG_NAME_CHARS];
                public Target target;
           }
      
           public static class Target extends Structure{
                public int dwType;
                public int dwDeviceID;
                public short wMid;
                public short wPid;
                public long vDriverVersion;
                public byte[] szPname=new byte[MixerConstants.MAXPNAMELEN];
           }
      
           public static class MIXERLINECONTROLS extends Structure{
                public int cbStruct;
                public int dwLineID;
                public int dwControlIdType;
      
                public int cControls;
                public int cbmxctrl;
                public MIXERCONTROL pamxctrl;
                public MIXERLINECONTROLS(int cControls){//right now only cControls=1 is supported in the code
                     super.setAlignType(STRUCTURE_ALLIGNMENT);
                     this.cControls=cControls;
                     this.pamxctrl=new MIXERCONTROL();
                     this.cbmxctrl=this.pamxctrl.size();
                     allocateMemory();
                }
           }
      
           public static class MIXERCONTROL extends Structure{
                public int cbStruct; 
                public int dwControlID; 
                public int dwControlType; 
                public int fdwControl; 
                public int cMultipleItems; 
                public byte[] szShortName=new byte[MixerConstants.MIXER_SHORT_NAME_CHARS];
                public byte[] szName=new byte[MixerConstants.MIXER_LONG_NAME_CHARS];
                public Bounds.ByValue bounds;
                public Metrics.ByValue metrics;
      
                public MIXERCONTROL(){
                     super.setAlignType(STRUCTURE_ALLIGNMENT);
                     allocateMemory();
                }
           }
      
           public static class Bounds extends Union{
                public static class ByValue extends Bounds implements Structure.ByValue {}
                public LMaxMin.ByValue lMaxMin; 
                public DwMaxMin.ByValue dwMaxMin;
                public int[] dwReserved=new int[6];
                public Bounds(){
                     super.setAlignType(STRUCTURE_ALLIGNMENT);
                }
           }
      
           public static class Metrics extends Union{
                public static class ByValue extends Metrics implements Structure.ByValue {}
                public int cSteps; 
                public int cbCustomData;
                public int[] dwReserved=new int[6];
                public Metrics(){
                     super.setAlignType(STRUCTURE_ALLIGNMENT);
                }
           }
      
           public static class LMaxMin extends Structure{
                public static class ByValue extends LMaxMin implements Structure.ByValue {}
                public long lMinimum; 
                public long lMaximum;
                public LMaxMin(){
                     super.setAlignType(STRUCTURE_ALLIGNMENT);
                }
           }
      
           public static class DwMaxMin extends Structure{
                public static class ByValue extends DwMaxMin implements Structure.ByValue {}
                public int dwMinimum; 
                public int dwMaximum;
                public DwMaxMin(){
                     super.setAlignType(STRUCTURE_ALLIGNMENT);
                }
           }
      
           private static int getNumberOfMixerInSystem(){
                int numOfMixer=-1;
                numOfMixer=winmmLib.mixerGetNumDevs();
                System.out.println("Number Of Mixer :"+numOfMixer);
                System.out.println();
                return numOfMixer;
           }
      
           private static IntByReference openMixerByMixerId(int pMxId){
                int dwCallback=0;
                int dwInstance=0;
                int fdwOpen=MixerConstants.MIXER_OBJECTF_MIXER;//0;
      
                IntByReference phmx=new IntByReference();
      
                int rc=winmmLib.mixerOpen( phmx, pMxId, dwCallback, dwInstance, fdwOpen);
                System.out.println("RC mixerOpen ="+rc);
                System.out.println("Mixer Id ="+pMxId);
                System.out.println("Mixer Handle value ="+phmx.getValue());
                System.out.println();
                return rc== MixerConstants.MMSYSERR_NOERROR? phmx: null;
           }
      
           private static void closeMixerByHanlde(IntByReference mixerHandle){
                int rc=winmmLib.mixerClose( mixerHandle.getValue());
                System.out.println("RC mixerClose ="+rc);
                System.out.println();
           }
      
           private static void getMixerCapabilitiesByMixerId(int pMxId){
                MIXERCAPS pmxcaps=new MIXERCAPS();
                int cbmxcaps =pmxcaps.size();
                int rc=winmmLib.mixerGetDevCapsA(pMxId,pmxcaps,cbmxcaps);
      
                System.out.println("RC mixerGetDevCaps ="+rc);
                System.out.println("Mixer Id ="+pMxId);
      
                System.out.println("Manufacturer identifier for the mixer device driver ="+pmxcaps.wMid);
                System.out.println("Product Name of the Mixer="+new String(pmxcaps.szPname));
                System.out.println("Destination Line Count="+pmxcaps.cDestinations);
                System.out.println();
           }
      
           /**
            * If VolumeConstants.MIXER_GETLINEINFOF_DESTINATION
            *           pmxl.dwDestination= [0,MIXERCAPS.cDestinations)
            *           
            * 
            * If VolumeConstants.MIXER_GETLINEINFOF_SOURCE
            *           pmxl.dwDestination= [0,MIXERCAPS.cDestinations)
            *           pmxl.dwSource=[0, MIXERLINE.cConnections) for each pmxl.dwDestination;  
            * 
            * If VolumeConstants.MIXER_GETLINEINFOF_LINEID
            *           pmxl.dwLineID=MIXERLINE.dwLineID; 
            * 
            * @param mixerHandle
            * @return
            */
           private static MIXERLINE getLineInfoOfMixer(IntByReference mixerHandle){
                MIXERLINE pmxl=new MIXERLINE ();
                pmxl.cbStruct=pmxl.size();
                pmxl.dwDestination=0;
      
                int rc=winmmLib.mixerGetLineInfoA(mixerHandle.getValue(),pmxl,MixerConstants.MIXER_GETLINEINFOF_DESTINATION);
                System.out.println("RC mixerGetLineInfoA ="+rc);
                System.out.println("dwLineID="+getUnsignedIntValue(pmxl.dwLineID)+" [Signed value="+pmxl.dwLineID+"]");
                String shortName=new String(pmxl.szShortName);
                System.out.println("szShortName =["+shortName+"]\nszName =["+new String(pmxl.szName)+"]");
                System.out.println("Mixer Line State ="+(pmxl.fdwLine==MixerConstants.MIXERLINE_LINEF_ACTIVE?"Active":
                     pmxl.fdwLine==MixerConstants.MIXERLINE_LINEF_SOURCE?"Source":"Disconnected")+" [fdwLine="+pmxl.fdwLine+"]");
                System.out.println("No of Audio Channels for this line that can be manipulated ="+pmxl.cChannels);
                System.out.println("No of Source Line associated ="+pmxl.cConnections);
                System.out.println("Number of Audio Controls for this line ="+pmxl.cControls);
                System.out.println("Component Type ="+pmxl.dwComponentType);
                System.out.println();
      
                return rc==MixerConstants.MMSYSERR_NOERROR?pmxl:null;
           }
      
           private static void getLineControlOfMixer(IntByReference mixerHandle, MIXERLINE pmxl){
                if(pmxl==null){
                     System.out.println("pmxl is null. mixerGetLineControlsA will not be dispatched.");
                     return;
                }
      
                MIXERLINECONTROLS pmxlc=new MIXERLINECONTROLS(1);
                pmxlc.cbStruct=pmxlc.size();
                pmxlc.dwControlIdType=MixerConstants.MIXERCONTROL_CONTROLTYPE_MUTE;
      
      
                int rc=winmmLib.mixerGetLineControlsA(mixerHandle.getValue(), pmxlc, MixerConstants.MIXER_GETLINECONTROLSF_ONEBYTYPE);
                System.out.println("RC mixerGetLineControlsA ="+rc);
      
           }
      
           public static long getUnsignedIntValue(int valueOfUnsignedInt){
                long MASK=0x00000000FFFFFFFFL;
                return MASK&valueOfUnsignedInt;
           }
      
           //An unsigned short of bit pattern 0xC000 [1100 0000 0000 0000] decimal value 49152 when assigned to java short becomes signed short
           //having a decimal value= -ve of (NOT (1100 0000 0000 0000 -1) ) = -16384
           //This method takes a short value of -16384 and return 49152 which of course requires higher bit data type i.e. int in this case
           public static int getUnsignedShortValue(short valueOfUnsignedShort){
                int MASK=0x0000FFFF;
                return MASK&valueOfUnsignedShort;
           }
      
           public static void main(String[] args) {
      
                int numOfMixer=getNumberOfMixerInSystem();
      
                for(int mixerId=0; mixerId<numOfMixer; mixerId++){
                     IntByReference mixerHandle=openMixerByMixerId(mixerId);
                     if(mixerHandle==null){continue;}
      
                     getMixerCapabilitiesByMixerId(mixerId);
      
                     MIXERLINE pmxl=getLineInfoOfMixer(mixerHandle);
      
                     getLineControlOfMixer(mixerHandle,pmxl);
      
                     closeMixerByHanlde(mixerHandle);
                     //Not interested about mixerId=1 so exit.
                     if(mixerId==0)System.exit(0);
                }
           }
      }
      The error & output:

      Number Of Mixer :2

      RC mixerOpen =0
      Mixer Id =0
      Mixer Handle value =2919296

      RC mixerGetDevCaps =0
      Mixer Id =0
      Manufacturer identifier for the mixer device driver =1
      Product Name of the Mixer=Speakers (Conexant 20672 SmartA
      Destination Line Count=1

      RC mixerGetLineInfoA =0
      dwLineID=4294901760 [Signed value=-65536]
      szShortName =[Volume]
      szName =[Master Volume]

      Mixer Line State =Active [fdwLine=1]
      No of Audio Channels for this line that can be manipulated =4
      No of Source Line associated =1
      Number of Audio Controls for this line =2
      Component Type =0

      Exception in thread "main" java.lang.Error: Invalid memory access
           at com.sun.jna.Native.invokeInt(Native Method)
           at com.sun.jna.Function.invoke(Function.java:344)
           at com.sun.jna.Function.invoke(Function.java:276)
           at com.sun.jna.Library$Handler.invoke(Library.java:216)
           at $Proxy0.mixerGetLineControlsA(Unknown Source)
           at com.kausik.jna.SystemSpeakerTest.getLineControlOfMixer(SystemSpeakerTest.java:293)
           at com.kausik.jna.SystemSpeakerTest.main(SystemSpeakerTest.java:323)