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
17 #include <debug.h>
18
19 #define ID_SOUND_TEST_TIMER 1
20
21 typedef struct _LABEL_MAP
22 {
23 PWSTR szName;
24 PWSTR szDesc;
25 PWSTR szIcon;
26 struct _APP_MAP *AppMap;
27 struct _LABEL_MAP *Next;
28 } LABEL_MAP, *PLABEL_MAP;
29
30 typedef struct _APP_MAP
31 {
32 WCHAR szName[MAX_PATH];
33 WCHAR szDesc[MAX_PATH];
34 WCHAR szIcon[MAX_PATH];
35
36 struct _APP_MAP *Next;
37 PLABEL_MAP LabelMap;
38 } APP_MAP, *PAPP_MAP;
39
40 typedef struct _LABEL_CONTEXT
41 {
42 PLABEL_MAP LabelMap;
43 PAPP_MAP AppMap;
44 WCHAR szValue[MAX_PATH];
45 struct _LABEL_CONTEXT *Next;
46 } LABEL_CONTEXT, *PLABEL_CONTEXT;
47
48 typedef struct _SOUND_SCHEME_CONTEXT
49 {
50 WCHAR szName[MAX_PATH];
51 WCHAR szDesc[MAX_PATH];
52 PLABEL_CONTEXT LabelContext;
53 } SOUND_SCHEME_CONTEXT, *PSOUND_SCHEME_CONTEXT;
54
55 typedef struct _GLOBAL_DATA
56 {
57 WCHAR szDefault[MAX_PATH];
58 HIMAGELIST hSoundsImageList;
59 PLABEL_MAP pLabelMap;
60 PAPP_MAP pAppMap;
61 UINT NumWavOut;
62 HICON hPlayIcon;
63 HICON hStopIcon;
64 } GLOBAL_DATA, *PGLOBAL_DATA;
65
66
67 /* A filter string is a list separated by NULL and ends with double NULLs. */
MakeFilter(LPWSTR psz)68 LPWSTR MakeFilter(LPWSTR psz)
69 {
70 PWCHAR pch;
71
72 ASSERT(psz[0] != UNICODE_NULL &&
73 psz[wcslen(psz) - 1] == L'|');
74 for (pch = psz; *pch != UNICODE_NULL; pch++)
75 {
76 /* replace vertical bar with NULL */
77 if (*pch == L'|')
78 {
79 *pch = UNICODE_NULL;
80 }
81 }
82 return psz;
83 }
84
FindLabel(PGLOBAL_DATA pGlobalData,PAPP_MAP pAppMap,PCWSTR szName)85 PLABEL_MAP FindLabel(PGLOBAL_DATA pGlobalData, PAPP_MAP pAppMap, PCWSTR szName)
86 {
87 PLABEL_MAP pMap = pGlobalData->pLabelMap;
88
89 while (pMap)
90 {
91 ASSERT(pMap);
92 ASSERT(pMap->szName);
93 if (!wcscmp(pMap->szName, szName))
94 return pMap;
95
96 pMap = pMap->Next;
97 }
98
99 pMap = pAppMap->LabelMap;
100
101 while (pMap)
102 {
103 ASSERT(pMap);
104 ASSERT(pMap->szName);
105 if (!wcscmp(pMap->szName, szName))
106 return pMap;
107
108 pMap = pMap->Next;
109 }
110
111 pMap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LABEL_MAP));
112 if (!pMap)
113 return NULL;
114
115 pMap->szName = pMap->szDesc = _wcsdup(szName);
116 if (!pMap->szName)
117 {
118 HeapFree(GetProcessHeap(), 0, pMap);
119 return NULL;
120 }
121
122 pMap->AppMap = pAppMap;
123 pMap->Next = pGlobalData->pLabelMap;
124 pGlobalData->pLabelMap = pMap;
125
126 return pMap;
127 }
128
129
RemoveLabel(PGLOBAL_DATA pGlobalData,PLABEL_MAP pMap)130 VOID RemoveLabel(PGLOBAL_DATA pGlobalData, PLABEL_MAP pMap)
131 {
132 PLABEL_MAP pCurMap = pGlobalData->pLabelMap;
133
134 if (pCurMap == pMap)
135 {
136 pGlobalData->pLabelMap = pGlobalData->pLabelMap->Next;
137 return;
138 }
139
140 while (pCurMap)
141 {
142 if (pCurMap->Next == pMap)
143 {
144 pCurMap->Next = pCurMap->Next->Next;
145 return;
146 }
147 pCurMap = pCurMap->Next;
148 }
149 }
150
151 static
152 VOID
FreeLabelMap(PGLOBAL_DATA pGlobalData)153 FreeLabelMap(PGLOBAL_DATA pGlobalData)
154 {
155 PLABEL_MAP pCurMap;
156
157 while (pGlobalData->pLabelMap)
158 {
159 pCurMap = pGlobalData->pLabelMap->Next;
160
161 /* Prevent double freeing (for "FindLabel") */
162 if (pGlobalData->pLabelMap->szName != pGlobalData->pLabelMap->szDesc)
163 {
164 free(pGlobalData->pLabelMap->szName);
165 }
166
167 free(pGlobalData->pLabelMap->szDesc);
168 free(pGlobalData->pLabelMap->szIcon);
169
170 HeapFree(GetProcessHeap(), 0, pGlobalData->pLabelMap);
171 pGlobalData->pLabelMap = pCurMap;
172 }
173 }
174
FindApp(PGLOBAL_DATA pGlobalData,PCWSTR szName)175 PAPP_MAP FindApp(PGLOBAL_DATA pGlobalData, PCWSTR szName)
176 {
177 PAPP_MAP pMap = pGlobalData->pAppMap;
178
179 while (pMap)
180 {
181 if (!wcscmp(pMap->szName, szName))
182 return pMap;
183
184 pMap = pMap->Next;
185
186 }
187 return NULL;
188 }
189
190 static
191 VOID
FreeAppMap(PGLOBAL_DATA pGlobalData)192 FreeAppMap(PGLOBAL_DATA pGlobalData)
193 {
194 PAPP_MAP pCurMap;
195
196 while (pGlobalData->pAppMap)
197 {
198 pCurMap = pGlobalData->pAppMap->Next;
199 HeapFree(GetProcessHeap(), 0, pGlobalData->pAppMap);
200 pGlobalData->pAppMap = pCurMap;
201 }
202 }
203
FindLabelContext(PGLOBAL_DATA pGlobalData,PSOUND_SCHEME_CONTEXT pSoundScheme,PCWSTR AppName,PCWSTR LabelName)204 PLABEL_CONTEXT FindLabelContext(PGLOBAL_DATA pGlobalData, PSOUND_SCHEME_CONTEXT pSoundScheme, PCWSTR AppName, PCWSTR LabelName)
205 {
206 PLABEL_CONTEXT pLabelContext;
207
208 pLabelContext = pSoundScheme->LabelContext;
209
210 while (pLabelContext)
211 {
212 ASSERT(pLabelContext->AppMap);
213 ASSERT(pLabelContext->LabelMap);
214
215 if (!_wcsicmp(pLabelContext->AppMap->szName, AppName) && !_wcsicmp(pLabelContext->LabelMap->szName, LabelName))
216 {
217 return pLabelContext;
218 }
219 pLabelContext = pLabelContext->Next;
220 }
221
222 pLabelContext = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LABEL_CONTEXT));
223 if (!pLabelContext)
224 return NULL;
225
226 pLabelContext->AppMap = FindApp(pGlobalData, AppName);
227 pLabelContext->LabelMap = FindLabel(pGlobalData, pLabelContext->AppMap, LabelName);
228 ASSERT(pLabelContext->AppMap);
229 ASSERT(pLabelContext->LabelMap);
230 pLabelContext->szValue[0] = UNICODE_NULL;
231 pLabelContext->Next = pSoundScheme->LabelContext;
232 pSoundScheme->LabelContext = pLabelContext;
233
234 return pLabelContext;
235 }
236
237
238 BOOL
LoadEventLabel(PGLOBAL_DATA pGlobalData,HKEY hKey,PCWSTR szSubKey)239 LoadEventLabel(PGLOBAL_DATA pGlobalData, HKEY hKey, PCWSTR szSubKey)
240 {
241 HKEY hSubKey;
242 DWORD cbValue;
243 WCHAR szDesc[MAX_PATH];
244 WCHAR szData[MAX_PATH];
245 PLABEL_MAP pMap;
246
247 if (RegOpenKeyExW(hKey,
248 szSubKey,
249 0,
250 KEY_READ,
251 &hSubKey) != ERROR_SUCCESS)
252 {
253 return FALSE;
254 }
255
256 cbValue = sizeof(szDesc);
257 if (RegQueryValueExW(hSubKey,
258 NULL,
259 NULL,
260 NULL,
261 (LPBYTE)szDesc,
262 &cbValue) != ERROR_SUCCESS)
263 {
264 RegCloseKey(hSubKey);
265 return FALSE;
266 }
267
268 cbValue = sizeof(szData);
269 if (RegQueryValueExW(hSubKey,
270 L"DispFileName",
271 NULL,
272 NULL,
273 (LPBYTE)szData,
274 &cbValue) != ERROR_SUCCESS)
275 {
276 RegCloseKey(hSubKey);
277 return FALSE;
278 }
279
280 pMap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LABEL_MAP));
281 if (!pMap)
282 {
283 return FALSE;
284 }
285
286 pMap->szName = _wcsdup(szSubKey);
287 pMap->szDesc = _wcsdup(szDesc);
288 pMap->szIcon = _wcsdup(szData);
289
290 if (pGlobalData->pLabelMap)
291 {
292 pMap->Next = pGlobalData->pLabelMap;
293 pGlobalData->pLabelMap = pMap;
294 }
295 else
296 {
297 pGlobalData->pLabelMap = pMap;
298 pGlobalData->pLabelMap->Next = NULL;
299 }
300 return TRUE;
301 }
302
303
304 BOOL
LoadEventLabels(PGLOBAL_DATA pGlobalData)305 LoadEventLabels(PGLOBAL_DATA pGlobalData)
306 {
307 HKEY hSubKey;
308 DWORD dwCurKey;
309 WCHAR szName[MAX_PATH];
310 DWORD dwName;
311 DWORD dwResult;
312 DWORD dwCount;
313 if (RegOpenKeyExW(HKEY_CURRENT_USER,
314 L"AppEvents\\EventLabels",
315 0,
316 KEY_READ,
317 &hSubKey) != ERROR_SUCCESS)
318 {
319 return FALSE;
320 }
321
322 dwCurKey = 0;
323 dwCount = 0;
324 do
325 {
326 dwName = _countof(szName);
327 dwResult = RegEnumKeyExW(hSubKey,
328 dwCurKey,
329 szName,
330 &dwName,
331 NULL,
332 NULL,
333 NULL,
334 NULL);
335
336 if (dwResult == ERROR_SUCCESS)
337 {
338 if (LoadEventLabel(pGlobalData, hSubKey, szName))
339 {
340 dwCount++;
341 }
342 }
343 dwCurKey++;
344
345 } while (dwResult == ERROR_SUCCESS);
346
347 RegCloseKey(hSubKey);
348 return (dwCount != 0);
349 }
350
351
352 BOOL
AddSoundProfile(HWND hwndDlg,HKEY hKey,PCWSTR szSubKey,BOOL SetDefault)353 AddSoundProfile(HWND hwndDlg, HKEY hKey, PCWSTR szSubKey, BOOL SetDefault)
354 {
355 HKEY hSubKey;
356 WCHAR szValue[MAX_PATH];
357 DWORD cbValue, dwResult;
358 LRESULT lResult;
359 PSOUND_SCHEME_CONTEXT pScheme;
360
361 if (RegOpenKeyExW(hKey,
362 szSubKey,
363 0,
364 KEY_READ,
365 &hSubKey) != ERROR_SUCCESS)
366 {
367 return FALSE;
368 }
369
370 cbValue = sizeof(szValue);
371 dwResult = RegQueryValueExW(hSubKey,
372 NULL,
373 NULL,
374 NULL,
375 (LPBYTE)szValue,
376 &cbValue);
377 RegCloseKey(hSubKey);
378
379 if (dwResult != ERROR_SUCCESS)
380 return FALSE;
381
382 /* Try to add the new profile */
383 lResult = ComboBox_AddString(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME), szValue);
384 if (lResult == CB_ERR)
385 return FALSE;
386
387 /* Allocate the profile scheme buffer */
388 pScheme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOUND_SCHEME_CONTEXT));
389 if (pScheme == NULL)
390 {
391 /* We failed to allocate the buffer, no need to keep a dangling string in the combobox */
392 ComboBox_DeleteString(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME), lResult);
393 return FALSE;
394 }
395
396 StringCchCopyW(pScheme->szDesc, _countof(pScheme->szDesc), szValue);
397 StringCchCopyW(pScheme->szName, _countof(pScheme->szName), szSubKey);
398
399 /* Associate the value with the item in the combobox */
400 ComboBox_SetItemData(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME), lResult, pScheme);
401
402 /* Optionally, select the profile */
403 if (SetDefault)
404 {
405 ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME), lResult);
406 }
407
408 return TRUE;
409 }
410
411
412 DWORD
EnumerateSoundProfiles(PGLOBAL_DATA pGlobalData,HWND hwndDlg,HKEY hKey)413 EnumerateSoundProfiles(PGLOBAL_DATA pGlobalData, HWND hwndDlg, HKEY hKey)
414 {
415 HKEY hSubKey;
416 DWORD dwName, dwCurKey, dwResult, dwNumSchemes;
417 DWORD cbDefault;
418 WCHAR szName[MAX_PATH];
419
420 cbDefault = sizeof(pGlobalData->szDefault);
421 if (RegQueryValueExW(hKey,
422 NULL,
423 NULL,
424 NULL,
425 (LPBYTE)pGlobalData->szDefault,
426 &cbDefault) != ERROR_SUCCESS)
427 {
428 return FALSE;
429 }
430
431 if (RegOpenKeyExW(hKey,
432 L"Names",
433 0,
434 KEY_READ,
435 &hSubKey) != ERROR_SUCCESS)
436 {
437 return FALSE;
438 }
439
440 dwNumSchemes = 0;
441 dwCurKey = 0;
442 do
443 {
444 dwName = _countof(szName);
445 dwResult = RegEnumKeyExW(hSubKey,
446 dwCurKey,
447 szName,
448 &dwName,
449 NULL,
450 NULL,
451 NULL,
452 NULL);
453
454 if (dwResult == ERROR_SUCCESS)
455 {
456 if (AddSoundProfile(hwndDlg, hSubKey, szName, (!_wcsicmp(szName, pGlobalData->szDefault))))
457 {
458 dwNumSchemes++;
459 }
460 }
461
462 dwCurKey++;
463 } while (dwResult == ERROR_SUCCESS);
464
465 RegCloseKey(hSubKey);
466 return dwNumSchemes;
467 }
468
469
FindSoundProfile(HWND hwndDlg,PCWSTR szName)470 PSOUND_SCHEME_CONTEXT FindSoundProfile(HWND hwndDlg, PCWSTR szName)
471 {
472 LRESULT lCount, lIndex, lResult;
473 PSOUND_SCHEME_CONTEXT pScheme;
474 HWND hwndComboBox;
475
476 hwndComboBox = GetDlgItem(hwndDlg, IDC_SOUND_SCHEME);
477 lCount = ComboBox_GetCount(hwndComboBox);
478 if (lCount == CB_ERR)
479 {
480 return NULL;
481 }
482
483 for (lIndex = 0; lIndex < lCount; lIndex++)
484 {
485 lResult = ComboBox_GetItemData(hwndComboBox, lIndex);
486 if (lResult == CB_ERR)
487 {
488 continue;
489 }
490
491 pScheme = (PSOUND_SCHEME_CONTEXT)lResult;
492 if (!_wcsicmp(pScheme->szName, szName))
493 {
494 return pScheme;
495 }
496 }
497 return NULL;
498 }
499
500 static
501 VOID
FreeSoundProfiles(HWND hwndDlg)502 FreeSoundProfiles(HWND hwndDlg)
503 {
504 LRESULT lCount, lIndex, lResult;
505 PSOUND_SCHEME_CONTEXT pScheme;
506 PLABEL_CONTEXT pLabelContext;
507 HWND hwndComboBox;
508
509 hwndComboBox = GetDlgItem(hwndDlg, IDC_SOUND_SCHEME);
510 lCount = ComboBox_GetCount(hwndComboBox);
511 if (lCount == CB_ERR)
512 return;
513
514 for (lIndex = 0; lIndex < lCount; lIndex++)
515 {
516 lResult = ComboBox_GetItemData(hwndComboBox, lIndex);
517 if (lResult == CB_ERR)
518 {
519 continue;
520 }
521
522 pScheme = (PSOUND_SCHEME_CONTEXT)lResult;
523
524 while (pScheme->LabelContext)
525 {
526 pLabelContext = pScheme->LabelContext->Next;
527 HeapFree(GetProcessHeap(), 0, pScheme->LabelContext);
528 pScheme->LabelContext = pLabelContext;
529 }
530
531 HeapFree(GetProcessHeap(), 0, pScheme);
532 }
533 }
534
535 BOOL
ImportSoundLabel(PGLOBAL_DATA pGlobalData,HWND hwndDlg,HKEY hKey,PCWSTR szProfile,PCWSTR szLabelName,PCWSTR szAppName,PAPP_MAP AppMap,PLABEL_MAP LabelMap)536 ImportSoundLabel(PGLOBAL_DATA pGlobalData, HWND hwndDlg, HKEY hKey, PCWSTR szProfile, PCWSTR szLabelName, PCWSTR szAppName, PAPP_MAP AppMap, PLABEL_MAP LabelMap)
537 {
538 HKEY hSubKey;
539 WCHAR szValue[MAX_PATH];
540 WCHAR szBuffer[MAX_PATH];
541 DWORD cbValue, cchLength;
542 PSOUND_SCHEME_CONTEXT pScheme;
543 PLABEL_CONTEXT pLabelContext;
544 BOOL bCurrentProfile, bActiveProfile;
545
546 bCurrentProfile = !_wcsicmp(szProfile, L".Current");
547 bActiveProfile = !_wcsicmp(szProfile, pGlobalData->szDefault);
548
549 if (RegOpenKeyExW(hKey,
550 szProfile,
551 0,
552 KEY_READ,
553 &hSubKey) != ERROR_SUCCESS)
554 {
555 return FALSE;
556 }
557
558 cbValue = sizeof(szValue);
559 if (RegQueryValueExW(hSubKey,
560 NULL,
561 NULL,
562 NULL,
563 (LPBYTE)szValue,
564 &cbValue) != ERROR_SUCCESS)
565 {
566 return FALSE;
567 }
568
569 if (bCurrentProfile)
570 pScheme = FindSoundProfile(hwndDlg, pGlobalData->szDefault);
571 else
572 pScheme = FindSoundProfile(hwndDlg, szProfile);
573
574 if (!pScheme)
575 {
576 return FALSE;
577 }
578 pLabelContext = FindLabelContext(pGlobalData, pScheme, AppMap->szName, LabelMap->szName);
579
580 cchLength = ExpandEnvironmentStringsW(szValue, szBuffer, _countof(szBuffer));
581 if (cchLength == 0 || cchLength > _countof(szBuffer))
582 {
583 /* fixme */
584 return FALSE;
585 }
586
587 if (bCurrentProfile)
588 StringCchCopyW(pLabelContext->szValue, _countof(pLabelContext->szValue), szBuffer);
589 else if (!bActiveProfile)
590 StringCchCopyW(pLabelContext->szValue, _countof(pLabelContext->szValue), szBuffer);
591
592 return TRUE;
593 }
594
595
596 DWORD
ImportSoundEntry(PGLOBAL_DATA pGlobalData,HWND hwndDlg,HKEY hKey,PCWSTR szLabelName,PCWSTR szAppName,PAPP_MAP pAppMap)597 ImportSoundEntry(PGLOBAL_DATA pGlobalData, HWND hwndDlg, HKEY hKey, PCWSTR szLabelName, PCWSTR szAppName, PAPP_MAP pAppMap)
598 {
599 HKEY hSubKey;
600 DWORD dwNumProfiles;
601 DWORD dwCurKey;
602 DWORD dwResult;
603 DWORD dwProfile;
604 WCHAR szProfile[MAX_PATH];
605 PLABEL_MAP pLabel;
606
607 if (RegOpenKeyExW(hKey,
608 szLabelName,
609 0,
610 KEY_READ,
611 &hSubKey) != ERROR_SUCCESS)
612 {
613 return FALSE;
614 }
615 pLabel = FindLabel(pGlobalData, pAppMap, szLabelName);
616
617 ASSERT(pLabel);
618 RemoveLabel(pGlobalData, pLabel);
619
620 pLabel->AppMap = pAppMap;
621 pLabel->Next = pAppMap->LabelMap;
622 pAppMap->LabelMap = pLabel;
623
624 dwNumProfiles = 0;
625 dwCurKey = 0;
626 do
627 {
628 dwProfile = _countof(szProfile);
629 dwResult = RegEnumKeyExW(hSubKey,
630 dwCurKey,
631 szProfile,
632 &dwProfile,
633 NULL,
634 NULL,
635 NULL,
636 NULL);
637
638 if (dwResult == ERROR_SUCCESS)
639 {
640 if (ImportSoundLabel(pGlobalData, hwndDlg, hSubKey, szProfile, szLabelName, szAppName, pAppMap, pLabel))
641 {
642 dwNumProfiles++;
643 }
644 }
645
646 dwCurKey++;
647 } while (dwResult == ERROR_SUCCESS);
648
649 RegCloseKey(hSubKey);
650
651 return dwNumProfiles;
652 }
653
654
655 DWORD
ImportAppProfile(PGLOBAL_DATA pGlobalData,HWND hwndDlg,HKEY hKey,PCWSTR szAppName)656 ImportAppProfile(PGLOBAL_DATA pGlobalData, HWND hwndDlg, HKEY hKey, PCWSTR szAppName)
657 {
658 HKEY hSubKey;
659 WCHAR szDefault[MAX_PATH];
660 DWORD cbValue;
661 DWORD dwCurKey;
662 DWORD dwResult;
663 DWORD dwNumEntry;
664 DWORD dwName;
665 WCHAR szName[MAX_PATH];
666 WCHAR szIcon[MAX_PATH];
667 PAPP_MAP AppMap;
668
669 AppMap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APP_MAP));
670 if (!AppMap)
671 return 0;
672
673 if (RegOpenKeyExW(hKey,
674 szAppName,
675 0,
676 KEY_READ,
677 &hSubKey) != ERROR_SUCCESS)
678 {
679 HeapFree(GetProcessHeap(), 0, AppMap);
680 return 0;
681 }
682
683 cbValue = sizeof(szDefault);
684 if (RegQueryValueExW(hSubKey,
685 NULL,
686 NULL,
687 NULL,
688 (LPBYTE)szDefault,
689 &cbValue) != ERROR_SUCCESS)
690 {
691 RegCloseKey(hSubKey);
692 HeapFree(GetProcessHeap(), 0, AppMap);
693 return 0;
694 }
695
696 cbValue = sizeof(szIcon);
697 if (RegQueryValueExW(hSubKey,
698 L"DispFileName",
699 NULL,
700 NULL,
701 (LPBYTE)szIcon,
702 &cbValue) != ERROR_SUCCESS)
703 {
704 szIcon[0] = UNICODE_NULL;
705 }
706
707 /* initialize app map */
708 StringCchCopyW(AppMap->szName, _countof(AppMap->szName), szAppName);
709 StringCchCopyW(AppMap->szDesc, _countof(AppMap->szDesc), szDefault);
710 StringCchCopyW(AppMap->szIcon, _countof(AppMap->szIcon), szIcon);
711
712 AppMap->Next = pGlobalData->pAppMap;
713 pGlobalData->pAppMap = AppMap;
714
715
716 dwCurKey = 0;
717 dwNumEntry = 0;
718 do
719 {
720 dwName = _countof(szName);
721 dwResult = RegEnumKeyExW(hSubKey,
722 dwCurKey,
723 szName,
724 &dwName,
725 NULL,
726 NULL,
727 NULL,
728 NULL);
729 if (dwResult == ERROR_SUCCESS)
730 {
731 if (ImportSoundEntry(pGlobalData, hwndDlg, hSubKey, szName, szAppName, AppMap))
732 {
733 dwNumEntry++;
734 }
735 }
736 dwCurKey++;
737 } while (dwResult == ERROR_SUCCESS);
738
739 RegCloseKey(hSubKey);
740 return dwNumEntry;
741 }
742
743
744 BOOL
ImportSoundProfiles(PGLOBAL_DATA pGlobalData,HWND hwndDlg,HKEY hKey)745 ImportSoundProfiles(PGLOBAL_DATA pGlobalData, HWND hwndDlg, HKEY hKey)
746 {
747 DWORD dwCurKey;
748 DWORD dwResult;
749 DWORD dwNumApps;
750 WCHAR szName[MAX_PATH];
751 HKEY hSubKey;
752
753 if (RegOpenKeyExW(hKey,
754 L"Apps",
755 0,
756 KEY_READ,
757 &hSubKey) != ERROR_SUCCESS)
758 {
759 return FALSE;
760 }
761
762 dwNumApps = 0;
763 dwCurKey = 0;
764 do
765 {
766 dwResult = RegEnumKeyW(hSubKey,
767 dwCurKey,
768 szName,
769 _countof(szName));
770
771 if (dwResult == ERROR_SUCCESS)
772 {
773 if (ImportAppProfile(pGlobalData, hwndDlg, hSubKey, szName))
774 {
775 dwNumApps++;
776 }
777 }
778 dwCurKey++;
779 } while (dwResult == ERROR_SUCCESS);
780
781 RegCloseKey(hSubKey);
782
783 return (dwNumApps != 0);
784 }
785
786
787 BOOL
LoadSoundProfiles(PGLOBAL_DATA pGlobalData,HWND hwndDlg)788 LoadSoundProfiles(PGLOBAL_DATA pGlobalData, HWND hwndDlg)
789 {
790 HKEY hSubKey;
791 DWORD dwNumSchemes;
792
793 if (RegOpenKeyExW(HKEY_CURRENT_USER,
794 L"AppEvents\\Schemes",
795 0,
796 KEY_READ,
797 &hSubKey) != ERROR_SUCCESS)
798 {
799 return FALSE;
800 }
801
802 dwNumSchemes = EnumerateSoundProfiles(pGlobalData, hwndDlg, hSubKey);
803
804
805 if (dwNumSchemes)
806 {
807 ImportSoundProfiles(pGlobalData, hwndDlg, hSubKey);
808 }
809
810 RegCloseKey(hSubKey);
811 return FALSE;
812 }
813
814
815 BOOL
LoadSoundFiles(HWND hwndDlg)816 LoadSoundFiles(HWND hwndDlg)
817 {
818 WCHAR szList[256];
819 WCHAR szPath[MAX_PATH];
820 PWSTR ptr;
821 WIN32_FIND_DATAW FileData;
822 HANDLE hFile;
823 LRESULT lResult;
824 UINT length;
825
826 /* Add no sound listview item */
827 if (LoadStringW(hApplet, IDS_NO_SOUND, szList, _countof(szList)))
828 {
829 szList[_countof(szList) - 1] = UNICODE_NULL;
830 ComboBox_AddString(GetDlgItem(hwndDlg, IDC_SOUND_LIST), szList);
831 }
832
833 /* Load sound files */
834 length = GetWindowsDirectoryW(szPath, _countof(szPath));
835 if (length == 0 || length >= _countof(szPath) - CONST_STR_LEN(L"\\media\\*"))
836 {
837 return FALSE;
838 }
839
840 //PathCchAppend(szPath, _countof(szPath), L"media\\*");
841 StringCchCatW(szPath, _countof(szPath), L"\\media\\*");
842
843 hFile = FindFirstFileW(szPath, &FileData);
844 if (hFile == INVALID_HANDLE_VALUE)
845 {
846 return FALSE;
847 }
848
849 do
850 {
851 if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
852 continue;
853
854 ptr = wcsrchr(FileData.cFileName, L'\\');
855 if (ptr)
856 {
857 ptr++;
858 }
859 else
860 {
861 ptr = FileData.cFileName;
862 }
863 lResult = SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, 0, (LPARAM)ptr);
864 if (lResult != CB_ERR)
865 {
866 StringCchCopyW(szPath + (length + CONST_STR_LEN(L"\\media\\")),
867 _countof(szPath) - (length + CONST_STR_LEN(L"\\media\\")),
868 FileData.cFileName);
869 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)_wcsdup(szPath));
870 }
871 } while (FindNextFileW(hFile, &FileData) != 0);
872
873 FindClose(hFile);
874 return TRUE;
875 }
876
877 static
878 VOID
FreeSoundFiles(HWND hwndDlg)879 FreeSoundFiles(HWND hwndDlg)
880 {
881 LRESULT lCount, lIndex, lResult;
882 PWSTR pSoundPath;
883 HWND hwndComboBox;
884
885 hwndComboBox = GetDlgItem(hwndDlg, IDC_SOUND_LIST);
886 lCount = ComboBox_GetCount(hwndComboBox);
887 if (lCount == CB_ERR)
888 return;
889
890 for (lIndex = 0; lIndex < lCount; lIndex++)
891 {
892 lResult = ComboBox_GetItemData(hwndComboBox, lIndex);
893 if (lResult == CB_ERR)
894 {
895 continue;
896 }
897
898 pSoundPath = (PWSTR)lResult;
899 free(pSoundPath);
900 }
901 }
902
903 static
904 LRESULT
FindSoundFileInList(HWND hwndDlg,LPCWSTR pSoundPath)905 FindSoundFileInList(HWND hwndDlg, LPCWSTR pSoundPath)
906 {
907 LRESULT lCount, lIndex, lResult;
908 LPWSTR pszPath;
909 HWND hwndComboBox;
910
911 hwndComboBox = GetDlgItem(hwndDlg, IDC_SOUND_LIST);
912 lCount = ComboBox_GetCount(hwndComboBox);
913 if (lCount == CB_ERR)
914 return CB_ERR;
915
916 for (lIndex = 0; lIndex < lCount; lIndex++)
917 {
918 lResult = ComboBox_GetItemData(hwndComboBox, lIndex);
919 if (lResult == CB_ERR || lResult == 0)
920 continue;
921
922 pszPath = (LPWSTR)lResult;
923 if (_wcsicmp(pszPath, pSoundPath) == 0)
924 return lIndex;
925 }
926
927 return CB_ERR;
928 }
929
930 BOOL
ShowSoundScheme(PGLOBAL_DATA pGlobalData,HWND hwndDlg)931 ShowSoundScheme(PGLOBAL_DATA pGlobalData, HWND hwndDlg)
932 {
933 LRESULT lIndex;
934 PSOUND_SCHEME_CONTEXT pScheme;
935 PAPP_MAP pAppMap;
936 PLABEL_MAP pLabelMap;
937 PLABEL_CONTEXT pLabelContext;
938 HWND hDlgCtrl, hList;
939 TVINSERTSTRUCTW tvItem;
940 HTREEITEM hTreeItem;
941
942 hDlgCtrl = GetDlgItem(hwndDlg, IDC_SOUND_SCHEME);
943 hList = GetDlgItem(hwndDlg, IDC_SCHEME_LIST);
944
945 if (pGlobalData->hSoundsImageList != NULL)
946 {
947 TreeView_SetImageList(hList, pGlobalData->hSoundsImageList, TVSIL_NORMAL);
948 }
949
950 lIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
951 if (lIndex == CB_ERR)
952 {
953 return FALSE;
954 }
955
956 lIndex = SendMessageW(hDlgCtrl, CB_GETITEMDATA, (WPARAM)lIndex, 0);
957 if (lIndex == CB_ERR)
958 {
959 return FALSE;
960 }
961 pScheme = (PSOUND_SCHEME_CONTEXT)lIndex;
962
963 StringCchCopyW(pGlobalData->szDefault, _countof(pGlobalData->szDefault), pScheme->szName);
964
965 pAppMap = pGlobalData->pAppMap;
966 while (pAppMap)
967 {
968 ZeroMemory(&tvItem, sizeof(tvItem));
969 tvItem.hParent = TVI_ROOT;
970 tvItem.hInsertAfter = TVI_FIRST;
971
972 tvItem.item.mask = TVIF_STATE | TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
973 tvItem.item.state = TVIS_EXPANDED;
974 tvItem.item.stateMask = TVIS_EXPANDED;
975 tvItem.item.pszText = pAppMap->szDesc;
976 tvItem.item.iImage = IMAGE_SOUND_SECTION;
977 tvItem.item.iSelectedImage = IMAGE_SOUND_SECTION;
978 tvItem.item.lParam = (LPARAM)NULL;
979
980 hTreeItem = TreeView_InsertItem(hList, &tvItem);
981
982 pLabelMap = pAppMap->LabelMap;
983 while (pLabelMap)
984 {
985 pLabelContext = FindLabelContext(pGlobalData, pScheme, pAppMap->szName, pLabelMap->szName);
986
987 ZeroMemory(&tvItem, sizeof(tvItem));
988 tvItem.hParent = hTreeItem;
989 tvItem.hInsertAfter = TVI_SORT;
990
991 tvItem.item.mask = TVIF_STATE | TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
992 tvItem.item.state = TVIS_EXPANDED;
993 tvItem.item.stateMask = TVIS_EXPANDED;
994 tvItem.item.pszText = pLabelMap->szDesc;
995 if (pLabelContext->szValue && wcslen(pLabelContext->szValue) > 0)
996 {
997 tvItem.item.iImage = IMAGE_SOUND_ASSIGNED;
998 tvItem.item.iSelectedImage = IMAGE_SOUND_ASSIGNED;
999 }
1000 else
1001 {
1002 tvItem.item.iImage = IMAGE_SOUND_NONE;
1003 tvItem.item.iSelectedImage = IMAGE_SOUND_NONE;
1004 }
1005 tvItem.item.lParam = (LPARAM)FindLabelContext(pGlobalData, pScheme, pAppMap->szName, pLabelMap->szName);
1006
1007 TreeView_InsertItem(hList, &tvItem);
1008
1009 pLabelMap = pLabelMap->Next;
1010 }
1011 pAppMap = pAppMap->Next;
1012 }
1013 return TRUE;
1014 }
1015
1016
1017 BOOL
ApplyChanges(HWND hwndDlg)1018 ApplyChanges(HWND hwndDlg)
1019 {
1020 HKEY hKey, hSubKey;
1021 DWORD dwType;
1022 LRESULT lIndex;
1023 PSOUND_SCHEME_CONTEXT pScheme;
1024 HWND hDlgCtrl;
1025 PLABEL_CONTEXT pLabelContext;
1026 WCHAR Buffer[100];
1027
1028 hDlgCtrl = GetDlgItem(hwndDlg, IDC_SOUND_SCHEME);
1029
1030 lIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
1031 if (lIndex == CB_ERR)
1032 {
1033 return FALSE;
1034 }
1035
1036 lIndex = SendMessageW(hDlgCtrl, CB_GETITEMDATA, (WPARAM)lIndex, 0);
1037 if (lIndex == CB_ERR)
1038 {
1039 return FALSE;
1040 }
1041 pScheme = (PSOUND_SCHEME_CONTEXT)lIndex;
1042
1043 if (RegOpenKeyExW(HKEY_CURRENT_USER,
1044 L"AppEvents\\Schemes",
1045 0,
1046 KEY_WRITE,
1047 &hKey) != ERROR_SUCCESS)
1048 {
1049 return FALSE;
1050 }
1051
1052 RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pScheme->szName, (wcslen(pScheme->szName) + 1) * sizeof(WCHAR));
1053 RegCloseKey(hKey);
1054
1055 if (RegOpenKeyExW(HKEY_CURRENT_USER,
1056 L"AppEvents\\Schemes\\Apps",
1057 0,
1058 KEY_WRITE,
1059 &hKey) != ERROR_SUCCESS)
1060 {
1061 return FALSE;
1062 }
1063
1064 pLabelContext = pScheme->LabelContext;
1065
1066 while (pLabelContext)
1067 {
1068 StringCchPrintfW(Buffer, _countof(Buffer), L"%s\\%s\\.Current", pLabelContext->AppMap->szName, pLabelContext->LabelMap->szName);
1069
1070 if (RegOpenKeyExW(hKey, Buffer, 0, KEY_WRITE, &hSubKey) == ERROR_SUCCESS)
1071 {
1072 dwType = (wcschr(pLabelContext->szValue, L'%') ? REG_EXPAND_SZ : REG_SZ);
1073 RegSetValueExW(hSubKey, NULL, 0, dwType, (LPBYTE)pLabelContext->szValue, (wcslen(pLabelContext->szValue) + 1) * sizeof(WCHAR));
1074 RegCloseKey(hSubKey);
1075 }
1076
1077 pLabelContext = pLabelContext->Next;
1078 }
1079 RegCloseKey(hKey);
1080
1081 SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)PSNRET_NOERROR);
1082 return TRUE;
1083 }
1084
1085
1086 HIMAGELIST
InitImageList(UINT StartResource,UINT EndResource,UINT Width,UINT Height,ULONG type)1087 InitImageList(UINT StartResource,
1088 UINT EndResource,
1089 UINT Width,
1090 UINT Height,
1091 ULONG type)
1092 {
1093 HANDLE hImage;
1094 HIMAGELIST himl;
1095 UINT i;
1096 INT ret;
1097
1098 /* Create the toolbar icon image list */
1099 himl = ImageList_Create(Width,
1100 Height,
1101 ILC_MASK | ILC_COLOR32,
1102 EndResource - StartResource,
1103 0);
1104 if (himl == NULL)
1105 return NULL;
1106
1107 ret = 0;
1108 for (i = StartResource; i <= EndResource && ret != -1; i++)
1109 {
1110 hImage = LoadImageW(hApplet,
1111 MAKEINTRESOURCEW(i),
1112 type,
1113 Width,
1114 Height,
1115 LR_LOADTRANSPARENT);
1116 if (hImage == NULL)
1117 {
1118 ret = -1;
1119 break;
1120 }
1121
1122 if (type == IMAGE_BITMAP)
1123 {
1124 ret = ImageList_AddMasked(himl,
1125 hImage,
1126 RGB(255, 0, 128));
1127 }
1128 else if (type == IMAGE_ICON)
1129 {
1130 ret = ImageList_AddIcon(himl,
1131 hImage);
1132 }
1133
1134 DeleteObject(hImage);
1135 }
1136
1137 if (ret == -1)
1138 {
1139 ImageList_Destroy(himl);
1140 himl = NULL;
1141 }
1142
1143 return himl;
1144 }
1145
1146
1147 /**
1148 * @brief
1149 * Get the duration of a waveform audio file.
1150 *
1151 * @param[in] pFileName
1152 * The file name or full path of the file.
1153 *
1154 * @return
1155 * The duration of the sound, in milliseconds.
1156 * Returns 0 in case of failure.
1157 **/
1158 static
1159 DWORD
GetSoundDuration(LPCWSTR pFileName)1160 GetSoundDuration(LPCWSTR pFileName)
1161 {
1162 MCI_OPEN_PARMSW openParms;
1163 MCI_GENERIC_PARMS closeParms;
1164 MCI_SET_PARMS setParms;
1165 MCI_STATUS_PARMS statusParms;
1166 MCIERROR mciError;
1167
1168 ZeroMemory(&openParms, sizeof(openParms));
1169 openParms.lpstrDeviceType = L"waveaudio";
1170 openParms.lpstrElementName = pFileName;
1171
1172 mciError = mciSendCommandW(0,
1173 MCI_OPEN,
1174 MCI_OPEN_TYPE | MCI_OPEN_ELEMENT | MCI_WAIT,
1175 (DWORD_PTR)&openParms);
1176 if (mciError != 0)
1177 return 0;
1178
1179 ZeroMemory(&setParms, sizeof(setParms));
1180 setParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
1181
1182 mciError = mciSendCommandW(openParms.wDeviceID,
1183 MCI_SET,
1184 MCI_SET_TIME_FORMAT | MCI_WAIT,
1185 (DWORD_PTR)&setParms);
1186 if (mciError == 0)
1187 {
1188 ZeroMemory(&statusParms, sizeof(statusParms));
1189 statusParms.dwItem = MCI_STATUS_LENGTH;
1190
1191 mciError = mciSendCommandW(openParms.wDeviceID,
1192 MCI_STATUS,
1193 MCI_STATUS_ITEM | MCI_WAIT,
1194 (DWORD_PTR)&statusParms);
1195 }
1196
1197 closeParms.dwCallback = 0;
1198 mciSendCommandW(openParms.wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&closeParms);
1199
1200 if (mciError != 0)
1201 return 0;
1202
1203 return statusParms.dwReturn;
1204 }
1205
1206 static
1207 BOOL
StartSoundTest(HWND hwndDlg,LPCWSTR pszSound)1208 StartSoundTest(HWND hwndDlg, LPCWSTR pszSound)
1209 {
1210 DWORD dwDuration;
1211
1212 dwDuration = GetSoundDuration(pszSound);
1213 if (dwDuration == 0)
1214 return FALSE;
1215
1216 if (PlaySoundW(pszSound, NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT))
1217 {
1218 SetTimer(hwndDlg, ID_SOUND_TEST_TIMER, dwDuration, NULL);
1219 return TRUE;
1220 }
1221
1222 return FALSE;
1223 }
1224
1225 static
1226 BOOL
StopSoundTest(HWND hwndDlg)1227 StopSoundTest(HWND hwndDlg)
1228 {
1229 /* Check if the sound is playing */
1230 if (KillTimer(hwndDlg, ID_SOUND_TEST_TIMER))
1231 {
1232 /* Stop the sound */
1233 PlaySoundW(NULL, NULL, SND_ASYNC);
1234 return TRUE;
1235 }
1236
1237 return FALSE;
1238 }
1239
1240 /* Sounds property page dialog callback */
1241 INT_PTR
1242 CALLBACK
SoundsDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)1243 SoundsDlgProc(HWND hwndDlg,
1244 UINT uMsg,
1245 WPARAM wParam,
1246 LPARAM lParam)
1247 {
1248 PGLOBAL_DATA pGlobalData;
1249
1250 OPENFILENAMEW ofn;
1251 WCHAR filename[MAX_PATH];
1252 WCHAR szFilter[256], szTitle[256];
1253 LPWSTR pFileName;
1254 LRESULT lResult;
1255
1256 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtrW(hwndDlg, DWLP_USER);
1257
1258 switch (uMsg)
1259 {
1260 case WM_INITDIALOG:
1261 {
1262 pGlobalData = (PGLOBAL_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA));
1263 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
1264
1265 pGlobalData->NumWavOut = waveOutGetNumDevs();
1266
1267 pGlobalData->hPlayIcon = LoadImageW(hApplet,
1268 MAKEINTRESOURCEW(IDI_PLAY_ICON),
1269 IMAGE_ICON,
1270 32,
1271 32,
1272 LR_DEFAULTCOLOR);
1273 pGlobalData->hStopIcon = LoadImageW(hApplet,
1274 MAKEINTRESOURCEW(IDI_STOP_ICON),
1275 IMAGE_ICON,
1276 32,
1277 32,
1278 LR_DEFAULTCOLOR);
1279 SendDlgItemMessageW(hwndDlg, IDC_PLAY_SOUND, BM_SETIMAGE,
1280 IMAGE_ICON, (LPARAM)pGlobalData->hPlayIcon);
1281
1282 pGlobalData->hSoundsImageList = InitImageList(IDI_SOUND_SECTION,
1283 IDI_SOUND_ASSIGNED,
1284 GetSystemMetrics(SM_CXSMICON),
1285 GetSystemMetrics(SM_CXSMICON),
1286 IMAGE_ICON);
1287
1288 LoadEventLabels(pGlobalData);
1289 LoadSoundProfiles(pGlobalData, hwndDlg);
1290 LoadSoundFiles(hwndDlg);
1291 ShowSoundScheme(pGlobalData, hwndDlg);
1292
1293 if (wParam == (WPARAM)GetDlgItem(hwndDlg, IDC_SOUND_SCHEME))
1294 return TRUE;
1295 SetFocus(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME));
1296 return FALSE;
1297 }
1298 case WM_COMMAND:
1299 {
1300 switch (LOWORD(wParam))
1301 {
1302 case IDC_BROWSE_SOUND:
1303 {
1304 ZeroMemory(&ofn, sizeof(ofn));
1305 ofn.lStructSize = sizeof(ofn);
1306 ofn.hwndOwner = hwndDlg;
1307 ofn.lpstrFile = filename;
1308 ofn.lpstrFile[0] = UNICODE_NULL;
1309 ofn.nMaxFile = _countof(filename);
1310 LoadStringW(hApplet, IDS_WAVE_FILES_FILTER, szFilter, _countof(szFilter));
1311 ofn.lpstrFilter = MakeFilter(szFilter);
1312 ofn.nFilterIndex = 0;
1313 LoadStringW(hApplet, IDS_BROWSE_FOR_SOUND, szTitle, _countof(szTitle));
1314 ofn.lpstrTitle = szTitle;
1315 ofn.lpstrInitialDir = L"%SystemRoot%\\Media";
1316 ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
1317
1318 if (GetOpenFileNameW(&ofn))
1319 {
1320 // search if list already contains that sound
1321 lResult = FindSoundFileInList(hwndDlg, filename);
1322 if (lResult != CB_ERR)
1323 {
1324 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)lResult, 0);
1325 break;
1326 }
1327
1328 // extract file name
1329 pFileName = wcsrchr(filename, L'\\');
1330 ASSERT(pFileName != NULL);
1331 pFileName++;
1332
1333 // add to list
1334 lResult = SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, 0, (LPARAM)pFileName);
1335 if (lResult != CB_ERR)
1336 {
1337 // add path and select item
1338 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)_wcsdup(filename));
1339 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)lResult, 0);
1340 }
1341 }
1342 break;
1343 }
1344 case IDC_PLAY_SOUND:
1345 {
1346 LRESULT lIndex;
1347
1348 if (StopSoundTest(hwndDlg))
1349 {
1350 SendDlgItemMessageW(hwndDlg, IDC_PLAY_SOUND, BM_SETIMAGE,
1351 IMAGE_ICON, (LPARAM)pGlobalData->hPlayIcon);
1352 break;
1353 }
1354
1355 lIndex = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST));
1356 if (lIndex == CB_ERR)
1357 {
1358 break;
1359 }
1360
1361 lIndex = ComboBox_GetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex);
1362 if (lIndex != CB_ERR)
1363 {
1364 if (StartSoundTest(hwndDlg, (LPWSTR)lIndex))
1365 {
1366 SendDlgItemMessageW(hwndDlg, IDC_PLAY_SOUND, BM_SETIMAGE,
1367 IMAGE_ICON, (LPARAM)pGlobalData->hStopIcon);
1368 }
1369 }
1370 break;
1371 }
1372 case IDC_SOUND_SCHEME:
1373 {
1374 if (HIWORD(wParam) == CBN_SELENDOK)
1375 {
1376 TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_SCHEME_LIST));
1377 ShowSoundScheme(pGlobalData, hwndDlg);
1378 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), FALSE);
1379 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), FALSE);
1380 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1381 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), FALSE);
1382 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1383 }
1384 break;
1385 }
1386 case IDC_SOUND_LIST:
1387 {
1388 if (HIWORD(wParam) == CBN_SELENDOK)
1389 {
1390 PLABEL_CONTEXT pLabelContext;
1391 HTREEITEM hItem;
1392 TVITEMW item;
1393 LRESULT lIndex;
1394
1395 hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_SCHEME_LIST));
1396 if (hItem == NULL)
1397 {
1398 break;
1399 }
1400
1401 lIndex = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST));
1402 if (lIndex == CB_ERR)
1403 {
1404 break;
1405 }
1406
1407 ZeroMemory(&item, sizeof(item));
1408 item.mask = TVIF_PARAM;
1409 item.hItem = hItem;
1410 if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item))
1411 {
1412 LRESULT lResult;
1413 pLabelContext = (PLABEL_CONTEXT)item.lParam;
1414
1415 lResult = ComboBox_GetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex);
1416 if (lResult == CB_ERR || lResult == 0)
1417 {
1418 if (lIndex != pLabelContext->szValue[0])
1419 {
1420 /* Update the tree view item image */
1421 item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1422 item.iImage = IMAGE_SOUND_NONE;
1423 item.iSelectedImage = IMAGE_SOUND_NONE;
1424 TreeView_SetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item);
1425
1426 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1427
1428 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1429 }
1430
1431 pLabelContext->szValue[0] = UNICODE_NULL;
1432
1433 break;
1434 }
1435
1436 if (_wcsicmp(pLabelContext->szValue, (PWSTR)lResult) || (lIndex != pLabelContext->szValue[0]))
1437 {
1438 /* Update the tree view item image */
1439 item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1440 item.iImage = IMAGE_SOUND_ASSIGNED;
1441 item.iSelectedImage = IMAGE_SOUND_ASSIGNED;
1442 TreeView_SetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item);
1443
1444 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1445
1446 ///
1447 /// Should store in current member
1448 ///
1449 StringCchCopyW(pLabelContext->szValue, _countof(pLabelContext->szValue), (PWSTR)lResult);
1450 }
1451
1452 if (wcslen((PWSTR)lResult) && lIndex != 0 && pGlobalData->NumWavOut != 0)
1453 {
1454 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), TRUE);
1455 }
1456 else
1457 {
1458 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1459 }
1460 }
1461 }
1462 break;
1463 }
1464 }
1465 break;
1466 }
1467 case WM_DESTROY:
1468 {
1469 StopSoundTest(hwndDlg);
1470 FreeSoundFiles(hwndDlg);
1471 FreeSoundProfiles(hwndDlg);
1472 FreeAppMap(pGlobalData);
1473 FreeLabelMap(pGlobalData);
1474 if (pGlobalData->hSoundsImageList)
1475 ImageList_Destroy(pGlobalData->hSoundsImageList);
1476
1477 if (pGlobalData->hStopIcon)
1478 DestroyIcon(pGlobalData->hStopIcon);
1479
1480 if (pGlobalData->hPlayIcon)
1481 DestroyIcon(pGlobalData->hPlayIcon);
1482
1483 HeapFree(GetProcessHeap(), 0, pGlobalData);
1484 break;
1485 }
1486 case WM_NOTIFY:
1487 {
1488 PLABEL_CONTEXT pLabelContext;
1489 PWSTR ptr;
1490
1491 LPNMHDR lpnm = (LPNMHDR)lParam;
1492
1493 switch (lpnm->code)
1494 {
1495 case PSN_APPLY:
1496 {
1497 ApplyChanges(hwndDlg);
1498 break;
1499 }
1500 case PSN_KILLACTIVE:
1501 {
1502 if (StopSoundTest(hwndDlg))
1503 {
1504 SendDlgItemMessageW(hwndDlg, IDC_PLAY_SOUND, BM_SETIMAGE,
1505 IMAGE_ICON, (LPARAM)pGlobalData->hPlayIcon);
1506 }
1507
1508 break;
1509 }
1510 case TVN_SELCHANGED:
1511 {
1512 LPNMTREEVIEWW nm = (LPNMTREEVIEWW)lParam;
1513 LRESULT lCount, lIndex, lResult;
1514
1515 if (StopSoundTest(hwndDlg))
1516 {
1517 SendDlgItemMessageW(hwndDlg, IDC_PLAY_SOUND, BM_SETIMAGE,
1518 IMAGE_ICON, (LPARAM)pGlobalData->hPlayIcon);
1519 }
1520
1521 pLabelContext = (PLABEL_CONTEXT)nm->itemNew.lParam;
1522 if (pLabelContext == NULL)
1523 {
1524 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), FALSE);
1525 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), FALSE);
1526 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), FALSE);
1527 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1528 return FALSE;
1529 }
1530
1531 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), TRUE);
1532 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), TRUE);
1533 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), TRUE);
1534
1535 if (wcslen(pLabelContext->szValue) == 0)
1536 {
1537 lIndex = ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST), 0);
1538 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE);
1539 break;
1540 }
1541
1542 if (pGlobalData->NumWavOut != 0)
1543 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), TRUE);
1544
1545 lCount = ComboBox_GetCount(GetDlgItem(hwndDlg, IDC_SOUND_LIST));
1546 for (lIndex = 0; lIndex < lCount; lIndex++)
1547 {
1548 lResult = ComboBox_GetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex);
1549 if (lResult == CB_ERR || lResult == 0)
1550 continue;
1551
1552 if (!wcscmp((PWSTR)lResult, pLabelContext->szValue))
1553 {
1554 ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex);
1555 return FALSE;
1556 }
1557 }
1558
1559 ptr = wcsrchr(pLabelContext->szValue, L'\\');
1560 if (ptr)
1561 {
1562 ptr++;
1563 }
1564 else
1565 {
1566 ptr = pLabelContext->szValue;
1567 }
1568
1569 lIndex = ComboBox_AddString(GetDlgItem(hwndDlg, IDC_SOUND_LIST), ptr);
1570 if (lIndex != CB_ERR)
1571 {
1572 ComboBox_SetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex, _wcsdup(pLabelContext->szValue));
1573 ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex);
1574 }
1575 break;
1576 }
1577 }
1578 break;
1579 }
1580 case WM_TIMER:
1581 {
1582 if (wParam == ID_SOUND_TEST_TIMER)
1583 {
1584 KillTimer(hwndDlg, ID_SOUND_TEST_TIMER);
1585 SendDlgItemMessageW(hwndDlg, IDC_PLAY_SOUND, BM_SETIMAGE,
1586 IMAGE_ICON, (LPARAM)pGlobalData->hPlayIcon);
1587 }
1588
1589 break;
1590 }
1591 }
1592
1593 return FALSE;
1594 }
1595