[CMAKE]
[reactos.git] / base / applications / sndvol32 / sndvol32.c
1 /*
2 * ReactOS Sound Volume Control
3 * Copyright (C) 2004-2005 Thomas Weidenmueller
4 *
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.
9 *
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.
14 *
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
18 */
19 /* $Id$
20 *
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>
25 */
26 #include <sndvol32.h>
27
28 HINSTANCE hAppInstance;
29 ATOM MainWindowClass;
30 HWND hMainWnd;
31 HANDLE hAppHeap;
32 LPTSTR lpAppTitle;
33
34 #define GetDialogData(hwndDlg, type) \
35 ( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER)
36 #define GetWindowData(hwnd, type) \
37 ( P##type )GetWindowLongPtr((hwnd), GWL_USERDATA)
38
39 /******************************************************************************/
40
41 typedef struct _PREFERENCES_CONTEXT
42 {
43 PMIXER_WINDOW MixerWindow;
44 PSND_MIXER Mixer;
45 HWND hwndDlg;
46
47 UINT Selected;
48 DWORD SelectedLine;
49 DWORD PlaybackID;
50 DWORD RecordingID;
51 UINT OtherLines;
52 TCHAR DeviceName[128];
53
54 DWORD tmp;
55 } PREFERENCES_CONTEXT, *PPREFERENCES_CONTEXT;
56
57 typedef struct _PREFERENCES_FILL_DEVICES
58 {
59 PPREFERENCES_CONTEXT PrefContext;
60 HWND hComboBox;
61 UINT Selected;
62 } PREFERENCES_FILL_DEVICES, *PPREFERENCES_FILL_DEVICES;
63
64 static BOOL CALLBACK
65 FillDeviceComboBox(PSND_MIXER Mixer,
66 UINT Id,
67 LPCTSTR ProductName,
68 PVOID Context)
69 {
70 LRESULT lres;
71 PPREFERENCES_FILL_DEVICES FillContext = (PPREFERENCES_FILL_DEVICES)Context;
72
73 UNREFERENCED_PARAMETER(Mixer);
74
75 lres = SendMessage(FillContext->hComboBox,
76 CB_ADDSTRING,
77 0,
78 (LPARAM)ProductName);
79 if (lres != CB_ERR)
80 {
81 /* save the index so we don't screw stuff when the combobox is sorted... */
82 SendMessage(FillContext->hComboBox,
83 CB_SETITEMDATA,
84 (WPARAM)lres,
85 Id);
86
87 if (Id == FillContext->Selected)
88 {
89 SendMessage(FillContext->hComboBox,
90 CB_SETCURSEL,
91 (WPARAM)lres,
92 0);
93 }
94 }
95
96 return TRUE;
97 }
98
99 static BOOL CALLBACK
100 PrefDlgAddLine(PSND_MIXER Mixer,
101 LPMIXERLINE Line,
102 UINT DisplayControls,
103 PVOID Context)
104 {
105 PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
106
107 UNREFERENCED_PARAMETER(Mixer);
108 UNREFERENCED_PARAMETER(DisplayControls);
109
110 switch (Line->dwComponentType)
111 {
112 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
113 if (PrefContext->PlaybackID == (DWORD)-1)
114 {
115 PrefContext->PlaybackID = Line->dwLineID;
116
117 if (PrefContext->SelectedLine == (DWORD)-1)
118 {
119 PrefContext->SelectedLine = Line->dwLineID;
120 }
121 }
122 else
123 goto AddToOthersLines;
124
125 break;
126
127 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN:
128 if (PrefContext->RecordingID == (DWORD)-1)
129 {
130 PrefContext->RecordingID = Line->dwLineID;
131
132 if (PrefContext->SelectedLine == (DWORD)-1)
133 {
134 PrefContext->SelectedLine = Line->dwLineID;
135 }
136 }
137 else
138 goto AddToOthersLines;
139
140 break;
141
142 default:
143 {
144 LRESULT lres;
145 HWND hwndCbOthers;
146
147 if (PrefContext->SelectedLine == (DWORD)-1)
148 {
149 PrefContext->SelectedLine = Line->dwLineID;
150 }
151
152 AddToOthersLines:
153 hwndCbOthers = GetDlgItem(PrefContext->hwndDlg,
154 IDC_LINE);
155
156 lres = SendMessage(hwndCbOthers,
157 CB_ADDSTRING,
158 0,
159 (LPARAM)Line->szName);
160 if (lres != CB_ERR)
161 {
162 SendMessage(hwndCbOthers,
163 CB_SETITEMDATA,
164 (WPARAM)lres,
165 Line->dwLineID);
166
167 PrefContext->OtherLines++;
168 }
169 break;
170 }
171 }
172
173 return TRUE;
174 }
175
176 static BOOL CALLBACK
177 PrefDlgAddConnection(PSND_MIXER Mixer,
178 DWORD LineID,
179 LPMIXERLINE Line,
180 PVOID Context)
181 {
182 PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
183 HWND hwndControls;
184 LVITEM lvi;
185 UINT i;
186
187 UNREFERENCED_PARAMETER(Mixer);
188 UNREFERENCED_PARAMETER(LineID);
189
190 if (Line->cControls != 0)
191 {
192 hwndControls = GetDlgItem(PrefContext->hwndDlg,
193 IDC_CONTROLS);
194
195 lvi.mask = LVIF_TEXT | LVIF_PARAM;
196 lvi.iItem = PrefContext->tmp++;
197 lvi.iSubItem = 0;
198 lvi.pszText = Line->szName;
199 lvi.lParam = (LPARAM)Line->dwSource;
200
201 i = SendMessage(hwndControls,
202 LVM_INSERTITEM,
203 0,
204 (LPARAM)&lvi);
205 if (i != (UINT)-1)
206 {
207 TCHAR LineName[MIXER_LONG_NAME_CHARS];
208 DWORD Flags;
209 BOOL SelLine = FALSE;
210
211 if (SndMixerGetLineName(PrefContext->Mixer,
212 PrefContext->SelectedLine,
213 LineName,
214 MIXER_LONG_NAME_CHARS,
215 FALSE) == -1)
216 {
217 LineName[0] = TEXT('\0');
218 }
219
220 if (ReadLineConfig(PrefContext->DeviceName,
221 LineName,
222 Line->szName,
223 &Flags))
224 {
225 if (Flags != 0x4)
226 {
227 SelLine = TRUE;
228 }
229 }
230
231 ListView_SetCheckState(hwndControls,
232 i,
233 SelLine);
234 }
235 }
236
237 return TRUE;
238 }
239
240 static VOID
241 UpdatePrefDlgControls(PPREFERENCES_CONTEXT Context,
242 DWORD LineID)
243 {
244 INT OldID, MixerID = 0;
245 INT DeviceCbIndex;
246
247 /* select the mixer */
248 DeviceCbIndex = SendDlgItemMessage(Context->hwndDlg,
249 IDC_MIXERDEVICE,
250 CB_GETCURSEL,
251 0,
252 0);
253 if (DeviceCbIndex != CB_ERR)
254 {
255 MixerID = SendDlgItemMessage(Context->hwndDlg,
256 IDC_MIXERDEVICE,
257 CB_GETITEMDATA,
258 DeviceCbIndex,
259 0);
260 if (MixerID == CB_ERR)
261 {
262 MixerID = 0;
263 }
264 }
265
266 OldID = Context->Selected;
267 if (MixerID != OldID &&
268 SndMixerSelect(Context->Mixer,
269 MixerID))
270 {
271 Context->Selected = SndMixerGetSelection(Context->Mixer);
272
273 /* update the controls */
274 Context->PlaybackID = (DWORD)-1;
275 Context->RecordingID = (DWORD)-1;
276 Context->OtherLines = 0;
277 Context->SelectedLine = (DWORD)-1;
278
279 SndMixerGetProductName(Context->Mixer,
280 Context->DeviceName,
281 sizeof(Context->DeviceName) / sizeof(Context->DeviceName[0]));
282
283 if (SndMixerEnumLines(Context->Mixer,
284 PrefDlgAddLine,
285 Context))
286 {
287 UINT SelBox = 0;
288
289 /* enable/disable controls and make default selection */
290 EnableWindow(GetDlgItem(Context->hwndDlg,
291 IDC_PLAYBACK),
292 Context->PlaybackID != (DWORD)-1);
293 CheckDlgButton(Context->hwndDlg,
294 IDC_PLAYBACK,
295 (Context->PlaybackID != (DWORD)-1 && SelBox++ == 0) ?
296 BST_CHECKED : BST_UNCHECKED);
297
298 EnableWindow(GetDlgItem(Context->hwndDlg,
299 IDC_RECORDING),
300 Context->RecordingID != (DWORD)-1);
301 CheckDlgButton(Context->hwndDlg,
302 IDC_RECORDING,
303 (Context->RecordingID != (DWORD)-1 && SelBox++ == 0) ?
304 BST_CHECKED : BST_UNCHECKED);
305
306 if (Context->OtherLines != 0)
307 {
308 /* select the first item in the other lines combo box by default */
309 SendDlgItemMessage(Context->hwndDlg,
310 IDC_LINE,
311 CB_SETCURSEL,
312 0,
313 0);
314 }
315 EnableWindow(GetDlgItem(Context->hwndDlg,
316 IDC_LINE),
317 FALSE);
318 EnableWindow(GetDlgItem(Context->hwndDlg,
319 IDC_OTHER),
320 Context->OtherLines != 0);
321 CheckDlgButton(Context->hwndDlg,
322 IDC_LINE,
323 (Context->OtherLines != 0 && SelBox++ == 0) ?
324 BST_CHECKED : BST_UNCHECKED);
325
326 /* disable the OK button if the device doesn't have any lines */
327 EnableWindow(GetDlgItem(Context->hwndDlg,
328 IDOK),
329 Context->PlaybackID != (DWORD)-1 ||
330 Context->RecordingID != (DWORD)-1 ||
331 Context->OtherLines != 0);
332
333 LineID = Context->SelectedLine;
334 }
335 }
336
337 /* update the line sources list */
338 if ((MixerID != OldID && Context->SelectedLine != (DWORD)-1) ||
339 (Context->SelectedLine != LineID && LineID != (DWORD)-1))
340 {
341 Context->SelectedLine = LineID;
342
343 (void)ListView_DeleteAllItems(GetDlgItem(Context->hwndDlg,
344 IDC_CONTROLS));
345
346 Context->tmp = 0;
347 SndMixerEnumConnections(Context->Mixer,
348 LineID,
349 PrefDlgAddConnection,
350 Context);
351 }
352 }
353
354 static INT_PTR CALLBACK
355 DlgPreferencesProc(HWND hwndDlg,
356 UINT uMsg,
357 WPARAM wParam,
358 LPARAM lParam)
359 {
360 PPREFERENCES_CONTEXT Context;
361
362 switch (uMsg)
363 {
364 case WM_COMMAND:
365 {
366 Context = GetDialogData(hwndDlg,
367 PREFERENCES_CONTEXT);
368 switch (LOWORD(wParam))
369 {
370 case IDC_MIXERDEVICE:
371 {
372 if (HIWORD(wParam) == CBN_SELCHANGE)
373 {
374 UpdatePrefDlgControls(Context,
375 (DWORD)-1);
376 }
377 break;
378 }
379
380 case IDC_LINE:
381 {
382 if (HIWORD(wParam) == CBN_SELCHANGE)
383 {
384 INT LineID;
385 INT Index;
386
387 Index = SendDlgItemMessage(hwndDlg,
388 IDC_LINE,
389 CB_GETCURSEL,
390 0,
391 0);
392 if (Index != CB_ERR)
393 {
394 LineID = SendDlgItemMessage(hwndDlg,
395 IDC_LINE,
396 CB_GETITEMDATA,
397 Index,
398 0);
399 if (LineID != CB_ERR)
400 {
401 UpdatePrefDlgControls(Context,
402 LineID);
403 }
404 }
405 }
406 break;
407 }
408
409 case IDC_PLAYBACK:
410 {
411 UpdatePrefDlgControls(Context,
412 Context->PlaybackID);
413 EnableWindow(GetDlgItem(hwndDlg,
414 IDC_LINE),
415 FALSE);
416 break;
417 }
418
419 case IDC_RECORDING:
420 {
421 UpdatePrefDlgControls(Context,
422 Context->RecordingID);
423 EnableWindow(GetDlgItem(hwndDlg,
424 IDC_LINE),
425 FALSE);
426 break;
427 }
428
429 case IDC_OTHER:
430 {
431 INT LineCbIndex;
432 INT LineID;
433
434 EnableWindow(GetDlgItem(hwndDlg,
435 IDC_LINE),
436 TRUE);
437
438 LineCbIndex = SendDlgItemMessage(hwndDlg,
439 IDC_LINE,
440 CB_GETCURSEL,
441 0,
442 0);
443 if (LineCbIndex != CB_ERR)
444 {
445 LineID = SendDlgItemMessage(hwndDlg,
446 IDC_LINE,
447 CB_GETITEMDATA,
448 LineCbIndex,
449 0);
450 if (LineID != CB_ERR)
451 {
452 UpdatePrefDlgControls(Context,
453 LineID);
454 }
455 }
456 break;
457 }
458
459 case IDOK:
460 case IDCANCEL:
461 {
462 EndDialog(hwndDlg,
463 LOWORD(wParam));
464 break;
465 }
466 }
467 break;
468 }
469
470 case MM_MIXM_LINE_CHANGE:
471 {
472 DPRINT("MM_MIXM_LINE_CHANGE\n");
473 break;
474 }
475
476 case MM_MIXM_CONTROL_CHANGE:
477 {
478 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
479 break;
480 }
481
482 case WM_INITDIALOG:
483 {
484 PREFERENCES_FILL_DEVICES FillDevContext;
485 LVCOLUMN lvc;
486 RECT rcClient;
487 HWND hwndControls;
488
489 SetWindowLongPtr(hwndDlg,
490 DWLP_USER,
491 (LONG_PTR)lParam);
492 Context = (PPREFERENCES_CONTEXT)((LONG_PTR)lParam);
493 Context->hwndDlg = hwndDlg;
494 Context->Mixer = SndMixerCreate(hwndDlg);
495 Context->Selected = (UINT)-1;
496
497 FillDevContext.PrefContext = Context;
498 FillDevContext.hComboBox = GetDlgItem(hwndDlg,
499 IDC_MIXERDEVICE);
500 FillDevContext.Selected = SndMixerGetSelection(Context->Mixer);
501 SndMixerEnumProducts(Context->Mixer,
502 FillDeviceComboBox,
503 &FillDevContext);
504
505 /* initialize the list view control */
506 hwndControls = GetDlgItem(hwndDlg,
507 IDC_CONTROLS);
508 (void)ListView_SetExtendedListViewStyle(hwndControls,
509 LVS_EX_CHECKBOXES);
510
511 GetClientRect(hwndControls,
512 &rcClient);
513 lvc.mask = LVCF_TEXT | LVCF_WIDTH;
514 lvc.pszText = TEXT("");
515 lvc.cx = rcClient.right;
516 SendMessage(hwndControls,
517 LVM_INSERTCOLUMN,
518 0,
519 (LPARAM)&lvc);
520
521 /* update all controls */
522 UpdatePrefDlgControls(Context,
523 (DWORD)-1);
524 return TRUE;
525 }
526
527 case WM_DESTROY:
528 {
529 Context = GetDialogData(hwndDlg,
530 PREFERENCES_CONTEXT);
531 if (Context->Mixer != NULL)
532 {
533 SndMixerDestroy(Context->Mixer);
534 }
535 break;
536 }
537
538 case WM_CLOSE:
539 {
540 EndDialog(hwndDlg,
541 IDCANCEL);
542 break;
543 }
544 }
545
546 return 0;
547 }
548
549 /******************************************************************************/
550
551 static VOID
552 DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow)
553 {
554 UNREFERENCED_PARAMETER(MixerWindow);
555 }
556
557 static BOOL
558 RebuildMixerWindowControls(PMIXER_WINDOW MixerWindow)
559 {
560 DeleteMixerWindowControls(MixerWindow);
561
562 return TRUE;
563 }
564
565 static LRESULT CALLBACK
566 MainWindowProc(HWND hwnd,
567 UINT uMsg,
568 WPARAM wParam,
569 LPARAM lParam)
570 {
571 PMIXER_WINDOW MixerWindow;
572 LRESULT Result = 0;
573
574 switch (uMsg)
575 {
576 case WM_COMMAND:
577 {
578 MixerWindow = GetWindowData(hwnd,
579 MIXER_WINDOW);
580
581 switch (LOWORD(wParam))
582 {
583 case IDC_PROPERTIES:
584 {
585 PREFERENCES_CONTEXT Preferences;
586
587 Preferences.MixerWindow = MixerWindow;
588 Preferences.Mixer = NULL;
589
590 if (DialogBoxParam(hAppInstance,
591 MAKEINTRESOURCE(IDD_PREFERENCES),
592 hwnd,
593 DlgPreferencesProc,
594 (LPARAM)&Preferences) == IDOK)
595 {
596 /* FIXME - update window */
597 }
598 break;
599 }
600
601 case IDC_EXIT:
602 {
603 PostQuitMessage(0);
604 break;
605 }
606
607 case IDC_ABOUT:
608 {
609 HICON hAppIcon = (HICON)GetClassLongPtrW(hwnd,
610 GCLP_HICON);
611 ShellAbout(hwnd,
612 lpAppTitle,
613 NULL,
614 hAppIcon);
615 break;
616 }
617 }
618 break;
619 }
620
621 case MM_MIXM_LINE_CHANGE:
622 {
623 DPRINT("MM_MIXM_LINE_CHANGE\n");
624 break;
625 }
626
627 case MM_MIXM_CONTROL_CHANGE:
628 {
629 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
630 break;
631 }
632
633 case WM_CREATE:
634 {
635 MixerWindow = ((LPCREATESTRUCT)lParam)->lpCreateParams;
636 SetWindowLongPtr(hwnd,
637 GWL_USERDATA,
638 (LONG_PTR)MixerWindow);
639 MixerWindow->hWnd = hwnd;
640 MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
641 NULL,
642 hwnd,
643 0);
644 if (MixerWindow->hStatusBar != NULL)
645 {
646 MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd);
647 if (MixerWindow->Mixer != NULL)
648 {
649 TCHAR szProduct[MAXPNAMELEN];
650
651 if (SndMixerGetProductName(MixerWindow->Mixer,
652 szProduct,
653 sizeof(szProduct) / sizeof(szProduct[0])) > 0)
654 {
655 SendMessage(MixerWindow->hStatusBar,
656 WM_SETTEXT,
657 0,
658 (LPARAM)szProduct);
659 }
660
661 if (!RebuildMixerWindowControls(MixerWindow))
662 {
663 DPRINT("Rebuilding mixer window controls failed!\n");
664 SndMixerDestroy(MixerWindow->Mixer);
665 MixerWindow->Mixer = NULL;
666 Result = -1;
667 }
668 }
669 else
670 {
671 Result = -1;
672 }
673 }
674 else
675 {
676 DPRINT("Failed to create status window!\n");
677 Result = -1;
678 }
679 break;
680 }
681
682 case WM_DESTROY:
683 {
684 MixerWindow = GetWindowData(hwnd,
685 MIXER_WINDOW);
686 if (MixerWindow->Mixer != NULL)
687 {
688 SndMixerDestroy(MixerWindow->Mixer);
689 }
690 break;
691 }
692
693 case WM_CLOSE:
694 {
695 PostQuitMessage(0);
696 break;
697 }
698
699 default:
700 {
701 Result = DefWindowProc(hwnd,
702 uMsg,
703 wParam,
704 lParam);
705 break;
706 }
707 }
708
709 return Result;
710 }
711
712 static BOOL
713 RegisterApplicationClasses(VOID)
714 {
715 WNDCLASSEX wc;
716
717 wc.cbSize = sizeof(WNDCLASSEX);
718 wc.style = CS_HREDRAW | CS_VREDRAW;
719 wc.lpfnWndProc = MainWindowProc;
720 wc.cbClsExtra = 0;
721 wc.cbWndExtra = sizeof(PMIXER_WINDOW);
722 wc.hInstance = hAppInstance;
723 wc.hIcon = LoadIcon(hAppInstance,
724 MAKEINTRESOURCE(IDI_MAINAPP));
725 wc.hCursor = LoadCursor(NULL,
726 IDC_ARROW);
727 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
728 wc.lpszMenuName = NULL;
729 wc.lpszClassName = SZ_APP_CLASS;
730 wc.hIconSm = NULL;
731 MainWindowClass = RegisterClassEx(&wc);
732
733 return MainWindowClass != 0;
734 }
735
736 static VOID
737 UnregisterApplicationClasses(VOID)
738 {
739 UnregisterClass(SZ_APP_CLASS,
740 hAppInstance);
741 }
742
743 static HWND
744 CreateApplicationWindow(VOID)
745 {
746 HWND hWnd;
747
748 PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap,
749 0,
750 sizeof(MIXER_WINDOW));
751 if (MixerWindow == NULL)
752 {
753 return NULL;
754 }
755
756 if (mixerGetNumDevs() > 0)
757 {
758 hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT,
759 SZ_APP_CLASS,
760 lpAppTitle,
761 WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
762 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
763 NULL,
764 LoadMenu(hAppInstance,
765 MAKEINTRESOURCE(IDM_MAINMENU)),
766 hAppInstance,
767 MixerWindow);
768 }
769 else
770 {
771 LPTSTR lpErrMessage;
772
773 /*
774 * no mixer devices are available!
775 */
776
777 hWnd = NULL;
778 if (AllocAndLoadString(&lpErrMessage,
779 hAppInstance,
780 IDS_NOMIXERDEVICES))
781 {
782 MessageBox(NULL,
783 lpErrMessage,
784 lpAppTitle,
785 MB_ICONINFORMATION);
786 LocalFree(lpErrMessage);
787 }
788 }
789
790 if (hWnd == NULL)
791 {
792 HeapFree(hAppHeap,
793 0,
794 MixerWindow);
795 }
796
797 return hWnd;
798 }
799
800 int WINAPI
801 _tWinMain(HINSTANCE hInstance,
802 HINSTANCE hPrevInstance,
803 LPTSTR lpszCmdLine,
804 int nCmdShow)
805 {
806 MSG Msg;
807 int Ret = 1;
808
809 UNREFERENCED_PARAMETER(hPrevInstance);
810 UNREFERENCED_PARAMETER(lpszCmdLine);
811 UNREFERENCED_PARAMETER(nCmdShow);
812
813 hAppInstance = hInstance;
814 hAppHeap = GetProcessHeap();
815
816 if (InitAppConfig())
817 {
818 /* load the application title */
819 if (!AllocAndLoadString(&lpAppTitle,
820 hAppInstance,
821 IDS_SNDVOL32))
822 {
823 lpAppTitle = NULL;
824 }
825
826 InitCommonControls();
827
828 if (RegisterApplicationClasses())
829 {
830 hMainWnd = CreateApplicationWindow();
831 if (hMainWnd != NULL)
832 {
833 BOOL bRet;
834 while ((bRet =GetMessage(&Msg,
835 NULL,
836 0,
837 0)) != 0)
838 {
839 if (bRet != -1)
840 {
841 TranslateMessage(&Msg);
842 DispatchMessage(&Msg);
843 }
844 }
845
846 DestroyWindow(hMainWnd);
847 Ret = 0;
848 }
849 else
850 {
851 DPRINT("Failed to create application window (LastError: %d)!\n", GetLastError());
852 }
853
854 UnregisterApplicationClasses();
855 }
856 else
857 {
858 DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError());
859 }
860
861 if (lpAppTitle != NULL)
862 {
863 LocalFree(lpAppTitle);
864 }
865
866 CloseAppConfig();
867 }
868 else
869 {
870 DPRINT("Unable to open the Volume Control registry key!\n");
871 }
872
873 return Ret;
874 }
875