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 ret = -1; 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 pGlobalData = (PGLOBAL_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA)); 1111 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData); 1112 1113 pGlobalData->NumWavOut = waveOutGetNumDevs(); 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 (wParam == (WPARAM)GetDlgItem(hwndDlg, IDC_SOUND_SCHEME)) 1131 return TRUE; 1132 SetFocus(GetDlgItem(hwndDlg, IDC_SOUND_SCHEME)); 1133 return FALSE; 1134 } 1135 case WM_COMMAND: 1136 { 1137 switch (LOWORD(wParam)) 1138 { 1139 case IDC_BROWSE_SOUND: 1140 { 1141 ZeroMemory(&ofn, sizeof(ofn)); 1142 ofn.lStructSize = sizeof(ofn); 1143 ofn.hwndOwner = hwndDlg; 1144 ofn.lpstrFile = filename; 1145 ofn.lpstrFile[0] = L'\0'; 1146 ofn.nMaxFile = _countof(filename); 1147 LoadStringW(hApplet, IDS_WAVE_FILES_FILTER, szFilter, _countof(szFilter)); 1148 ofn.lpstrFilter = MakeFilter(szFilter); 1149 ofn.nFilterIndex = 0; 1150 LoadStringW(hApplet, IDS_BROWSE_FOR_SOUND, szTitle, _countof(szTitle)); 1151 ofn.lpstrTitle = szTitle; 1152 ofn.lpstrInitialDir = L"%SystemRoot%\\Media"; 1153 ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 1154 1155 if (GetOpenFileNameW(&ofn) != FALSE) 1156 { 1157 // FIXME search if list already contains that sound 1158 1159 // extract file name 1160 pFileName = wcsrchr(filename, L'\\'); 1161 ASSERT(pFileName != NULL); 1162 pFileName++; 1163 1164 // add to list 1165 lResult = SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_ADDSTRING, (WPARAM)0, (LPARAM)pFileName); 1166 if (lResult != CB_ERR) 1167 { 1168 // add path and select item 1169 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)_wcsdup(filename)); 1170 SendDlgItemMessageW(hwndDlg, IDC_SOUND_LIST, CB_SETCURSEL, (WPARAM)lResult, (LPARAM)0); 1171 } 1172 } 1173 break; 1174 } 1175 case IDC_PLAY_SOUND: 1176 { 1177 LRESULT lIndex; 1178 lIndex = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST)); 1179 if (lIndex == CB_ERR) 1180 { 1181 break; 1182 } 1183 1184 lIndex = ComboBox_GetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex); 1185 if (lIndex != CB_ERR) 1186 { 1187 PlaySound((TCHAR*)lIndex, NULL, SND_FILENAME); 1188 } 1189 break; 1190 } 1191 case IDC_SOUND_SCHEME: 1192 { 1193 if (HIWORD(wParam) == CBN_SELENDOK) 1194 { 1195 (void)TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_SCHEME_LIST)); 1196 ShowSoundScheme(pGlobalData, hwndDlg); 1197 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), FALSE); 1198 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), FALSE); 1199 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE); 1200 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), FALSE); 1201 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1202 } 1203 break; 1204 } 1205 case IDC_SOUND_LIST: 1206 { 1207 if (HIWORD(wParam) == CBN_SELENDOK) 1208 { 1209 PLABEL_CONTEXT pLabelContext; 1210 HTREEITEM hItem; 1211 TVITEM item; 1212 LRESULT lIndex; 1213 1214 hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_SCHEME_LIST)); 1215 if (hItem == NULL) 1216 { 1217 break; 1218 } 1219 1220 lIndex = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST)); 1221 if (lIndex == CB_ERR) 1222 { 1223 break; 1224 } 1225 1226 ZeroMemory(&item, sizeof(item)); 1227 item.mask = TVIF_PARAM; 1228 item.hItem = hItem; 1229 if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item)) 1230 { 1231 LRESULT lResult; 1232 pLabelContext = (PLABEL_CONTEXT)item.lParam; 1233 1234 lResult = ComboBox_GetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex); 1235 if (lResult == CB_ERR || lResult == 0) 1236 { 1237 if (lIndex != pLabelContext->szValue[0]) 1238 { 1239 /* Update the tree view item image */ 1240 item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; 1241 item.iImage = IMAGE_SOUND_NONE; 1242 item.iSelectedImage = IMAGE_SOUND_NONE; 1243 TreeView_SetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item); 1244 1245 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1246 1247 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE); 1248 } 1249 1250 pLabelContext->szValue[0] = L'\0'; 1251 1252 break; 1253 } 1254 1255 if (_tcsicmp(pLabelContext->szValue, (TCHAR*)lResult) || (lIndex != pLabelContext->szValue[0])) 1256 { 1257 /* Update the tree view item image */ 1258 item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; 1259 item.iImage = IMAGE_SOUND_ASSIGNED; 1260 item.iSelectedImage = IMAGE_SOUND_ASSIGNED; 1261 TreeView_SetItem(GetDlgItem(hwndDlg, IDC_SCHEME_LIST), &item); 1262 1263 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1264 1265 /// 1266 /// Should store in current member 1267 /// 1268 _tcscpy(pLabelContext->szValue, (TCHAR*)lResult); 1269 } 1270 1271 if (_tcslen((TCHAR*)lResult) && lIndex != 0 && pGlobalData->NumWavOut != 0) 1272 { 1273 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), TRUE); 1274 } 1275 else 1276 { 1277 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE); 1278 } 1279 } 1280 } 1281 break; 1282 } 1283 } 1284 break; 1285 } 1286 case WM_DESTROY: 1287 { 1288 FreeSoundProfiles(hwndDlg); 1289 FreeAppMap(pGlobalData); 1290 FreeLabelMap(pGlobalData); 1291 if (pGlobalData->hSoundsImageList) 1292 ImageList_Destroy(pGlobalData->hSoundsImageList); 1293 HeapFree(GetProcessHeap(), 0, pGlobalData); 1294 break; 1295 } 1296 case WM_NOTIFY: 1297 { 1298 PLABEL_CONTEXT pLabelContext; 1299 TCHAR * ptr; 1300 1301 LPNMHDR lpnm = (LPNMHDR)lParam; 1302 1303 switch(lpnm->code) 1304 { 1305 case PSN_APPLY: 1306 { 1307 ApplyChanges(hwndDlg); 1308 break; 1309 } 1310 case TVN_SELCHANGED: 1311 { 1312 LPNMTREEVIEW nm = (LPNMTREEVIEW)lParam; 1313 LRESULT lCount, lIndex, lResult; 1314 1315 pLabelContext = (PLABEL_CONTEXT)nm->itemNew.lParam; 1316 if (pLabelContext == NULL) 1317 { 1318 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), FALSE); 1319 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), FALSE); 1320 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), FALSE); 1321 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE); 1322 return FALSE; 1323 } 1324 1325 EnableWindow(GetDlgItem(hwndDlg, IDC_SOUND_LIST), TRUE); 1326 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_SOUND), TRUE); 1327 EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE_SOUND), TRUE); 1328 1329 if (_tcslen(pLabelContext->szValue) == 0) 1330 { 1331 lIndex = ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST), 0); 1332 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), FALSE); 1333 break; 1334 } 1335 1336 if (pGlobalData->NumWavOut != 0) 1337 EnableWindow(GetDlgItem(hwndDlg, IDC_PLAY_SOUND), TRUE); 1338 1339 lCount = ComboBox_GetCount(GetDlgItem(hwndDlg, IDC_SOUND_LIST)); 1340 for (lIndex = 0; lIndex < lCount; lIndex++) 1341 { 1342 lResult = ComboBox_GetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex); 1343 if (lResult == CB_ERR || lResult == 0) 1344 continue; 1345 1346 if (!_tcscmp((TCHAR*)lResult, pLabelContext->szValue)) 1347 { 1348 ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex); 1349 return FALSE; 1350 } 1351 } 1352 1353 ptr = _tcsrchr(pLabelContext->szValue, _T('\\')); 1354 if (ptr) 1355 { 1356 ptr++; 1357 } 1358 else 1359 { 1360 ptr = pLabelContext->szValue; 1361 } 1362 1363 lIndex = ComboBox_AddString(GetDlgItem(hwndDlg, IDC_SOUND_LIST), ptr); 1364 if (lIndex != CB_ERR) 1365 { 1366 ComboBox_SetItemData(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex, _tcsdup(pLabelContext->szValue)); 1367 ComboBox_SetCurSel(GetDlgItem(hwndDlg, IDC_SOUND_LIST), lIndex); 1368 } 1369 break; 1370 } 1371 } 1372 } 1373 break; 1374 } 1375 1376 return FALSE; 1377 } 1378