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