ReactOS  0.4.15-dev-1386-g5cb9f87
volume.cpp
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS system libraries
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: dll/shellext/stobject/volume.cpp
5  * PURPOSE: Volume notification icon handler
6  * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
7  */
8 
9 #include "precomp.h"
10 
11 #include <mmddk.h>
12 
15 
16 HMIXER g_hMixer;
20 
22 
23 static BOOL g_IsMute = FALSE;
24 
26 {
28  UINT mixerId = 0;
29  DWORD waveOutId = 0;
30  DWORD param2 = 0;
31 
32  TRACE("Volume_FindDefaultMixerID\n");
33 
35  if (result)
36  return E_FAIL;
37 
38  if (waveOutId == (DWORD)-1)
39  {
40  TRACE("WARNING: waveOut has no default device, trying with first available device...\n", waveOutId);
41 
42  mixerId = 0;
43  }
44  else
45  {
46  TRACE("waveOut default device is %d\n", waveOutId);
47 
48  result = mixerGetID((HMIXEROBJ)UlongToHandle(waveOutId), &mixerId, MIXER_OBJECTF_WAVEOUT);
49  if (result)
50  return E_FAIL;
51 
52  TRACE("mixerId for waveOut default device is %d\n", mixerId);
53  }
54 
55  g_mixerId = mixerId;
56  return S_OK;
57 
58  MIXERCAPS mixerCaps;
59  MIXERLINE mixerLine;
60  MIXERCONTROL mixerControl;
61  MIXERLINECONTROLS mixerLineControls;
62 
63  g_mixerLineID = -1;
64  g_muteControlID = -1;
65 
66  if (mixerGetDevCapsW(g_mixerId, &mixerCaps, sizeof(mixerCaps)))
67  return E_FAIL;
68 
69  if (mixerCaps.cDestinations == 0)
70  return S_FALSE;
71 
72  TRACE("mixerCaps.cDestinations %d\n", mixerCaps.cDestinations);
73 
74  DWORD idx;
75  for (idx = 0; idx < mixerCaps.cDestinations; idx++)
76  {
77  mixerLine.cbStruct = sizeof(mixerLine);
78  mixerLine.dwDestination = idx;
79  if (!mixerGetLineInfoW((HMIXEROBJ)UlongToHandle(g_mixerId), &mixerLine, 0))
80  {
83  break;
84  TRACE("Destination %d was not speakers or headphones.\n");
85  }
86  }
87 
88  if (idx >= mixerCaps.cDestinations)
89  return E_FAIL;
90 
91  TRACE("Valid destination %d found.\n");
92 
93  g_mixerLineID = mixerLine.dwLineID;
94 
95  mixerLineControls.cbStruct = sizeof(mixerLineControls);
96  mixerLineControls.dwLineID = mixerLine.dwLineID;
97  mixerLineControls.cControls = 1;
98  mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
99  mixerLineControls.pamxctrl = &mixerControl;
100  mixerLineControls.cbmxctrl = sizeof(mixerControl);
101 
103  return E_FAIL;
104 
105  TRACE("Found control id %d for mute: %d\n", mixerControl.dwControlID);
106 
107  g_muteControlID = mixerControl.dwControlID;
108 
109  return S_OK;
110 }
111 
113 {
114 #if 0
115  MIXERCONTROLDETAILS mixerControlDetails;
116 
117  if (g_mixerId != (UINT)-1 && g_muteControlID != (DWORD)-1)
118  {
119  BOOL detailsResult = 0;
120  mixerControlDetails.cbStruct = sizeof(mixerControlDetails);
121  mixerControlDetails.hwndOwner = 0;
122  mixerControlDetails.dwControlID = g_muteControlID;
123  mixerControlDetails.cChannels = 1;
124  mixerControlDetails.paDetails = &detailsResult;
125  mixerControlDetails.cbDetails = sizeof(detailsResult);
126  if (mixerGetControlDetailsW((HMIXEROBJ) g_mixerId, &mixerControlDetails, 0))
127  return E_FAIL;
128 
129  TRACE("Obtained mute status %d\n", detailsResult);
130 
131  g_IsMute = detailsResult != 0;
132  }
133 #endif
134  return S_OK;
135 }
136 
138 {
139  HRESULT hr;
140  WCHAR strTooltip[128];
141 
142  TRACE("Volume_Init\n");
143 
144  if (!g_hMixer)
145  {
146  hr = Volume_FindMixerControl(pSysTray);
147  if (FAILED(hr))
148  return hr;
149 
150  g_mmDeviceChange = RegisterWindowMessageW(L"winmm_devicechange");
151  }
152 
155 
156  Volume_IsMute();
157 
158  HICON icon;
159  if (g_IsMute)
160  icon = g_hIconMute;
161  else
162  icon = g_hIconVolume;
163 
164  LoadStringW(g_hInstance, IDS_VOL_VOLUME, strTooltip, _countof(strTooltip));
165  return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_VOLUME, icon, strTooltip);
166 }
167 
169 {
170  BOOL PrevState;
171 
172  TRACE("Volume_Update\n");
173 
174  PrevState = g_IsMute;
175  Volume_IsMute();
176 
177  if (PrevState != g_IsMute)
178  {
179  WCHAR strTooltip[128];
180  HICON icon;
181  if (g_IsMute)
182  {
183  icon = g_hIconMute;
184  LoadStringW(g_hInstance, IDS_VOL_MUTED, strTooltip, _countof(strTooltip));
185  }
186  else
187  {
188  icon = g_hIconVolume;
189  LoadStringW(g_hInstance, IDS_VOL_VOLUME, strTooltip, _countof(strTooltip));
190  }
191 
192  return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, strTooltip);
193  }
194  else
195  {
196  return S_OK;
197  }
198 }
199 
201 {
202  TRACE("Volume_Shutdown\n");
203 
204  return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_VOLUME, NULL, NULL);
205 }
206 
208 {
209  return Volume_FindMixerControl(pSysTray);
210 }
211 
212 static void _RunVolume(BOOL bTray)
213 {
215  NULL,
216  L"sndvol32.exe",
217  bTray ? L"/t" : NULL,
218  NULL,
219  SW_SHOWNORMAL);
220 }
221 
222 static void _RunMMCpl()
223 {
224  ShellExecuteW(NULL, NULL, L"mmsys.cpl", NULL, NULL, SW_NORMAL);
225 }
226 
227 static void _ShowContextMenu(CSysTray * pSysTray)
228 {
229  WCHAR strAdjust[128];
230  WCHAR strOpen[128];
231  LoadStringW(g_hInstance, IDS_VOL_OPEN, strOpen, _countof(strOpen));
232  LoadStringW(g_hInstance, IDS_VOL_ADJUST, strAdjust, _countof(strAdjust));
233 
234  HMENU hPopup = CreatePopupMenu();
235  AppendMenuW(hPopup, MF_STRING, IDS_VOL_OPEN, strOpen);
236  AppendMenuW(hPopup, MF_STRING, IDS_VOL_ADJUST, strAdjust);
238 
240  POINT pt;
241  SetForegroundWindow(pSysTray->GetHWnd());
242  GetCursorPos(&pt);
243 
244  DWORD id = TrackPopupMenuEx(hPopup, flags,
245  pt.x, pt.y,
246  pSysTray->GetHWnd(), NULL);
247 
248  DestroyMenu(hPopup);
249 
250  switch (id)
251  {
252  case IDS_VOL_OPEN:
253  _RunVolume(FALSE);
254  break;
255  case IDS_VOL_ADJUST:
256  _RunMMCpl();
257  break;
258  }
259 }
260 
262 {
263  if (uMsg == g_mmDeviceChange)
264  return Volume_OnDeviceChange(pSysTray, wParam, lParam);
265 
266  switch (uMsg)
267  {
268  case WM_USER + 220:
269  TRACE("Volume_Message: WM_USER+220\n");
271  {
272  if (lParam)
273  {
274  pSysTray->EnableService(VOLUME_SERVICE_FLAG, TRUE);
275  return Volume_Init(pSysTray);
276  }
277  else
278  {
279  pSysTray->EnableService(VOLUME_SERVICE_FLAG, FALSE);
280  return Volume_Shutdown(pSysTray);
281  }
282  }
283  return S_FALSE;
284 
285  case WM_USER + 221:
286  TRACE("Volume_Message: WM_USER+221\n");
288  {
289  lResult = (LRESULT)pSysTray->IsServiceEnabled(VOLUME_SERVICE_FLAG);
290  return S_OK;
291  }
292  return S_FALSE;
293 
294  case WM_TIMER:
295  if (wParam == VOLUME_TIMER_ID)
296  {
297  KillTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID);
298  _RunVolume(TRUE);
299  }
300  break;
301 
302  case ID_ICON_VOLUME:
303  TRACE("Volume_Message uMsg=%d, w=%x, l=%x\n", uMsg, wParam, lParam);
304 
305  Volume_Update(pSysTray);
306 
307  switch (lParam)
308  {
309  case WM_LBUTTONDOWN:
310  SetTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID, GetDoubleClickTime(), NULL);
311  break;
312 
313  case WM_LBUTTONUP:
314  break;
315 
316  case WM_LBUTTONDBLCLK:
317  KillTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID);
318  _RunVolume(FALSE);
319  break;
320 
321  case WM_RBUTTONDOWN:
322  break;
323 
324  case WM_RBUTTONUP:
325  _ShowContextMenu(pSysTray);
326  break;
327 
328  case WM_RBUTTONDBLCLK:
329  break;
330 
331  case WM_MOUSEMOVE:
332  break;
333  }
334  return S_OK;
335 
336  default:
337  TRACE("Volume_Message received for unknown ID %d, ignoring.\n");
338  return S_FALSE;
339  }
340 
341  return S_FALSE;
342 }
#define MAKEINTRESOURCE
Definition: winuser.h:591
#define SW_NORMAL
Definition: winuser.h:763
static HICON
Definition: imagelist.c:84
#define IDI_VOLMUTE
Definition: resource.h:30
#define WM_LBUTTONDOWN
Definition: winuser.h:1758
UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo)
Definition: winmm.c:595
#define DRVM_MAPPER_PREFERRED_GET
Definition: mmsys.h:37
HRESULT hr
Definition: shlfolder.c:183
UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, DWORD fdwDetails)
Definition: winmm.c:426
GLuint64EXT * result
Definition: glext.h:11304
UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Definition: winmm.c:2541
HRESULT Volume_IsMute()
Definition: volume.cpp:112
#define TRUE
Definition: types.h:120
#define pt(x, y)
Definition: drawing.c:79
#define TPM_RETURNCMD
Definition: winuser.h:2362
BOOL WINAPI TrackPopupMenuEx(_In_ HMENU, _In_ UINT, _In_ int, _In_ int, _In_ HWND, _In_opt_ LPTPMPARAMS)
#define MF_STRING
Definition: winuser.h:138
#define IDS_VOL_ADJUST
Definition: resource.h:33
#define IDS_VOL_VOLUME
Definition: resource.h:32
UINT MMRESULT
Definition: mmsystem.h:962
UINT g_mmDeviceChange
Definition: volume.cpp:21
UINT_PTR WPARAM
Definition: windef.h:207
static HRESULT __stdcall Volume_FindMixerControl(CSysTray *pSysTray)
Definition: volume.cpp:25
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2635
#define E_FAIL
Definition: ddrawi.h:102
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
WPARAM wParam
Definition: combotst.c:138
HICON g_hIconMute
Definition: volume.cpp:14
BOOL WINAPI AppendMenuW(_In_ HMENU, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
UINT g_mixerId
Definition: volume.cpp:17
#define FALSE
Definition: types.h:117
LPMIXERCONTROLA pamxctrl
Definition: mmsystem.h:1338
HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray *pSysTray)
Definition: volume.cpp:168
unsigned int BOOL
Definition: ntddk_ex.h:94
#define ID_ICON_VOLUME
Definition: precomp.h:38
DWORD g_mixerLineID
Definition: volume.cpp:18
unsigned int idx
Definition: utils.c:41
#define S_FALSE
Definition: winerror.h:2357
#define TPM_BOTTOMALIGN
Definition: winuser.h:2360
LONG_PTR LPARAM
Definition: windef.h:208
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_RBUTTONDOWN
Definition: winuser.h:1761
DWORD dwLineID
Definition: mmsystem.h:1235
#define TRACE(s)
Definition: solgame.cpp:4
#define WAVE_MAPPER
Definition: mmsystem.h:187
#define VOLUME_TIMER_ID
Definition: precomp.h:78
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define VOLUME_SERVICE_FLAG
Definition: precomp.h:39
LONG HRESULT
Definition: typedefs.h:79
#define UlongToHandle(ul)
Definition: basetsd.h:97
#define _countof(array)
Definition: sndvol32.h:68
#define WM_TIMER
Definition: winuser.h:1724
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
unsigned long DWORD
Definition: ntddk_ex.h:95
#define NIM_DELETE
Definition: shellapi.h:93
#define __stdcall
Definition: typedefs.h:25
HRESULT Volume_OnDeviceChange(_In_ CSysTray *pSysTray, WPARAM wParam, LPARAM lParam)
Definition: volume.cpp:207
#define WM_RBUTTONUP
Definition: winuser.h:1762
#define TPM_NONOTIFY
Definition: winuser.h:2361
GLbitfield flags
Definition: glext.h:7161
static BOOL g_IsMute
Definition: volume.cpp:23
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, DWORD fdwControls)
Definition: winmm.c:574
static void _RunVolume(BOOL bTray)
Definition: volume.cpp:212
static const WCHAR L[]
Definition: oid.c:1250
#define MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
Definition: mmsystem.h:320
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1760
UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
Definition: winmm.c:317
#define LRESULT
Definition: ole.h:14
#define MIXER_OBJECTF_WAVEOUT
Definition: mmsystem.h:302
uint32_t DWORD_PTR
Definition: typedefs.h:65
#define WM_USER
Definition: winuser.h:1877
DWORD g_muteControlID
Definition: volume.cpp:19
BOOL WINAPI DestroyMenu(_In_ HMENU)
#define _In_
Definition: no_sal2.h:158
UINT WINAPI RegisterWindowMessageW(_In_ LPCWSTR)
#define S_OK
Definition: intsafe.h:51
#define SW_SHOWNORMAL
Definition: winuser.h:764
#define MIXERCONTROL_CONTROLTYPE_MUTE
Definition: mmsystem.h:384
DWORD dwDestination
Definition: mmsystem.h:1233
HICON g_hIconVolume
Definition: volume.cpp:13
DWORD cDestinations
Definition: mmsystem.h:1219
#define MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
Definition: mmsystem.h:319
DWORD cbStruct
Definition: mmsystem.h:1232
#define WM_LBUTTONUP
Definition: winuser.h:1759
HRESULT STDMETHODCALLTYPE Volume_Init(_In_ CSysTray *pSysTray)
Definition: volume.cpp:137
HWND GetHWnd()
Definition: csystray.h:53
unsigned int UINT
Definition: ndis.h:50
#define WM_MOUSEMOVE
Definition: winuser.h:1757
#define NULL
Definition: types.h:112
#define IDS_VOL_MUTED
Definition: resource.h:36
#define MIXER_GETLINECONTROLSF_ONEBYTYPE
Definition: mmsystem.h:410
BOOL WINAPI SetMenuDefaultItem(_In_ HMENU, _In_ UINT, _In_ UINT)
HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray *pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult)
Definition: volume.cpp:261
#define NIM_ADD
Definition: shellapi.h:91
DWORD dwComponentType
Definition: mmsystem.h:1238
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:846
static void _RunMMCpl()
Definition: volume.cpp:222
HMIXER g_hMixer
Definition: volume.cpp:16
UINT WINAPI GetDoubleClickTime(void)
Definition: ntwrapper.h:314
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1763
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2274
BOOL WINAPI SetForegroundWindow(_In_ HWND)
HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray *pSysTray)
Definition: volume.cpp:200
#define IDS_VOL_OPEN
Definition: resource.h:34
#define LoadIcon
Definition: winuser.h:5788
HINSTANCE g_hInstance
Definition: MainWindow.cpp:18
LONG_PTR LRESULT
Definition: windef.h:209
#define IDI_VOLUME
Definition: resource.h:29
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
static void _ShowContextMenu(CSysTray *pSysTray)
Definition: volume.cpp:227
LPARAM lParam
Definition: combotst.c:139
UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
Definition: winmm.c:407
#define TPM_RIGHTALIGN
Definition: winuser.h:2353
#define NIM_MODIFY
Definition: shellapi.h:92