79350925

Date: 2025-01-13 00:11:43
Score: 0.5
Natty:
Report link

Thank you for your brilliant answer RRUZ! :-)
It's certainly not easy to work with the Windows Audio SDK in Delphi.
So I have modified the code slightly to make it easier to use as a volume control in a Delphi application...
See the Unit below >>

unit VolApiU;

// Original Api code from : https://stackoverflow.com/questions/17612666/controlling-the-master-speaker-volume-in-windows-7
// Thank you "RRUZ"!   :-)

interface

uses
  SysUtils, Windows, ActiveX, ComObj;

// Published functions
procedure InitVol;
procedure CloseVol;
procedure SetMasterVolume(VolP: integer);
function GetMasterVolume: integer;

implementation

const
  CLASS_IMMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
  IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
  IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';

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

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


var
  pEndpointVolume: IAudioEndpointVolume;


procedure InitVol;
var
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev: IMMDevice;
begin
  try
    CoInitialize(nil);
  except
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
  end;

  if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
    RaiseLastWin32Error;

  if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint($00000000, $00000000, Dev)) then
    RaiseLastWin32Error;

  if not Succeeded( Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
    RaiseLastWin32Error;
end;


procedure CloseVol;
begin
  try
    CoUninitialize;
  except
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
  end;
end;


procedure SetMasterVolume(VolP: integer); // 0 - 100
var
  fLevelSc: single;  // 0.0 - 1.0
begin
  fLevelSc := VolP / 100;

  if not Succeeded(pEndpointVolume.SetMasterVolumeLevelScalar(fLevelSc, nil)) then
    RaiseLastWin32Error;
end;


function GetMasterVolume: integer;  // 0 - 100
var
  fLevelSc: single; // 0.0 - 1.0
begin
  if not Succeeded(pEndpointVolume.GetMasterVolumeLevelScalar(fLevelSc)) then
    RaiseLastWin32Error;

  Result := Round(fLevelSc * 100);
end;


end.

Using this unit; here is an easy example of how to use it to control the master volume.
It is a Form with a Edit and TrackBar on it (set the Max = 100) >>

unit VolTestU;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    TrackBar1: TTrackBar;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1: TForm1;

implementation

{$R *.DFM}

uses VolApiU;


procedure TForm1.FormCreate(Sender: TObject);
begin
  VolApiU.InitVol;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  VolP : integer; // Volume in Precentage 0 - 100%
begin
   VolP := VolApiU.GetMasterVolume; // Get the volume 0 - 100
   TrackBar1.Position := VolP;
   Edit1.Text := IntToStr(VolP);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  VolApiU.CloseVol;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  VolApiU.SetMasterVolume(TrackBar1.Position); // Set the volume  0 - 100
  Edit1.Text := IntToStr(TrackBar1.Position);
end;

end.

Hope someone finds it useful. :-)

Reasons:
  • Blacklisted phrase (0.5): Thank you
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: Johan