Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

881 lines
32 KiB

  1. /*
  2. ** SND.C
  3. **
  4. ** Sound applet for the NT Control Panel.
  5. **
  6. */
  7. /* Revision history:
  8. * Laurie Griffiths 19/12/91 Ported the windows 3.1 code to NT
  9. */
  10. /*=============================================================================
  11. | The whole thing is kicked off by Init.c
  12. | When the DLL is loaded DllInitialize in init.c is called (as a result of
  13. | the DLLENTRY line in SOURCES). This just loads some static strings
  14. | with values dug out of resources.
  15. |
  16. | The control panel then calls CPlApplet in init.c with a series of
  17. | messages which are explained in control\h\cpl.h
  18. |
  19. | The CPL_INQUIRE message is different in 3.1 (CPL_NEWINQUIRE).
  20. |
  21. | The big one is CPL_DBLCLK which is the go signal.
  22. | A dialog box is created in RunApplet in init.c with window procedure
  23. | SoundDlg (end of this file).
  24. |
  25. | WM_INITDIALOG is the trigger to fill the list boxes with text which is
  26. | taken from the INI file (InitDialog). If there is no wave device present
  27. | then it just allows the user to set the message beep flag (displays
  28. | original state and allows alteration). If there is a wave device then
  29. | the Test button is enabled. Whether or not there is a device to play the
  30. | files, you can still assign them to events. This could be useful
  31. | to someone installing the system. There's no real reason why they should
  32. | be forced to configure the sound board first.
  33. |
  34. | Currently it does a message box to say that there's no sound board.
  35. | Is this too intrusive?
  36. |
  37. | The calling tree looks like:
  38. |
  39. | DllInitialize loads resources
  40. |
  41. | CPlApplet main entry point from control panel (in init.c)
  42. | RunApplet brings up dialog box (in init.c)
  43. | DialogBox
  44. | SoundDlg dialog procedure
  45. | InitDialog
  46. | FindDescription find description in <name=file,descr> string
  47. | ShowSound show filename associated with a sound
  48. | NewSound update list box with new <name,file,descr>
  49. | catPath concatenate path onto file
  50. | DrawItem draw item in list box
  51. | DrawItemText draw text of item
  52. | GetSoundEntry interrogate list box
  53. | ControlMessage process messages from controls in dialogs
  54. | EnablePlay enable/disable the TEST button
  55. | FillDirBox fill list box from files in current dir
  56. | ShowSound show filename associated with a sound
  57. | PlayTheSound play the i-th sound entry
  58. | GetSoundEntry interrogate list box
  59. | WriteSounds write out a new [sounds] section
  60. | ChangeSound change the filename associated with a sound
  61. | QualifyFileName get full path name of file
  62. | NewSound update list box with new <name,file,descr>
  63. | GetSoundEntry interrogate list box
  64. |
  65. | The following are called from several places in the above
  66. |
  67. | GetSoundEntry
  68. | FindDescription find description in <name=file,descr> string
  69. |
  70. | EnablePlay enable/disable the TEST button
  71. | GetSoundEntry interrogate list box
  72. |
  73. | ShowSound show filename associated with a sound
  74. | GetSoundEntry interrogate list box
  75. | QualifyFileName get full path name of file
  76. | FileName extract file name from full path name
  77. | StripPathName split path into path and file by inserting null
  78. | FileName extract file name from full path name
  79. | FillDirBox fill list box from files in current dir
  80. | EnablePlay enable/disable the TEST button
  81. ============================================================================*/
  82. #include <windows.h>
  83. #include <mmsystem.h>
  84. #include <port1632.h>
  85. #include <cphelp.h>
  86. #include <cpl.h>
  87. #include <shellapi.h>
  88. #include "snd.h"
  89. #define SetWindowRedraw(hwnd, fRedraw) \
  90. ((VOID)SendMessage(hwnd, WM_SETREDRAW, (UINT)(BOOL)(fRedraw), 0L))
  91. /*---------------------------------------------------------------------------*/
  92. #define STRSIZ MAX_PATH // maximum size of a string or filename
  93. #define MAXINI 4096 // max size of all ini keys in [sounds] section
  94. #define SLASH(c) ((c) == '/' || (c) == '\\')
  95. /*
  96. ** DLGOPEN private definitions
  97. **/
  98. #define ATTRFILELIST 0x0000 // include files only
  99. #define ATTRDIRLIST 0xC010 // directories and drives ONLY
  100. /*---------------------------------------------------------------------------*/
  101. static SZCODE aszNull[] = "";
  102. static SZCODE aszDirSeparator[] = "\\";
  103. static SZCODE aszResourceDir[]= "resource";
  104. static SZCODE aszSounds[] = "sounds";
  105. static SZCODE aszNewSoundFindFormat[] = "%s=";
  106. static SZCODE aszNewSoundFormat[] = "%s=%s,%s";
  107. static SZCODE aszCurrentDir[] = ".";
  108. static SZCODE aszFileFilter[] = "*.wav";
  109. static char aszAllFiles[] = "*.*"; // this is written on by DlgDirList()
  110. static BOOL fSndPlaySound; // sound board working
  111. static BOOL fIniChanged;
  112. static BOOL fEnabled= FALSE; // True iff [Sounds] Enabled=1 in Win.ini
  113. #if PARANOIA
  114. /*---------------------------------------------------------------------------
  115. | put <title><str>"\n" out onto debug screen
  116. ----------------------------------------------------------------------------*/
  117. void Trace(LPSTR lpstr, LPSTR lpstrTitle)
  118. { char msg[255];
  119. if (!lpstr) lpstr = "";
  120. if (!lpstrTitle) lpstrTitle = "SOUND: SND.C";
  121. wsprintf(msg, "%s %s\n", lpstrTitle, lpstr);
  122. OutputDebugString(msg);
  123. } /* Trace */
  124. #endif
  125. /*---------------------------------------------------------------------------
  126. | ?
  127. ----------------------------------------------------------------------------*/
  128. static VOID PASCAL NEAR CPHelp( HWND hwnd, DWORD dContext)
  129. { WinHelp(hwnd, aszSoundHlp, HELP_CONTEXT, dContext);
  130. } /* CPHelp */
  131. /*---------------------------------------------------------------------------
  132. | lszEntry points to a string from WIN.INI
  133. | split it at the start of the description by inserting 0 and return
  134. | pointer to the description
  135. |
  136. | CASE1 (nice -- delimiter present )
  137. | input string : text<delim>text
  138. | return ptr : ^
  139. | output string: text0 text
  140. | where <delim> ::= ","[{<tab>|<space>|","}...]
  141. | 0 represents the end-of-string delimiter
  142. |
  143. | CASE2 (nasty -- no delimiter present )
  144. | input string : text0
  145. | return ptr : ^
  146. | output string: text0
  147. | (Since Fangled And Tangled file systems allow spaces in names, the delimiter
  148. | rules were changed from DOS require the delimiter to start with comma).
  149. ----------------------------------------------------------------------------*/
  150. static LPSTR FindDescription( LPSTR lszEntry)
  151. {
  152. /* skip to next end-of-string or comma (space or tab no longer count) */
  153. for (
  154. ; *lszEntry && *lszEntry!=','
  155. ; lszEntry++
  156. )
  157. ;
  158. if (*lszEntry)
  159. { BOOL fComma;
  160. fComma = (*lszEntry == ',');
  161. *lszEntry = (char)0;
  162. /* skip the inserted null and any following blanks and tabs */
  163. for (lszEntry++; *lszEntry == ' ' || *lszEntry == '\t'; lszEntry++)
  164. ;
  165. /* if now found a comma and hadn't before, skip tabs and spaces again */
  166. if (!fComma && (*lszEntry == ','))
  167. { for (lszEntry++; *lszEntry == ' ' || *lszEntry == '\t'; lszEntry++)
  168. ;
  169. }
  170. }
  171. return lszEntry;
  172. } /* FindDescription */
  173. /*---------------------------------------------------------------------------
  174. | Get (Event, File, Description) from the iListEntry-th entry in the NAMES list box
  175. | iListEntry==-1 means use the current selection
  176. | Supplying NULL for any of these PLPSTRs is safe and means don't bother
  177. | to return this item.
  178. ----------------------------------------------------------------------------*/
  179. static VOID NEAR GetSoundEntry( HWND hwnd /* dialog box */
  180. , int iListEntry /* number of event */
  181. , LPSTR lszEvent /* event name returned */
  182. , LPSTR lszFile /* file name returned */
  183. , LPSTR lszDescription /* description returned */
  184. )
  185. { char aszBuffer[STRSIZ];
  186. LPSTR lszCur;
  187. LPSTR lszStart;
  188. /* aszBuffer = text of iListEntry-th entry in list box, -1 => use current */
  189. hwnd = GetDlgItem(hwnd, LB_NAMES);
  190. if (iListEntry == -1)
  191. iListEntry = (int)(LONG)
  192. SendMessage(hwnd, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
  193. lstrcpy(aszBuffer, (PSTR)SendMessage(hwnd, LB_GETITEMDATA, (WPARAM)iListEntry, (LPARAM)0));
  194. /* replace "=" in aszBuffer with NULL (there'd better be one there!) */
  195. for (lszCur = aszBuffer; *lszCur != '='; lszCur++)
  196. ;
  197. *lszCur = (char)0;
  198. /* lszEvent = <Event> from list entry */
  199. if (lszEvent)
  200. { lstrcpy(lszEvent, aszBuffer);
  201. }
  202. lszStart = ++lszCur;
  203. lszCur = FindDescription(lszCur);
  204. if (lszFile)
  205. { if (!lstrcmpi(lszStart, aszNoSound))
  206. *lszFile = (char)0;
  207. else
  208. lstrcpy(lszFile, lszStart);
  209. }
  210. if (lszDescription)
  211. { if (!*lszCur)
  212. lszCur = aszBuffer;
  213. lstrcpy(lszDescription, lszCur);
  214. }
  215. }/* GetSoundEntry */
  216. /*---------------------------------------------------------------------------
  217. | get full path name of file. Return TRUE iff it worked.
  218. | updates lszFile, assumes there is enough room.
  219. ----------------------------------------------------------------------------*/
  220. static BOOL NEAR PASCAL QualifyFileName( LPSTR lszFile )
  221. { OFSTRUCT of;
  222. UINT fErrMode;
  223. BOOL fReturn;
  224. fErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); /* return errors to us */
  225. if ( OpenFile( lszFile
  226. , &of
  227. , OF_EXIST | OF_SHARE_DENY_NONE | OF_READ
  228. )
  229. != HFILE_ERROR
  230. )
  231. { OemToAnsi(of.szPathName, lszFile);
  232. fReturn = TRUE;
  233. } else
  234. fReturn = FALSE;
  235. SetErrorMode(fErrMode);
  236. return fReturn;
  237. }/* QualifyFileName */
  238. /*---------------------------------------------------------------------------
  239. | update lszPath to point to file-name at end of path-and-file-name
  240. ----------------------------------------------------------------------------*/
  241. static LPSTR NEAR PASCAL FileName( LPCSTR lszPath)
  242. { LPCSTR lszCur;
  243. /* move forward to first null */
  244. for (lszCur = lszPath; *lszCur; lszCur++)
  245. ;
  246. /* move backwards until find SLASH or colon */
  247. for (; lszCur >= lszPath && !SLASH(*lszCur) && *lszCur != ':'; lszCur--)
  248. ;
  249. /* move forwards one char */
  250. return (LPSTR)++lszCur;
  251. }/* FileName */
  252. /*---------------------------------------------------------------------------
  253. | update lszPath to insert a null at end of path (possibly hitting the "\"
  254. | possibly hitting the start of the file name)
  255. ----------------------------------------------------------------------------*/
  256. static VOID NEAR PASCAL StripPathName( LPSTR lszPath)
  257. { LPSTR lszCur;
  258. /* move on to first char of filename at end of path */
  259. lszCur = FileName(lszPath);
  260. /* if path at least two chars long and ends in \ and not in :\
  261. | then move back one char
  262. */
  263. if (lszCur > lszPath+1 && SLASH(lszCur[-1]) && lszCur[-2] != ':')
  264. lszCur--;
  265. /* insert null */
  266. *lszCur = (char)0;
  267. }/* StripPathName */
  268. /*---------------------------------------------------------------------------
  269. | show the filenames that can be associated with sounds
  270. ----------------------------------------------------------------------------*/
  271. static VOID NEAR FillDirBox( HWND hwnd
  272. , LPSTR lszDir // the path
  273. )
  274. { char aszCWD[STRSIZ];
  275. char aszNewCWD[STRSIZ];
  276. int iDirLen;
  277. UINT fErrMode;
  278. // remove any trailing '/'
  279. iDirLen = lstrlen(lszDir) - 1;
  280. if (SLASH(lszDir[iDirLen]) && lszDir[iDirLen - 1] != ':')
  281. lszDir[iDirLen] = (char)0;
  282. GetCurrentDirectory(STRSIZ, aszCWD);
  283. fErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); /* return errors to us */
  284. if ( !SetCurrentDirectory(lszDir) // set from string
  285. || !GetCurrentDirectory(STRSIZ, aszNewCWD) // get canonical form?
  286. )
  287. { /* failed! back out and beep */
  288. SetCurrentDirectory(aszCWD);
  289. SetErrorMode(fErrMode);
  290. MessageBeep(0);
  291. } else
  292. { HWND hwndFiles;
  293. SetErrorMode(fErrMode);
  294. hwndFiles = GetDlgItem(hwnd, LB_FILES);
  295. if ( !(int)(LONG)
  296. SendMessage( hwndFiles, LB_GETCOUNT, (WPARAM)0, (LPARAM)0)
  297. || lstrcmpi(aszNewCWD, aszCWD)
  298. )
  299. { /* Fill directory listbox from current directory */
  300. SetWindowRedraw(hwndFiles, FALSE);
  301. DlgDirList(hwnd, aszAllFiles, LB_FILES, ID_DIR, ATTRDIRLIST);
  302. SendMessage( hwndFiles
  303. , LB_DIR
  304. , (WPARAM)ATTRFILELIST
  305. , (LPARAM)(LPCSTR)aszFileFilter
  306. );
  307. SetWindowRedraw(hwndFiles, TRUE);
  308. SendMessage( hwndFiles
  309. , LB_ADDSTRING
  310. , (WPARAM)0
  311. , (LPARAM)(LPCSTR)aszNoSound
  312. );
  313. }
  314. }
  315. }/* FillDirBox */
  316. /*---------------------------------------------------------------------------
  317. | Enable or Disable the test button, file and sound displays
  318. ----------------------------------------------------------------------------*/
  319. static VOID NEAR EnablePlay( HWND hwnd)
  320. { char aszFile[STRSIZ];
  321. int iSelection;
  322. BOOL fSelection;
  323. HWND hwndFiles;
  324. hwndFiles = GetDlgItem(hwnd, LB_FILES);
  325. iSelection = (int)(LONG)
  326. SendMessage(hwndFiles, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
  327. fSelection = DlgDirSelectEx(hwnd, aszFile, STRSIZ, LB_FILES);
  328. GetSoundEntry(hwnd, -1, NULL, aszFile, NULL);
  329. EnableWindow( GetDlgItem(hwnd, ID_PLAY) // the TEST button
  330. , fSndPlaySound
  331. && !fSelection
  332. && *aszFile
  333. && (iSelection != LB_ERR)
  334. );
  335. // enable disable the listboxes -- actually always enable (LKG)
  336. EnableWindow(GetDlgItem(hwnd, LB_NAMES), TRUE || fSndPlaySound);
  337. EnableWindow(hwndFiles, TRUE || fSndPlaySound);
  338. }/* EnablePlay */
  339. /*---------------------------------------------------------------------------
  340. | Select the i-th element in the event NAMES list box
  341. | Look up the file from the registry.
  342. | Refill the FILES list box based on the dir containing the file
  343. | Highlight (select) the file associated with it in the FILES list box
  344. | if possible - the filename from the registry might be crap
  345. | If there is no file, set the selection to no sound
  346. ----------------------------------------------------------------------------*/
  347. static VOID NEAR ShowSound( HWND hwnd, int i)
  348. { char aszFile[STRSIZ];
  349. char aszPath[STRSIZ];
  350. if (i != -1)
  351. SendDlgItemMessage(hwnd, LB_NAMES, LB_SETCURSEL, (WPARAM)i, (LPARAM)0);
  352. GetSoundEntry(hwnd, i, NULL, aszFile, NULL);
  353. lstrcpy(aszPath, aszFile);
  354. if (QualifyFileName(aszPath))
  355. {
  356. LRESULT lRc;
  357. StripPathName(aszPath); /* aszPath is now just the path */
  358. FillDirBox(hwnd, aszPath);
  359. lRc = SendDlgItemMessage( hwnd
  360. , LB_FILES
  361. , LB_SELECTSTRING
  362. , (WPARAM)-1
  363. , (LPARAM)FileName(aszFile)
  364. );
  365. if (lRc==-1) {
  366. /* We couldn't find the file name in the list box.
  367. ** The most likely reason is that the file name contains a comma
  368. ** and we have stored the short file name in the registry.
  369. ** (storing file names with commas in the registry breaks the
  370. ** parsing scheme which is inherited from DOS. Some apps go
  371. ** looking there so we need to keep compatibility.
  372. ** FindFirstFile is how you get the long name back
  373. */
  374. WIN32_FIND_DATA fd;
  375. FindFirstFile(aszFile, &fd);
  376. lRc = SendDlgItemMessage( hwnd
  377. , LB_FILES
  378. , LB_SELECTSTRING
  379. , (WPARAM)-1
  380. , (LPARAM)FileName(fd.cFileName)
  381. );
  382. if (lRc==-1) {
  383. /* Can't even find the long name - maybe there' stuff in the registry
  384. ** or the file has been deleted.
  385. */
  386. SendDlgItemMessage(hwnd, LB_FILES, LB_SETCURSEL, (WPARAM)(-1), (LPARAM)0);
  387. }
  388. }
  389. } else
  390. {
  391. FillDirBox(hwnd, aszCurrentDir);
  392. SendDlgItemMessage( hwnd
  393. , LB_FILES
  394. , LB_SELECTSTRING
  395. , (WPARAM)-1
  396. , (LPARAM)(LPCSTR)aszNoSound
  397. );
  398. }
  399. EnablePlay(hwnd);
  400. }/* ShowSound */
  401. /*---------------------------------------------------------------------------
  402. | play the filename associated with a sound
  403. ----------------------------------------------------------------------------*/
  404. static VOID NEAR PlayTheSound( HWND hwnd, int i)
  405. { char aszFile[STRSIZ];
  406. GetSoundEntry(hwnd, i, NULL, aszFile, NULL);
  407. // play the sound if it is not associated with <none>
  408. if (fSndPlaySound && *aszFile)
  409. { BOOL fPlayed;
  410. HCURSOR hcur;
  411. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  412. fPlayed = sndPlaySound(aszFile, SND_ASYNC | SND_FILENAME);
  413. #if PARANOIA
  414. Trace("Sound should have played", NULL);
  415. #endif //DBG
  416. SetCursor(hcur);
  417. // The sound did not play, tell the user.
  418. if (!fPlayed)
  419. MessageBox(hwnd, aszErrorPlayMessage, aszErrorPlayTitle, MB_OK);
  420. }
  421. }/* PlayTheSound */
  422. /*---------------------------------------------------------------------------
  423. | update list box.
  424. | add/repl any <lszEvent>=... entry with <lszEvent>=<lszFile>,<lszDescription>
  425. ----------------------------------------------------------------------------*/
  426. static VOID NEAR NewSound( HWND hwnd /* dialog box window handle */
  427. , LPCSTR lszEvent
  428. , LPCSTR lszFile
  429. , LPCSTR lszDescription
  430. )
  431. {
  432. PSTR szEntry;
  433. int iSound;
  434. int iNewSound;
  435. hwnd = GetDlgItem(hwnd, LB_NAMES);
  436. /*
  437. ** The original Win 31 did not check the return value from LocalAlloc
  438. ** i'll just return if we could not allocate the storage.
  439. */
  440. szEntry = (PSTR)LocalAlloc(LMEM_FIXED, lstrlen(lszEvent)
  441. + lstrlen(lszFile)
  442. + lstrlen(lszDescription) + 3);
  443. if ( szEntry == NULL ) {
  444. return;
  445. }
  446. iSound = (int)(LONG)SendMessage(hwnd, LB_FINDSTRING, (WPARAM)-1, (LPARAM)lszDescription);
  447. if (iSound == LB_ERR)
  448. iNewSound = (int)(DWORD)SendMessage(hwnd, LB_ADDSTRING,
  449. (WPARAM)0, (LPARAM)lszDescription);
  450. else {
  451. LocalFree((HLOCAL)SendMessage(hwnd, LB_GETITEMDATA,
  452. (WPARAM)iSound, (LPARAM)0));
  453. iNewSound = iSound;
  454. }
  455. wsprintf(szEntry, aszNewSoundFormat, lszEvent, lszFile, lszDescription);
  456. SendMessage(hwnd, LB_SETITEMDATA, (WPARAM)iNewSound, (LPARAM)szEntry );
  457. if (iSound == LB_ERR)
  458. SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iNewSound, (LPARAM)0);
  459. if (iSound != LB_ERR)
  460. SetWindowRedraw(hwnd, TRUE);
  461. }/* NewSound */
  462. /*---------------------------------------------------------------------------
  463. | change the file associated with a sound
  464. ----------------------------------------------------------------------------*/
  465. static VOID NEAR ChangeSound(HWND hwnd,int iSound, LPSTR lszFile)
  466. { char aszName[STRSIZ];
  467. char aszDescription[STRSIZ];
  468. char aszShortName[STRSIZ];
  469. if (!QualifyFileName(lszFile))
  470. lszFile = aszNull;
  471. GetSoundEntry(hwnd, iSound, aszName, NULL, aszDescription);
  472. /* because long file names can contain commas which totally mess with the parsing
  473. of the directory entries (basically <event>=<file>,<descr>), if there is
  474. a comma in the long file name, we put the short one in instead.
  475. If the short name also has a comma, then we're in trouble. Such file
  476. names are not allowed! In this case we set the sound to <none>
  477. */
  478. if (0 != strchr(lszFile,',')) {
  479. GetShortPathName(lszFile, aszShortName, STRSIZ);
  480. lszFile = aszShortName;
  481. if (0 != strchr(lszFile,','))
  482. strcpy(lszFile, "<none>");
  483. }
  484. NewSound(hwnd, aszName, lszFile, aszDescription);
  485. }/* ChangeSound */
  486. /*---------------------------------------------------------------------------
  487. | write out a new [sounds] section
  488. ----------------------------------------------------------------------------*/
  489. static VOID NEAR WriteSounds(HWND hwnd)
  490. { int iSound;
  491. int iTotalSounds;
  492. BOOL bAllOK = TRUE; /* all sounds written OK */
  493. DWORD dwLastError = 0;
  494. /* The idea is to capture the error code of the first error that we see,
  495. to put up an error box in the event of any error (so that the user has
  496. some idea of what has happened), but to continue to the end anyway
  497. as it may be that it's still going to write all the data anyway
  498. */
  499. hwnd = GetDlgItem(hwnd, LB_NAMES);
  500. iTotalSounds = (int)(LONG)SendMessage( hwnd
  501. , LB_GETCOUNT
  502. , (WPARAM)0
  503. , (LPARAM)0
  504. );
  505. // delete the whole section;
  506. bAllOK = WriteProfileString(aszSounds, NULL, NULL);
  507. if (!bAllOK)
  508. { dwLastError = GetLastError();
  509. if (dwLastError==259) /* "No more items". This is normal */
  510. { bAllOK = TRUE;
  511. dwLastError = 0;
  512. }
  513. }
  514. //Write Enabled flag
  515. if(fEnabled)
  516. { BOOL bOK = WriteProfileString(aszSounds, "Enable", "1");
  517. if (bAllOK && !bOK)
  518. { dwLastError = GetLastError();
  519. }
  520. bAllOK = bAllOK && bOK;
  521. }
  522. else
  523. { BOOL bOK = WriteProfileString(aszSounds, "Enable", "0");
  524. if (bAllOK && !bOK)
  525. { dwLastError = GetLastError();
  526. }
  527. bAllOK = bAllOK && bOK;
  528. }
  529. for (iSound = 0; iSound < iTotalSounds; iSound++)
  530. { char aszBuffer[STRSIZ];
  531. LPSTR lszCur;
  532. BOOL bOK;
  533. lstrcpy(aszBuffer, (PSTR)SendMessage(hwnd, LB_GETITEMDATA, (WPARAM)iSound, (LPARAM)0));
  534. for (lszCur = aszBuffer; *lszCur != '='; lszCur++)
  535. ;
  536. *lszCur = (char)0;
  537. bOK = WriteProfileString(aszSounds, aszBuffer, lszCur + 1);
  538. if (bAllOK && !bOK)
  539. { dwLastError = GetLastError();
  540. }
  541. bAllOK = bAllOK && bOK;
  542. }
  543. if (!bAllOK)
  544. { char szErr[STRSIZ];
  545. wsprintf(szErr, aszWriteErr, GetLastError());
  546. MessageBox(hwnd, szErr, aszAppName, MB_OK);
  547. }
  548. SendMessage( (HWND)-1
  549. , WM_WININICHANGE
  550. , (WPARAM)0
  551. , (LPARAM)(LPCSTR)aszSounds
  552. );
  553. } /* WriteSounds */
  554. /*---------------------------------------------------------------------------
  555. | Process control message from dialog box
  556. ----------------------------------------------------------------------------*/
  557. static VOID PASCAL NEAR ControlMessage(HWND hwnd, WPARAM wParam, LPARAM lParam)
  558. {
  559. switch ((WORD)wParam)
  560. { HWND hwndFocus;
  561. case IDH_CHILD_SND:
  562. CPHelp(hwnd, dwContext);
  563. break;
  564. case IDOK:
  565. hwndFocus = GetFocus();
  566. if (hwndFocus && (GetDlgCtrlID(hwndFocus) == LB_FILES))
  567. #if defined(WIN16)
  568. PostMessage( hwnd
  569. , WM_COMMAND
  570. , (WPARAM)LB_FILES
  571. , MAKELPARAM(hwndFocus, LBN_DBLCLK)
  572. );
  573. #else
  574. PostMessage( hwnd
  575. , WM_COMMAND
  576. , (WPARAM)MAKELONG(LB_FILES,LBN_DBLCLK)
  577. , (LPARAM)hwndFocus
  578. );
  579. #endif //WIN16
  580. else
  581. { HCURSOR hcur;
  582. BOOL fBeep;
  583. if (fIniChanged)
  584. { if ( MessageBox( hwnd
  585. , aszWarningMessage
  586. , aszWarningTitle
  587. , MB_ICONEXCLAMATION | MB_OKCANCEL
  588. )
  589. == IDCANCEL
  590. )
  591. { // PostMessage(hwnd, WM_INITDIALOG, 0, 0L);
  592. //Bug #3298 -jyg-
  593. break;
  594. }
  595. }
  596. /* hourglass while we do things */
  597. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  598. /* write any sounds away. */
  599. if (fSndPlaySound)
  600. sndPlaySound(NULL, 0); // flush any cached sounds
  601. #if PARANOIA
  602. Trace("Sound should have been flushed", NULL);
  603. #endif //DBG
  604. WriteSounds(hwnd);
  605. /* Write the new beep setting */
  606. SystemParametersInfo(SPI_GETBEEP, 0, &fBeep, 0);
  607. if (fBeep != (BOOL)IsDlgButtonChecked(hwnd, ID_BEEP))
  608. SystemParametersInfo( SPI_SETBEEP
  609. , !fBeep
  610. , NULL
  611. , SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE
  612. );
  613. /* restore pointer */
  614. SetCursor(hcur);
  615. EndDialog(hwnd, TRUE);
  616. }
  617. break;
  618. case IDCANCEL:
  619. if (fSndPlaySound)
  620. sndPlaySound(NULL, 0); // Shut up when the dialog exits
  621. // meaningful when we go async
  622. #if PARANOIA
  623. Trace("Sound should have been killed", NULL);
  624. #endif // DBG
  625. EndDialog(hwnd, FALSE);
  626. break;
  627. case ID_PLAY:
  628. PlayTheSound(hwnd, -1);
  629. break;
  630. case ID_BEEP:
  631. break;
  632. case LB_NAMES:
  633. switch(HIWORD(wParam)) /* NT change, was HIWORD(lParam) */
  634. { case LBN_SELCHANGE:
  635. ShowSound(hwnd, -1);
  636. break;
  637. case LBN_DBLCLK:
  638. PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PLAY, (LPARAM)0);
  639. break;
  640. }
  641. break;
  642. case LB_FILES:
  643. switch(HIWORD(wParam))
  644. { char aszSelection[STRSIZ];
  645. case LBN_SELCHANGE:
  646. if (!DlgDirSelectEx(hwnd, aszSelection, STRSIZ, LB_FILES))
  647. ChangeSound(hwnd, -1, aszSelection);
  648. EnablePlay(hwnd);
  649. break;
  650. case LBN_DBLCLK:
  651. if (DlgDirSelectEx(hwnd, aszSelection, STRSIZ, LB_FILES))
  652. FillDirBox(hwnd, aszSelection);
  653. else
  654. PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PLAY, (LPARAM)0);
  655. break;
  656. }
  657. break;
  658. }
  659. }/* ControlMessage */
  660. /*---------------------------------------------------------------------------
  661. | lszpath = lszpath [\] xlsz
  662. | where xlsz is lsz with any leading drive: and .\ removed
  663. ----------------------------------------------------------------------------*/
  664. static VOID NEAR PASCAL catpath( LPSTR lszpath, LPCSTR lsz)
  665. {
  666. // Remove any drive letters from the directory to append
  667. if (lsz[1] == ':')
  668. lsz += 2;
  669. // Remove any current directories ".\" from directory to append
  670. while (*lsz == '.' && SLASH(lsz[1]))
  671. lsz += 2;
  672. // Dont append a NULL string or a single "."
  673. if (*lsz && !(*lsz == '.' && !lsz[1]))
  674. { /* add a "\" unless it already ends in "\" or ":" */
  675. if ( (!SLASH(lszpath[lstrlen(lszpath)-1]))
  676. && ((lszpath[lstrlen(lszpath)-1]) != ':')
  677. )
  678. lstrcat(lszpath, aszDirSeparator);
  679. lstrcat(lszpath, lsz);
  680. }
  681. }/* catpath */
  682. /*---------------------------------------------------------------------------
  683. | Initialse the dialog
  684. | fIniChanged = FALSE
  685. ----------------------------------------------------------------------------*/
  686. static BOOL PASCAL NEAR InitDialog( HWND hwnd /* dlg box window */
  687. )
  688. { char aszBuffer[STRSIZ];
  689. WAVEOUTCAPS woCaps;
  690. LPSTR lszSection;
  691. HANDLE hgSection;
  692. BOOL fBeep;
  693. BOOL fSoundsExist = TRUE;
  694. fIniChanged = FALSE;
  695. // Determine if there is a wave device;
  696. fSndPlaySound = waveOutGetNumDevs()
  697. && !waveOutGetDevCaps(0, &woCaps, sizeof(woCaps))
  698. && woCaps.dwFormats != 0L;
  699. /*********************************************
  700. * fSndPlaySound
  701. * = (IDYES==MessageBox(NULL,"Pretend sound device available?","???",MB_YESNO));
  702. **********************************************/
  703. if (!fSndPlaySound)
  704. MessageBox(hwnd, aszNoDevice, aszErrorPlayTitle, MB_OK);
  705. // Set the Windows Enabled flag
  706. fEnabled = (1==GetProfileInt(aszSounds, "Enable", 0));
  707. /* fill the list box with the [sounds] section of WIN.INI; */
  708. if ((hgSection = GlobalAlloc(GMEM_MOVEABLE, (DWORD)MAXINI)) == NULL)
  709. return FALSE;
  710. lszSection = (LPVOID)GlobalLock(hgSection);
  711. if (0<(int)GetProfileString(aszSounds, NULL, aszNull, lszSection, MAXINI))
  712. {
  713. for (; *lszSection; lszSection += lstrlen(lszSection) + 1)
  714. {
  715. LPSTR lszDescription;
  716. if (0>=(int)GetProfileString( aszSounds
  717. , lszSection
  718. , aszNull
  719. , aszBuffer
  720. , sizeof(aszBuffer)
  721. )
  722. ) break;
  723. /* split string by inserting null and get pointer to second part */
  724. lszDescription = FindDescription(aszBuffer);
  725. if (!*lszDescription)
  726. lszDescription = lszSection;
  727. if (0!=lstrcmpi(lszSection,"Enable"))
  728. {
  729. NewSound(hwnd, lszSection, aszBuffer, lszDescription);
  730. }
  731. }
  732. }
  733. else fSoundsExist = FALSE;
  734. GlobalUnlock(hgSection);
  735. GlobalFree(hgSection);
  736. // Try to change to the windows "resource" directory;
  737. // if that fails hit up the windows "system" directory;
  738. GetWindowsDirectory(aszBuffer, sizeof(aszBuffer));
  739. catpath(aszBuffer, aszResourceDir);
  740. if (!SetCurrentDirectory(aszBuffer))
  741. { GetSystemDirectory(aszBuffer, sizeof(aszBuffer));
  742. SetCurrentDirectory(aszBuffer);
  743. }
  744. // select the first sound; There might not be any courtesy SteveWo.
  745. if (fSoundsExist) ShowSound(hwnd, 0);
  746. // Get the beep enabled flag from USER;
  747. SystemParametersInfo(SPI_GETBEEP, 0, (&fBeep), 0);
  748. CheckDlgButton(hwnd, ID_BEEP, fBeep);
  749. }/* InitDialog */
  750. /*---------------------------------------------------------------------------*/
  751. static VOID PASCAL NEAR Destroy(
  752. HWND hwnd)
  753. {
  754. int iEvents;
  755. hwnd = GetDlgItem(hwnd, LB_NAMES);
  756. iEvents = (int)(DWORD)SendMessage(hwnd, LB_GETCOUNT, (WPARAM)0, (LPARAM)0);
  757. for (; iEvents--;)
  758. LocalFree((HLOCAL)SendMessage(hwnd, LB_GETITEMDATA, (WPARAM)iEvents, (LPARAM)0));
  759. }
  760. /*---------------------------------------------------------------------------
  761. | Dialog procedure for the dialog box
  762. ----------------------------------------------------------------------------*/
  763. INT_PTR SoundDlg( HWND hwnd
  764. , UINT uMsg
  765. , WPARAM wParam
  766. , LPARAM lParam
  767. )
  768. {
  769. switch (uMsg)
  770. {
  771. case WM_WININICHANGE:
  772. // See if someone has modified the sounds section or can't tell;
  773. if ( !lstrcmpi((LPCSTR)lParam, aszSounds)
  774. || !*((LPCSTR)lParam)
  775. )
  776. fIniChanged = TRUE;
  777. break;
  778. case WM_COMMAND:
  779. ControlMessage(hwnd, wParam, lParam);
  780. return TRUE;
  781. case WM_INITDIALOG:
  782. return InitDialog(hwnd);
  783. case WM_DESTROY:
  784. Destroy(hwnd);
  785. break;
  786. default:
  787. if (uMsg == uHelpMessage)
  788. { CPHelp(hwnd, dwContext);
  789. return TRUE;
  790. }
  791. break;
  792. }
  793. return FALSE;
  794. }/* SoundDlg */