locked
Vista volume control using Delphi 5 RRS feed

  • Question

  • Hello,

    I have written a delphi application to change the master volume on a Vista machine .

    The application is developed using Delphi 5.

    I have written a _TLB file for the MMDEVAPI.dll.

    But I am getting the access violation exception for the FDevice.Activate call.

    In the code,

    FDevice.GetState function is working properly but for the 'Activate' call I am getting access violation in module mmdevapi.dll.

    It is failing while 'write of some address'.

    Following is the code for the MMDevApi_tlb.pas.

     

    //-------------------------------------------------------

    unit MMDevApi_tlb;

    interface
      uses Windows, ActiveX, Classes, Graphics, OleServer, OleCtrls, StdVCL,ComObj;
    const
      // TypeLibrary Major and minor versions

      CLASS_IMMDeviceEnumerator: TGUID             = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
      IID_IMMDeviceEnumerator: TGUID                = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
      IID_IMMDevice: TGUID                          = '{D666063F-1587-4E43-81F1-B948E807363F}';
      IID_IMMDeviceCollection: TGUID                = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
      IID_IAudioEndpointVolume: TGUID               = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
      IID_IAudioMeterInformation : TGUID            = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
      IID_IAudioEndpointVolumeCallback: TGUID       = '{657804FA-D6AD-4496-8A60-352752AF4F89}';

      DEVICE_STATE_ACTIVE                   = $00000001;
      DEVICE_STATE_UNPLUGGED                = $00000002;
      DEVICE_STATE_NOTPRESENT               = $00000004;
      DEVICE_STATEMASK_ALL                  = $00000007;

    type
      EDataFlow = TOleEnum;
    const
      eRender                               = $00000000;
      eCapture                              = $00000001;
      eAll                                  = $00000002;
      EDataFlow_enum_count                  = $00000003;

    type
      ERole = TOleEnum;
    const
      eConsole                              = $00000000;
      eMultimedia                           = $00000001;
      eCommunications                       = $00000002;
      ERole_enum_count                      = $00000003;

    type
      IAudioEndpointVolumeCallback = interface(IUnknown)
      ['{657804FA-D6AD-4496-8A60-352752AF4F89}']
      end;

      IMMAudioEndpointVolume = interface(IUnknown)
      ['{5CDF2C82-841E-4546-9722-0CF74078229A}']
        Function RegisterControlChangeNotify( AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
        Function UnregisterControlChangeNotify( AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
        Function GetChannelCount(out PInteger): Integer; stdcall;
        Function SetMasterVolumeLevel(fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function SetMasterVolumeLevelScalar(fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function GetMasterVolumeLevel(out fLevelDB: double):Integer; stdcall;
        Function GetMasterVolumeLevelScaler(out fLevel: double):Integer; stdcall;
        Function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double) : Integer; stdcall;
        Function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double) : Integer; stdcall;
        Function SetMute(bMute: Boolean ; pguidEventContext: TGUID) :Integer; stdcall;
        Function GetMute(out bMute: Boolean ) :Integer; stdcall;
        Function GetVolumeStepInfo( pnStep: Integer; out pnStepCount: Integer):Integer; stdcall;
        Function VolumeStepUp(pguidEventContext: TGUID) :Integer; stdcall;
        Function VolumeStepDown(pguidEventContext: TGUID) :Integer; stdcall;
        Function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
        Function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
      end;

     

      IPropertyStore = interface(IUnknown)
      end;

    type
      IMMDevice = interface(IUnknown)
      ['{D666063F-1587-4E43-81F1-B948E807363F}']
        Function Activate(  refId :TGUID;
                            dwClsCtx: DWORD;
                            pActivationParams: PInteger ;
                            out pEndpointVolume:
    IMMAudioEndpointVolume): Hresult; stdCall;
        Function OpenPropertyStore(stgmAccess: DWORD; out ppProperties :IPropertyStore): Hresult; stdcall;
        Function GetId(out ppstrId: PLPWSTR ): Hresult; stdcall;
        Function GetState(out State :Integer): Hresult; stdcall;

      end;


      IMMDeviceCollection = interface(IUnknown)
      ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
      end;

      IMMNotificationClient = interface (IUnknown)
      ['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
      end;

      IMMDeviceEnumerator = interface(IUnknown)
      ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
        Function EnumAudioEndpoints( dataFlow: EDataFlow; deviceState: SYSUINT; DevCollection:IMMDeviceCollection ): Hresult ; stdcall;
        Function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): Hresult ; stdcall;
        Function GetDevice( pwstrId: pointer ; out Dev :IMMDevice) : HResult; stdcall;
        Function RegisterEndpointNotificationCallback(pClient :IMMNotificationClient) :Hresult; stdcall;
      end;

      implementation
    end.

    //-------------------------------------------------------

     

    Thanks in advance,

    Mukta...

    Tuesday, May 22, 2007 10:51 AM

All replies

  • All the EventContext parameters are pointers to GUIDs, it appears that your declaration treats them as references to GUIDS instead.

     

    Thursday, May 24, 2007 11:45 PM
  • Hello Larry.

    Thanks for the quick reply

    1. In http://msdn2.microsoft.com/en-us/library/ms679029.aspx

    Activate method's documentation says it needs iid --

    iid [in]  The interface identifier. This parameter is a reference to a GUID that identifies the interface that the caller requests be activated.

    Please confirm.

     

    2. I got the mmdeviceapi.tlb and from that I built the mmdeviceapi_tlb.pas file (which i can use in delphi application).

    But now the problem is for the endpointvolume.h file.

    The .tlb for endpointvolume.h is not provided.

    So I am not able to build the _tlb.pas. So again I wrote it ... but it is still failing for Activate method.

     

    The generated  mmdeviceapi_tlb.pas is as follows. --

    The highlighted part is added by me.

     

    unit MMDevApi_tlb;

    interface
      uses Windows, ActiveX, Classes, Graphics, OleServer, OleCtrls, StdVCL,ComObj;
    const
      // TypeLibrary Major and minor versions

      CLASS_IMMDeviceEnumerator: TGUID              = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
      IID_IMMDeviceEnumerator: TGUID                = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
      IID_IMMDevice: TGUID                          = '{D666063F-1587-4E43-81F1-B948E807363F}';
      IID_IMMDeviceCollection: TGUID                = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
      IID_IAudioEndpointVolume: TGUID               = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
      IID_IAudioMeterInformation : TGUID            = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
      IID_IAudioEndpointVolumeCallback: TGUID       = '{657804FA-D6AD-4496-8A60-352752AF4F89}';

      DEVICE_STATE_ACTIVE                   = $00000001;
      DEVICE_STATE_UNPLUGGED                = $00000002;
      DEVICE_STATE_NOTPRESENT               = $00000004;
      DEVICE_STATEMASK_ALL                  = $00000007;

    type
      EDataFlow = TOleEnum;
    const
      eRender                               = $00000000;
      eCapture                              = $00000001;
      eAll                                  = $00000002;
      EDataFlow_enum_count                  = $00000003;

    type
      ERole = TOleEnum;
    const
      eConsole                              = $00000000;
      eMultimedia                           = $00000001;
      eCommunications                       = $00000002;
      ERole_enum_count                      = $00000003;

    type
      IAudioEndpointVolumeCallback = interface(IUnknown)
      ['{657804FA-D6AD-4496-8A60-352752AF4F89}']
      end;

      IMMAudioEndpointVolume = interface(IUnknown)
      ['{5CDF2C82-841E-4546-9722-0CF74078229A}']
        Function RegisterControlChangeNotify( AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
        Function UnregisterControlChangeNotify( AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
        Function GetChannelCount(out PInteger): Integer; stdcall;
        Function SetMasterVolumeLevel(fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function SetMasterVolumeLevelScalar(fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function GetMasterVolumeLevel(out fLevelDB: double):Integer; stdcall;
        Function GetMasterVolumeLevelScaler(out fLevel: double):Integer; stdcall;
        Function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
        Function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double) : Integer; stdcall;
        Function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double) : Integer; stdcall;
        Function SetMute(bMute: Boolean ; pguidEventContext: TGUID) :Integer; stdcall;
        Function GetMute(out bMute: Boolean ) :Integer; stdcall;
        Function GetVolumeStepInfo( pnStep: Integer; out pnStepCount: Integer):Integer; stdcall;
        Function VolumeStepUp(pguidEventContext: TGUID) :Integer; stdcall;
        Function VolumeStepDown(pguidEventContext: TGUID) :Integer; stdcall;
        Function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
        Function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
      end;

    {  IAudioMeterInformation = interface(IUnknown)
      ['{C02216F6-8C67-4B5B-9D00-D008E73E0064']
      end;}

      IPropertyStore = interface(IUnknown)
      end;

    type
      IMMDevice = interface(IUnknown)
      ['{D666063F-1587-4E43-81F1-B948E807363F}']
        Function Activate(  refId :TGUID;
                            dwClsCtx: DWORD;
                            pActivationParams: PInteger ;
                            out pEndpointVolume: IMMAudioEndpointVolume): Hresult; stdCall;
        Function OpenPropertyStore(stgmAccess: DWORD; out ppProperties :IPropertyStore): Hresult; stdcall;
        Function GetId(out ppstrId: PLPWSTR ): Hresult; stdcall;
        Function GetState(out State :Integer): Hresult; stdcall;

      end;


      IMMDeviceCollection = interface(IUnknown)
      ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
      end;

      IMMNotificationClient = interface (IUnknown)
      ['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
      end;

      IMMDeviceEnumerator = interface(IUnknown)
      ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
        Function EnumAudioEndpoints( dataFlow: EDataFlow; deviceState: SYSUINT; DevCollection:IMMDeviceCollection ): Hresult ; stdcall;
        Function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): Hresult ; stdcall;
        Function GetDevice( pwstrId: pointer ; out Dev :IMMDevice) : HResult; stdcall;
        Function RegisterEndpointNotificationCallback(pClient :IMMNotificationClient) :Hresult; stdcall;
      end;

      implementation
    end.

     

     

    Thanks & Reagrds,
    Mukta ...

    Monday, May 28, 2007 11:49 AM
  • I was referring to the endpoint volume interface in your code - you still have the event context declared as a reference to a guid not a pointer to a guid.

     

    I'm not sure why the activate method is failing, unfortunately I'm totally unfamiliar with delphi.

     

    Tuesday, May 29, 2007 3:14 PM
  • You have to declare your function like this :
        Function Activate( CONST refId :TGUID;
                            dwClsCtx: DWORD;
                            pActivationParams: PInteger ;
                            out pEndpointVolume:
    IMMAudioEndpointVolume): Hresult; stdCall

    Monday, September 24, 2007 4:39 PM
  • Mukta, did you find a solution with worked?

    I still try to figure out.

    Thanks

    Sunday, October 7, 2007 1:16 AM
  • L.S.,

    The solution provided by Bioupy worked for me. Indeed, the GUID was not passed as a pointer and hence the last bit of the GUID ("4078229A") was interpreted as a pointer ("9A227840"), which was the address causing the access violation. Besides this modification I also found that the DB levels should be passed as single precision floating points to make things work. The relevant changes are marked in red.

        Function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID):Integer; stdcall;
        Function GetMasterVolumeLevel(out fLevelDB: single):Integer; stdcall;


    I hope this helps,

    Lennert.

    Thursday, May 8, 2008 12:12 PM
  •  it's work in Delphi 7
    //////////////////////////

    unit MMDevApi;

    interface

    uses
      Windows, ActiveX, ComObj;

    const
      CLASS_IMMDeviceEnumerator             : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
      IID_IMMDeviceEnumerator               : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
      IID_IMMDevice                         : TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}';
      IID_IMMDeviceCollection               : TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
      IID_IAudioEndpointVolume              : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
      IID_IAudioMeterInformation            : TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
      IID_IAudioEndpointVolumeCallback      : TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}';

      DEVICE_STATE_ACTIVE                   = $00000001;
      DEVICE_STATE_UNPLUGGED                = $00000002;
      DEVICE_STATE_NOTPRESENT               = $00000004;
      DEVICE_STATEMASK_ALL                  = $00000007;

    type
      EDataFlow = TOleEnum;

    const
      eRender                               = $00000000;
      eCapture                              = $00000001;
      eAll                                  = $00000002;
      EDataFlow_enum_count                  = $00000003;

    type
      ERole = TOleEnum;

    const
      eConsole                              = $00000000;
      eMultimedia                           = $00000001;
      eCommunications                       = $00000002;
      ERole_enum_count                      = $00000003;

    type
      IAudioEndpointVolumeCallback = interface(IUnknown)
      ['{657804FA-D6AD-4496-8A60-352752AF4F89}']
      end;

      IAudioEndpointVolume = interface(IUnknown)
      ['{5CDF2C82-841E-4546-9722-0CF74078229A}']
        function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
        function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
        function GetChannelCount(out PInteger): Integer; stdcall;
        function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
        function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
        function GetMasterVolumeLevel(out fLevelDB: single): Integer; stdcall;
        function GetMasterVolumeLevelScaler(out fLevelDB: single): Integer; stdcall;
        function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
        function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
        function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): Integer; stdcall;
        function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): Integer; stdcall;
        function SetMute(bMute: Boolean; pguidEventContext: PGUID): Integer; stdcall;
        function GetMute(out bMute: Boolean): Integer; stdcall;
        function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): Integer; stdcall;
        function VolumeStepUp(pguidEventContext: PGUID): Integer; stdcall;
        function VolumeStepDown(pguidEventContext: PGUID): Integer; stdcall;
        function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
        function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
      end;

      IAudioMeterInformation = interface(IUnknown)
      ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
      end;

      IPropertyStore = interface(IUnknown)
      end;

      IMMDevice = interface(IUnknown)
      ['{D666063F-1587-4E43-81F1-B948E807363F}']
        function Activate(const refId: TGUID;
                          dwClsCtx: DWORD;
                          pActivationParams: PInteger;
                          out pEndpointVolume: IAudioEndpointVolume): Hresult; stdCall;
        function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): Hresult; stdcall;
        function GetId(out ppstrId: PLPWSTR): Hresult; stdcall;
        function GetState(out State: Integer): Hresult; stdcall;
      end;


      IMMDeviceCollection = interface(IUnknown)
      ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
      end;

      IMMNotificationClient = interface(IUnknown)
      ['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
      end;

      IMMDeviceEnumerator = interface(IUnknown)
      ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
        function EnumAudioEndpoints(dataFlow: EDataFlow; deviceState: SYSUINT; DevCollection: IMMDeviceCollection): Hresult; stdcall;
        function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): Hresult; stdcall;
        function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HResult; stdcall;
        function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): Hresult; stdcall;
      end;

    implementation

    end.

    ///////////////////////
    simple sample :)
    ///////////////////////

    //...... other code

    uses ... ActiveX, MMDevApi, ...;

    //...... other code

    var
      endpointVolume: IAudioEndpointVolume = nil;

    procedure TForm1.FormCreate(Sender: TObject);
    var
      deviceEnumerator: IMMDeviceEnumerator;
      defaultDevice: IMMDevice;
    begin
      CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, deviceEnumerator);
      deviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, defaultDevice);
      defaultDevice.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, endpointVolume);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
      VolumeLevel: Single;
    begin
      if endpointVolume = nil then Exit;
      VolumeLevel := 0.50;
      endpointVolume.SetMasterVolumeLevelScalar(VolumeLevel, nil);
      Caption := Format('%1.8f', [VolumeLevel])
    end;

    /////////////////////////////////////

    // with best regards ToxicDream

    Thursday, February 12, 2009 10:12 AM
  • hi Mukta, good day i just want to ask if we could add to Get/Set the microphone level? how?
    Tuesday, August 10, 2010 6:00 AM