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.

550 lines
18 KiB

  1. /****************************************************************************
  2. *
  3. * AVIOPTS.C
  4. *
  5. * routine for bringing up the compression options dialog
  6. *
  7. * AVISaveOptions()
  8. *
  9. * Copyright (c) 1992 Microsoft Corporation. All Rights Reserved.
  10. *
  11. * You have a royalty-free right to use, modify, reproduce and
  12. * distribute the Sample Files (and/or any modified version) in
  13. * any way you find useful, provided that you agree that
  14. * Microsoft has no warranty obligations or liability for any
  15. * Sample Application Files which are modified.
  16. *
  17. ***************************************************************************/
  18. #include <win32.h>
  19. #include <mmreg.h>
  20. #include <msacm.h>
  21. #include <compman.h>
  22. #include "avifile.h"
  23. #include "aviopts.h"
  24. #include "aviopts.dlg"
  25. #ifdef WIN32
  26. //!!! ACK the ACM does not work on NT
  27. #define acmGetVersion() 0
  28. #define acmFormatChoose(x) 1 // some error.
  29. #define ICCompressorChoose(hwnd,a,b,c,d,e) 0
  30. #define ICCompressorFree(x)
  31. #endif
  32. /****************************************************************************
  33. ***************************************************************************/
  34. extern HINSTANCE ghMod;
  35. LONG FAR PASCAL _export AVICompressOptionsDlgProc(HWND hwnd, unsigned msg, WORD wParam, LONG lParam);
  36. /****************************************************************************
  37. ***************************************************************************/
  38. int gnNumStreams = 0; // how many streams in array
  39. int gnCurStream = 0; // which stream's options we're setting
  40. PAVISTREAM FAR *gapAVI; // array of stream pointers
  41. LPAVICOMPRESSOPTIONS FAR *gapOpt; // array of option structures to fill
  42. UINT guiFlags;
  43. COMPVARS gCompVars; // for ICCompressorChoose
  44. /****************************************************************************
  45. ***************************************************************************/
  46. /*************************************************************
  47. * @doc EXTERNAL AVISaveOptions
  48. *
  49. * @api BOOL | AVISaveOptions | This function gets the save options for
  50. * a file and returns them in a buffer.
  51. *
  52. * @parm HWND | hwnd | Specifies the parent window handle for the Compression Options
  53. * dialog box.
  54. *
  55. * @parm UINT | uiFlags | Specifies the flags for displaying the
  56. * Compression Options dialog box. The following flags are defined:
  57. *
  58. * @flag ICMF_CHOOSE_KEYFRAME | Displays a "Key frame every" box for
  59. * the video options. This is the same flag used in <f ICCompressorChoose>.
  60. *
  61. * @flag ICMF_CHOOSE_DATARATE | Displays a "Data rate" box for the video
  62. * options. This is the same flag used in <f ICCompressorChoose>.
  63. *
  64. * @flag ICMF_CHOOSE_PREVIEW | Displays a "Preview" button for
  65. * the video options. This button previews the compression
  66. * using a frame from the stream. This is the same flag
  67. * used in <f ICCompressorChoose>.
  68. *
  69. * @parm int | nStreams | Specifies the number of streams
  70. * that will have their options set by the dialog box.
  71. *
  72. * @parm PAVISTREAM FAR * | ppavi | Specifies a pointer to an
  73. * array of stream interface pointers. The <p nStreams>
  74. * parameter indicates the number of pointers in the array.
  75. *
  76. * @parm LPAVICOMPRESSOPTIONS FAR * | plpOptions | Specifies a pointer
  77. * to an array of <t LPAVICOMPRESSOPTIONS> pointers
  78. * to hold the compression options set by the dialog box. The
  79. * <p nStreams> parameter indicates the number of
  80. * pointers in the array.
  81. *
  82. * @rdesc Returns TRUE if the user pressed OK, FALSE for CANCEL or an error.
  83. *
  84. * @comm This function presents a standard Compression Options dialog
  85. * box using <p hwnd> as the parent window handle. When the
  86. * user is finished selecting the compression options for
  87. * each stream, the options are returned in the <t AVICOMPRESSOPTIONS>
  88. * structures in the array referenced by <p lpOptions>. The caller
  89. * must pass the interface pointers for the streams
  90. * in the array referenced by <p ppavi>.
  91. *
  92. ******************************************************************/
  93. STDAPI_(BOOL) AVISaveOptions(HWND hwnd, UINT uiFlags, int nStreams, PAVISTREAM FAR *ppavi, LPAVICOMPRESSOPTIONS FAR *plpOptions)
  94. {
  95. BOOL f;
  96. AVICOMPRESSOPTIONS FAR *aOptions;
  97. int i;
  98. /* Save the stream pointer */
  99. gnNumStreams = nStreams;
  100. gnCurStream = -1;
  101. gapAVI = ppavi;
  102. gapOpt = plpOptions;
  103. guiFlags = uiFlags;
  104. //
  105. // Remember the old compression options in case we cancel and need to
  106. // restore them
  107. //
  108. aOptions = (AVICOMPRESSOPTIONS FAR *)GlobalAllocPtr(GMEM_MOVEABLE,
  109. nStreams * sizeof(AVICOMPRESSOPTIONS));
  110. if (!aOptions)
  111. return FALSE;
  112. for (i = 0; i < nStreams; i++)
  113. aOptions[i] = *plpOptions[i];
  114. f = DialogBox (ghMod, "AVICompressOptionsDialog", hwnd,
  115. (DLGPROC)AVICompressOptionsDlgProc);
  116. //
  117. // The user cancelled... put the old compression options back.
  118. //
  119. if (f == 0)
  120. for (i = 0; i < nStreams; i++)
  121. *plpOptions[i] = aOptions[i];
  122. // Couldn't bring up the dialog
  123. if (f == -1)
  124. f = 0;
  125. GlobalFreePtr(aOptions);
  126. // !!! Returning TRUE doesn't guarantee something actually changed...
  127. return f;
  128. }
  129. /*************************************************************
  130. * @doc EXTERNAL AVISaveOptionsFree
  131. *
  132. * @api LONG | AVISaveOptionsFree | This function frees the resources allocated
  133. * by <f AVISaveOptions>.
  134. *
  135. * @parm int | nStreams | Specifies the number of <t AVICOMPRESSOPTIONS>
  136. * structures in the array passed in as the next parameter.
  137. *
  138. * @parm LPAVICOMPRESSOPTIONS FAR * | plpOptions | Specifies a pointer
  139. * to an array of <t LPAVICOMPRESSOPTIONS> pointers
  140. * to hold the compression options set by the dialog box. The
  141. * resources in each of these structures that were allocated by
  142. * <f AVISaveOptions> will be freed.
  143. *
  144. * @rdesc This function always returns AVIERR_OK (zero)
  145. *
  146. * @comm This function frees the resources allocated by <f AVISaveOptions>.
  147. **************************************************************/
  148. STDAPI AVISaveOptionsFree(int nStreams, LPAVICOMPRESSOPTIONS FAR *plpOptions)
  149. {
  150. for (; nStreams > 0; nStreams--) {
  151. if (plpOptions[nStreams-1]->lpParms)
  152. GlobalFreePtr(plpOptions[nStreams-1]->lpParms);
  153. plpOptions[nStreams-1]->lpParms = NULL;
  154. if (plpOptions[nStreams-1]->lpFormat)
  155. GlobalFreePtr(plpOptions[nStreams-1]->lpFormat);
  156. plpOptions[nStreams-1]->lpFormat = NULL;
  157. }
  158. return AVIERR_OK;
  159. }
  160. /****************************************************************************
  161. Bring up the compression options for the current stream
  162. ***************************************************************************/
  163. BOOL StreamOptions(HWND hwnd) {
  164. AVISTREAMINFO avis;
  165. BOOL f = FALSE;
  166. LONG lTemp;
  167. UINT w;
  168. // Get the stream type
  169. if (AVIStreamInfo(gapAVI[gnCurStream], &avis, sizeof(avis)) != 0)
  170. return FALSE;
  171. //
  172. // Video stream -- bring up the video compression dlg
  173. //
  174. if (avis.fccType == streamtypeVIDEO) {
  175. // The structure we have now is not filled in ... init it
  176. if (!(gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_VALID)) {
  177. _fmemset(gapOpt[gnCurStream], 0,
  178. sizeof(AVICOMPRESSOPTIONS));
  179. gapOpt[gnCurStream]->fccHandler = comptypeDIB;
  180. gapOpt[gnCurStream]->dwQuality = DEFAULT_QUALITY;
  181. }
  182. _fmemset(&gCompVars, 0, sizeof(gCompVars));
  183. gCompVars.cbSize = sizeof(gCompVars);
  184. gCompVars.dwFlags = ICMF_COMPVARS_VALID;
  185. gCompVars.fccHandler = gapOpt[gnCurStream]->fccHandler;
  186. gCompVars.lQ = gapOpt[gnCurStream]->dwQuality;
  187. gCompVars.lpState = gapOpt[gnCurStream]->lpParms;
  188. gCompVars.cbState = gapOpt[gnCurStream]->cbParms;
  189. gCompVars.lKey =
  190. (gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_KEYFRAMES)?
  191. (gapOpt[gnCurStream]->dwKeyFrameEvery) : 0;
  192. gCompVars.lDataRate =
  193. (gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_DATARATE) ?
  194. (gapOpt[gnCurStream]->dwBytesPerSecond / 1024) : 0;
  195. // !!! Don't pass flags verbatim if others are defined!!!
  196. f = ICCompressorChoose(hwnd, guiFlags, NULL,
  197. gapAVI[gnCurStream], &gCompVars, NULL);
  198. /* Set the options to our new values */
  199. gapOpt[gnCurStream]->lpParms = gCompVars.lpState;
  200. gapOpt[gnCurStream]->cbParms = gCompVars.cbState;
  201. gCompVars.lpState = NULL; // so it won't be freed
  202. gapOpt[gnCurStream]->fccHandler = gCompVars.fccHandler;
  203. gapOpt[gnCurStream]->dwQuality = gCompVars.lQ;
  204. gapOpt[gnCurStream]->dwKeyFrameEvery = gCompVars.lKey;
  205. gapOpt[gnCurStream]->dwBytesPerSecond = gCompVars.lDataRate
  206. * 1024;
  207. if (gCompVars.lKey)
  208. gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_KEYFRAMES;
  209. else
  210. gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_KEYFRAMES;
  211. if (gCompVars.lDataRate)
  212. gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_DATARATE;
  213. else
  214. gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_DATARATE;
  215. // If they pressed OK, we have valid stuff in here now.
  216. if (f)
  217. gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_VALID;
  218. // Close the stuff opened by ICCompressorChoose
  219. ICCompressorFree(&gCompVars);
  220. //
  221. // Bring up the ACM format dialog and stuff it in our
  222. // compression options structure
  223. //
  224. } else if (avis.fccType == streamtypeAUDIO) {
  225. ACMFORMATCHOOSE acf;
  226. LONG lsizeF = 0;
  227. if (acmGetVersion() < 0x02000000L) {
  228. char achACM[160];
  229. char achACMV[40];
  230. LoadString(ghMod, IDS_BADACM, achACM, sizeof(achACM));
  231. LoadString(ghMod, IDS_BADACMV, achACMV, sizeof(achACMV));
  232. MessageBox(hwnd, achACM, achACMV, MB_OK | MB_ICONHAND);
  233. return FALSE;
  234. }
  235. _fmemset(&acf, 0, sizeof(acf)); // or ACM blows up
  236. acf.cbStruct = sizeof(ACMFORMATCHOOSE);
  237. // If our options struct has valid data, use it to init
  238. // the acm dialog with, otherwise pick a default.
  239. acf.fdwStyle = (gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_VALID)
  240. ? ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT : 0;
  241. acf.hwndOwner = hwnd;
  242. // Make sure the AVICOMPRESSOPTIONS has a big enough lpFormat
  243. acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID)&lTemp);
  244. if ((gapOpt[gnCurStream]->cbFormat == 0 ||
  245. gapOpt[gnCurStream]->lpFormat == NULL) && lTemp) {
  246. gapOpt[gnCurStream]->lpFormat =
  247. GlobalAllocPtr(GMEM_MOVEABLE, lTemp);
  248. gapOpt[gnCurStream]->cbFormat = lTemp;
  249. } else if (gapOpt[gnCurStream]->cbFormat < (DWORD)lTemp && lTemp) {
  250. gapOpt[gnCurStream]->lpFormat =
  251. GlobalReAllocPtr(gapOpt[gnCurStream]->lpFormat, lTemp,
  252. GMEM_MOVEABLE);
  253. gapOpt[gnCurStream]->cbFormat = lTemp;
  254. }
  255. if (!gapOpt[gnCurStream]->lpFormat)
  256. return FALSE;
  257. acf.pwfx = gapOpt[gnCurStream]->lpFormat;
  258. acf.cbwfx = gapOpt[gnCurStream]->cbFormat;
  259. //
  260. // Only ask for choices that we can actually convert to
  261. //
  262. AVIStreamReadFormat(gapAVI[gnCurStream],
  263. AVIStreamStart(gapAVI[gnCurStream]), NULL, &lsizeF);
  264. // !!! Work around ACM bug by making sure our format is big enough
  265. lsizeF = max(lsizeF, sizeof(WAVEFORMATEX));
  266. acf.pwfxEnum = (LPWAVEFORMATEX)
  267. GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, lsizeF);
  268. if (acf.pwfxEnum) {
  269. AVIStreamReadFormat(gapAVI[gnCurStream],
  270. AVIStreamStart(gapAVI[gnCurStream]), acf.pwfxEnum, &lsizeF);
  271. acf.fdwEnum |= ACM_FORMATENUMF_CONVERT;
  272. }
  273. // If they pressed OK, we now have valid stuff in here!
  274. w = acmFormatChoose(&acf);
  275. if (w == MMSYSERR_NOERROR)
  276. gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_VALID;
  277. else if (w != ACMERR_CANCELED) {
  278. MessageBeep(0); // !!! Should really be a message box!
  279. }
  280. if (acf.pwfxEnum)
  281. GlobalFreePtr(acf.pwfxEnum);
  282. f = (w == MMSYSERR_NOERROR);
  283. }
  284. return f;
  285. }
  286. void NEAR PASCAL NewStreamChosen(HWND hwnd)
  287. {
  288. BOOL f;
  289. AVISTREAMINFO avis;
  290. DWORD dw;
  291. HIC hic;
  292. ICINFO icinfo;
  293. ACMFORMATDETAILS acmfmt;
  294. ACMFORMATTAGDETAILS aftd;
  295. LONG lsizeF;
  296. LPBITMAPINFOHEADER lp = NULL;
  297. char szFFDesc[80];
  298. char szDesc[120];
  299. // Set the interleave options for the selection we're leaving
  300. // !!! This code also appears in the OK button
  301. if (gnCurStream >= 0) { // there is a previous sel
  302. if (IsDlgButtonChecked(hwnd, IDC_intINTERLEAVE)) {
  303. dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT,
  304. NULL, FALSE);
  305. gapOpt[gnCurStream]->dwInterleaveEvery = dw;
  306. gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
  307. } else {
  308. dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT,
  309. NULL, FALSE);
  310. gapOpt[gnCurStream]->dwInterleaveEvery = dw;
  311. gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_INTERLEAVE;
  312. }
  313. }
  314. gnCurStream = (int)SendDlgItemMessage(hwnd, IDC_intCHOOSESTREAM,
  315. CB_GETCURSEL, 0, 0L);
  316. if (gnCurStream < 0)
  317. return;
  318. if (AVIStreamInfo(gapAVI[gnCurStream], &avis, sizeof(avis)) != 0)
  319. return;
  320. //
  321. // Show a string describing the current format
  322. //
  323. szDesc[0] = '\0';
  324. lsizeF = 0;
  325. AVIStreamReadFormat(gapAVI[gnCurStream],
  326. AVIStreamStart(gapAVI[gnCurStream]), NULL, &lsizeF);
  327. if (lsizeF) {
  328. lp = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, lsizeF);
  329. if (lp) {
  330. if (AVIStreamReadFormat(gapAVI[gnCurStream],
  331. AVIStreamStart(gapAVI[gnCurStream]),
  332. lp, &lsizeF) == AVIERR_OK) {
  333. if (avis.fccType == streamtypeVIDEO) {
  334. wsprintf(szDesc, "%ldx%ldx%d\n", lp->biWidth,
  335. lp->biHeight, lp->biBitCount);
  336. if (lp->biCompression == BI_RGB) {
  337. LoadString(ghMod, IDS_FFDESC, szFFDesc,
  338. sizeof(szFFDesc));
  339. lstrcat(szDesc, szFFDesc);
  340. } else {
  341. hic = ICDecompressOpen(ICTYPE_VIDEO,avis.fccHandler,
  342. lp, NULL);
  343. if (hic) {
  344. if (ICGetInfo(hic, &icinfo,sizeof(icinfo)) != 0)
  345. lstrcat(szDesc, icinfo.szDescription);
  346. ICClose(hic);
  347. }
  348. }
  349. } else if (avis.fccType == streamtypeAUDIO) {
  350. _fmemset(&acmfmt, 0, sizeof(acmfmt));
  351. acmfmt.pwfx = (LPWAVEFORMATEX) lp;
  352. acmfmt.cbStruct = sizeof(ACMFORMATDETAILS);
  353. acmfmt.dwFormatTag = acmfmt.pwfx->wFormatTag;
  354. acmfmt.cbwfx = lsizeF;
  355. aftd.cbStruct = sizeof(aftd);
  356. aftd.dwFormatTag = acmfmt.pwfx->wFormatTag;
  357. aftd.fdwSupport = 0;
  358. if ((acmFormatTagDetails(NULL,
  359. &aftd,
  360. ACM_FORMATTAGDETAILSF_FORMATTAG) == 0) &&
  361. (acmFormatDetails(NULL, &acmfmt,
  362. ACM_FORMATDETAILSF_FORMAT) == 0)) {
  363. wsprintf(szDesc, "%s %s", (LPSTR) acmfmt.szFormat,
  364. (LPSTR) aftd.szFormatTag);
  365. }
  366. }
  367. }
  368. GlobalFreePtr(lp);
  369. }
  370. }
  371. SetDlgItemText(hwnd, IDC_intFORMAT, szDesc);
  372. //
  373. // AUDIO and VIDEO streams have a compression dialog
  374. //
  375. if (avis.fccType == streamtypeAUDIO ||
  376. avis.fccType == streamtypeVIDEO)
  377. EnableWindow(GetDlgItem(hwnd, IDC_intOPTIONS), TRUE);
  378. else
  379. EnableWindow(GetDlgItem(hwnd, IDC_intOPTIONS), FALSE);
  380. //
  381. // Every stream but the first has an interleave options
  382. //
  383. if (gnCurStream > 0) {
  384. EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVE), TRUE);
  385. EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVEEDIT),
  386. TRUE);
  387. EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVETEXT),
  388. TRUE);
  389. // Set the interleave situation for this stream
  390. f = (gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
  391. != 0;
  392. dw = gapOpt[gnCurStream]->dwInterleaveEvery;
  393. CheckDlgButton(hwnd, IDC_intINTERLEAVE, f);
  394. SetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, (int)dw, FALSE);
  395. } else {
  396. EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVE),FALSE);
  397. EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVEEDIT),
  398. FALSE);
  399. EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVETEXT),
  400. FALSE);
  401. }
  402. }
  403. /*--------------------------------------------------------------+
  404. * Dialog Proc for the main compression options dialog *
  405. +--------------------------------------------------------------*/
  406. LONG FAR PASCAL _export AVICompressOptionsDlgProc(HWND hwnd, unsigned msg, WORD wParam, LONG lParam)
  407. {
  408. int nVal;
  409. AVISTREAMINFO avis;
  410. DWORD dw;
  411. switch(msg){
  412. case WM_INITDIALOG:
  413. //
  414. // If we've only got one stream to set the options for, it seems
  415. // strange to bring up a box to let you choose which stream you want.
  416. // Let's skip straight to the proper options dlg box.
  417. //
  418. if (gnNumStreams == 1) {
  419. gnCurStream = 0;
  420. EndDialog(hwnd, StreamOptions(hwnd));
  421. return TRUE;
  422. }
  423. /* Add the list of streams to the drop-down box */
  424. for (nVal = 0; nVal < gnNumStreams; nVal++) {
  425. // Get the name of this stream
  426. AVIStreamInfo(gapAVI[nVal], &avis, sizeof(avis));
  427. SendDlgItemMessage(hwnd, IDC_intCHOOSESTREAM, CB_ADDSTRING, 0,
  428. (LONG) (LPSTR)avis.szName);
  429. }
  430. // Set our initial selection to the first item
  431. SendDlgItemMessage(hwnd, IDC_intCHOOSESTREAM, CB_SETCURSEL, 0, 0L);
  432. // Make sure we see it
  433. SendMessage(hwnd, WM_COMMAND, IDC_intCHOOSESTREAM,
  434. MAKELONG(GetDlgItem(hwnd, IDC_intCHOOSESTREAM), CBN_SELCHANGE));
  435. return TRUE;
  436. case WM_COMMAND:
  437. switch(wParam){
  438. case IDOK:
  439. // Set the interleave options for the selection we're on
  440. // !!! This code also appears in the SELCHANGE code
  441. if (gnCurStream >= 0) { // there is a valid selection
  442. if (IsDlgButtonChecked(hwnd, IDC_intINTERLEAVE)) {
  443. dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT,
  444. NULL, FALSE);
  445. gapOpt[gnCurStream]->dwInterleaveEvery = dw;
  446. gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
  447. } else {
  448. // why not remember edit box entry anyway?
  449. dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT,
  450. NULL, FALSE);
  451. gapOpt[gnCurStream]->dwInterleaveEvery = dw;
  452. gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_INTERLEAVE;
  453. }
  454. }
  455. // fall through (AAAAaaaahhhhh.....)
  456. case IDCANCEL:
  457. EndDialog(hwnd, wParam == IDOK);
  458. break;
  459. case IDC_intOPTIONS:
  460. StreamOptions(hwnd);
  461. break;
  462. //
  463. // Somebody chose a new stream. Do we need to grey InterleaveOpts?
  464. // Set the current stream.
  465. //
  466. case IDC_intCHOOSESTREAM:
  467. if (HIWORD(lParam) != CBN_SELCHANGE)
  468. break;
  469. NewStreamChosen(hwnd);
  470. break;
  471. case IDC_intINTERLEAVE:
  472. break;
  473. default:
  474. break;
  475. }
  476. break;
  477. default:
  478. return FALSE;
  479. }
  480. return FALSE;
  481. }