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. :-)