ReactOS 0.4.17-dev-966-gf06eace
volume.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS system libraries
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Volume notification icon handler
5 * COPYRIGHT: Copyright 2014-2015 David Quintana <gigaherz@gmail.com>
6 * Copyright 2026 Vitaly Orekhov <vkvo2000@vivaldi.net>
7 */
8
9#include "precomp.h"
10
11#include <mmddk.h>
12
15
16HMIXER g_hMixer;
19
21
23
25{
27 UINT mixerId = 0;
28 DWORD waveOutId = 0;
29 DWORD param2 = 0;
30
31 TRACE("Volume_FindDefaultMixerID\n");
32
33 if (g_hMixer)
35 g_hMixer = NULL;
36
38 if (result)
39 return E_FAIL;
40
41 if (waveOutId == (DWORD)-1)
42 {
43 TRACE("WARNING: waveOut has no default device, trying with first available device...\n", waveOutId);
44
45 mixerId = 0;
46 }
47 else
48 {
49 TRACE("waveOut default device is %d\n", waveOutId);
50
51 result = mixerGetID((HMIXEROBJ)UlongToHandle(waveOutId), &mixerId, MIXER_OBJECTF_WAVEOUT);
52 if (result)
53 return E_FAIL;
54
55 TRACE("mixerId for waveOut default device is %d\n", mixerId);
56 }
57
58 MIXERLINE mixerLine;
59 MIXERCONTROL mixerControl;
60 MIXERLINECONTROLS mixerLineControls;
61
62 g_mixerLineID = -1;
63 g_muteControlID = -1;
64
65 result = mixerOpen(&g_hMixer, mixerId, (DWORD_PTR)pSysTray->m_hWnd, 0, MIXER_OBJECTF_HMIXER | CALLBACK_WINDOW);
66 if (result)
67 {
68 ERR("mixerOpen failed (%lu)\n", result);
69 return E_FAIL;
70 }
71
72 mixerLine.cbStruct = sizeof(mixerLine);
74
75 result = mixerGetLineInfoW((HMIXEROBJ)g_hMixer, &mixerLine,
77 if (result)
78 {
79 ERR("mixerGetLineInfoW failed (%lu)\n", result);
80 return E_FAIL;
81 }
82
83 g_mixerLineID = mixerLine.dwLineID;
84
85 mixerLineControls.cbStruct = sizeof(mixerLineControls);
86 mixerLineControls.dwLineID = mixerLine.dwLineID;
87 mixerLineControls.cControls = 1;
89 mixerLineControls.pamxctrl = &mixerControl;
90 mixerLineControls.cbmxctrl = sizeof(mixerControl);
91
93 {
94 ERR("mixerGetLineControlsW failed (%lu)\n", result);
95 return E_FAIL;
96 }
97
98 TRACE("Found control id %d for mute\n", mixerControl.dwControlID);
99
100 g_muteControlID = mixerControl.dwControlID;
101
102 return S_OK;
103}
104
106{
107 MIXERCONTROLDETAILS mixerControlDetails;
108
109 if (g_hMixer != NULL && g_muteControlID != (DWORD)-1)
110 {
111 BOOL detailsResult = 0;
112 mixerControlDetails.cbStruct = sizeof(mixerControlDetails);
113 mixerControlDetails.hwndOwner = 0;
114 mixerControlDetails.dwControlID = g_muteControlID;
115 mixerControlDetails.cChannels = 1;
116 mixerControlDetails.paDetails = &detailsResult;
117 mixerControlDetails.cbDetails = sizeof(detailsResult);
119 return E_FAIL;
120
121 TRACE("Obtained mute status %d\n", detailsResult);
122
123 g_IsMute = detailsResult != 0;
124 }
125
126 return S_OK;
127}
128
130{
131 HRESULT hr;
132 WCHAR strTooltip[128];
133
134 TRACE("Volume_Init\n");
135
136 if (!g_hMixer)
137 {
138 hr = Volume_FindMixerControl(pSysTray);
139 if (FAILED(hr))
140 return hr;
141
142 g_mmDeviceChange = RegisterWindowMessageW(L"winmm_devicechange");
143 }
144
147
149
150 HICON icon;
151 if (g_IsMute)
152 icon = g_hIconMute;
153 else
154 icon = g_hIconVolume;
155
156 LoadStringW(g_hInstance, IDS_VOL_VOLUME, strTooltip, _countof(strTooltip));
157 return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_VOLUME, icon, strTooltip);
158}
159
161{
162 BOOL PrevState;
163
164 TRACE("Volume_Update\n");
165
166 PrevState = g_IsMute;
168
169 if (PrevState != g_IsMute)
170 {
171 WCHAR strTooltip[128];
172 HICON icon;
173 if (g_IsMute)
174 {
175 icon = g_hIconMute;
176 LoadStringW(g_hInstance, IDS_VOL_MUTED, strTooltip, _countof(strTooltip));
177 }
178 else
179 {
180 icon = g_hIconVolume;
181 LoadStringW(g_hInstance, IDS_VOL_VOLUME, strTooltip, _countof(strTooltip));
182 }
183
184 return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, strTooltip);
185 }
186 else
187 {
188 return S_OK;
189 }
190}
191
193{
194 TRACE("Volume_Shutdown\n");
195
196 return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_VOLUME, NULL, NULL);
197}
198
200{
201 return Volume_FindMixerControl(pSysTray);
202}
203
204static void _RunVolume(BOOL bTray)
205{
207 NULL,
208 L"sndvol32.exe",
209 bTray ? L"/t" : NULL,
210 NULL,
212}
213
214static void _RunMMCpl()
215{
216 CSysTray::RunDll("mmsys.cpl", "");
217}
218
219static void _ShowContextMenu(CSysTray * pSysTray)
220{
221 WCHAR strAdjust[128];
222 WCHAR strOpen[128];
223 LoadStringW(g_hInstance, IDS_VOL_OPEN, strOpen, _countof(strOpen));
224 LoadStringW(g_hInstance, IDS_VOL_ADJUST, strAdjust, _countof(strAdjust));
225
226 HMENU hPopup = CreatePopupMenu();
227 AppendMenuW(hPopup, MF_STRING, IDS_VOL_OPEN, strOpen);
228 AppendMenuW(hPopup, MF_STRING, IDS_VOL_ADJUST, strAdjust);
230
232 POINT pt;
233 SetForegroundWindow(pSysTray->GetHWnd());
235
236 DWORD id = TrackPopupMenuEx(hPopup, flags,
237 pt.x, pt.y,
238 pSysTray->GetHWnd(), NULL);
239
240 DestroyMenu(hPopup);
241
242 switch (id)
243 {
244 case IDS_VOL_OPEN:
246 break;
247 case IDS_VOL_ADJUST:
248 _RunMMCpl();
249 break;
250 }
251}
252
254{
255 if (uMsg == g_mmDeviceChange)
256 return Volume_OnDeviceChange(pSysTray, wParam, lParam);
257
258 switch (uMsg)
259 {
260 case WM_USER + 220:
261 TRACE("Volume_Message: WM_USER+220\n");
263 {
264 if (lParam)
265 {
266 pSysTray->EnableService(VOLUME_SERVICE_FLAG, TRUE);
267 return Volume_Init(pSysTray);
268 }
269 else
270 {
271 pSysTray->EnableService(VOLUME_SERVICE_FLAG, FALSE);
272 return Volume_Shutdown(pSysTray);
273 }
274 }
275 return S_FALSE;
276
277 case WM_USER + 221:
278 TRACE("Volume_Message: WM_USER+221\n");
280 {
281 lResult = (LRESULT)pSysTray->IsServiceEnabled(VOLUME_SERVICE_FLAG);
282 return S_OK;
283 }
284 return S_FALSE;
285
286 case WM_TIMER:
287 if (wParam == VOLUME_TIMER_ID)
288 {
289 KillTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID);
291 }
292 break;
293
294 case ID_ICON_VOLUME:
295 TRACE("Volume_Message uMsg=%d, w=%x, l=%x\n", uMsg, wParam, lParam);
296
297 switch (lParam)
298 {
299 case WM_LBUTTONDOWN:
300 SetTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID, GetDoubleClickTime(), NULL);
301 break;
302
303 case WM_LBUTTONUP:
304 break;
305
306 case WM_LBUTTONDBLCLK:
307 KillTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID);
309 break;
310
311 case WM_RBUTTONDOWN:
312 break;
313
314 case WM_RBUTTONUP:
315 _ShowContextMenu(pSysTray);
316 break;
317
318 case WM_RBUTTONDBLCLK:
319 break;
320
321 case WM_MOUSEMOVE:
322 break;
323 }
324 return S_OK;
325
327 Volume_Update(pSysTray);
328 return S_OK;
329
330 default:
331 TRACE("Volume_Message received for unknown ID %d, ignoring.\n");
332 return S_FALSE;
333 }
334
335 return S_FALSE;
336}
HINSTANCE g_hInstance
Definition: MainWindow.cpp:18
#define ERR(fmt,...)
Definition: precomp.h:57
#define UlongToHandle(ul)
Definition: basetsd.h:91
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
HWND GetHWnd()
Definition: csystray.h:53
static void RunDll(PCSTR Dll, PCSTR Parameters)
Definition: csystray.cpp:420
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define E_FAIL
Definition: ddrawi.h:102
HRESULT hr
Definition: delayimp.cpp:582
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ID_ICON_VOLUME
Definition: precomp.h:38
#define VOLUME_TIMER_ID
Definition: precomp.h:93
#define VOLUME_SERVICE_FLAG
Definition: precomp.h:40
#define IDS_VOL_VOLUME
Definition: resource.h:33
#define IDS_VOL_ADJUST
Definition: resource.h:34
#define IDS_VOL_OPEN
Definition: resource.h:35
#define IDI_VOLMUTE
Definition: resource.h:31
#define IDI_VOLUME
Definition: resource.h:30
#define IDS_VOL_MUTED
Definition: resource.h:37
#define __stdcall
Definition: corecrt.h:120
#define pt(x, y)
Definition: drawing.c:79
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLbitfield flags
Definition: glext.h:7161
GLuint64EXT * result
Definition: glext.h:11304
unsigned int UINT
Definition: sysinfo.c:13
#define S_OK
Definition: intsafe.h:52
#define FAILED(hr)
Definition: intsafe.h:51
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
#define DRVM_MAPPER_PREFERRED_GET
Definition: mmsys.h:39
#define CALLBACK_WINDOW
Definition: mmsystem.h:148
#define MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
Definition: mmsystem.h:319
UINT MMRESULT
Definition: mmsystem.h:964
#define MIXER_OBJECTF_WAVEOUT
Definition: mmsystem.h:302
#define MIXER_GETCONTROLDETAILSF_VALUE
Definition: mmsystem.h:412
#define WAVE_MAPPER
Definition: mmsystem.h:187
#define MIXER_GETLINEINFOF_COMPONENTTYPE
Definition: mmsystem.h:347
#define MM_MIXM_LINE_CHANGE
Definition: mmsystem.h:82
#define MIXER_GETLINECONTROLSF_ONEBYTYPE
Definition: mmsystem.h:410
#define MIXER_OBJECTF_HMIXER
Definition: mmsystem.h:301
#define MIXERCONTROL_CONTROLTYPE_MUTE
Definition: mmsystem.h:384
static HICON
Definition: imagelist.c:80
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
#define _In_
Definition: no_sal2.h:158
#define MAKEINTRESOURCE(i)
Definition: ntverrsrc.c:25
#define LRESULT
Definition: ole.h:14
short WCHAR
Definition: pedump.c:58
#define SW_SHOWNORMAL
Definition: winuser.h:781
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:838
BOOL WINAPI SetMenuDefaultItem(_In_ HMENU, _In_ UINT, _In_ UINT)
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1806
#define TPM_BOTTOMALIGN
Definition: winuser.h:2421
#define MF_STRING
Definition: winuser.h:138
BOOL WINAPI SetForegroundWindow(_In_ HWND)
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:3074
#define WM_RBUTTONUP
Definition: winuser.h:1808
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1809
#define WM_MOUSEMOVE
Definition: winuser.h:1803
#define TPM_RIGHTALIGN
Definition: winuser.h:2414
#define TPM_NONOTIFY
Definition: winuser.h:2422
#define WM_LBUTTONDOWN
Definition: winuser.h:1804
BOOL WINAPI TrackPopupMenuEx(_In_ HMENU, _In_ UINT, _In_ int, _In_ int, _In_ HWND, _In_opt_ LPTPMPARAMS)
UINT WINAPI GetDoubleClickTime(void)
Definition: ntwrapper.h:314
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_RBUTTONDOWN
Definition: winuser.h:1807
#define WM_TIMER
Definition: winuser.h:1770
#define LoadIcon
Definition: winuser.h:5979
UINT WINAPI RegisterWindowMessageW(_In_ LPCWSTR)
#define WM_LBUTTONUP
Definition: winuser.h:1805
BOOL WINAPI DestroyMenu(_In_ HMENU)
#define WM_USER
Definition: winuser.h:1923
#define TPM_RETURNCMD
Definition: winuser.h:2423
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
BOOL WINAPI AppendMenuW(_In_ HMENU, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
#define LoadStringW
Definition: utils.h:64
#define NIM_DELETE
Definition: shellapi.h:96
#define NIM_MODIFY
Definition: shellapi.h:95
#define NIM_ADD
Definition: shellapi.h:94
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2787
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwComponentType
Definition: mmsystem.h:1240
DWORD dwLineID
Definition: mmsystem.h:1237
DWORD cbStruct
Definition: mmsystem.h:1234
LPMIXERCONTROLA pamxctrl
Definition: mmsystem.h:1340
uint32_t DWORD_PTR
Definition: typedefs.h:65
DWORD g_muteControlID
Definition: volume.cpp:18
HRESULT Volume_IsMute()
Definition: volume.cpp:105
static BOOL g_IsMute
Definition: volume.cpp:22
HRESULT STDMETHODCALLTYPE Volume_Init(_In_ CSysTray *pSysTray)
Definition: volume.cpp:129
UINT g_mmDeviceChange
Definition: volume.cpp:20
HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray *pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult)
Definition: volume.cpp:253
HRESULT Volume_OnDeviceChange(_In_ CSysTray *pSysTray, WPARAM wParam, LPARAM lParam)
Definition: volume.cpp:199
static void _RunVolume(BOOL bTray)
Definition: volume.cpp:204
DWORD g_mixerLineID
Definition: volume.cpp:17
HICON g_hIconVolume
Definition: volume.cpp:13
static HRESULT __stdcall Volume_FindMixerControl(CSysTray *pSysTray)
Definition: volume.cpp:24
HMIXER g_hMixer
Definition: volume.cpp:16
HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray *pSysTray)
Definition: volume.cpp:192
static void _RunMMCpl()
Definition: volume.cpp:214
static void _ShowContextMenu(CSysTray *pSysTray)
Definition: volume.cpp:219
HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray *pSysTray)
Definition: volume.cpp:160
HICON g_hIconMute
Definition: volume.cpp:14
#define S_FALSE
Definition: winerror.h:3451
UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, DWORD fdwControls)
Definition: winmm.c:571
UINT WINAPI mixerClose(HMIXER hMix)
Definition: winmm.c:386
UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, DWORD fdwDetails)
Definition: winmm.c:423
UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo)
Definition: winmm.c:592
UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
Definition: winmm.c:339
UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
Definition: winmm.c:404
UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Definition: winmm.c:2538