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