2 * ReactOS Sound Volume Control
3 * Copyright (C) 2004-2005 Thomas Weidenmueller
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Sound Volume Control
23 * FILE: subsys/system/sndvol32/sndvol32.c
24 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
28 HINSTANCE hAppInstance
;
34 #define GetDialogData(hwndDlg, type) \
35 ( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER)
36 #define GetWindowData(hwnd, type) \
37 ( P##type )GetWindowLongPtr((hwnd), GWL_USERDATA)
39 /******************************************************************************/
41 typedef struct _PREFERENCES_CONTEXT
43 PMIXER_WINDOW MixerWindow
;
52 TCHAR DeviceName
[128];
55 } PREFERENCES_CONTEXT
, *PPREFERENCES_CONTEXT
;
57 typedef struct _PREFERENCES_FILL_DEVICES
59 PPREFERENCES_CONTEXT PrefContext
;
62 } PREFERENCES_FILL_DEVICES
, *PPREFERENCES_FILL_DEVICES
;
65 FillDeviceComboBox(PSND_MIXER Mixer
,
71 PPREFERENCES_FILL_DEVICES FillContext
= (PPREFERENCES_FILL_DEVICES
)Context
;
73 UNREFERENCED_PARAMETER(Mixer
);
75 lres
= SendMessage(FillContext
->hComboBox
,
81 /* save the index so we don't screw stuff when the combobox is sorted... */
82 SendMessage(FillContext
->hComboBox
,
87 if (Id
== FillContext
->Selected
)
89 SendMessage(FillContext
->hComboBox
,
100 PrefDlgAddLine(PSND_MIXER Mixer
,
102 UINT DisplayControls
,
105 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
107 UNREFERENCED_PARAMETER(Mixer
);
108 UNREFERENCED_PARAMETER(DisplayControls
);
110 switch (Line
->dwComponentType
)
112 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
:
113 if (PrefContext
->PlaybackID
== (DWORD
)-1)
115 PrefContext
->PlaybackID
= Line
->dwLineID
;
117 if (PrefContext
->SelectedLine
== (DWORD
)-1)
119 PrefContext
->SelectedLine
= Line
->dwLineID
;
123 goto AddToOthersLines
;
127 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN
:
128 if (PrefContext
->RecordingID
== (DWORD
)-1)
130 PrefContext
->RecordingID
= Line
->dwLineID
;
132 if (PrefContext
->SelectedLine
== (DWORD
)-1)
134 PrefContext
->SelectedLine
= Line
->dwLineID
;
138 goto AddToOthersLines
;
147 if (PrefContext
->SelectedLine
== (DWORD
)-1)
149 PrefContext
->SelectedLine
= Line
->dwLineID
;
153 hwndCbOthers
= GetDlgItem(PrefContext
->hwndDlg
,
156 lres
= SendMessage(hwndCbOthers
,
159 (LPARAM
)Line
->szName
);
162 SendMessage(hwndCbOthers
,
167 PrefContext
->OtherLines
++;
177 PrefDlgAddConnection(PSND_MIXER Mixer
,
182 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
187 UNREFERENCED_PARAMETER(Mixer
);
188 UNREFERENCED_PARAMETER(LineID
);
190 if (Line
->cControls
!= 0)
192 hwndControls
= GetDlgItem(PrefContext
->hwndDlg
,
195 lvi
.mask
= LVIF_TEXT
| LVIF_PARAM
;
196 lvi
.iItem
= PrefContext
->tmp
++;
198 lvi
.pszText
= Line
->szName
;
199 lvi
.lParam
= (LPARAM
)Line
->dwSource
;
201 i
= SendMessage(hwndControls
,
207 TCHAR LineName
[MIXER_LONG_NAME_CHARS
];
209 BOOL SelLine
= FALSE
;
211 if (SndMixerGetLineName(PrefContext
->Mixer
,
212 PrefContext
->SelectedLine
,
214 MIXER_LONG_NAME_CHARS
,
217 LineName
[0] = TEXT('\0');
220 if (ReadLineConfig(PrefContext
->DeviceName
,
231 ListView_SetCheckState(hwndControls
,
241 UpdatePrefDlgControls(PPREFERENCES_CONTEXT Context
,
244 INT OldID
, MixerID
= 0;
247 /* select the mixer */
248 DeviceCbIndex
= SendDlgItemMessage(Context
->hwndDlg
,
253 if (DeviceCbIndex
!= CB_ERR
)
255 MixerID
= SendDlgItemMessage(Context
->hwndDlg
,
260 if (MixerID
== CB_ERR
)
266 OldID
= Context
->Selected
;
267 if (MixerID
!= OldID
&&
268 SndMixerSelect(Context
->Mixer
,
271 Context
->Selected
= SndMixerGetSelection(Context
->Mixer
);
273 /* update the controls */
274 Context
->PlaybackID
= (DWORD
)-1;
275 Context
->RecordingID
= (DWORD
)-1;
276 Context
->OtherLines
= 0;
277 Context
->SelectedLine
= (DWORD
)-1;
279 SndMixerGetProductName(Context
->Mixer
,
281 sizeof(Context
->DeviceName
) / sizeof(Context
->DeviceName
[0]));
283 if (SndMixerEnumLines(Context
->Mixer
,
289 /* enable/disable controls and make default selection */
290 EnableWindow(GetDlgItem(Context
->hwndDlg
,
292 Context
->PlaybackID
!= (DWORD
)-1);
293 CheckDlgButton(Context
->hwndDlg
,
295 (Context
->PlaybackID
!= (DWORD
)-1 && SelBox
++ == 0) ?
296 BST_CHECKED
: BST_UNCHECKED
);
298 EnableWindow(GetDlgItem(Context
->hwndDlg
,
300 Context
->RecordingID
!= (DWORD
)-1);
301 CheckDlgButton(Context
->hwndDlg
,
303 (Context
->RecordingID
!= (DWORD
)-1 && SelBox
++ == 0) ?
304 BST_CHECKED
: BST_UNCHECKED
);
306 if (Context
->OtherLines
!= 0)
308 /* select the first item in the other lines combo box by default */
309 SendDlgItemMessage(Context
->hwndDlg
,
315 EnableWindow(GetDlgItem(Context
->hwndDlg
,
318 EnableWindow(GetDlgItem(Context
->hwndDlg
,
320 Context
->OtherLines
!= 0);
321 CheckDlgButton(Context
->hwndDlg
,
323 (Context
->OtherLines
!= 0 && SelBox
++ == 0) ?
324 BST_CHECKED
: BST_UNCHECKED
);
326 /* disable the OK button if the device doesn't have any lines */
327 EnableWindow(GetDlgItem(Context
->hwndDlg
,
329 Context
->PlaybackID
!= (DWORD
)-1 ||
330 Context
->RecordingID
!= (DWORD
)-1 ||
331 Context
->OtherLines
!= 0);
333 LineID
= Context
->SelectedLine
;
337 /* update the line sources list */
338 if ((MixerID
!= OldID
&& Context
->SelectedLine
!= (DWORD
)-1) ||
339 (Context
->SelectedLine
!= LineID
&& LineID
!= (DWORD
)-1))
341 Context
->SelectedLine
= LineID
;
343 (void)ListView_DeleteAllItems(GetDlgItem(Context
->hwndDlg
,
347 SndMixerEnumConnections(Context
->Mixer
,
349 PrefDlgAddConnection
,
354 static INT_PTR CALLBACK
355 DlgPreferencesProc(HWND hwndDlg
,
360 PPREFERENCES_CONTEXT Context
;
366 Context
= GetDialogData(hwndDlg
,
367 PREFERENCES_CONTEXT
);
368 switch (LOWORD(wParam
))
370 case IDC_MIXERDEVICE
:
372 if (HIWORD(wParam
) == CBN_SELCHANGE
)
374 UpdatePrefDlgControls(Context
,
382 if (HIWORD(wParam
) == CBN_SELCHANGE
)
387 Index
= SendDlgItemMessage(hwndDlg
,
394 LineID
= SendDlgItemMessage(hwndDlg
,
399 if (LineID
!= CB_ERR
)
401 UpdatePrefDlgControls(Context
,
411 UpdatePrefDlgControls(Context
,
412 Context
->PlaybackID
);
413 EnableWindow(GetDlgItem(hwndDlg
,
421 UpdatePrefDlgControls(Context
,
422 Context
->RecordingID
);
423 EnableWindow(GetDlgItem(hwndDlg
,
434 EnableWindow(GetDlgItem(hwndDlg
,
438 LineCbIndex
= SendDlgItemMessage(hwndDlg
,
443 if (LineCbIndex
!= CB_ERR
)
445 LineID
= SendDlgItemMessage(hwndDlg
,
450 if (LineID
!= CB_ERR
)
452 UpdatePrefDlgControls(Context
,
470 case MM_MIXM_LINE_CHANGE
:
472 DPRINT("MM_MIXM_LINE_CHANGE\n");
476 case MM_MIXM_CONTROL_CHANGE
:
478 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
484 PREFERENCES_FILL_DEVICES FillDevContext
;
489 SetWindowLongPtr(hwndDlg
,
492 Context
= (PPREFERENCES_CONTEXT
)((LONG_PTR
)lParam
);
493 Context
->hwndDlg
= hwndDlg
;
494 Context
->Mixer
= SndMixerCreate(hwndDlg
);
495 Context
->Selected
= (UINT
)-1;
497 FillDevContext
.PrefContext
= Context
;
498 FillDevContext
.hComboBox
= GetDlgItem(hwndDlg
,
500 FillDevContext
.Selected
= SndMixerGetSelection(Context
->Mixer
);
501 SndMixerEnumProducts(Context
->Mixer
,
505 /* initialize the list view control */
506 hwndControls
= GetDlgItem(hwndDlg
,
508 (void)ListView_SetExtendedListViewStyle(hwndControls
,
511 GetClientRect(hwndControls
,
513 lvc
.mask
= LVCF_TEXT
| LVCF_WIDTH
;
514 lvc
.pszText
= TEXT("");
515 lvc
.cx
= rcClient
.right
;
516 SendMessage(hwndControls
,
521 /* update all controls */
522 UpdatePrefDlgControls(Context
,
529 Context
= GetDialogData(hwndDlg
,
530 PREFERENCES_CONTEXT
);
531 if (Context
->Mixer
!= NULL
)
533 SndMixerDestroy(Context
->Mixer
);
549 /******************************************************************************/
552 DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow
)
554 UNREFERENCED_PARAMETER(MixerWindow
);
558 RebuildMixerWindowControls(PMIXER_WINDOW MixerWindow
)
560 DeleteMixerWindowControls(MixerWindow
);
565 static LRESULT CALLBACK
566 MainWindowProc(HWND hwnd
,
571 PMIXER_WINDOW MixerWindow
;
578 MixerWindow
= GetWindowData(hwnd
,
581 switch (LOWORD(wParam
))
585 PREFERENCES_CONTEXT Preferences
;
587 Preferences
.MixerWindow
= MixerWindow
;
588 Preferences
.Mixer
= NULL
;
590 if (DialogBoxParam(hAppInstance
,
591 MAKEINTRESOURCE(IDD_PREFERENCES
),
594 (LPARAM
)&Preferences
) == IDOK
)
596 /* FIXME - update window */
609 HICON hAppIcon
= (HICON
)GetClassLongPtrW(hwnd
,
621 case MM_MIXM_LINE_CHANGE
:
623 DPRINT("MM_MIXM_LINE_CHANGE\n");
627 case MM_MIXM_CONTROL_CHANGE
:
629 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
635 MixerWindow
= ((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
636 SetWindowLongPtr(hwnd
,
638 (LONG_PTR
)MixerWindow
);
639 MixerWindow
->hWnd
= hwnd
;
640 MixerWindow
->hStatusBar
= CreateStatusWindow(WS_VISIBLE
| WS_CHILD
| WS_CLIPSIBLINGS
,
644 if (MixerWindow
->hStatusBar
!= NULL
)
646 MixerWindow
->Mixer
= SndMixerCreate(MixerWindow
->hWnd
);
647 if (MixerWindow
->Mixer
!= NULL
)
649 TCHAR szProduct
[MAXPNAMELEN
];
651 if (SndMixerGetProductName(MixerWindow
->Mixer
,
653 sizeof(szProduct
) / sizeof(szProduct
[0])) > 0)
655 SendMessage(MixerWindow
->hStatusBar
,
661 if (!RebuildMixerWindowControls(MixerWindow
))
663 DPRINT("Rebuilding mixer window controls failed!\n");
664 SndMixerDestroy(MixerWindow
->Mixer
);
665 MixerWindow
->Mixer
= NULL
;
676 DPRINT("Failed to create status window!\n");
684 MixerWindow
= GetWindowData(hwnd
,
686 if (MixerWindow
->Mixer
!= NULL
)
688 SndMixerDestroy(MixerWindow
->Mixer
);
701 Result
= DefWindowProc(hwnd
,
713 RegisterApplicationClasses(VOID
)
717 wc
.cbSize
= sizeof(WNDCLASSEX
);
718 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
719 wc
.lpfnWndProc
= MainWindowProc
;
721 wc
.cbWndExtra
= sizeof(PMIXER_WINDOW
);
722 wc
.hInstance
= hAppInstance
;
723 wc
.hIcon
= LoadIcon(hAppInstance
,
724 MAKEINTRESOURCE(IDI_MAINAPP
));
725 wc
.hCursor
= LoadCursor(NULL
,
727 wc
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
728 wc
.lpszMenuName
= NULL
;
729 wc
.lpszClassName
= SZ_APP_CLASS
;
731 MainWindowClass
= RegisterClassEx(&wc
);
733 return MainWindowClass
!= 0;
737 UnregisterApplicationClasses(VOID
)
739 UnregisterClass(SZ_APP_CLASS
,
744 CreateApplicationWindow(VOID
)
748 PMIXER_WINDOW MixerWindow
= HeapAlloc(hAppHeap
,
750 sizeof(MIXER_WINDOW
));
751 if (MixerWindow
== NULL
)
756 if (mixerGetNumDevs() > 0)
758 hWnd
= CreateWindowEx(WS_EX_WINDOWEDGE
| WS_EX_CONTROLPARENT
,
761 WS_DLGFRAME
| WS_CAPTION
| WS_MINIMIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VISIBLE
,
762 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
764 LoadMenu(hAppInstance
,
765 MAKEINTRESOURCE(IDM_MAINMENU
)),
774 * no mixer devices are available!
778 if (AllocAndLoadString(&lpErrMessage
,
786 LocalFree(lpErrMessage
);
801 _tWinMain(HINSTANCE hInstance
,
802 HINSTANCE hPrevInstance
,
809 UNREFERENCED_PARAMETER(hPrevInstance
);
810 UNREFERENCED_PARAMETER(lpszCmdLine
);
811 UNREFERENCED_PARAMETER(nCmdShow
);
813 hAppInstance
= hInstance
;
814 hAppHeap
= GetProcessHeap();
818 /* load the application title */
819 if (!AllocAndLoadString(&lpAppTitle
,
826 InitCommonControls();
828 if (RegisterApplicationClasses())
830 hMainWnd
= CreateApplicationWindow();
831 if (hMainWnd
!= NULL
)
834 while ((bRet
=GetMessage(&Msg
,
841 TranslateMessage(&Msg
);
842 DispatchMessage(&Msg
);
846 DestroyWindow(hMainWnd
);
851 DPRINT("Failed to create application window (LastError: %d)!\n", GetLastError());
854 UnregisterApplicationClasses();
858 DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError());
861 if (lpAppTitle
!= NULL
)
863 LocalFree(lpAppTitle
);
870 DPRINT("Unable to open the Volume Control registry key!\n");