home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / viscobv6.zip / vac22os2 / ibmcobol / samples / toolkit / mm / ultimoio / ioedit.c < prev    next >
C/C++ Source or Header  |  1996-11-19  |  24KB  |  577 lines

  1. /*************************START OF SPECIFICATIONS *************************/
  2. /* SOURCE FILE NAME:  IOEDIT.C                                            */
  3. /*                                                                        */
  4. /* DESCRIPTIVE NAME: Clipboard Editing support for SMV files              */
  5. /*                                                                        */
  6. /* COPYRIGHT:   Copyright (c) IBM Corporation  1993                       */
  7. /*                        All Rights Reserved                             */
  8. /*                                                                        */
  9. /* STATUS: OS/2 Release 2.1                                               */
  10. /*                                                                        */
  11. /* FUNCTION: This source module contains all the routines to support      */
  12. /*           copy, cut, delete, paste, undo and redo.                     */
  13. /*                                                                        */
  14. /* NOTES:                                                                 */
  15. /*    DEPENDENCIES: none                                                  */
  16. /*    RESTRICTIONS: Runs in 32 bit protect mode (OS/2 2.0)                */
  17. /*                                                                        */
  18. /* ENTRY POINTS:                                                          */
  19. /*      ioEditSetup                                                       */
  20. /*      ioEditCleanup                                                     */
  21. /*      ioEditFindHeaders                                                 */
  22. /*      ioEditCloneEditList                                               */
  23. /*      ioEditTimeToFrame                                                 */
  24. /*      ioEditFrameToTime                                                 */
  25. /*      ioEditDuration                                                    */
  26. /*      ioEditGetFullName                                                 */
  27. /*      IOProcWinMsg                                                      */
  28. /*                                                                        */
  29. /************************** END OF SPECIFICATIONS *************************/
  30.  
  31. #define         INCL_DOS
  32. #define         INCL_ERRORS
  33. #define         INCL_WIN
  34. #define         INCL_GPI
  35. #include        <os2.h>
  36. #include        <pmbitmap.h>
  37.  
  38. #define         INCL_OS2MM
  39. #define         INCL_MMIO_CODEC
  40. #define         INCL_MMIO_DOSIOPROC
  41. #include        <os2me.h>
  42. #include        <hhpheap.h>
  43. #define         INCL_DBCSCRT
  44. #include        <mmiocrt.h>
  45. #include        <ioi.h>
  46.  
  47.    extern HHUGEHEAP  hheap;
  48.    extern HMTX       hmtxGlobalHeap;
  49.  
  50. /************************** START OF SPECIFICATIONS *************************/
  51. /*                                                                          */
  52. /* SUBROUTINE NAME: ioEditFindHeaders                                       */
  53. /*                                                                          */
  54. /* DESCRIPTIVE NAME: Find the video and audio headers                       */
  55. /*                                                                          */
  56. /* FUNCTION: Return the address of the video and audio headers.             */
  57. /*                                                                          */
  58. /*************************** END OF SPECIFICATIONS **************************/
  59.  
  60. LONG ioEditFindHeaders(PINSTANCE pinstance, PMMVIDEOHEADER *pVideo,
  61.                        PMMAUDIOHEADER *pAudio) {
  62.    LONG           i;
  63.    PTRACKI        pTrackList;
  64.    PMMMOVIEHEADER pMovieHeader;
  65.    PMMTRACKINFO   pTrackInfo;
  66.    PMMVIDEOHEADER pTHVideo = NULL;
  67.    PMMAUDIOHEADER pTHAudio = NULL;
  68.    ULONG          numTracks;
  69.    LONG           videoTrackID = -1, audioTrackID = -1;
  70.  
  71.    pMovieHeader = pinstance->pmmhdr;
  72.    if (pMovieHeader == NULL) goto bad_structure;
  73.  
  74.    // only support one mandatory video track and one optional audio track
  75.  
  76.    numTracks = pMovieHeader->ulNumEntries;
  77.    if ((numTracks == 0) || (numTracks > 2)) goto bad_structure;
  78.  
  79.    pTrackInfo = pMovieHeader->pmmTrackInfoList;
  80.    if (pTrackInfo == NULL) goto bad_structure;
  81.  
  82.    for (i = 0; i < numTracks; i++, pTrackInfo++) { // get track IDs
  83.       if (IS_VIDEO_TRACK(pTrackInfo->ulMediaType)) {
  84.          if (videoTrackID == -1) videoTrackID = pTrackInfo->ulTrackID;
  85.          else goto bad_structure;                  // 2nd video track
  86.       }
  87.       if (IS_AUDIO_TRACK(pTrackInfo->ulMediaType)) {
  88.          if (audioTrackID == -1) audioTrackID = pTrackInfo->ulTrackID;
  89.          else goto bad_structure;                  // 2nd audio track
  90.       }
  91.    }
  92.  
  93.    if (videoTrackID == -1) goto bad_structure;     // must have a video track
  94.  
  95.    pTrackList = pinstance->ptrackiList;            // linked list of TRACKI structures
  96.  
  97.    while (pTrackList != NULL) {
  98.       if (IS_VIDEO_TRACK(pTrackList->ulMediaType))
  99.          pTHVideo = (PMMVIDEOHEADER)(pTrackList->pTrackHeader);
  100.       if (IS_AUDIO_TRACK(pTrackList->ulMediaType))
  101.          pTHAudio = (PMMAUDIOHEADER)(pTrackList->pTrackHeader);
  102.       pTrackList = pTrackList->ptrackiNext;
  103.    }
  104.  
  105.    if (pTHVideo == NULL) goto bad_structure;
  106.  
  107.    *pVideo = pTHVideo;
  108.    *pAudio = pTHAudio;
  109.  
  110.    return MMIO_SUCCESS;
  111.  
  112. bad_structure:                                     // error exit
  113.    return MMIOERR_INVALID_STRUCTURE;
  114. }
  115.  
  116. /************************** START OF SPECIFICATIONS *************************/
  117. /*                                                                          */
  118. /* SUBROUTINE NAME: ioEditSetup                                             */
  119. /*                                                                          */
  120. /* DESCRIPTIVE NAME: Prepare the Edit List                                  */
  121. /*                                                                          */
  122. /* FUNCTION: This function prepares the edit list and is called when the    */
  123. /*           first editing message is received.                             */
  124. /*                                                                          */
  125. /*************************** END OF SPECIFICATIONS **************************/
  126.  
  127. LONG ioEditSetup(PMMIOINFO pmmioinfo, PMMIO_EDIT_PARMS pParms) {
  128.    LONG           rc;
  129.    PEDITELEMENT   pNew;
  130.    PINSTANCE      pinstance;
  131.    PMMVIDEOHEADER pVideo;
  132.    PMMAUDIOHEADER pAudio;
  133.  
  134.    rc = ioGetPtrInstance(pmmioinfo, &pinstance);
  135.    if (rc != MMIO_SUCCESS) {
  136.       pmmioinfo->ulErrorRet = rc;
  137.       return MMIO_ERROR;
  138.    }
  139.  
  140.    // make sure that the movie and track headers have been setup
  141.  
  142.    if (pinstance->pmmhdr == NULL) {
  143.       pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE;
  144.       return MMIO_ERROR;
  145.    }
  146.  
  147.    rc = ioEditFindHeaders(pinstance, &pVideo, &pAudio);
  148.    if (rc != MMIO_SUCCESS) {
  149.       pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE;
  150.       return MMIO_ERROR;
  151.    }
  152.  
  153.    // if the 1st time, allocate a virgin EDITELEMENT
  154.  
  155.    pNew = pinstance->pEditList;          // pEditList is null if the file
  156.    if (pNew == NULL) {                   // ... has not been edited
  157.       ENTERCRITX;
  158.       pNew = (PEDITELEMENT)HhpAllocMem(hheap, sizeof(EDITELEMENT));
  159.       if (pNew == NULL) {
  160.          EXITCRIT;
  161.          pmmioinfo->ulErrorRet = MMIOERR_OUTOFMEMORY;
  162.          return MMIO_ERROR;
  163.       }
  164.       EXITCRIT;
  165.  
  166.       // fill in the non-zero values
  167.  
  168.       pNew->ulDuration     = pVideo->ulTotalFrames;
  169.       pNew->pInstance      = pinstance;
  170.       pNew->ulFilePosition = pParms->ulCurrentFilePosition;
  171.  
  172.       pinstance->pEditList = pinstance->pCurrentElement = pNew;
  173.    }
  174.  
  175.    pmmioinfo->ulErrorRet = 0;
  176.    return MMIO_SUCCESS;
  177. }
  178.  
  179. /************************** START OF SPECIFICATIONS *************************/
  180. /*                                                                          */
  181. /* SUBROUTINE NAME: ioEditCloneEditList                                     */
  182. /*                                                                          */
  183. /* DESCRIPTIVE NAME: Make a copy of the current edit list                   */
  184. /*                                                                          */
  185. /* FUNCTION: This function makes a copy of the edit list so that it         */
  186. /*           can be placed on the undo list.                                */
  187. /*                                                                          */
  188. /*************************** END OF SPECIFICATIONS **************************/
  189.  
  190. PEDITELEMENT ioEditCloneEditList(PINSTANCE pinstance) {
  191.    LONG           rc;
  192.    PEDITELEMENT   p1, p2, p3, pOld, pNew;
  193.  
  194.    pOld = pinstance->pEditList;          // be sure a list is there
  195.    if (pOld == NULL) return NULL;
  196.  
  197.    ENTERCRIT(rc);
  198.    if (rc) return NULL;
  199.  
  200.    // get storage for the first new EDITELEMENT
  201.  
  202.    pNew = (PEDITELEMENT)HhpAllocMem(hheap, sizeof(EDITELEMENT));
  203.    if (pNew == NULL) {
  204.          EXITCRIT;
  205.          return NULL;                     // error exit
  206.    }
  207.    *pNew           = *pOld;               // initialize the first new EDITELEMENT
  208.    pNew->pNext     = NULL;
  209.    pNew->pPrevious = NULL;
  210.    p1              = pOld->pNext;
  211.    p3              = pNew;
  212.  
  213.    // get storage for the rest in the list
  214.  
  215.    while (p1 != NULL) {                   // p1 walks the old list
  216.  
  217.       p2 = (PEDITELEMENT)HhpAllocMem(hheap, sizeof(EDITELEMENT));
  218.       if (p2 == NULL) {
  219.          p1 = pNew;                       // free any gotten so far
  220.          while (p1 != NULL) {
  221.             p2 = p1->pNext;
  222.             HhpFreeMem(hheap, p1);        // free current EDITELEMENT
  223.             p1 = p2;
  224.          }
  225.          EXITCRIT;
  226.          return NULL;                     // error exit
  227.        }
  228.  
  229.       p3->pNext     = p2;                 // chain this one from the previous
  230.       *p2           = *p1;                // copy old to new
  231.       p2->pNext     = NULL;
  232.       p2->pPrevious = p3;
  233.  
  234.       p3 = p2;                            // save for pPrevious
  235.       p1 = p1->pNext;                     // move to next old EDITELEMENT
  236.    }
  237.  
  238.    EXITCRIT;
  239.    return pNew;
  240. }
  241.  
  242. /************************** START OF SPECIFICATIONS *************************/
  243. /*                                                                          */
  244. /* SUBROUTINE NAME: ioEditCleanup                                           */
  245. /*                                                                          */
  246. /* DESCRIPTIVE NAME: Cleanup editing lists                                  */
  247. /*                                                                          */
  248. /* FUNCTION: This function frees the storage of all control blocks anchored */
  249. /*           from the INSTANCE structure that were created by editing.      */
  250. /*                                                                          */
  251. /*************************** END OF SPECIFICATIONS **************************/
  252.  
  253. /**************************************************
  254.  * ioEditFreeEditList
  255.  *
  256.  * free all EDITELEMENTs in a chain
  257.  **************************************************/
  258.  
  259. static void ioEditFreeEditList(PINSTANCE pinstance) {
  260.    PEDITELEMENT p1, p2;
  261.  
  262.    p1 = pinstance->pEditList;       // set p1 to first EDITELEMENT in list
  263.  
  264.    while (p1 != NULL) {
  265.       p2 = p1->pNext;               // remember next EDITELEMENT
  266.       HhpFreeMem(hheap, p1);        // free current EDITELEMENT
  267.       p1 = p2;                      // set p1 to next EDITELEMENT in list
  268.    }
  269.  
  270.    pinstance->pEditList = NULL;
  271. }
  272.  
  273. /*****************************************************
  274.  * ioEditFreeFileList
  275.  *
  276.  * free all FILEELEMENTs in a chain
  277.  *****************************************************/
  278.  
  279. static void ioEditFreeFileList(PINSTANCE pinstance) {
  280.    PFILEELEMENT p1, p2;
  281.  
  282.    p1 = pinstance->pFileList;       // p1 -> first FILEELEMENT in list
  283.  
  284.    while (p1 != NULL) {
  285.       p2 = p1->pNext;               // remember next FILEELEMENT
  286.       HhpFreeMem(hheap, p1);        // free current FILEELEMENT
  287.       p1 = p2;                      // set p1 to next FILEELEMENT in list
  288.    }
  289.  
  290.    pinstance->pFileList = NULL;
  291. }
  292.  
  293. /*******************************************************
  294.  * ioEditFreeUndoList
  295.  *
  296.  * free all Edit List chains anchored on the Undo List
  297.  *******************************************************/
  298.  
  299. static void ioEditFreeUndoList(PINSTANCE pinstance) {
  300.    PEDITELEMENT p1, p2, p3, p4;
  301.  
  302.    p3 = pinstance->pUndoList;          // p3 -> first edit list
  303.  
  304.    while (p3 != NULL) {
  305.  
  306.       p4 = p3->pUndoRedoChain;         // p4 -> next edit list
  307.       p1 = p3;                         // p1 -> current edit list
  308.  
  309.       while (p1 != NULL) {
  310.          p2 = p1->pNext;               // remember next EDITELEMENT
  311.          HhpFreeMem(hheap, p1);        // free current EDITELEMENT
  312.          p1 = p2;                      // set p1 to next EDITELEMENT in list
  313.       };
  314.  
  315.       p3 = p4;                         // p3 -> next edit list
  316.    }
  317.  
  318.    pinstance->pUndoList = NULL;
  319. }
  320.  
  321. /*********************************************************
  322.  * ioEditFreeRedoList
  323.  *
  324.  * free all Edit List chains anchored on the Redo List
  325.  *********************************************************/
  326.  
  327. static void ioEditFreeRedoList(PINSTANCE pinstance) {
  328.    PEDITELEMENT p1, p2, p3, p4;
  329.  
  330.    p3 = pinstance->pRedoList;          // p3 -> first edit list
  331.  
  332.    while (p3 != NULL) {
  333.  
  334.       p4 = p3->pUndoRedoChain;         // p4 -> next edit list
  335.       p1 = p3;                         // p1 -> current edit list
  336.  
  337.       while (p1 != NULL) {
  338.          p2 = p1->pNext;               // remember next EDITELEMENT
  339.          HhpFreeMem(hheap, p1);        // free current EDITELEMENT
  340.          p1 = p2;                      // set p1 to next EDITELEMENT in list
  341.       };
  342.  
  343.       p3 = p4;                         // p3 -> next edit list
  344.    }
  345.  
  346.    pinstance->pRedoList = NULL;
  347. }
  348.  
  349. /************************** START OF SPECIFICATIONS *************************/
  350. /*                                                                          */
  351. /* SUBROUTINE NAME: ioEditCleanup                                           */
  352. /*                                                                          */
  353. /* DESCRIPTIVE NAME: Clean up after editing                                 */
  354. /*                                                                          */
  355. /* FUNCTION: Frees all storage for editing data structures.                 */
  356. /*                                                                          */
  357. /*************************** END OF SPECIFICATIONS **************************/
  358.  
  359. void ioEditCleanup(PINSTANCE pinstance) {
  360.  
  361.       // caller must have acquired the global semaphore
  362.  
  363.       ioEditFreeFileList(pinstance);
  364.       ioEditFreeEditList(pinstance);
  365.       ioEditFreeUndoList(pinstance);
  366.       ioEditFreeRedoList(pinstance);
  367.  
  368.       pinstance->ulEditFlags = 0;
  369. }
  370.  
  371. /************************** START OF SPECIFICATIONS *************************/
  372. /*                                                                          */
  373. /* SUBROUTINE NAME: ioEditTimeToFrame                                       */
  374. /*                                                                          */
  375. /* DESCRIPTIVE NAME: Convert time to frame number                           */
  376. /*                                                                          */
  377. /* FUNCTION: This function converts a time to a frame number.               */
  378. /*                                                                          */
  379. /*************************** END OF SPECIFICATIONS **************************/
  380.  
  381. ULONG ioEditTimeToFrame(PMMVIDEOHEADER pTHVideo, ULONG ulTime)
  382.  
  383. {
  384. // this number is rounded slightly to take into account rounding down errors
  385. // that occur from converting mmtime numbers to microseconds.  The 0.01 at
  386. // the end of the expression is used to round movies with a frame rate of
  387. // slightly less than a whole number (i.e. 14.999925) which at the end of
  388. // file would lose the last frame from a cut.
  389.  
  390.    double val = (((double) (ulTime + 1.0) * (double) (pTHVideo->ulRate)) / (1000000.0 * (double)(pTHVideo->ulScale)) + 0.01);
  391.  
  392.    return((ULONG) (val));
  393.  
  394. //   return((ULONG) (((double) ulTime * (double) (pTHVideo->ulRate)) / (1000000.0 * (double)(pTHVideo->ulScale))));
  395.  
  396. //   fps  = (double)(pTHVideo->ulRate) / (double)(pTHVideo->ulScale);
  397. //   uspf = 1000000.0 / fps;
  398. //   return (double)ulTime / uspf;       // ULONG coersion is like floor()
  399. }
  400.  
  401. /************************** START OF SPECIFICATIONS *************************/
  402. /*                                                                          */
  403. /* SUBROUTINE NAME: ioEditFrameToTime                                       */
  404. /*                                                                          */
  405. /* DESCRIPTIVE NAME: Frame number to microseconds                           */
  406. /*                                                                          */
  407. /* FUNCTION: This function converts a frame number to microseconds.         */
  408. /*                                                                          */
  409. /*************************** END OF SPECIFICATIONS **************************/
  410.  
  411. ULONG ioEditFrameToTime(PMMVIDEOHEADER pTHVideo, ULONG frame)
  412.  
  413. {
  414.    double fps;
  415.  
  416.    return ((double)frame * (double)pTHVideo->mmtimePerFrame * 1000.0 / 3.0);
  417.  
  418. // fps  = (double)(pTHVideo->ulRate) / (double)(pTHVideo->ulScale);
  419. // return ((double)frame * 1000000.0 / fps) + 0.5;              // @T01
  420.  
  421. }
  422.  
  423. /************************** START OF SPECIFICATIONS *************************/
  424. /*                                                                          */
  425. /* SUBROUTINE NAME: ioEditDuration                                          */
  426. /*                                                                          */
  427. /* DESCRIPTIVE NAME: Find the length of an edited file in frames            */
  428. /*                                                                          */
  429. /* FUNCTION: This function returns the number of frames in an edited file.  */
  430. /*                                                                          */
  431. /*************************** END OF SPECIFICATIONS **************************/
  432.  
  433. ULONG ioEditDuration(PINSTANCE pinstance, PMMIO_EDIT_PARMS pParms) {
  434.    PEDITELEMENT   pTemp;
  435.    ULONG          duration = 0, rc;
  436.    PMMVIDEOHEADER pVideo = NULL;
  437.    PMMAUDIOHEADER pAudio = NULL;
  438.  
  439.    pTemp = pinstance->pEditList;
  440.  
  441.    while (pTemp != NULL) {
  442.       duration += pTemp->ulDuration;
  443.       pTemp = pTemp->pNext;
  444.    }
  445.  
  446.    pParms->ulNewFileLength = 0;
  447.  
  448.    rc = ioEditFindHeaders(pinstance, &pVideo, &pAudio);
  449.  
  450.    pParms->ulNewFileLength = ioEditFrameToTime(pVideo, duration);
  451.  
  452.    return duration;
  453. }
  454.  
  455. /************************** START OF SPECIFICATIONS *************************/
  456. /*                                                                          */
  457. /* SUBROUTINE NAME: ioEditGetFullName                                       */
  458. /*                                                                          */
  459. /* DESCRIPTIVE NAME: Get Full Name                                          */
  460. /*                                                                          */
  461. /* FUNCTION: Form a fully qualified file name for a file                    */
  462. /*                                                                          */
  463. /*************************** END OF SPECIFICATIONS **************************/
  464.  
  465. LONG ioEditGetFullName(PSZ inputName, PSZ outputName) {
  466.    ULONG          driveNumber, logicalDriveMap, dirPathLen = CCHMAXPATH;
  467.    ULONG          length;
  468.    APIRET         apiRC;
  469.    BYTE           dirPath[CCHMAXPATH];
  470.    SZ             tempBuffer[CCHMAXPATH];
  471.  
  472.    length = strlen(inputName);
  473.  
  474.    if (length >= CCHMAXPATH) return MMIOERR_INVALID_FILENAME;
  475.  
  476.    if ((length >= 2) && (inputName[1] == ':')) {
  477.       strcpy(outputName, inputName);
  478.       return MMIO_SUCCESS;
  479.    }
  480.  
  481.    outputName[0] = '\0';                     // be sure output is a string
  482.  
  483.    // copy the input to a temporary buffer so that the same area can
  484.    // be used for input and output
  485.  
  486.    if (length == 0) tempBuffer[0] = '\0';
  487.    else strcpy(tempBuffer, inputName);
  488.  
  489.    // get current drive and directory info
  490.  
  491.    apiRC = DosQueryCurrentDisk(&driveNumber, &logicalDriveMap);
  492.  
  493.    outputName[0] = 'A' + driveNumber - 1;
  494.    outputName[1] = ':';
  495.    outputName[2] = '\0';
  496.  
  497.    // if the input begins with a '\' then all we need to add is the drive,
  498.    // otherwise we also need to add the current path
  499.  
  500.    if (tempBuffer[0] != '\\') {
  501.       outputName[2] = '\\';
  502.       outputName[3] = '\0';
  503.  
  504.       apiRC = DosQueryCurrentDir(0, &dirPath[0], &dirPathLen);
  505.       if (apiRC != NO_ERROR) return MMIOERR_INTERNAL_SYSTEM;
  506.  
  507.       // if dirpath is empty, we don't want to append "\\"
  508.  
  509.       if (strcmp (dirPath, ""))
  510.       {
  511.          strcat(outputName, &dirPath[0]);
  512.          strcat(outputName, "\\");
  513.       }
  514.  
  515.    }
  516.  
  517.    strcat(outputName, tempBuffer);
  518.  
  519.    return MMIO_SUCCESS;
  520. }
  521.  
  522. /************************** START OF SPECIFICATIONS *************************/
  523. /*                                                                          */
  524. /* SUBROUTINE NAME: IOProcWinMsg                                            */
  525. /*                                                                          */
  526. /* DESCRIPTIVE NAME: Process Window Messages                                */
  527. /*                                                                          */
  528. /* FUNCTION: Handle window messages passed from the MCD                     */
  529. /*                                                                          */
  530. /* NOTES: None                                                              */
  531. /*                                                                          */
  532. /* ENTRY POINT: IOProcWinMsg                                                */
  533. /*                                                                          */
  534. /* INPUT:    PMMIOINFO  pmmioinfo - pointer to MMIOINFO instance structure  */
  535. /*           PMMIO_WINMSG         - pointer to MMIO_WINMSG structure        */
  536. /*                                                                          */
  537. /* EXIT-NORMAL:                                                             */
  538. /*              MMIO_SUCCESS                                                */
  539. /*                                                                          */
  540. /* EXIT-ERROR:                                                              */
  541. /*              MMIO_ERROR                                                  */
  542. /*                                                                          */
  543. /* SIDE EFFECTS:                                                            */
  544. /*                                                                          */
  545. /*************************** END OF SPECIFICATIONS **************************/
  546.  
  547. LONG IOProcWinMsg(PMMIOINFO pmmioinfo, PMMIO_WINMSG pParms) {
  548.    LONG           rc;
  549.    PINSTANCE      pinstance;
  550.  
  551.    if (pmmioinfo == NULL) return MMIO_ERROR;
  552.  
  553.    if (CheckMem((PVOID)pmmioinfo, sizeof(MMIOINFO), PAG_WRITE))
  554.       return MMIO_ERROR;
  555.  
  556.    pmmioinfo->ulErrorRet = 0;
  557.  
  558.    rc = ioGetPtrInstance(pmmioinfo, &pinstance);
  559.    if (rc != MMIO_SUCCESS) {
  560.       pmmioinfo->ulErrorRet = rc;
  561.       return MMIO_ERROR;
  562.    }
  563.  
  564.    switch (pParms->usMessage) {
  565.  
  566.       case WM_DESTROYCLIPBOARD:
  567.          pinstance->ulEditFlags &= ~ACTIVE_CLIPBRD_REFERENCE;
  568.          break;
  569.  
  570.       default:
  571.          break;
  572.    }
  573.  
  574.    return MMIO_SUCCESS;
  575. }
  576.  
  577.