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