3ebd097fd3ffa48ac636d1d369c27406a62bfa86
[reactos.git] / reactos / dll / cpl / mmsys / sounds.c
1 /*
2 * PROJECT: ReactOS Multimedia Control Panel
3 * FILE: dll/cpl/mmsys/sounds.c
4 * PURPOSE: ReactOS Multimedia Control Panel
5 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
6 * Johannes Anderwald <janderwald@reactos.com>
7 * Dmitry Chapyshev <dmitry@reactos.org>
8 * Victor Martinez Calvo <victor.martinez@reactos.org>
9 */
10
11 #include "mmsys.h"
12
13 #include <commdlg.h>
14 #include <strsafe.h>
15
16 #include <debug.h>
17
18 struct __APP_MAP__;
19
20 typedef struct __LABEL_MAP__
21 {
22 TCHAR * szName;
23 TCHAR * szDesc;
24 TCHAR * szIcon;
25 struct __APP_MAP__ * AppMap;
26 struct __LABEL_MAP__ * Next;
27 } LABEL_MAP, *PLABEL_MAP;
28
29 typedef struct __APP_MAP__
30 {
31 TCHAR szName[MAX_PATH];
32 TCHAR szDesc[MAX_PATH];
33 TCHAR szIcon[MAX_PATH];
34
35 struct __APP_MAP__ *Next;
36 PLABEL_MAP LabelMap;
37 } APP_MAP, *PAPP_MAP;
38
39 typedef struct __LABEL_CONTEXT__
40 {
41 PLABEL_MAP LabelMap;
42 PAPP_MAP AppMap;
43 TCHAR szValue[MAX_PATH];
44 struct __LABEL_CONTEXT__ *Next;
45 } LABEL_CONTEXT, *PLABEL_CONTEXT;
46
47 typedef struct __SOUND_SCHEME_CONTEXT__
48 {
49 TCHAR szName[MAX_PATH];
50 TCHAR szDesc[MAX_PATH];
51 PLABEL_CONTEXT LabelContext;
52 } SOUND_SCHEME_CONTEXT, *PSOUND_SCHEME_CONTEXT;
53
54 static PLABEL_MAP s_Map = NULL;
55 static PAPP_MAP s_App = NULL;
56
57 TCHAR szDefault[MAX_PATH];
58
59
60 PLABEL_MAP FindLabel(PAPP_MAP pAppMap, TCHAR * szName)
61 {
62 PLABEL_MAP pMap = s_Map;
63
64 while (pMap)
65 {
66 ASSERT(pMap);
67 ASSERT(pMap->szName);
68 if (!_tcscmp(pMap->szName, szName))
69 return pMap;
70
71 pMap = pMap->Next;
72 }
73
74 pMap = pAppMap->LabelMap;
75
76 while (pMap)
77 {
78 ASSERT(pMap);
79 ASSERT(pMap->szName);
80 if (!_tcscmp(pMap->szName, szName))
81 return pMap;
82
83 pMap = pMap->Next;
84 }
85
86 pMap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LABEL_MAP));
87 if (!pMap)
88 return NULL;
89
90 pMap->szName = pMap->szDesc = _tcsdup(szName);
91 if (!pMap->szName)
92 {
93 HeapFree(GetProcessHeap(), 0, pMap);
94 return NULL;
95 }
96
97 pMap->AppMap = pAppMap;
98 pMap->Next = s_Map;
99 s_Map = pMap;
100
101 return pMap;
102 }
103
104
105 VOID RemoveLabel(PLABEL_MAP pMap)
106 {
107 PLABEL_MAP pCurMap = s_Map;
108
109 if (pCurMap == pMap)
110 {
111 s_Map = s_Map->Next;
112 return;
113 }
114
115 while (pCurMap)
116 {
117 if (pCurMap->Next == pMap)
118 {
119 pCurMap->Next = pCurMap->Next->Next;
120 return;
121 }
122 pCurMap = pCurMap->Next;
123 }
124 }
125
126
127 PAPP_MAP FindApp(TCHAR * szName)
128 {
129 PAPP_MAP pMap = s_App;
130
131 while (pMap)
132 {
133 if (!_tcscmp(pMap->szName, szName))
134 return pMap;
135
136 pMap = pMap->Next;
137
138 }
139 return NULL;
140 }
141
142
143 PLABEL_CONTEXT FindLabelContext(PSOUND_SCHEME_CONTEXT pSoundScheme, TCHAR * AppName, TCHAR * LabelName)
144 {
145 PLABEL_CONTEXT pLabelContext;
146
147 pLabelContext = pSoundScheme->LabelContext;
148
149 while (pLabelContext)
150 {
151 ASSERT(pLabelContext->AppMap);
152 ASSERT(pLabelContext->LabelMap);
153
154 if (!_tcsicmp(pLabelContext->AppMap->szName, AppName) && !_tcsicmp(pLabelContext->LabelMap->szName, LabelName))
155 {
156 return pLabelContext;
157 }
158 pLabelContext = pLabelContext->Next;
159 }
160
161 pLabelContext = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LABEL_CONTEXT));
162 if (!pLabelContext)
163 return NULL;
164
165 pLabelContext->AppMap = FindApp(AppName);
166 pLabelContext->LabelMap = FindLabel(pLabelContext->AppMap, LabelName);
167 ASSERT(pLabelContext->AppMap);
168 ASSERT(pLabelContext->LabelMap);
169 pLabelContext->szValue[0] = _T('\0');
170 pLabelContext->Next = pSoundScheme->LabelContext;
171 pSoundScheme->LabelContext = pLabelContext;
172
173 return pLabelContext;
174 }
175
176
177 BOOL
178 LoadEventLabel(HKEY hKey, TCHAR * szSubKey)
179 {
180 HKEY hSubKey;
181 DWORD cbValue;
182 TCHAR szDesc[MAX_PATH];
183 TCHAR szData[MAX_PATH];
184 PLABEL_MAP pMap;
185
186 if (RegOpenKeyEx(hKey,
187 szSubKey,
188 0,
189 KEY_READ,
190 &hSubKey) != ERROR_SUCCESS)
191 {
192 return FALSE;
193 }
194
195 cbValue = sizeof(szDesc);
196 if (RegQueryValueEx(hSubKey,
197 NULL,
198 NULL,
199 NULL,
200 (LPBYTE)szDesc,
201 &cbValue) != ERROR_SUCCESS)
202 {
203 RegCloseKey(hSubKey);
204 return FALSE;
205 }
206
207 cbValue = sizeof(szData);
208 if (RegQueryValueEx(hSubKey,
209 _T("DispFileName"),
210 NULL,
211 NULL,
212 (LPBYTE)szData,
213 &cbValue) != ERROR_SUCCESS)
214 {
215 RegCloseKey(hSubKey);
216 return FALSE;
217 }
218
219 pMap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LABEL_MAP));
220 if (!pMap)
221 {
222 return FALSE;
223 }
224 pMap->szName = _tcsdup(szSubKey);
225 pMap->szDesc = _tcsdup(szDesc);
226 pMap->szIcon = _tcsdup(szData);
227
228 if (s_Map)
229 {
230 pMap->Next = s_Map;
231 s_Map = pMap;
232 }
233 else
234 {
235 s_Map = pMap;
236 s_Map->Next = 0;
237 }
238 return TRUE;
239 }
240
241
242 BOOL
243 LoadEventLabels()
244 {
245 HKEY hSubKey;
246 DWORD dwCurKey;
247 TCHAR szName[MAX_PATH];
248 DWORD dwName;
249 DWORD dwResult;
250 DWORD dwCount;
251 if (RegOpenKeyEx(HKEY_CURRENT_USER,
252 _T("AppEvents\\EventLabels"),
253 0,
254 KEY_READ,
255 &hSubKey) != ERROR_SUCCESS)
256 {
257 return FALSE;
258 }
259
260 dwCurKey = 0;
261 dwCount = 0;
262 do
263 {
264 dwName = _countof(szName);
265 dwResult = RegEnumKeyEx(hSubKey,
266 dwCurKey,
267 szName,
268 &dwName,
269 NULL,
270 NULL,
271 NULL,
272 NULL);
273
274 if (dwResult == ERROR_SUCCESS)
275 {
276 if (LoadEventLabel(hSubKey, szName))
277 {
278 dwCount++;
279 }
280 }
281 dwCurKey++;
282
283 } while (dwResult == ERROR_SUCCESS);
284
285 RegCloseKey(hSubKey);
286 return (dwCount != 0);
287 }
288
289
290 BOOL
291 AddSoundProfile(HWND hwndDlg, HKEY hKey, TCHAR * szSubKey, BOOL SetDefault)
292 {
293 HKEY hSubKey;
294 TCHAR szValue[MAX_PATH];
295 DWORD cbValue, dwResult;
296 LRESULT lResult;
297 PSOUND_SCHEME_CONTEXT pScheme;
298
299 if (RegOpenKeyEx(hKey,
300 szSubKey,
301 0,
302 KEY_READ,
303 &hSubKey) != ERROR_SUCCESS)
304 {
305 return FALSE;
306 }
307
308 cbValue = sizeof(szValue);
309 dwResult = RegQueryValueEx(hSubKey,
310 NULL,
311 NULL,
312 NULL,
313 (LPBYTE)szValue,
314 &cbValue);
315 RegCloseKey(hSubKey);
316
317 if (dwResult != ERROR_SUCCESS)
318 return FALSE;
319
320 /* Try to add the new profile */
321 lResult = SendDlgItemMessage(hwndDlg, IDC_SOUND_SCHEME, CB_ADDSTRING, (WPARAM)0, (LPARAM)szValue);
322 if (lResult == CB_ERR)
323 return FALSE;
324
325 /* Allocate the profile scheme buffer */
326 pScheme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOUND_SCHEME_CONTEXT));
327 if (pScheme == NULL)
328 {
329 /* We failed to allocate the buffer, no need to keep a dangling string in the combobox */
330 SendDlgItemMessage(hwndDlg, IDC_SOUND_SCHEME, CB_DELETESTRING, (WPARAM)lResult, (LPARAM)0);
331 return FALSE;
332 }
333
334 StringCchCopy(pScheme->szDesc, MAX_PATH, szValue);
335 StringCchCopy(pScheme->szName, MAX_PATH, szSubKey);
336
337 /* Associate the value with the item in the combobox */
338 SendDlgItemMessage(hwndDlg, IDC_SOUND_SCHEME, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)pScheme);
339
340 /* Optionally, select the profile */
341 if (SetDefault)
342 SendDlgItemMessage(hwndDlg, IDC_SOUND_SCHEME, CB_SETCURSEL, (WPARAM)lResult, (LPARAM)0);
343
344 return TRUE;
345 }
346
347
348 DWORD
349 EnumerateSoundProfiles(HWND hwndDlg, HKEY hKey)
350 {
351 HKEY hSubKey;
352 DWORD dwName, dwCurKey, dwResult, dwNumSchemes;
353 DWORD cbDefault;
354 TCHAR szName[MAX_PATH];
355
356 cbDefault = sizeof(szDefault);
357 if (RegQueryValueEx(hKey,
358 NULL,
359 NULL,
360 NULL,
361 (LPBYTE)szDefault,
362 &cbDefault) != ERROR_SUCCESS)
363 {
364 return FALSE;
365 }
366
367
368
369 if (RegOpenKeyEx(hKey,
370 _T("Names"),
371 0,
372 KEY_READ,
373 &hSubKey) != ERROR_SUCCESS)
374 {
375 return FALSE;
376 }
377
378 dwNumSchemes = 0;
379 dwCurKey = 0;
380 do
381 {
382 dwName = _countof(szName);
383 dwResult = RegEnumKeyEx(hSubKey,
384 dwCurKey,
385 szName,
386 &dwName,
387 NULL,
388 NULL,
389 NULL,
390 NULL);
391
392 if (dwResult == ERROR_SUCCESS)
393 {
394 if (AddSoundProfile(hwndDlg, hSubKey, szName, (!_tcsicmp(szName, szDefault))))
395 {
396 dwNumSchemes++;
397 }
398 }
399
400 dwCurKey++;
401 } while (dwResult == ERROR_SUCCESS);
402
403 RegCloseKey(hSubKey);
404 return dwNumSchemes;
405 }
406
407
408 PSOUND_SCHEME_CONTEXT FindSoundProfile(HWND hwndDlg, TCHAR * szName)
409 {
410 LRESULT lCount, lIndex, lResult;
411 PSOUND_SCHEME_CONTEXT pScheme;
412
413 lCount = SendDlgItemMessage(hwndDlg, IDC_SOUND_SCHEME, CB_GETCOUNT, (WPARAM)0, (LPARAM)0);
414 if (lCount == CB_ERR)
415 {
416 return NULL;
417 }
418
419 for(lIndex = 0; lIndex < lCount; lIndex++)
420 {
421 lResult = SendDlgItemMessage(hwndDlg, IDC_SOUND_SCHEME, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
422 if (lResult == CB_ERR)
423 {
424 continue;
425 }
426
427 pScheme = (PSOUND_SCHEME_CONTEXT)lResult;
428 if (!_tcsicmp(pScheme->szName, szName))
429 {
430 return pScheme;
431 }
432 }
433 return NULL;
434 }
435
436
437 BOOL
438 ImportSoundLabel(HWND hwndDlg, HKEY hKey, TCHAR * szProfile, TCHAR * szLabelName, TCHAR * szAppName, PAPP_MAP AppMap, PLABEL_MAP LabelMap)
439 {
440 HKEY hSubKey;
441 TCHAR szValue[MAX_PATH];
442 TCHAR szBuffer[MAX_PATH];
443 DWORD cbValue, cchLength;
444 PSOUND_SCHEME_CONTEXT pScheme;
445 PLABEL_CONTEXT pLabelContext;
446 BOOL bCurrentProfile, bActiveProfile;
447
448 //MessageBox(hwndDlg, szProfile, szLabelName, MB_OK);
449
450 bCurrentProfile = !_tcsicmp(szProfile, _T(".Current"));
451 bActiveProfile = !_tcsicmp(szProfile, szDefault);
452
453 if (RegOpenKeyEx(hKey,
454 szProfile,
455 0,
456 KEY_READ,
457 &hSubKey) != ERROR_SUCCESS)
458 {
459 return FALSE;
460 }
461
462 cbValue = sizeof(szValue);
463 if (RegQueryValueEx(hSubKey,
464 NULL,
465 NULL,
466 NULL,
467 (LPBYTE)szValue,
468 &cbValue) != ERROR_SUCCESS)
469 {
470 return FALSE;
471 }
472
473 if (bCurrentProfile)
474 pScheme = FindSoundProfile(hwndDlg, szDefault);
475 else
476 pScheme = FindSoundProfile(hwndDlg, szProfile);
477
478 if (!pScheme)
479 {
480 //MessageBox(hwndDlg, szProfile, _T("no profile!!"), MB_OK);
481 return FALSE;
482 }
483 pLabelContext = FindLabelContext(pScheme, AppMap->szName, LabelMap->szName);
484
485 cchLength = ExpandEnvironmentStrings(szValue, szBuffer, _countof(szBuffer));
486 if (cchLength == 0 || cchLength > _countof(szBuffer))
487 {
488 /* fixme */
489 return FALSE;
490 }
491
492 if (bCurrentProfile)
493 _tcscpy(pLabelContext->szValue, szBuffer);
494 else if (!bActiveProfile)
495 _tcscpy(pLabelContext->szValue, szBuffer);
496
497 return TRUE;
498 }
499
500
501 DWORD
502 ImportSoundEntry(HWND hwndDlg, HKEY hKey, TCHAR * szLabelName, TCHAR * szAppName, PAPP_MAP pAppMap)
503 {
504 HKEY hSubKey;
505 DWORD dwNumProfiles;
506 DWORD dwCurKey;
507 DWORD dwResult;
508 DWORD dwProfile;
509 TCHAR szProfile[MAX_PATH];
510 PLABEL_MAP pLabel;
511
512 if (RegOpenKeyEx(hKey,
513 szLabelName,
514 0,
515 KEY_READ,
516 &hSubKey) != ERROR_SUCCESS)
517 {
518 return FALSE;
519 }
520 pLabel = FindLabel(pAppMap, szLabelName);
521
522 ASSERT(pLabel);
523 RemoveLabel(pLabel);
524
525 pLabel->AppMap = pAppMap;
526 pLabel->Next = pAppMap->LabelMap;
527 pAppMap->LabelMap = pLabel;
528
529 dwNumProfiles = 0;
530 dwCurKey = 0;
531 do
532 {
533 dwProfile = _countof(szProfile);
534 dwResult = RegEnumKeyEx(hSubKey,
535 dwCurKey,
536 szProfile,
537 &dwProfile,
538 NULL,
539 NULL,
540 NULL,
541 NULL);
542
543 if (dwResult == ERROR_SUCCESS)
544 {
545 if (ImportSoundLabel(hwndDlg, hSubKey, szProfile, szLabelName, szAppName, pAppMap, pLabel))
546 {
547 dwNumProfiles++;
548 }
549 }
550
551 dwCurKey++;
552 } while (dwResult == ERROR_SUCCESS);
553
554 RegCloseKey(hSubKey);
555
556 return dwNumProfiles;
557 }
558
559
560 DWORD
561 ImportAppProfile(HWND hwndDlg, HKEY hKey, TCHAR * szAppName)
562 {
563 HKEY hSubKey;
564 TCHAR szDefault[MAX_PATH];
565 DWORD cbValue;
566 DWORD dwCurKey;
567 DWORD dwResult;
568 DWORD dwNumEntry;
569 DWORD dwName;
570 TCHAR szName[MAX_PATH];
571 TCHAR szIcon[MAX_PATH];
572 PAPP_MAP AppMap;
573
574 //MessageBox(hwndDlg, szAppName, _T("Importing...\n"), MB_OK);
575
576 AppMap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APP_MAP));
577 if (!AppMap)
578 return 0;
579
580 if (RegOpenKeyEx(hKey,
581 szAppName,
582 0,
583 KEY_READ,
584 &hSubKey) != ERROR_SUCCESS)
585 {
586 HeapFree(GetProcessHeap(), 0, AppMap);
587 return 0;
588 }
589
590 cbValue = sizeof(szDefault);
591 if (RegQueryValueEx(hSubKey,
592 NULL,
593 NULL,
594 NULL,
595 (LPBYTE)szDefault,
596 &cbValue) != ERROR_SUCCESS)
597 {
598 RegCloseKey(hSubKey);
599 HeapFree(GetProcessHeap(), 0, AppMap);
600 return 0;
601 }
602
603 cbValue = sizeof(szIcon);
604 if (RegQueryValueEx(hSubKey,
605 _T("DispFileName"),
606 NULL,
607 NULL,
608 (LPBYTE)szIcon,
609 &cbValue) != ERROR_SUCCESS)
610 {
611 szIcon[0] = _T('\0');
612 }
613
614 /* initialize app map */
615 _tcscpy(AppMap->szName, szAppName);
616 _tcscpy(AppMap->szDesc, szDefault);
617 _tcscpy(AppMap->szIcon, szIcon);
618
619 AppMap->Next = s_App;
620 s_App = AppMap;
621
622
623 dwCurKey = 0;
624 dwNumEntry = 0;
625 do
626 {
627 dwName = _countof(szName);
628 dwResult = RegEnumKeyEx(hSubKey,
629 dwCurKey,
630 szName,
631 &dwName,
632 NULL,
633 NULL,
634 NULL,
635 NULL);
636 if (dwResult == ERROR_SUCCESS)
637 {
638 if (ImportSoundEntry(hwndDlg, hSubKey, szName, szAppName, AppMap))
639 {
640 dwNumEntry++;
641 }
642 }
643 dwCurKey++;
644 } while (dwResult == ERROR_SUCCESS);
645
646 RegCloseKey(hSubKey);
647 return dwNumEntry;
648 }
649
650
651 BOOL
652 ImportSoundProfiles(HWND hwndDlg, HKEY hKey)
653 {
654 DWORD dwCurKey;
655 DWORD dwResult;
656 DWORD dwNumApps;
657 TCHAR szName[MAX_PATH];
658 HKEY hSubKey;
659
660 if (RegOpenKeyEx(hKey,
661 _T("Apps"),
662 0,
663 KEY_READ,
664 &hSubKey) != ERROR_SUCCESS)
665 {
666 return FALSE;
667 }
668
669 dwNumApps = 0;
670 dwCurKey = 0;
671 do
672 {
673 dwResult = RegEnumKey(hSubKey,
674 dwCurKey,
675 szName,
676 _countof(szName));
677
678 if (dwResult == ERROR_SUCCESS)
679 {
680 if (ImportAppProfile(hwndDlg, hSubKey, szName))
681 {
682 dwNumApps++;
683 }
684 }
685 dwCurKey++;
686 } while (dwResult == ERROR_SUCCESS);
687
688 RegCloseKey(hSubKey);
689
690 return (dwNumApps != 0);
691 }
692
693
694 BOOL
695 LoadSoundProfiles(HWND hwndDlg)
696 {
697 HKEY hSubKey;
698 DWORD dwNumSchemes;
699
700 if (RegOpenKeyEx(HKEY_CURRENT_USER,
701 _T("AppEvents\\Schemes"),
702 0,
703 KEY_READ,
704 &hSubKey) != ERROR_SUCCESS)
705 {
706 return FALSE;
707 }
708
709 dwNumSchemes = EnumerateSoundProfiles(hwndDlg, hSubKey);
710
711
712 if (dwNumSchemes)
713 {
714 //MessageBox(hwndDlg, _T("importing sound profiles..."), NULL, MB_OK);
715 ImportSoundProfiles(hwndDlg, hSubKey);
716 }
717
718 RegCloseKey(hSubKey);
719 return FALSE;
720 }
721
722
723 BOOL
724 LoadSoundFiles(HWND hwndDlg)
725 {
726 WCHAR szPath[MAX_PATH];
727 WCHAR * ptr;
728 WIN32_FIND_DATAW FileData;
729 HANDLE hFile;
730 LRESULT lResult;
731 UINT length;
732
733 /* Add no sound listview item */
734 if (LoadString(hApplet, IDS_NO_SOUND, szPath, _countof(szPath)))
735 {
736 szPath[_countof(szPath)-1] = L'\0';
737 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, (WPARAM)0, (LPARAM)szPath);
738 }
739
740 /* Load sound files */
741 length = GetWindowsDirectoryW(szPath, MAX_PATH);
742 if (length == 0 || length >= MAX_PATH - 9)
743 {
744 return FALSE;
745 }
746 if (szPath[length-1] != L'\\')
747 {
748 szPath[length] = L'\\';
749 length++;
750 }
751 wcscpy(&szPath[length], L"media\\*");
752 length += 7;
753
754 hFile = FindFirstFileW(szPath, &FileData);
755 if (hFile == INVALID_HANDLE_VALUE)
756 {
757 return FALSE;
758 }
759
760 do
761 {
762 if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
763 continue;
764
765 ptr = wcsrchr(FileData.cFileName, L'\\');
766 if (ptr)
767 {
768 ptr++;
769 }
770 else
771 {
772 ptr = FileData.cFileName;
773 }
774 lResult = SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, (WPARAM)0, (LPARAM)ptr);
775 if (lResult != CB_ERR)
776 {
777 wcscpy(&szPath[length-1], FileData.cFileName);
778 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)_wcsdup(szPath));
779 }
780 } while (FindNextFileW(hFile, &FileData) != 0);
781
782 FindClose(hFile);
783 return TRUE;
784 }
785
786
787 BOOL
788 ShowSoundScheme(HWND hwndDlg)
789 {
790 LRESULT lIndex;
791 PSOUND_SCHEME_CONTEXT pScheme;
792 PAPP_MAP pAppMap;
793 LV_ITEM listItem;
794 LV_COLUMN dummy;
795 HWND hDlgCtrl, hList;
796 RECT rect;
797 int ItemIndex;
798 hDlgCtrl = GetDlgItem(hwndDlg, IDC_SOUND_SCHEME);
799 hList = GetDlgItem(hwndDlg, IDC_SCHEME_LIST);
800
801 lIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
802 if (lIndex == CB_ERR)
803 {
804 return FALSE;
805 }
806
807 lIndex = SendMessage(hDlgCtrl, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
808 if (lIndex == CB_ERR)
809 {
810 return FALSE;
811 }
812 pScheme = (PSOUND_SCHEME_CONTEXT)lIndex;
813
814 _tcscpy(szDefault, pScheme->szName);
815
816 /* add column for app */
817 GetClientRect(hList, &rect);
818 ZeroMemory(&dummy, sizeof(dummy));
819 dummy.mask = LVCF_WIDTH;
820 dummy.iSubItem = 0;
821 dummy.cx = rect.right - rect.left - GetSystemMetrics(SM_CXVSCROLL);
822 (void)ListView_InsertColumn(hList, 0, &dummy);
823 ItemIndex = 0;
824
825 pAppMap = s_App;
826 while (pAppMap)
827 {
828 PLABEL_MAP pLabelMap = pAppMap->LabelMap;
829 while (pLabelMap)
830 {
831 ZeroMemory(&listItem, sizeof(listItem));
832 listItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
833 listItem.pszText = pLabelMap->szDesc;
834 listItem.lParam = (LPARAM)FindLabelContext(pScheme, pAppMap->szName, pLabelMap->szName);
835 listItem.iItem = ItemIndex;
836 listItem.iImage = -1;
837 (void)ListView_InsertItem(hList, &listItem);
838 ItemIndex++;
839
840 pLabelMap = pLabelMap->Next;
841 }
842 pAppMap = pAppMap->Next;
843 }
844 return TRUE;
845 }
846
847
848 BOOL
849 ApplyChanges(HWND hwndDlg)
850 {
851 HKEY hKey, hSubKey;
852 LRESULT lIndex;
853 PSOUND_SCHEME_CONTEXT pScheme;
854 HWND hDlgCtrl;
855 PLABEL_CONTEXT pLabelContext;
856 TCHAR Buffer[100];
857
858 hDlgCtrl = GetDlgItem(hwndDlg, IDC_SOUND_SCHEME);
859
860 lIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
861 if (lIndex == CB_ERR)
862 {
863 return FALSE;
864 }
865
866 lIndex = SendMessage(hDlgCtrl, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
867 if (lIndex == CB_ERR)
868 {
869 return FALSE;
870 }
871 pScheme = (PSOUND_SCHEME_CONTEXT)lIndex;
872
873 if (RegOpenKeyEx(HKEY_CURRENT_USER,
874 _T("AppEvents\\Schemes"),
875 0,
876 KEY_WRITE,
877 &hKey) != ERROR_SUCCESS)
878 {
879 return FALSE;
880 }
881
882 RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)pScheme->szName, (_tcslen(pScheme->szName) +1) * sizeof(TCHAR));
883 RegCloseKey(hKey);
884
885 if (RegOpenKeyEx(HKEY_CURRENT_USER,
886 _T("AppEvents\\Schemes\\Apps"),
887 0,
888 KEY_WRITE,
889 &hKey) != ERROR_SUCCESS)
890 {
891 return FALSE;
892 }
893
894 pLabelContext = pScheme->LabelContext;
895
896 while (pLabelContext)
897 {
898 _stprintf(Buffer, _T("%s\\%s\\.Current"), pLabelContext->AppMap->szName, pLabelContext->LabelMap->szName);
899
900 if (RegOpenKeyEx(hKey, Buffer, 0, KEY_WRITE, &hSubKey) == ERROR_SUCCESS)
901 {
902 RegSetValueEx(hSubKey, NULL, 0, REG_EXPAND_SZ, (LPBYTE)pLabelContext->szValue, (_tcslen(pLabelContext->szValue) +1) * sizeof(TCHAR));
903 RegCloseKey(hSubKey);
904 }
905
906 pLabelContext = pLabelContext->Next;
907 }
908 RegCloseKey(hKey);
909
910 SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)PSNRET_NOERROR);
911 return TRUE;
912 }
913
914
915 /* Sounds property page dialog callback */
916 INT_PTR
917 CALLBACK
918 SoundsDlgProc(HWND hwndDlg,
919 UINT uMsg,
920 WPARAM wParam,
921 LPARAM lParam)
922 {
923 OPENFILENAMEW ofn;
924 WCHAR filename[MAX_PATH];
925 LPWSTR pFileName;
926 LRESULT lResult;
927
928 switch (uMsg)
929 {
930 case WM_INITDIALOG:
931 {
932 UINT NumWavOut = waveOutGetNumDevs();
933
934 SendMessage(GetDlgItem(hwndDlg, IDC_PLAY_SOUND),
935 BM_SETIMAGE,(WPARAM)IMAGE_ICON,
936 (LPARAM)(HANDLE)LoadIcon(hApplet, MAKEINTRESOURCE(IDI_PLAY_ICON)));
937
938 LoadEventLabels();
939 LoadSoundProfiles(hwndDlg);
940 LoadSoundFiles(hwndDlg);
941 ShowSoundScheme(hwndDlg);
942
943 if (!NumWavOut)
944 {
945 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME), FALSE);
946 EnableWindow(GetDlgItem(hwndDlg, IDC_SAVEAS_BTN), FALSE);
947 EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_BTN), FALSE);
948 EnableWindow(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), FALSE);
949 }
950
951 if (wParam == (WPARAM)GetDlgItem(hwndDlg, IDC_SOUND_SCHEME))
952 return TRUE;
953 SetFocus(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME));
954 return FALSE;
955 }
956 case WM_COMMAND:
957 {
958 switch (LOWORD(wParam))
959 {
960 case IDC_BROWSE_SOUND:
961 {
962 ZeroMemory(&ofn, sizeof(ofn));
963 ofn.lStructSize = sizeof(ofn);
964 ofn.hwndOwner = hwndDlg;
965 ofn.lpstrFile = filename;
966 ofn.lpstrFile[0] = L'\0';
967 ofn.nMaxFile = MAX_PATH;
968 ofn.lpstrFilter = L"Wave Files (*.wav)\0*.wav\0"; //FIXME non-nls
969 ofn.nFilterIndex = 0;
970 ofn.lpstrFileTitle = L"Search for new sounds"; //FIXME non-nls
971 ofn.nMaxFileTitle = wcslen(ofn.lpstrFileTitle);
972 ofn.lpstrInitialDir = NULL;
973 ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
974
975 if (GetOpenFileNameW(&ofn) == TRUE)
976 {
977 // FIXME search if list already contains that sound
978
979 // extract file name
980 pFileName = wcsrchr(filename, L'\\');
981 ASSERT(pFileName != NULL);
982 pFileName++;
983
984 // add to list
985 lResult = SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, (WPARAM)0, (LPARAM)pFileName);
986 if (lResult != CB_ERR)
987 {
988 // add path and select item
989 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)_wcsdup(filename));
990 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)lResult, (LPARAM)0);
991 }
992 }
993 break;
994 }
995 case IDC_PLAY_SOUND:
996 {
997 LRESULT lIndex;
998 lIndex = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
999 if (lIndex == CB_ERR)
1000 {
1001 break;
1002 }
1003
1004 lIndex = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
1005 if (lIndex != CB_ERR)
1006 {
1007 PlaySound((TCHAR*)lIndex, NULL, SND_FILENAME);
1008 }
1009 break;
1010 }
1011 case IDC_SOUND_SCHEME:
1012 {
1013 if (HIWORD(wParam) == CBN_SELENDOK)
1014 {
1015 (void)ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_SCHEME_LIST));
1016 ShowSoundScheme(hwndDlg);
1017 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), FALSE);
1018 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), FALSE);
1019 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1020 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), FALSE);
1021 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1022 }
1023 break;
1024 }
1025 case IDC_SOUND_LIST:
1026 {
1027 if (HIWORD(wParam) == CBN_SELENDOK)
1028 {
1029 PLABEL_CONTEXT pLabelContext;
1030 INT SelCount;
1031 LVITEM item;
1032 LRESULT lIndex;
1033 SelCount = ListView_GetSelectionMark(GetDlgItem(hwndDlg, IDC_SCHEME_LIST));
1034 if (SelCount == -1)
1035 {
1036 break;
1037 }
1038 lIndex = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
1039 if (lIndex == CB_ERR)
1040 {
1041 break;
1042 }
1043 ZeroMemory(&item, sizeof(item));
1044 item.mask = LVIF_PARAM;
1045 item.iItem = SelCount;
1046 if (ListView_GetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item))
1047 {
1048 LRESULT lResult;
1049 pLabelContext = (PLABEL_CONTEXT)item.lParam;
1050
1051 lResult = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
1052 if (lResult == CB_ERR || lResult == 0)
1053 {
1054 if (lIndex != pLabelContext->szValue[0])
1055 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1056
1057 pLabelContext->szValue[0] = L'\0';
1058 break;
1059 }
1060
1061 if (_tcsicmp(pLabelContext->szValue, (TCHAR*)lResult) || (lIndex != pLabelContext->szValue[0]))
1062 {
1063 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1064 ///
1065 /// Should store in current member
1066 ///
1067 _tcscpy(pLabelContext->szValue, (TCHAR*)lResult);
1068 }
1069 if (_tcslen((TCHAR*)lResult) && lIndex != 0)
1070 {
1071 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), TRUE);
1072 }
1073 else
1074 {
1075 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1076 }
1077 }
1078 }
1079 break;
1080 }
1081 }
1082 break;
1083 }
1084 case WM_NOTIFY:
1085 {
1086 LVITEM item;
1087 PLABEL_CONTEXT pLabelContext;
1088 TCHAR * ptr;
1089
1090 LPNMHDR lpnm = (LPNMHDR)lParam;
1091
1092 switch(lpnm->code)
1093 {
1094 case PSN_APPLY:
1095 {
1096 ApplyChanges(hwndDlg);
1097 break;
1098 }
1099 case LVN_ITEMCHANGED:
1100 {
1101 LPNMLISTVIEW nm = (LPNMLISTVIEW)lParam;
1102
1103 if ((nm->uNewState & LVIS_SELECTED) == 0)
1104 {
1105 return FALSE;
1106 }
1107 ZeroMemory(&item, sizeof(item));
1108 item.mask = LVIF_PARAM;
1109 item.iItem = nm->iItem;
1110
1111 if (ListView_GetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item))
1112 {
1113 LRESULT lCount, lIndex, lResult;
1114 pLabelContext = (PLABEL_CONTEXT)item.lParam;
1115 if (!pLabelContext)
1116 {
1117 return FALSE;
1118 }
1119 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), TRUE);
1120 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), TRUE);
1121 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), TRUE);
1122 if (_tcslen(pLabelContext->szValue) == 0)
1123 {
1124 lIndex = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
1125 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1126 break;
1127
1128 }
1129 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), TRUE);
1130 lCount = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_GETCOUNT, (WPARAM)0, (LPARAM)0);
1131 for (lIndex = 0; lIndex < lCount; lIndex++)
1132 {
1133 lResult = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_GETITEMDATA, (WPARAM)lIndex, (LPARAM)0);
1134 if (lResult == CB_ERR || lResult == 0)
1135 continue;
1136
1137 if (!_tcscmp((TCHAR*)lResult, pLabelContext->szValue))
1138 {
1139 SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)lIndex, (LPARAM)0);
1140 return FALSE;
1141 }
1142 }
1143 ptr = _tcsrchr(pLabelContext->szValue, _T('\\'));
1144 if (ptr)
1145 {
1146 ptr++;
1147 }
1148 else
1149 {
1150 ptr = pLabelContext->szValue;
1151 }
1152 lIndex = SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, (WPARAM)0, (LPARAM)ptr);
1153 if (lIndex != CB_ERR)
1154 {
1155 SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_SETITEMDATA, (WPARAM)lIndex, (LPARAM)_tcsdup(pLabelContext->szValue));
1156 SendDlgItemMessage(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)lIndex, (LPARAM)0);
1157 }
1158 }
1159 break;
1160 }
1161 }
1162 }
1163 break;
1164 }
1165
1166 return FALSE;
1167 }