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.

1968 lines
52 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1992 - 1994 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // acmapp.c
  13. //
  14. // Description:
  15. // This is a sample application that demonstrates how to use the
  16. // Audio Compression Manager API's in Windows. This application is
  17. // also useful as an ACM driver test.
  18. //
  19. //==========================================================================;
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <mmsystem.h>
  23. #include <commdlg.h>
  24. #include <shellapi.h>
  25. #include <stdarg.h>
  26. #include <memory.h>
  27. #include <mmreg.h>
  28. #include <msacm.h>
  29. #include "appport.h"
  30. #include "acmapp.h"
  31. #include "debug.h"
  32. //
  33. // globals, no less
  34. //
  35. HINSTANCE ghinst;
  36. BOOL gfAcmAvailable;
  37. UINT gfuAppOptions = APP_OPTIONSF_AUTOOPEN;
  38. HFONT ghfontApp;
  39. HACMDRIVERID ghadidNotify;
  40. UINT guWaveInId = (UINT)WAVE_MAPPER;
  41. UINT guWaveOutId = (UINT)WAVE_MAPPER;
  42. TCHAR gszNull[] = TEXT("");
  43. TCHAR gszAppProfile[] = TEXT("acmapp.ini");
  44. TCHAR gszYes[] = TEXT("Yes");
  45. TCHAR gszNo[] = TEXT("No");
  46. TCHAR gszAppName[APP_MAX_APP_NAME_CHARS];
  47. TCHAR gszFileUntitled[APP_MAX_FILE_TITLE_CHARS];
  48. TCHAR gszInitialDirOpen[APP_MAX_FILE_PATH_CHARS];
  49. TCHAR gszInitialDirSave[APP_MAX_FILE_PATH_CHARS];
  50. TCHAR gszLastSaveFile[APP_MAX_FILE_PATH_CHARS];
  51. ACMAPPFILEDESC gaafd;
  52. //==========================================================================;
  53. //
  54. // Application helper functions
  55. //
  56. //
  57. //==========================================================================;
  58. //--------------------------------------------------------------------------;
  59. //
  60. // int AppMsgBox
  61. //
  62. // Description:
  63. // This function displays a message for the application in a standard
  64. // message box.
  65. //
  66. // Note that this function takes any valid argument list that can
  67. // be passed to wsprintf. Because of this, the application must
  68. // remember to cast near string pointers to FAR when built for Win 16.
  69. // You will get a nice GP fault if you do not cast them correctly.
  70. //
  71. // Arguments:
  72. // HWND hwnd: Handle to parent window for message box holding the
  73. // message.
  74. //
  75. // UINT fuStyle: Style flags for MessageBox().
  76. //
  77. // PTSTR pszFormat: Format string used for wvsprintf().
  78. //
  79. // Return (int):
  80. // The return value is the result of MessageBox() function.
  81. //
  82. //--------------------------------------------------------------------------;
  83. int FNCGLOBAL AppMsgBox
  84. (
  85. HWND hwnd,
  86. UINT fuStyle,
  87. PTSTR pszFormat,
  88. ...
  89. )
  90. {
  91. va_list va;
  92. TCHAR ach[1024];
  93. int n;
  94. //
  95. // format and display the message..
  96. //
  97. va_start(va, pszFormat);
  98. #ifdef WIN32
  99. wvsprintf(ach, pszFormat, va);
  100. #else
  101. wvsprintf(ach, pszFormat, (LPSTR)va);
  102. #endif
  103. va_end(va);
  104. n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  105. return (n);
  106. } // AppMsgBox()
  107. //--------------------------------------------------------------------------;
  108. //
  109. // int AppMsgBoxId
  110. //
  111. // Description:
  112. // This function displays a message for the application. The message
  113. // text is retrieved from the string resource table using LoadString.
  114. //
  115. // Note that this function takes any valid argument list that can
  116. // be passed to wsprintf. Because of this, the application must
  117. // remember to cast near string pointers to FAR when built for Win 16.
  118. // You will get a nice GP fault if you do not cast them correctly.
  119. //
  120. // Arguments:
  121. // HWND hwnd: Handle to parent window for message box holding the
  122. // message.
  123. //
  124. // UINT fuStyle: Style flags for MessageBox().
  125. //
  126. // UINT uIdsFormat: String resource id to be loaded with LoadString()
  127. // and used a the format string for wvsprintf().
  128. //
  129. // Return (int):
  130. // The return value is the result of MessageBox() if the string
  131. // resource specified by uIdsFormat is valid. The return value is zero
  132. // if the string resource failed to load.
  133. //
  134. //--------------------------------------------------------------------------;
  135. int FNCGLOBAL AppMsgBoxId
  136. (
  137. HWND hwnd,
  138. UINT fuStyle,
  139. UINT uIdsFormat,
  140. ...
  141. )
  142. {
  143. va_list va;
  144. TCHAR szFormat[APP_MAX_STRING_RC_CHARS];
  145. TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
  146. int n;
  147. n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  148. if (0 != n)
  149. {
  150. //
  151. // format and display the message..
  152. //
  153. va_start(va, uIdsFormat);
  154. #ifdef WIN32
  155. wvsprintf(ach, szFormat, va);
  156. #else
  157. wvsprintf(ach, szFormat, (LPSTR)va);
  158. #endif
  159. va_end(va);
  160. n = MessageBox(hwnd, ach, gszAppName, fuStyle);
  161. }
  162. return (n);
  163. } // AppMsgBoxId()
  164. //--------------------------------------------------------------------------;
  165. //
  166. // void AppHourGlass
  167. //
  168. // Description:
  169. // This function changes the cursor to that of the hour glass or
  170. // back to the previous cursor.
  171. //
  172. // This function can be called recursively.
  173. //
  174. // Arguments:
  175. // BOOL fHourGlass: TRUE if we need the hour glass. FALSE if we need
  176. // the arrow back.
  177. //
  178. // Return (void):
  179. // On return, the cursor will be what was requested.
  180. //
  181. //--------------------------------------------------------------------------;
  182. void FNGLOBAL AppHourGlass
  183. (
  184. BOOL fHourGlass
  185. )
  186. {
  187. static HCURSOR hcur;
  188. static UINT uWaiting = 0;
  189. if (fHourGlass)
  190. {
  191. if (!uWaiting)
  192. {
  193. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  194. ShowCursor(TRUE);
  195. }
  196. uWaiting++;
  197. }
  198. else
  199. {
  200. --uWaiting;
  201. if (!uWaiting)
  202. {
  203. ShowCursor(FALSE);
  204. SetCursor(hcur);
  205. }
  206. }
  207. } // AppHourGlass()
  208. //--------------------------------------------------------------------------;
  209. //
  210. // BOOL AppYield
  211. //
  212. // Description:
  213. // This function yields by dispatching all messages stacked up in the
  214. // application queue.
  215. //
  216. // Arguments:
  217. // HWND hwnd: Handle to main window of application if not yielding
  218. // for a dialog. Handle to dialog box if yielding for a dialog box.
  219. //
  220. // BOOL fIsDialog: TRUE if being called to yield for a dialog box.
  221. //
  222. // Return (BOOL):
  223. // The return value is always TRUE.
  224. //
  225. //--------------------------------------------------------------------------;
  226. BOOL FNGLOBAL AppYield
  227. (
  228. HWND hwnd,
  229. BOOL fIsDialog
  230. )
  231. {
  232. MSG msg;
  233. if (fIsDialog)
  234. {
  235. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  236. {
  237. if ((NULL == hwnd) || !IsDialogMessage(hwnd, &msg))
  238. {
  239. TranslateMessage(&msg);
  240. DispatchMessage(&msg);
  241. }
  242. }
  243. }
  244. else
  245. {
  246. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  247. {
  248. TranslateMessage(&msg);
  249. DispatchMessage(&msg);
  250. }
  251. }
  252. return (TRUE);
  253. } // AppYield()
  254. //--------------------------------------------------------------------------;
  255. //
  256. // int AppSetWindowText
  257. //
  258. // Description:
  259. // This function formats a string and sets the specified window text
  260. // to the result.
  261. //
  262. // Arguments:
  263. // HWND hwnd: Handle to window to receive the new text.
  264. //
  265. // PTSTR pszFormat: Pointer to any valid format for wsprintf.
  266. //
  267. // Return (int):
  268. // The return value is the number of bytes that the resulting window
  269. // text was.
  270. //
  271. //--------------------------------------------------------------------------;
  272. int FNCGLOBAL AppSetWindowText
  273. (
  274. HWND hwnd,
  275. PTSTR pszFormat,
  276. ...
  277. )
  278. {
  279. va_list va;
  280. TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
  281. int n;
  282. //
  283. // format and display the string in the window...
  284. //
  285. va_start(va, pszFormat);
  286. #ifdef WIN32
  287. n = wvsprintf(ach, pszFormat, va);
  288. #else
  289. n = wvsprintf(ach, pszFormat, (LPSTR)va);
  290. #endif
  291. va_end(va);
  292. SetWindowText(hwnd, ach);
  293. return (n);
  294. } // AppSetWindowText()
  295. //--------------------------------------------------------------------------;
  296. //
  297. // int AppSetWindowTextId
  298. //
  299. // Description:
  300. // This function formats a string and sets the specified window text
  301. // to the result. The format string is extracted from the string
  302. // table using LoadString() on the uIdsFormat argument.
  303. //
  304. // Arguments:
  305. // HWND hwnd: Handle to window to receive the new text.
  306. //
  307. // UINT uIdsFormat: String resource id to be loaded with LoadString()
  308. // and used a the format string for wvsprintf().
  309. //
  310. // Return (int):
  311. // The return value is the number of bytes that the resulting window
  312. // text was. This value is zero if the LoadString() function fails
  313. // for the uIdsFormat argument.
  314. //
  315. //--------------------------------------------------------------------------;
  316. int FNCGLOBAL AppSetWindowTextId
  317. (
  318. HWND hwnd,
  319. UINT uIdsFormat,
  320. ...
  321. )
  322. {
  323. va_list va;
  324. TCHAR szFormat[APP_MAX_STRING_RC_CHARS];
  325. TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
  326. int n;
  327. n = LoadString(ghinst, uIdsFormat, szFormat, SIZEOF(szFormat));
  328. if (0 != n)
  329. {
  330. //
  331. // format and display the string in the window...
  332. //
  333. va_start(va, uIdsFormat);
  334. #ifdef WIN32
  335. n = wvsprintf(ach, szFormat, va);
  336. #else
  337. n = wvsprintf(ach, szFormat, (LPSTR)va);
  338. #endif
  339. va_end(va);
  340. SetWindowText(hwnd, ach);
  341. }
  342. return (n);
  343. } // AppSetWindowTextId()
  344. //--------------------------------------------------------------------------;
  345. //
  346. // BOOL AppFormatBigNumber
  347. //
  348. // Description:
  349. //
  350. //
  351. // Arguments:
  352. // LPTSTR pszNumber:
  353. //
  354. // DWORD dw:
  355. //
  356. // Return (BOOL):
  357. //
  358. //--------------------------------------------------------------------------;
  359. BOOL FNGLOBAL AppFormatBigNumber
  360. (
  361. LPTSTR pszNumber,
  362. DWORD dw
  363. )
  364. {
  365. //
  366. // this is ugly...
  367. //
  368. //
  369. if (dw >= 1000000000L)
  370. {
  371. wsprintf(pszNumber, TEXT("%u,%03u,%03u,%03u"),
  372. (WORD)(dw / 1000000000L),
  373. (WORD)((dw % 1000000000L) / 1000000L),
  374. (WORD)((dw % 1000000L) / 1000),
  375. (WORD)(dw % 1000));
  376. }
  377. else if (dw >= 1000000L)
  378. {
  379. wsprintf(pszNumber, TEXT("%u,%03u,%03u"),
  380. (WORD)(dw / 1000000L),
  381. (WORD)((dw % 1000000L) / 1000),
  382. (WORD)(dw % 1000));
  383. }
  384. else if (dw >= 1000)
  385. {
  386. wsprintf(pszNumber, TEXT("%u,%03u"),
  387. (WORD)(dw / 1000),
  388. (WORD)(dw % 1000));
  389. }
  390. else
  391. {
  392. wsprintf(pszNumber, TEXT("%lu"), dw);
  393. }
  394. return (TRUE);
  395. } // AppFormatBigNumber()
  396. //--------------------------------------------------------------------------;
  397. //
  398. // BOOL AppFormatDosDateTime
  399. //
  400. // Description:
  401. //
  402. //
  403. // Arguments:
  404. // LPTSTR pszDateTime:
  405. //
  406. // UINT uDosDate:
  407. //
  408. // UINT uDosTime:
  409. //
  410. // Return (BOOL):
  411. //
  412. //--------------------------------------------------------------------------;
  413. BOOL FNGLOBAL AppFormatDosDateTime
  414. (
  415. LPTSTR pszDateTime,
  416. UINT uDosDate,
  417. UINT uDosTime
  418. )
  419. {
  420. static TCHAR szFormatDateTime[] = TEXT("%.02u/%.02u/%.02u %.02u:%.02u:%.02u");
  421. UINT uDateMonth;
  422. UINT uDateDay;
  423. UINT uDateYear;
  424. UINT uTimeHour;
  425. UINT uTimeMinute;
  426. UINT uTimeSecond;
  427. //
  428. //
  429. //
  430. uTimeHour = uDosTime >> 11;
  431. uTimeMinute = (uDosTime & 0x07E0) >> 5;
  432. uTimeSecond = (uDosTime & 0x001F) << 1;
  433. uDateMonth = (uDosDate & 0x01E0) >> 5;
  434. uDateDay = (uDosDate & 0x001F);
  435. uDateYear = (uDosDate >> 9) + 80;
  436. //
  437. //
  438. //
  439. //
  440. wsprintf(pszDateTime, szFormatDateTime,
  441. uDateMonth,
  442. uDateDay,
  443. uDateYear,
  444. uTimeHour,
  445. uTimeMinute,
  446. uTimeSecond);
  447. return (TRUE);
  448. } // AppFormatDosDateTime()
  449. //--------------------------------------------------------------------------;
  450. //
  451. // void AcmAppDebugLog
  452. //
  453. // Description:
  454. // This function logs information to the debugger if the Debug Log
  455. // option is set. You can then run DBWin (or something similar)
  456. // to redirect the output whereever you want. Very useful for debugging
  457. // ACM drivers.
  458. //
  459. // Arguments:
  460. // PTSTR pszFormat: Pointer to any valid format for wsprintf.
  461. //
  462. // Return (void):
  463. // None.
  464. //
  465. //--------------------------------------------------------------------------;
  466. void FNCGLOBAL AcmAppDebugLog
  467. (
  468. PTSTR pszFormat,
  469. ...
  470. )
  471. {
  472. static TCHAR szDebugLogSeparator[] = TEXT("=============================================================================\r\n");
  473. va_list va;
  474. TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
  475. //
  476. // !!! UNICODE !!!
  477. //
  478. //
  479. if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions))
  480. {
  481. if (NULL == pszFormat)
  482. {
  483. OutputDebugString(szDebugLogSeparator);
  484. return;
  485. }
  486. //
  487. // format and display the string in a message box...
  488. //
  489. va_start(va, pszFormat);
  490. #ifdef WIN32
  491. wvsprintf(ach, pszFormat, va);
  492. #else
  493. wvsprintf(ach, pszFormat, (LPSTR)va);
  494. #endif
  495. va_end(va);
  496. OutputDebugString(ach);
  497. }
  498. } // AcmAppDebugLog()
  499. //--------------------------------------------------------------------------;
  500. //
  501. // int MEditPrintF
  502. //
  503. // Description:
  504. // This function is used to print formatted text into a Multiline
  505. // Edit Control as if it were a standard console display. This is
  506. // a very easy way to display small amounts of text information
  507. // that can be scrolled and copied to the clip-board.
  508. //
  509. // Arguments:
  510. // HWND hedit: Handle to a Multiline Edit control.
  511. //
  512. // PTSTR pszFormat: Pointer to any valid format for wsprintf. If
  513. // this argument is NULL, then the Multiline Edit Control is cleared
  514. // of all text.
  515. //
  516. //
  517. // Return (int):
  518. // Returns the number of characters written into the edit control.
  519. //
  520. // Notes:
  521. // The pszFormat string can contain combinations of escapes that
  522. // modify the default behaviour of this function. Escapes are single
  523. // character codes placed at the _beginning_ of the format string.
  524. //
  525. // Current escapes defined are:
  526. //
  527. // ~ : Suppresses the default CR/LF added to the end of the
  528. // printed line. Since the most common use of this function
  529. // is to output a whole line of text with a CR/LF, that is
  530. // the default.
  531. //
  532. // ` : Suppresses logging to the debug terminal (regardless of
  533. // the global debug log options flag).
  534. //
  535. //
  536. //--------------------------------------------------------------------------;
  537. int FNCGLOBAL MEditPrintF
  538. (
  539. HWND hedit,
  540. PTSTR pszFormat,
  541. ...
  542. )
  543. {
  544. static TCHAR szCRLF[] = TEXT("\r\n");
  545. va_list va;
  546. TCHAR ach[APP_MAX_STRING_RC_CHARS];
  547. int n;
  548. BOOL fCRLF;
  549. BOOL fDebugLog;
  550. //
  551. // default the escapes
  552. //
  553. fCRLF = TRUE;
  554. fDebugLog = TRUE;
  555. //
  556. // if the pszFormat argument is NULL, then just clear all text in
  557. // the edit control..
  558. //
  559. if (NULL == pszFormat)
  560. {
  561. SetWindowText(hedit, gszNull);
  562. AcmAppDebugLog(NULL);
  563. return (0);
  564. }
  565. //
  566. // format and display the string in the window... first search for
  567. // escapes to modify default behaviour.
  568. //
  569. for (;;)
  570. {
  571. switch (*pszFormat)
  572. {
  573. case '~':
  574. fCRLF = FALSE;
  575. pszFormat++;
  576. continue;
  577. case '`':
  578. fDebugLog = FALSE;
  579. pszFormat++;
  580. continue;
  581. }
  582. break;
  583. }
  584. va_start(va, pszFormat);
  585. #ifdef WIN32
  586. n = wvsprintf(ach, pszFormat, va);
  587. #else
  588. n = wvsprintf(ach, pszFormat, (LPSTR)va);
  589. #endif
  590. va_end(va);
  591. Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
  592. Edit_ReplaceSel(hedit, ach);
  593. if (fDebugLog)
  594. {
  595. AcmAppDebugLog(ach);
  596. }
  597. if (fCRLF)
  598. {
  599. Edit_SetSel(hedit, (WPARAM)-1, (LPARAM)-1);
  600. Edit_ReplaceSel(hedit, szCRLF);
  601. if (fDebugLog)
  602. {
  603. AcmAppDebugLog(szCRLF);
  604. }
  605. }
  606. return (n);
  607. } // MEditPrintF()
  608. //--------------------------------------------------------------------------;
  609. //
  610. // BOOL AppGetFileTitle
  611. //
  612. // Description:
  613. // This function extracts the file title from a file path and returns
  614. // it in the caller's specified buffer.
  615. //
  616. // Arguments:
  617. // PTSTR pszFilePath: Pointer to null terminated file path.
  618. //
  619. // PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  620. //
  621. // Return (BOOL):
  622. // Always returns TRUE. But should return FALSE if this function
  623. // checked for bogus values, etc.
  624. //
  625. //
  626. //--------------------------------------------------------------------------;
  627. BOOL FNGLOBAL AppGetFileTitle
  628. (
  629. PTSTR pszFilePath,
  630. PTSTR pszFileTitle
  631. )
  632. {
  633. #define IS_SLASH(c) ('/' == (c) || '\\' == (c))
  634. PTSTR pch;
  635. //
  636. // scan to the end of the file path string..
  637. //
  638. for (pch = pszFilePath; '\0' != *pch; pch++)
  639. ;
  640. //
  641. // now scan back toward the beginning of the string until a slash (\),
  642. // colon, or start of the string is encountered.
  643. //
  644. while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch))
  645. {
  646. pch--;
  647. }
  648. //
  649. // finally, copy the 'title' into the destination buffer.. skip ahead
  650. // one char since the above loop steps back one too many chars...
  651. //
  652. lstrcpy(pszFileTitle, ++pch);
  653. return (TRUE);
  654. } // AppGetFileTitle()
  655. //--------------------------------------------------------------------------;
  656. //
  657. // BOOL AppGetFileName
  658. //
  659. // Description:
  660. // This function is a wrapper for the Get[Open/Save]FileName commdlg
  661. // chooser dialogs. Based on the fuFlags argument, this function will
  662. // display the appropriate chooser dialog and return the result.
  663. //
  664. // Arguments:
  665. // HWND hwnd: Handle to parent window for chooser dialog.
  666. //
  667. // PTSTR pszFilePath: Pointer to buffer to receive the file path.
  668. //
  669. // PTSTR pszFileTitle: Pointer to buffer to receive the file title.
  670. // This argument may be NULL, in which case no title will be returned.
  671. //
  672. // UINT fuFlags:
  673. //
  674. // Return (BOOL):
  675. // The return value is TRUE if a file was chosen. It is FALSE if the
  676. // user canceled the operation.
  677. //
  678. //
  679. //--------------------------------------------------------------------------;
  680. BOOL FNGLOBAL AppGetFileName
  681. (
  682. HWND hwnd,
  683. PTSTR pszFilePath,
  684. PTSTR pszFileTitle,
  685. UINT fuFlags
  686. )
  687. {
  688. #define APP_OFN_FLAGS_SAVE (OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT)
  689. #define APP_OFN_FLAGS_OPEN (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST)
  690. TCHAR szExtDefault[APP_MAX_EXT_DEFAULT_CHARS];
  691. TCHAR szExtFilter[APP_MAX_EXT_FILTER_CHARS];
  692. OPENFILENAME ofn;
  693. BOOL f;
  694. PTCHAR pch;
  695. //
  696. // get the extension filter and default extension for this application
  697. //
  698. LoadString(ghinst, IDS_OFN_EXT_DEF, szExtDefault, SIZEOF(szExtDefault));
  699. LoadString(ghinst, IDS_OFN_EXT_FILTER, szExtFilter, SIZEOF(szExtFilter));
  700. //
  701. // NOTE! building the filter string for the OPENFILENAME structure
  702. // is a bit more difficult when dealing with Unicode and C8's new
  703. // optimizer. it joyfully removes literal '\0' characters from
  704. // strings that are concatted together. if you try making each
  705. // string separate (array of pointers to strings), the compiler
  706. // will dword align them... etc, etc.
  707. //
  708. // if you can think of a better way to build the filter string
  709. // for common dialogs and still work in Win 16 and Win 32 [Unicode]
  710. // i'd sure like to hear about it...
  711. //
  712. for (pch = &szExtFilter[0]; '\0' != *pch; pch++)
  713. {
  714. if ('!' == *pch)
  715. *pch = '\0';
  716. }
  717. //
  718. // initialize the OPENFILENAME members
  719. //
  720. memset(&ofn, 0, sizeof(OPENFILENAME));
  721. pszFilePath[0] = '\0';
  722. if (pszFileTitle)
  723. pszFileTitle[0] = '\0';
  724. ofn.lStructSize = sizeof(OPENFILENAME);
  725. ofn.hwndOwner = hwnd;
  726. ofn.lpstrFilter = szExtFilter;
  727. ofn.lpstrCustomFilter = NULL;
  728. ofn.nMaxCustFilter = 0L;
  729. ofn.nFilterIndex = 1L;
  730. ofn.lpstrFile = pszFilePath;
  731. ofn.nMaxFile = APP_MAX_FILE_PATH_CHARS;
  732. ofn.lpstrFileTitle = pszFileTitle;
  733. ofn.nMaxFileTitle = pszFileTitle ? APP_MAX_FILE_TITLE_CHARS : 0;
  734. if (fuFlags & APP_GETFILENAMEF_SAVE)
  735. {
  736. ofn.lpstrInitialDir = gszInitialDirSave;
  737. }
  738. else
  739. {
  740. ofn.lpstrInitialDir = gszInitialDirOpen;
  741. }
  742. ofn.nFileOffset = 0;
  743. ofn.nFileExtension = 0;
  744. ofn.lpstrDefExt = szExtDefault;
  745. //
  746. // if the fuFlags.APP_GETFILENAMEF_SAVE bit is set, then call
  747. // GetSaveFileName() otherwise call GetOpenFileName(). why commdlg was
  748. // designed with two separate functions for save and open only clark
  749. // knows.
  750. //
  751. if (fuFlags & APP_GETFILENAMEF_SAVE)
  752. {
  753. ofn.Flags = APP_OFN_FLAGS_SAVE;
  754. f = GetSaveFileName(&ofn);
  755. if (f)
  756. {
  757. if (NULL != pszFilePath)
  758. {
  759. lstrcpy(gszInitialDirSave, pszFilePath);
  760. pch = &gszInitialDirSave[lstrlen(gszInitialDirSave) - 1];
  761. for ( ; gszInitialDirSave != pch; pch--)
  762. {
  763. if ('\\' == *pch)
  764. {
  765. *pch = '\0';
  766. break;
  767. }
  768. }
  769. }
  770. }
  771. }
  772. else
  773. {
  774. ofn.Flags = APP_OFN_FLAGS_OPEN;
  775. f = GetOpenFileName(&ofn);
  776. if (f)
  777. {
  778. if (NULL != pszFilePath)
  779. {
  780. lstrcpy(gszInitialDirOpen, pszFilePath);
  781. pch = &gszInitialDirOpen[lstrlen(gszInitialDirOpen) - 1];
  782. for ( ; gszInitialDirOpen != pch; pch--)
  783. {
  784. if ('\\' == *pch)
  785. {
  786. *pch = '\0';
  787. break;
  788. }
  789. }
  790. }
  791. }
  792. }
  793. return (f);
  794. } // AppGetFileName()
  795. //--------------------------------------------------------------------------;
  796. //
  797. // BOOL AppTitle
  798. //
  799. // Description:
  800. // This function formats and sets the title text of the application's
  801. // window.
  802. //
  803. // Arguments:
  804. // HWND hwnd: Handle to application window to set title text for.
  805. //
  806. // PTSTR pszFileTitle: Pointer to file title to display.
  807. //
  808. // Return (BOOL):
  809. // The return value is always TRUE.
  810. //
  811. //
  812. //--------------------------------------------------------------------------;
  813. BOOL FNGLOBAL AppTitle
  814. (
  815. HWND hwnd,
  816. PTSTR pszFileTitle
  817. )
  818. {
  819. static TCHAR szFormatTitle[] = TEXT("%s - %s");
  820. TCHAR ach[APP_MAX_FILE_PATH_CHARS];
  821. //
  822. // format the title text as 'AppName - FileTitle'
  823. //
  824. wsprintf(ach, szFormatTitle, (LPSTR)gszAppName, (LPSTR)pszFileTitle);
  825. SetWindowText(hwnd, ach);
  826. return (TRUE);
  827. } // AppTitle()
  828. //--------------------------------------------------------------------------;
  829. //
  830. // BOOL AppFileNew
  831. //
  832. // Description:
  833. // This function is called to handle the IDM_FILE_NEW message. It is
  834. // responsible for clearing the working area for a new unnamed file.
  835. //
  836. // Arguments:
  837. // HWND hwnd: Handle to application window.
  838. //
  839. // PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  840. //
  841. // Return (BOOL):
  842. // The return value is TRUE if the working area was cleared and is
  843. // ready for new stuff. The return value is FALSE if the user canceled
  844. // the operation.
  845. //
  846. //--------------------------------------------------------------------------;
  847. BOOL FNGLOBAL AppFileNew
  848. (
  849. HWND hwnd,
  850. PACMAPPFILEDESC paafd,
  851. BOOL fCreate
  852. )
  853. {
  854. BOOL f;
  855. if (fCreate)
  856. {
  857. f = AcmAppFileNew(hwnd, paafd);
  858. if (!f)
  859. return (FALSE);
  860. }
  861. else
  862. {
  863. //
  864. // if there is currently a file path, then we have to do some real
  865. // work...
  866. //
  867. if ('\0' != paafd->szFilePath[0])
  868. {
  869. f = AcmAppFileNew(hwnd, paafd);
  870. if (!f)
  871. return (FALSE);
  872. }
  873. //
  874. // blow away the old file path and title; set the window title
  875. // and return success
  876. //
  877. lstrcpy(paafd->szFilePath, gszFileUntitled);
  878. lstrcpy(paafd->szFileTitle, gszFileUntitled);
  879. }
  880. AppTitle(hwnd, paafd->szFileTitle);
  881. AcmAppDisplayFileProperties(hwnd, paafd);
  882. return (TRUE);
  883. } // AppFileNew()
  884. //--------------------------------------------------------------------------;
  885. //
  886. // BOOL AppFileOpen
  887. //
  888. // Description:
  889. // This function handles the IDM_FILE_OPEN message. It is responsible
  890. // for getting a new file name from the user and opening that file
  891. // if possible.
  892. //
  893. // Arguments:
  894. // HWND hwnd: Handle to application window.
  895. //
  896. // PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  897. //
  898. // Return (BOOL):
  899. // The return value is TRUE if a new file was selected and opened.
  900. // It is FALSE if the user canceled the operation.
  901. //
  902. //--------------------------------------------------------------------------;
  903. BOOL FNLOCAL AppFileOpen
  904. (
  905. HWND hwnd,
  906. PACMAPPFILEDESC paafd
  907. )
  908. {
  909. TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS];
  910. TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  911. BOOL f;
  912. //
  913. // first test for a modified file that has not been saved. if the
  914. // return value is FALSE we should cancel the File.Open operation.
  915. //
  916. f = AcmAppFileSaveModified(hwnd, paafd);
  917. if (!f)
  918. return (FALSE);
  919. //
  920. // get the file name of the new file into temporary buffers (so
  921. // if we fail to open it we can back out cleanly).
  922. //
  923. f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_OPEN);
  924. if (!f)
  925. return (FALSE);
  926. //!!!
  927. // read the new file...
  928. //
  929. lstrcpy(paafd->szFilePath, szFilePath);
  930. lstrcpy(paafd->szFileTitle, szFileTitle);
  931. f = AcmAppFileOpen(hwnd, paafd);
  932. if (f)
  933. {
  934. //
  935. // set the window title text...
  936. //
  937. AppTitle(hwnd, szFileTitle);
  938. AcmAppDisplayFileProperties(hwnd, paafd);
  939. }
  940. return (f);
  941. } // AppFileOpen()
  942. //--------------------------------------------------------------------------;
  943. //
  944. // BOOL AppFileSave
  945. //
  946. // Description:
  947. // This function handles the IDM_FILE_SAVE[AS] messages. It is
  948. // responsible for saving the current file. If a file name needs
  949. // to be specified then the save file dialog is displayed.
  950. //
  951. // Arguments:
  952. // HWND hwnd: Handle to application window.
  953. //
  954. // PACMAPPFILEDESC paafd: Pointer to current file descriptor.
  955. //
  956. // BOOL fSaveAs: TRUE if the save file chooser should be displayed
  957. // before saving the file. FALSE if should operate like File.Save.
  958. //
  959. // Return (BOOL):
  960. // The return value is TRUE if the file was saved. It is FALSE if the
  961. // user canceled the operation or the file does not need saved.
  962. //
  963. //--------------------------------------------------------------------------;
  964. BOOL FNGLOBAL AppFileSave
  965. (
  966. HWND hwnd,
  967. PACMAPPFILEDESC paafd,
  968. BOOL fSaveAs
  969. )
  970. {
  971. TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS];
  972. TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS];
  973. BOOL f;
  974. //
  975. //
  976. //
  977. lstrcpy(szFilePath, paafd->szFilePath);
  978. lstrcpy(szFileTitle, paafd->szFileTitle);
  979. //
  980. // check if we should bring up the save file chooser dialog...
  981. //
  982. if (fSaveAs || (0 == lstrcmp(paafd->szFileTitle, gszFileUntitled)))
  983. {
  984. //
  985. // get the file name for saving the data to into temporary
  986. // buffers (so if we fail to save it we can back out cleanly).
  987. //
  988. f = AppGetFileName(hwnd, szFilePath, szFileTitle, APP_GETFILENAMEF_SAVE);
  989. if (!f)
  990. return (FALSE);
  991. }
  992. //
  993. // save the file...
  994. //
  995. f = AcmAppFileSave(hwnd, paafd, szFilePath, szFileTitle, 0);
  996. if (f)
  997. {
  998. //
  999. // changes have been saved, so clear the modified bit...
  1000. //
  1001. paafd->fdwState &= ~ACMAPPFILEDESC_STATEF_MODIFIED;
  1002. AppTitle(hwnd, paafd->szFileTitle);
  1003. AcmAppDisplayFileProperties(hwnd, paafd);
  1004. }
  1005. return (f);
  1006. } // AppFileSave()
  1007. //==========================================================================;
  1008. //
  1009. // Main application window handling code...
  1010. //
  1011. //
  1012. //==========================================================================;
  1013. //--------------------------------------------------------------------------;
  1014. //
  1015. // LRESULT AppInitMenuPopup
  1016. //
  1017. // Description:
  1018. // This function handles the WM_INITMENUPOPUP message. This message
  1019. // is sent to the window owning the menu that is going to become
  1020. // active. This gives an application the ability to modify the menu
  1021. // before it is displayed (disable/add items, etc).
  1022. //
  1023. // Arguments:
  1024. // HWND hwnd: Handle to window that generated the WM_INITMENUPOPUP
  1025. // message.
  1026. //
  1027. // HMENU hmenu: Handle to the menu that is to become active.
  1028. //
  1029. // int nItem: Specifies the zero-based relative position of the menu
  1030. // item that invoked the popup menu.
  1031. //
  1032. // BOOL fSysMenu: Specifies whether the popup menu is a System menu
  1033. // (TRUE) or it is not a System menu (FALSE).
  1034. //
  1035. // Return (LRESULT):
  1036. // Returns zero if the message is processed.
  1037. //
  1038. //--------------------------------------------------------------------------;
  1039. LRESULT FNLOCAL AppInitMenuPopup
  1040. (
  1041. HWND hwnd,
  1042. HMENU hmenu,
  1043. int nItem,
  1044. BOOL fSysMenu
  1045. )
  1046. {
  1047. BOOL f;
  1048. int nSelStart;
  1049. int nSelEnd;
  1050. HWND hedit;
  1051. DPF(4, "AppInitMenuPopup(hwnd=%Xh, hmenu=%Xh, nItem=%d, fSysMenu=%d)",
  1052. hwnd, hmenu, nItem, fSysMenu);
  1053. //
  1054. // if the system menu is what got hit, succeed immediately... this
  1055. // application has no stuff in the system menu.
  1056. //
  1057. if (fSysMenu)
  1058. return (0L);
  1059. //
  1060. // initialize the menu that is being 'popped up'
  1061. //
  1062. switch (nItem)
  1063. {
  1064. case APP_MENU_ITEM_FILE:
  1065. EnableMenuItem(hmenu, IDM_FILE_NEW,
  1066. (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
  1067. f = (NULL != gaafd.pwfx);
  1068. EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_PLAY,
  1069. (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1070. EnableMenuItem(hmenu, IDM_FILE_SNDPLAYSOUND_STOP,
  1071. (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1072. f = (NULL != gaafd.pwfx) && gfAcmAvailable;
  1073. EnableMenuItem(hmenu, IDM_FILE_CONVERT,
  1074. (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1075. //
  1076. // if the file has been modified, then enable the File.Save
  1077. // menu
  1078. //
  1079. f = (0 != (gaafd.fdwState & ACMAPPFILEDESC_STATEF_MODIFIED));
  1080. EnableMenuItem(hmenu, IDM_FILE_SAVE,
  1081. (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1082. // f = (NULL != gaafd.pwfx);
  1083. EnableMenuItem(hmenu, IDM_FILE_SAVEAS,
  1084. (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1085. break;
  1086. case APP_MENU_ITEM_EDIT:
  1087. //
  1088. // check to see if something is selected in the display
  1089. // window and enable/disable Edit menu options appropriately
  1090. //
  1091. hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1092. Edit_GetSelEx(hedit, &nSelStart, &nSelEnd);
  1093. f = (nSelStart != nSelEnd);
  1094. EnableMenuItem(hmenu, WM_COPY, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1095. break;
  1096. case APP_MENU_ITEM_VIEW:
  1097. EnableMenuItem(hmenu, IDM_VIEW_ACM_DRIVERS,
  1098. (UINT)(gfAcmAvailable ? MF_ENABLED : MF_GRAYED));
  1099. break;
  1100. case APP_MENU_ITEM_OPTIONS:
  1101. f = (0 != waveInGetNumDevs());
  1102. EnableMenuItem(hmenu, IDM_OPTIONS_WAVEINDEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1103. f = (0 != waveOutGetNumDevs());
  1104. EnableMenuItem(hmenu, IDM_OPTIONS_WAVEOUTDEVICE, (UINT)(f ? MF_ENABLED : MF_GRAYED));
  1105. //
  1106. // make sure the options that need a checkmark are checked..
  1107. //
  1108. f = (0 != (APP_OPTIONSF_AUTOOPEN & gfuAppOptions));
  1109. CheckMenuItem(hmenu, IDM_OPTIONS_AUTOOPEN,
  1110. (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  1111. f = (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions));
  1112. CheckMenuItem(hmenu, IDM_OPTIONS_DEBUGLOG,
  1113. (UINT)(f ? MF_CHECKED : MF_UNCHECKED));
  1114. break;
  1115. }
  1116. //
  1117. // we processed the message--return 0...
  1118. //
  1119. return (0L);
  1120. } // AppInitMenuPopup()
  1121. //--------------------------------------------------------------------------;
  1122. //
  1123. // LRESULT AppCommand
  1124. //
  1125. // Description:
  1126. // This function handles the WM_COMMAND message.
  1127. //
  1128. // Arguments:
  1129. // HWND hwnd: Handle to window receiving the WM_COMMAND message.
  1130. //
  1131. // int nId: Control or menu item identifier.
  1132. //
  1133. // HWND hwndCtl: Handle of control if the message is from a control.
  1134. // This argument is NULL if the message was not generated by a control.
  1135. //
  1136. // UINT uCode: Notification code. This argument is 1 if the message
  1137. // was generated by an accelerator. If the message is from a menu,
  1138. // this argument is 0.
  1139. //
  1140. // Return (LRESULT):
  1141. // Returns zero if the message is processed.
  1142. //
  1143. //--------------------------------------------------------------------------;
  1144. LRESULT FNLOCAL AppCommand
  1145. (
  1146. HWND hwnd,
  1147. int nId,
  1148. HWND hwndCtl,
  1149. UINT uCode
  1150. )
  1151. {
  1152. BOOL f;
  1153. DWORD dw;
  1154. UINT uDevId;
  1155. switch (nId)
  1156. {
  1157. case IDM_FILE_NEW:
  1158. AppFileNew(hwnd, &gaafd, TRUE);
  1159. break;
  1160. case IDM_FILE_OPEN:
  1161. AppFileOpen(hwnd, &gaafd);
  1162. break;
  1163. case IDM_FILE_SAVE:
  1164. AppFileSave(hwnd, &gaafd, FALSE);
  1165. break;
  1166. case IDM_FILE_SAVEAS:
  1167. AppFileSave(hwnd, &gaafd, TRUE);
  1168. break;
  1169. case IDM_FILE_SNDPLAYSOUND_PLAY:
  1170. if (NULL == gaafd.pwfx)
  1171. {
  1172. MessageBeep((UINT)-1);
  1173. break;
  1174. }
  1175. AppHourGlass(TRUE);
  1176. dw = timeGetTime();
  1177. f = sndPlaySound(gaafd.szFilePath, SND_ASYNC | SND_NODEFAULT);
  1178. dw = timeGetTime() - dw;
  1179. AppHourGlass(FALSE);
  1180. if (0 != (APP_OPTIONSF_DEBUGLOG & gfuAppOptions))
  1181. {
  1182. AcmAppDebugLog(NULL);
  1183. AcmAppDebugLog(TEXT("sndPlaySound(%s) took %lu milliseconds to %s.\r\n"),
  1184. (LPTSTR)gaafd.szFilePath,
  1185. dw,
  1186. f ? (LPTSTR)TEXT("succeed") : (LPTSTR)TEXT("fail"));
  1187. }
  1188. if (!f)
  1189. {
  1190. AppMsgBox(hwnd, MB_OK | MB_ICONEXCLAMATION,
  1191. TEXT("The file '%s' cannot be played by sndPlaySound."),
  1192. (LPSTR)gaafd.szFilePath);
  1193. }
  1194. break;
  1195. case IDM_FILE_SNDPLAYSOUND_STOP:
  1196. sndPlaySound(NULL, 0L);
  1197. break;
  1198. case IDM_FILE_CONVERT:
  1199. AcmAppFileConvert(hwnd, &gaafd);
  1200. break;
  1201. case IDM_FILE_ABOUT:
  1202. DialogBox(ghinst, DLG_ABOUT, hwnd, AboutDlgProc);
  1203. break;
  1204. case IDM_FILE_EXIT:
  1205. FORWARD_WM_CLOSE(hwnd, SendMessage);
  1206. break;
  1207. case WM_COPY:
  1208. //
  1209. // pass on edit messages received to the display window
  1210. //
  1211. SendMessage(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), nId, 0, 0L);
  1212. break;
  1213. case IDM_EDIT_SELECTALL:
  1214. Edit_SetSel(GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY), 0, -1);
  1215. break;
  1216. case IDM_UPDATE:
  1217. AcmAppFileOpen(hwnd, &gaafd);
  1218. AcmAppDisplayFileProperties(hwnd, &gaafd);
  1219. break;
  1220. case IDM_VIEW_SYSTEMINFO:
  1221. DialogBox(ghinst, DLG_AADETAILS, hwnd, AcmAppSystemInfoDlgProc);
  1222. break;
  1223. case IDM_VIEW_ACM_DRIVERS:
  1224. DialogBox(ghinst, DLG_AADRIVERS, hwnd, AcmAppDriversDlgProc);
  1225. break;
  1226. case IDM_OPTIONS_WAVEINDEVICE:
  1227. uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd,
  1228. AcmAppWaveDeviceDlgProc,
  1229. MAKELONG((WORD)guWaveInId, TRUE));
  1230. if (uDevId != guWaveInId)
  1231. {
  1232. guWaveInId = uDevId;
  1233. AcmAppDisplayFileProperties(hwnd, &gaafd);
  1234. }
  1235. break;
  1236. case IDM_OPTIONS_WAVEOUTDEVICE:
  1237. uDevId = DialogBoxParam(ghinst, DLG_AAWAVEDEVICE, hwnd,
  1238. AcmAppWaveDeviceDlgProc,
  1239. MAKELONG((WORD)guWaveOutId, FALSE));
  1240. if (uDevId != guWaveOutId)
  1241. {
  1242. guWaveOutId = uDevId;
  1243. AcmAppDisplayFileProperties(hwnd, &gaafd);
  1244. }
  1245. break;
  1246. case IDM_OPTIONS_AUTOOPEN:
  1247. gfuAppOptions ^= APP_OPTIONSF_AUTOOPEN;
  1248. break;
  1249. case IDM_OPTIONS_DEBUGLOG:
  1250. gfuAppOptions ^= APP_OPTIONSF_DEBUGLOG;
  1251. break;
  1252. case IDM_OPTIONS_FONT:
  1253. AcmAppChooseFont(hwnd);
  1254. break;
  1255. case IDM_PLAYRECORD:
  1256. if (NULL == gaafd.pwfx)
  1257. {
  1258. f = AppFileNew(hwnd, &gaafd, TRUE);
  1259. if (!f)
  1260. break;
  1261. if (NULL == gaafd.pwfx)
  1262. break;
  1263. }
  1264. f = DialogBoxParam(ghinst, DLG_AAPLAYRECORD, hwnd,
  1265. AcmAppPlayRecord, (LPARAM)(LPVOID)&gaafd);
  1266. if (f)
  1267. {
  1268. AcmAppFileOpen(hwnd, &gaafd);
  1269. AcmAppDisplayFileProperties(hwnd, &gaafd);
  1270. }
  1271. break;
  1272. }
  1273. return (0L);
  1274. } // AppCommand()
  1275. //--------------------------------------------------------------------------;
  1276. //
  1277. // BOOL AcmAppDlgProcDragDropContinue
  1278. //
  1279. // Description:
  1280. //
  1281. // Arguments:
  1282. // HWND hwnd: Handle to window.
  1283. //
  1284. // UINT uMsg: Message being sent to the window.
  1285. //
  1286. // WPARAM wParam: Specific argument to message.
  1287. //
  1288. // LPARAM lParam: Specific argument to message.
  1289. //
  1290. // Return (BOOL):
  1291. // The return value is specific to the message that was received. For
  1292. // the most part, it is FALSE if this dialog procedure does not handle
  1293. // a message.
  1294. //
  1295. //--------------------------------------------------------------------------;
  1296. BOOL FNEXPORT AcmAppDlgProcDragDropContinue
  1297. (
  1298. HWND hwnd,
  1299. UINT uMsg,
  1300. WPARAM wParam,
  1301. LPARAM lParam
  1302. )
  1303. {
  1304. UINT uId;
  1305. switch (uMsg)
  1306. {
  1307. case WM_INITDIALOG:
  1308. AppSetWindowText(hwnd, TEXT("File %u of %u"), LOWORD(lParam), HIWORD(lParam));
  1309. return (TRUE);
  1310. case WM_COMMAND:
  1311. uId = GET_WM_COMMAND_ID(wParam, lParam);
  1312. if ((IDOK == uId) || (IDCANCEL == uId))
  1313. {
  1314. EndDialog(hwnd, uId);
  1315. }
  1316. break;
  1317. }
  1318. return (FALSE);
  1319. } // AcmAppDlgProcDragDropContinue()
  1320. //--------------------------------------------------------------------------;
  1321. //
  1322. // LRESULT AppDropFiles
  1323. //
  1324. // Description:
  1325. // This function handles the WM_DROPFILES message. This message is
  1326. // sent when files are 'dropped' on the window from file manager
  1327. // (or other drag/drop servers made by ISV's that figured out the
  1328. // undocumented internal workings of the SHELL).
  1329. //
  1330. // A window must be registered to receive these messages either by
  1331. // called DragAcceptFiles() or using CreateWindowEx() with the
  1332. // WS_EX_ACCEPTFILES style bit.
  1333. //
  1334. // Arguments:
  1335. // HWND hwnd: Handle to window receiving the message.
  1336. //
  1337. // HDROP hdrop: Handle to drop structure.
  1338. //
  1339. // Return (LRESULT):
  1340. // Returns 0 if the message is processed.
  1341. //
  1342. //--------------------------------------------------------------------------;
  1343. LRESULT FNLOCAL AppDropFiles
  1344. (
  1345. HWND hwnd,
  1346. HDROP hdrop
  1347. )
  1348. {
  1349. TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS];
  1350. UINT cFiles;
  1351. UINT u;
  1352. BOOL f;
  1353. int n;
  1354. //
  1355. // first test for a file that has not been saved. if the return
  1356. // value is FALSE we should cancel the drop operation.
  1357. //
  1358. f = AcmAppFileSaveModified(hwnd, &gaafd);
  1359. if (!f)
  1360. {
  1361. goto App_Drop_Files_Exit;
  1362. }
  1363. //
  1364. // get number of files dropped on our window
  1365. //
  1366. cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
  1367. DPF(4, "AppDropFiles(hwnd=%Xh, hdrop=%Xh)--cFiles=%u", hwnd, hdrop, cFiles);
  1368. //
  1369. // step through each file and stop on the one the user wants or
  1370. // the last file (whichever comes first).
  1371. //
  1372. for (u = 0; u < cFiles; u++)
  1373. {
  1374. //
  1375. // get the next file name and try to open it--if not a valid
  1376. // file, then skip to the next one (if there is one).
  1377. //
  1378. DragQueryFile(hdrop, u, szFilePath, SIZEOF(szFilePath));
  1379. //
  1380. // !!! destructive !!!
  1381. //
  1382. // attempt to open the file
  1383. //
  1384. lstrcpy(gaafd.szFilePath, szFilePath);
  1385. lstrcpy(gaafd.szFileTitle, gszNull);
  1386. f = AcmAppFileOpen(hwnd, &gaafd);
  1387. if (!f)
  1388. {
  1389. continue;
  1390. }
  1391. AppTitle(hwnd, gaafd.szFileTitle);
  1392. AcmAppDisplayFileProperties(hwnd, &gaafd);
  1393. //
  1394. // if this is NOT the last file in the list of files that are
  1395. // being dropped on us, then bring up a box asking if we should
  1396. // continue or stop where we are..
  1397. //
  1398. if ((cFiles - 1) != u)
  1399. {
  1400. n = DialogBoxParam(ghinst,
  1401. DLG_AADRAGDROP,
  1402. hwnd,
  1403. AcmAppDlgProcDragDropContinue,
  1404. MAKELPARAM((WORD)(u + 1), (WORD)cFiles));
  1405. if (IDCANCEL == n)
  1406. break;
  1407. }
  1408. }
  1409. //
  1410. // tell the shell to release the memory it allocated for beaming
  1411. // the file name(s) over to us... return 0 to show we processed
  1412. // the message.
  1413. //
  1414. App_Drop_Files_Exit:
  1415. DragFinish(hdrop);
  1416. return (0L);
  1417. } // AppDropFiles()
  1418. //--------------------------------------------------------------------------;
  1419. //
  1420. // LRESULT AppSize
  1421. //
  1422. // Description:
  1423. // This function handles the WM_SIZE message for the application's
  1424. // window. This message is sent to the application window after the
  1425. // size has changed (but before it is painted).
  1426. //
  1427. // Arguments:
  1428. // HWND hwnd: Handle to window that generated the WM_SIZE message.
  1429. //
  1430. // UINT fuSizeType: Specifies the type of resizing requested. This
  1431. // argument is one of the following: SIZE_MAXIMIZED, SIZE_MINIMIZED,
  1432. // SIZE_RESTORED, SIZE_MAXHIDE, or SIZE_MAXSHOW.
  1433. //
  1434. // int nWidth: Width of the new client area for the window.
  1435. //
  1436. // int nHeight: Height of the new client area for the window.
  1437. //
  1438. // Return (LRESULT):
  1439. // Returns zero if the application processes the message.
  1440. //
  1441. //--------------------------------------------------------------------------;
  1442. LRESULT FNLOCAL AppSize
  1443. (
  1444. HWND hwnd,
  1445. UINT fuSizeType,
  1446. int nWidth,
  1447. int nHeight
  1448. )
  1449. {
  1450. HWND hedit;
  1451. RECT rc;
  1452. DPF(4, "AppSize(hwnd=%Xh, fuSizeType=%u, nWidth=%d, nHeight=%d)",
  1453. hwnd, fuSizeType, nWidth, nHeight);
  1454. //
  1455. // unless this application is the one being resized then don't waste
  1456. // time computing stuff that doesn't matter. this applies to being
  1457. // minimized also because this application does not have a custom
  1458. // minimized state.
  1459. //
  1460. if ((SIZE_RESTORED != fuSizeType) && (SIZE_MAXIMIZED != fuSizeType))
  1461. return (0L);
  1462. //
  1463. //
  1464. //
  1465. GetClientRect(hwnd, &rc);
  1466. InflateRect(&rc, 1, 1);
  1467. hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  1468. SetWindowPos(hedit,
  1469. NULL,
  1470. rc.left,
  1471. rc.top,
  1472. rc.right - rc.left,
  1473. rc.bottom - rc.top,
  1474. SWP_NOZORDER);
  1475. //
  1476. // we processed the message..
  1477. //
  1478. return (0L);
  1479. } // AppSize()
  1480. //--------------------------------------------------------------------------;
  1481. //
  1482. // LRESULT AcmAppNotify
  1483. //
  1484. // Description:
  1485. //
  1486. //
  1487. // Arguments:
  1488. //
  1489. // Return (LRESULT):
  1490. //
  1491. //
  1492. //--------------------------------------------------------------------------;
  1493. LRESULT FNLOCAL AcmAppNotify
  1494. (
  1495. HWND hwnd,
  1496. WPARAM wParam,
  1497. LPARAM lParam
  1498. )
  1499. {
  1500. HWND hwndNext;
  1501. DPF(1, "AcmAppNotify: hwnd=%.04Xh, wParam=%.04Xh, lParam2=%.08lXh",
  1502. hwnd, wParam, lParam);
  1503. //
  1504. //
  1505. //
  1506. hwndNext = GetWindow(hwnd, GW_HWNDFIRST);
  1507. while (NULL != hwndNext)
  1508. {
  1509. if (GetParent(hwndNext) == hwnd)
  1510. {
  1511. SendMessage(hwndNext, WM_ACMAPP_ACM_NOTIFY, wParam, lParam);
  1512. }
  1513. hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
  1514. }
  1515. //
  1516. // now force an update to our display in case driver [dis/en]able
  1517. // changed what is playable/recordable.
  1518. //
  1519. AcmAppDisplayFileProperties(hwnd, &gaafd);
  1520. //
  1521. //
  1522. //
  1523. return (1L);
  1524. } // AcmAppNotify()
  1525. //--------------------------------------------------------------------------;
  1526. //
  1527. // LRESULT AppWndProc
  1528. //
  1529. // Description:
  1530. // This is the main application window procedure.
  1531. //
  1532. // Arguments:
  1533. // HWND hwnd: Handle to window.
  1534. //
  1535. // UINT uMsg: Message being sent to the window.
  1536. //
  1537. // WPARAM wParam: Specific argument to message.
  1538. //
  1539. // LPARAM lParam: Specific argument to message.
  1540. //
  1541. // Return (LRESULT):
  1542. // The return value depends on the message that is being processed.
  1543. //
  1544. //--------------------------------------------------------------------------;
  1545. LRESULT FNEXPORT AppWndProc
  1546. (
  1547. HWND hwnd,
  1548. UINT uMsg,
  1549. WPARAM wParam,
  1550. LPARAM lParam
  1551. )
  1552. {
  1553. LRESULT lr;
  1554. switch (uMsg)
  1555. {
  1556. case WM_CREATE:
  1557. lr = HANDLE_WM_CREATE(hwnd, wParam, lParam, AppCreate);
  1558. return (lr);
  1559. case WM_WININICHANGE:
  1560. HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, AppWinIniChange);
  1561. return (0L);
  1562. case WM_INITMENUPOPUP:
  1563. HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, AppInitMenuPopup);
  1564. return (0L);
  1565. case WM_COMMAND:
  1566. lr = HANDLE_WM_COMMAND(hwnd, wParam, lParam, AppCommand);
  1567. return (lr);
  1568. case WM_DROPFILES:
  1569. //
  1570. // some windowsx.h files have a messed up message cracker for
  1571. // WM_DROPFILES. because this is a sample app, i don't want
  1572. // people having trouble with bogus windowsx.h files, so crack
  1573. // the message manually... you should use the message cracker
  1574. // if you know your windowsx.h file is good.
  1575. //
  1576. // lr = HANDLE_WM_DROPFILES(hwnd, wParam, lParam, AppDropFiles);
  1577. //
  1578. lr = AppDropFiles(hwnd, (HDROP)wParam);
  1579. return (lr);
  1580. case WM_SIZE:
  1581. //
  1582. // handle what we want for sizing, and then always call the
  1583. // default handler...
  1584. //
  1585. HANDLE_WM_SIZE(hwnd, wParam, lParam, AppSize);
  1586. break;
  1587. case WM_QUERYENDSESSION:
  1588. lr = HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, AppQueryEndSession);
  1589. return (lr);
  1590. case WM_ENDSESSION:
  1591. HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, AppEndSession);
  1592. return (0L);
  1593. case WM_CLOSE:
  1594. HANDLE_WM_CLOSE(hwnd, wParam, lParam, AppClose);
  1595. return (0L);
  1596. case WM_DESTROY:
  1597. PostQuitMessage(0);
  1598. return (0L);
  1599. case WM_ACMAPP_ACM_NOTIFY:
  1600. AcmAppNotify(hwnd, wParam, lParam);
  1601. return (0L);
  1602. }
  1603. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1604. } // AppWndProc()
  1605. //==========================================================================;
  1606. //
  1607. // Main entry and message dispatching code
  1608. //
  1609. //
  1610. //==========================================================================;
  1611. //--------------------------------------------------------------------------;
  1612. //
  1613. // int WinMain
  1614. //
  1615. // Description:
  1616. // This function is called by the system as the initial entry point
  1617. // for a Windows application.
  1618. //
  1619. // Arguments:
  1620. // HINSTANCE hinst: Identifies the current instance of the
  1621. // application.
  1622. //
  1623. // HINSTANCE hinstPrev: Identifies the previous instance of the
  1624. // application (NULL if first instance). For Win 32, this argument
  1625. // is _always_ NULL.
  1626. //
  1627. // LPSTR pszCmdLine: Points to null-terminated unparsed command line.
  1628. // This string is strictly ANSI regardless of whether the application
  1629. // is built for Unicode. To get the Unicode equivalent call the
  1630. // GetCommandLine() function (Win 32 only).
  1631. //
  1632. // int nCmdShow: How the main window for the application is to be
  1633. // shown by default.
  1634. //
  1635. // Return (int):
  1636. // Returns result from WM_QUIT message (in wParam of MSG structure) if
  1637. // the application is able to enter its message loop. Returns 0 if
  1638. // the application is not able to enter its message loop.
  1639. //
  1640. //--------------------------------------------------------------------------;
  1641. int PASCAL WinMain
  1642. (
  1643. HINSTANCE hinst,
  1644. HINSTANCE hinstPrev,
  1645. LPSTR pszCmdLine,
  1646. int nCmdShow
  1647. )
  1648. {
  1649. int nResult;
  1650. HWND hwnd;
  1651. MSG msg;
  1652. HACCEL haccl;
  1653. DbgInitialize(TRUE);
  1654. //
  1655. // our documentation states that WinMain is supposed to return 0 if
  1656. // we do not enter our message loop--so assume the worst...
  1657. //
  1658. nResult = 0;
  1659. //
  1660. // make our instance handle global for convenience..
  1661. //
  1662. ghinst = hinst;
  1663. //
  1664. // init some stuff, create window, etc.. note the explicit cast of
  1665. // pszCmdLine--this is to mute a warning (and an ugly ifdef) when
  1666. // compiling for Unicode. see AppInit() for more details.
  1667. //
  1668. hwnd = AppInit(hinst, hinstPrev, (LPTSTR)pszCmdLine, nCmdShow);
  1669. if (hwnd)
  1670. {
  1671. haccl = LoadAccelerators(hinst, ACCEL_APP);
  1672. //
  1673. // dispatch messages
  1674. //
  1675. while (GetMessage(&msg, NULL, 0, 0))
  1676. {
  1677. //
  1678. // do all the special stuff required for this application
  1679. // when dispatching messages..
  1680. //
  1681. if (!TranslateAccelerator(hwnd, haccl, &msg))
  1682. {
  1683. TranslateMessage(&msg);
  1684. DispatchMessage(&msg);
  1685. }
  1686. }
  1687. //
  1688. // return result of WM_QUIT message.
  1689. //
  1690. nResult = (int)msg.wParam;
  1691. }
  1692. //
  1693. // shut things down, clean up, etc.
  1694. //
  1695. nResult = AppExit(hinst, nResult);
  1696. return (nResult);
  1697. } // WinMain()