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