home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / aniedit / anicmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-07  |  37.9 KB  |  1,379 lines

  1. /****************************************************************************\
  2. *
  3. *     MODULE: anicmd.c
  4. *
  5. *     PURPOSE: Processes WM_COMMANDs for the Animated Cursor Editor
  6. *
  7. *     Copyright 1993-1996 Microsoft Corp.
  8. *
  9. *
  10. * History:
  11. *   21-Apr-1993 JonPa   Wrote it.
  12. *
  13. \****************************************************************************/
  14.  
  15. #include <windows.h>
  16. #include <commdlg.h>
  17. #include <search.h>
  18. #include "anidefs.h"
  19.  
  20. static DWORD WINAPI ProcWaitThread( LPVOID lpv );
  21. static BOOL CALLBACK ETWProc( HWND hwnd, LPARAM lParam );
  22.  
  23. BOOL gfEditFrame = FALSE;
  24. TCHAR gszTempFile[MAX_PATH];
  25.  
  26.  
  27. /****************************************************************************\
  28. *
  29. *     FUNCTION: void AniEndDialog( HDLG hdlg, int i )
  30. *
  31. *     PURPOSE:  Destroys Modless Dialogs
  32. *
  33. *
  34. * History:
  35. *   08-Sep-1995 JonPa   Created it
  36. *
  37. \****************************************************************************/
  38. #define AniEndDialog( hdlg, i )         DestroyWindow( hdlg )
  39.  
  40. /****************************************************************************\
  41. *
  42. *     FUNCTION: void LoadAniFile(hWnd, hfCursor, szFileTitle, szFile)
  43. *
  44. *     PURPOSE:  Loads an ANI from the given handle, and sets up ganiAcon
  45. *
  46. *
  47. * History:
  48. *   31-May-1995 JonPa   Created it
  49. *
  50. \****************************************************************************/
  51. void LoadAniFile(HWND hWnd, HANDLE hfCursor, LPTSTR szFileTitle, LPTSTR szFile)
  52. {
  53.     /* delete any existing ani file */
  54.     NewAniCursor( hWnd );
  55.  
  56.     /* read in the file */
  57.     if (!ReadAniFile( hWnd, hfCursor )) {
  58.         FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE,
  59.                 MSG_INVALIDCURSORFILE, szFileTitle );
  60.     } else {
  61.         /*
  62.          * Put the filename in the title.
  63.          */
  64.         lstrcpy(ganiAcon.szFile, szFile);
  65.         SetWindowFileTitle(hWnd, szFileTitle);
  66.         SetDlgItemInt( hWnd, DLG_MAIN_RATE, ganiAcon.anih.jifRate, FALSE);
  67.     }
  68.  
  69.     ResumePreview(hWnd, DLG_MAIN_PREVIEW);
  70. }
  71.  
  72. /****************************************************************************\
  73. *
  74. *     FUNCTION: DoCommand(HWND, unsigned, WORD, LONG)
  75. *
  76. *     PURPOSE:  Processes commands for the main dialog box
  77. *
  78. *     MESSAGES:
  79. *
  80. *         WM_INITDIALOG - initialize dialog box
  81. *         WM_COMMAND    - Input received
  82. *
  83. *     COMMENTS:
  84. *
  85. *
  86. * History:
  87. *   21-Apr-1993 JonPa   Created it
  88. *
  89. \****************************************************************************/
  90. BOOL DoCommand( HWND hWnd, UINT wParam, LONG lParam )
  91. {
  92.     int cmd = LOWORD(wParam);
  93.  
  94.     switch(cmd){
  95.  
  96.  
  97.     case MENU_FILE_NEW:
  98.     case DLG_MAIN_BTNNEW:
  99.         /* If dirty, then prompt for save */
  100.         if(!CheckDirty(hWnd))
  101.             break;
  102.  
  103.         /* free used memory and init structures and dlg */
  104.         NewAniCursor(hWnd);
  105.         ResumePreview(hWnd, DLG_MAIN_PREVIEW);
  106.         break;
  107.  
  108.     case DLG_MAIN_BTNOPEN:
  109.     case MENU_FILE_OPEN: {
  110.         HANDLE hfCursor;
  111.         TCHAR szFileTitle[MAX_PATH];
  112.         TCHAR szFile[MAX_PATH];
  113.  
  114.  
  115.         szFile[0] = TEXT('\0');
  116.  
  117.         /* check for dirty file */
  118.         if(!CheckDirty(hWnd))
  119.             break;
  120.  
  121.         /* Put up the open file dialog and get the open handle back */
  122.         hfCursor = PromptAndOpenFile(hWnd, MAX_PATH, szFileTitle,
  123.                  COUNTOF(ganiAcon.szFile), szFile, gpszAniFilter);
  124.  
  125.         if (hfCursor == INVALID_HANDLE_VALUE)
  126.             break;
  127.  
  128.         LoadAniFile(hWnd, hfCursor, szFileTitle, szFile );
  129.  
  130.         break;
  131.     }
  132.  
  133.     case DLG_MAIN_BTNSAVE:
  134.     case MENU_FILE_SAVE:
  135.     case MENU_FILE_SAVEAS:
  136.         SaveFile(hWnd, cmd == MENU_FILE_SAVEAS);
  137.         break;
  138.  
  139.     case MENU_FILE_INSERT: {
  140.         TCHAR szFile[MAX_PATH];
  141.  
  142.         szFile[0] = TEXT('\0');
  143.  
  144.         /* Put up the open file dialog and get the open handle back */
  145.         if (PromptForFile(hWnd, 0, NULL,
  146.                  MAX_PATH, szFile, gpszCurFilter, gpszImport, FALSE)) {
  147.  
  148.             /*
  149.              * If we got a file, open it and read the icon data, linking
  150.              * it into the frame list and maintaining the steps as well.
  151.              */
  152.             ganiAcon.fDirty = TRUE;
  153.             CreateFrameFromCursorFile(hWnd, szFile, FALSE);
  154.         }
  155.         break;
  156.     }
  157.  
  158.     case MENU_FILE_EXPORT: {
  159. #if 0
  160.         TCHAR szFile[MAX_PATH];
  161.         szFile[0] = TEXT('\0');
  162.  
  163.         /* Put up the open file dialog and get the open handle back */
  164.         if (PromptForFile(hWnd, 0, NULL,
  165.                  MAX_PATH, szFile, NULL, gpszExport, TRUE)) {
  166.  
  167.             /*
  168.              * If we got a file, open it and read the icon data, linking
  169.              * it into the frame list and maintaining the steps as well.
  170.              */
  171.             ????
  172.         }
  173. #else
  174.         WRITEME(hWnd);
  175. #endif
  176.         break;
  177.     }
  178.  
  179.     case MENU_FILE_EXIT:
  180.         ExitCommand(hWnd);
  181.         break;
  182.  
  183.     case DLG_MAIN_BTNCUT:
  184.     case MENU_EDIT_CUT:
  185.         ganiAcon.fDirty = TRUE;
  186.  
  187.         FALLTHRU(MENU_EDIT_COPY);
  188.  
  189.     case DLG_MAIN_BTNCOPY:
  190.     case MENU_EDIT_COPY: {
  191.         int *piSel;
  192.         int cSel;
  193.  
  194.         cSel = GetSelStepCount(hWnd);
  195.  
  196.         if( cSel > 0 && (piSel = AllocMem(cSel * sizeof(int))) != NULL) {
  197.             PCLPBRDDAT pcbd, pcbdNext, *ppcbd;
  198.  
  199.             int i;
  200.  
  201.             GetCurrentSel(hWnd, DLG_MAIN_FRAMELIST, piSel, cSel, &cSel);
  202.  
  203.             /* Clear clipboard */
  204.             for( pcbd = gpbdClipBoard; pcbd != NULL; pcbd = pcbdNext ) {
  205.                 pcbdNext = pcbd->pcbdNext;
  206.  
  207.                 DestroyClpBrdDat(pcbd);
  208.             }
  209.  
  210.             /*
  211.              * Get the steps and put them in the clipboard in the correct order
  212.              */
  213.             ppcbd = &gpbdClipBoard;
  214.  
  215.             for( i = 0; i < cSel; i++ ) {
  216.                 PSTEP ps;
  217.  
  218.                 ps = GetStep(hWnd, piSel[i]);
  219.  
  220.                 if( IsValidPS(ps) && (pcbd = NewClpBrdDat()) != NULL) {
  221.                     CopyStep(&(pcbd->stp), ps);
  222.                     *ppcbd = pcbd;
  223.                     ppcbd = &(pcbd->pcbdNext);
  224.                 }
  225.             }
  226.  
  227.             *ppcbd = NULL;
  228.  
  229.             /*
  230.              * If this is a cut, then yank them out of the listbox
  231.              */
  232.             if (cmd == MENU_EDIT_CUT || cmd == DLG_MAIN_BTNCUT) {
  233.                 qsort( piSel, cSel, sizeof(piSel[0]), RevCompInts );
  234.                 for( i = 0; i < cSel; i++ ) {
  235.                     SendDlgItemMessage(hWnd, DLG_MAIN_FRAMELIST,
  236.                             LB_DELETESTRING, piSel[i], 0);
  237.                 }
  238.  
  239.                 FreeMem(piSel);
  240.  
  241.                 ClearStepSel(hWnd);
  242.             }
  243.         }
  244.  
  245.         break;
  246.     }
  247.  
  248.     case DLG_MAIN_BTNPASTE:
  249.     case MENU_EDIT_PASTE: {
  250.         PCLPBRDDAT pcbd;
  251.         int iSel, cSel;
  252.  
  253.         cSel = GetSelStepCount(hWnd);
  254.  
  255.         if (cSel > 1) {
  256.             FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
  257.                     TRUE, MSG_LESSEQONEFRAME);
  258.             break;
  259.         }
  260.  
  261.         GetCurrentSel(hWnd, DLG_MAIN_FRAMELIST, &iSel, 1, &cSel);
  262.  
  263.         if (cSel == 0)
  264.             iSel = GetStepCount(hWnd) - 1;
  265.  
  266.         cSel = iSel;
  267.         ganiAcon.fDirty = TRUE;
  268.  
  269.         for( pcbd = gpbdClipBoard; pcbd != NULL; pcbd = pcbd->pcbdNext ) {
  270.             PSTEP ps = NewStep();
  271.  
  272.             if (IsValidPS(ps)) {
  273.                 CopyStep(ps, &(pcbd->stp));
  274.  
  275.                 SendDlgItemMessage(hWnd, DLG_MAIN_FRAMELIST, LB_INSERTSTRING,
  276.                     ++cSel, (LPARAM)ps);
  277.             } else {
  278.                 FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OKCANCEL |
  279.                         MB_ICONEXCLAMATION, TRUE, MSG_PASTEERR );
  280.             }
  281.         }
  282.  
  283.         /* in this case, cSel is actually an index */
  284.         iSel += 1;
  285.         ClearStepSel(hWnd);
  286.         SetStepSel(hWnd, iSel, cSel);
  287.  
  288.         break;
  289.     }
  290.  
  291.     case DLG_MAIN_DELFRAME:
  292.     case MENU_EDIT_CLEAR: {
  293.         int *piSel;
  294.         int cSteps = GetSelStepCount(hWnd);
  295.         int i;
  296.  
  297.         if (cSteps <= 0)
  298.             //BUGBUG - should we put a message box up here?
  299.             break;
  300.  
  301.         ganiAcon.fDirty = TRUE;
  302.  
  303.         piSel = AllocMem(cSteps * sizeof(int));
  304.         if (piSel == NULL)
  305.             break;
  306.  
  307.         GetCurrentSel(hWnd, DLG_MAIN_FRAMELIST, piSel, cSteps, &cSteps);
  308.  
  309.         qsort( piSel, cSteps, sizeof(piSel[0]), RevCompInts );
  310.         for( i = 0; i < cSteps; i++ ) {
  311.             SendDlgItemMessage(hWnd, DLG_MAIN_FRAMELIST, LB_DELETESTRING,
  312.                     piSel[i], 0);
  313.         }
  314.  
  315.         FreeMem(piSel);
  316.         ClearStepSel(hWnd);
  317.  
  318.         break;
  319.     }
  320.  
  321.     case DLG_MAIN_DUPFRAME:
  322.     case MENU_EDIT_DUP:
  323.         /* copy */
  324.         /* paste */
  325.         ganiAcon.fDirty = TRUE;
  326.         WRITEME(hWnd);
  327.         break;
  328.  
  329.     case DLG_MAIN_EDITFRAME:
  330.     case MENU_EDIT_EDITFRAME:
  331.     case DLG_MAIN_ADDFRAME:
  332.     case MENU_EDIT_ADDFRAME: {
  333.         BOOL fEditFrame;
  334.  
  335.         ganiAcon.fDirty = TRUE;
  336.  
  337.         fEditFrame = (cmd == MENU_EDIT_EDITFRAME ||
  338.                     cmd == DLG_MAIN_EDITFRAME);
  339.  
  340.  
  341.         EditFrame(hWnd, fEditFrame);
  342.  
  343.         break;
  344.     }
  345.  
  346.     case DLG_MAIN_STOP:
  347.         PausePreview(hWnd, DLG_MAIN_PREVIEW);
  348.         break;
  349.  
  350.     case DLG_MAIN_PLAY:
  351.         ResumePreview(hWnd, DLG_MAIN_PREVIEW);
  352.         break;
  353.  
  354.     case MENU_HELP_ABOUT:
  355.         DialogBox(hInst, MAKEINTRESOURCE(DLG_ABOUT), hWnd, About);
  356.         break;
  357.  
  358.     case MENU_HELP_CONTENTS:
  359.  
  360.         //WinHelp(hWnd, TEXT("RKTOOLS.HLP"), HELP_COMMAND, (DWORD)TEXT("JI(\"RKTOOLS.HLP\">\"main\",\"aniedit\")"));
  361.         //WinHelp(hWnd, TEXT("RKTOOLS.HLP"), HELP_COMMAND, (DWORD)TEXT("JI(\"RKTOOLS.HLP\",\"aniedit\")"));
  362.         WinHelp(hWnd, TEXT("RKTOOLS.HLP"), HELP_COMMAND, (DWORD)TEXT("JI(\"RKTOOLS.HLP>main\",\"aniedit\")"));
  363.         break;
  364.  
  365.     case MENU_EDIT_OPTIONS:
  366.         if (DialogBox(hInst, MAKEINTRESOURCE(DLG_OPTIONS), hWnd, OptionsProc)){
  367.             InvalidateRect( GetDlgItem(hWnd, DLG_MAIN_PREVIEW), NULL, TRUE);
  368.         }
  369.         break;
  370.  
  371.     case DLG_MAIN_FRAMELIST: {
  372.         HWND hwndLB = (HWND)lParam;
  373.  
  374.         switch(HIWORD(wParam)) {
  375.  
  376.             case LBN_SELCHANGE: {
  377.                 PSTEP ps;
  378.                 int cSel;
  379.                 LPTSTR pszText;
  380.  
  381.                 cSel = SendMessage(hwndLB, LB_GETSELCOUNT, 0, 0);
  382.  
  383.                 if (cSel > 1) {
  384.                     int *piSel;
  385.                     int i;
  386.  
  387.                     pszText = FmtSprintf( cSel == GetStepCount(hWnd) ?
  388.                             MSG_ALLFRAMES : MSG_FRAMESSELECTED, cSel );
  389.                     SetDlgItemText(hWnd, DLG_MAIN_FRAMEGRP, pszText);
  390.                     FmtFree( pszText );
  391.  
  392.                     piSel = AllocMem( cSel * sizeof(int) );
  393.                     if( piSel == NULL )
  394.                         break;
  395.  
  396.                     GetCurrentSel(hWnd, DLG_MAIN_FRAMELIST, piSel, cSel, &cSel);
  397.                     for( i = 0; i < cSel; i++ ) {
  398.                         ps = GetStep(hWnd, piSel[i]);
  399.  
  400.                         if( IsValidPS(ps) ) {
  401.                             if (i == 0) {
  402.                                 ganiAcon.anih.jifRate = ps->jif;
  403.                             } else if(ganiAcon.anih.jifRate != ps->jif) {
  404.                                 break;
  405.                             }
  406.                         }
  407.                     }
  408.  
  409.                     if (i < cSel) {
  410.                         /* rates differ, wipe out jiffy edit control */
  411.                         SetDlgItemText(hWnd, DLG_MAIN_RATE, "");
  412.                     } else {
  413.                         SetDlgItemInt(hWnd, DLG_MAIN_RATE,
  414.                                 ganiAcon.anih.jifRate, FALSE);
  415.                     }
  416.  
  417.                     FreeMem(piSel);
  418.  
  419.                 } else if (cSel == 1) {
  420.                     int iLBSel;
  421.  
  422.                     GetCurrentSel(hWnd, DLG_MAIN_FRAMELIST, &iLBSel, 1, &cSel);
  423.  
  424.                     SetPreviewStep(hWnd, DLG_MAIN_PREVIEW, iLBSel);
  425.  
  426.                     pszText = FmtSprintf( MSG_FRAMEOFSEL, iLBSel + 1,
  427.                             GetStepCount(hWnd) );
  428.                     SetDlgItemText(hWnd, DLG_MAIN_FRAMEGRP, pszText);
  429.                     FmtFree( pszText );
  430.  
  431.                     ps = (PSTEP)SendMessage(hwndLB, LB_GETITEMDATA, iLBSel, 0);
  432.  
  433.                     if (IsValidPS(ps)) {
  434.                         SetDlgItemInt( hWnd, DLG_MAIN_RATE, ps->jif, FALSE);
  435.                     }
  436.                 } else {
  437.                     pszText = FmtSprintf( MSG_NOFRAMESSEL );
  438.                     SetDlgItemText(hWnd, DLG_MAIN_FRAMEGRP, pszText);
  439.                     FmtFree( pszText );
  440.                     SetPreviewStep(hWnd, DLG_MAIN_PREVIEW, 0);
  441.                 }
  442.                 break;
  443.  
  444.             case LBN_DBLCLK:
  445.                 ganiAcon.fDirty = TRUE;
  446.                 EditFrame(hWnd, TRUE);
  447.                 break;
  448.             }
  449.         }
  450.         break;
  451.  
  452.     }
  453.  
  454.     case DLG_MAIN_RATE: {
  455.         static BOOL fEditCtlHasFocus = FALSE;
  456.         static BOOL fEditCtlHasChanged = FALSE;
  457.         int *piSel;
  458.         int cSteps;
  459.         int i;
  460.  
  461.         switch(HIWORD(wParam)) {
  462.         case EN_SETFOCUS:
  463.             fEditCtlHasFocus = TRUE;
  464.             break;
  465.  
  466.         case EN_KILLFOCUS:
  467.             fEditCtlHasFocus = FALSE;
  468.             break;
  469.  
  470.         case EN_CHANGE:
  471.  
  472.             cSteps = GetSelStepCount(hWnd);
  473.  
  474.             if (fEditCtlHasFocus && cSteps >=1 &&
  475.                     GetWindowTextLength(GetDlgItem(hWnd, DLG_MAIN_RATE)) > 0) {
  476.                 JIF jif;
  477.                 BOOL fOK;
  478.  
  479.                 ganiAcon.fDirty = TRUE;
  480.                 piSel = AllocMem( cSteps * sizeof(int) );
  481.                 if (piSel == NULL) {
  482.                     SetFocus((HWND)lParam);
  483.                     break;
  484.                 }
  485.  
  486.  
  487.                 jif = GetDlgItemInt(hWnd, DLG_MAIN_RATE, &fOK, FALSE);
  488.  
  489.                 if (jif == 0 || !fOK) {
  490.                     FmtMessageBox(hWnd, MSG_LITERAL, gszWindowTitle,
  491.                         MB_OK | MB_ICONEXCLAMATION, TRUE,
  492.                         MSG_RATERANGE);
  493.                     SetFocus((HWND)lParam);
  494.                     break;
  495.                 }
  496.  
  497.                 GetCurrentSel(hWnd, DLG_MAIN_FRAMELIST, piSel, cSteps,
  498.                         &cSteps);
  499.  
  500.                 for( i = 0; i < cSteps; i++ ) {
  501.                     PSTEP ps = GetStep(hWnd, piSel[i]);
  502.  
  503.                     if (IsValidPS(ps)) {
  504.                         ps->jif = jif;
  505.                     }
  506.                 }
  507.                 InvalidateRect(GetDlgItem(hWnd,DLG_MAIN_FRAMELIST), NULL,TRUE);
  508.  
  509.                 FreeMem( piSel );
  510.             }
  511.             break;
  512.         }
  513.         break;
  514.     }
  515.  
  516.     default:
  517.         return FALSE;
  518.     }
  519.  
  520.     return TRUE;
  521. }
  522.  
  523. /****************************************************************************\
  524. *
  525. *     FUNCTION: About(HWND, unsigned, WORD, LONG)
  526. *
  527. *     PURPOSE:  Processes messages for "About" dialog box
  528. *
  529. *     MESSAGES:
  530. *
  531. *         WM_INITDIALOG - initialize dialog box
  532. *         WM_COMMAND    - Input received
  533. *
  534. *     COMMENTS:
  535. *
  536. *         No initialization is needed for this particular dialog box, but TRUE
  537. *         must be returned to Windows.
  538. *
  539. *         Wait for user to click on "Ok" button, then close the dialog box.
  540. *
  541. \****************************************************************************/
  542.  
  543. BOOL APIENTRY About(
  544.         HWND hDlg,                /* window handle of the dialog box */
  545.         UINT message,             /* type of message                 */
  546.         UINT wParam,              /* message-specific information    */
  547.         LONG lParam)
  548. {
  549.     switch (message) {
  550.         case WM_INITDIALOG:                /* message: initialize dialog box */
  551.             return (TRUE);
  552.  
  553.         case WM_COMMAND:                      /* message: received a command */
  554.             if (LOWORD(wParam) == IDOK        /* "OK" box selected?          */
  555.                 || LOWORD(wParam) == IDCANCEL) { /*System menu close command?*/
  556.                 EndDialog(hDlg, TRUE);        /* Exits the dialog box        */
  557.                 return (TRUE);
  558.             }
  559.             break;
  560.     }
  561.     return (FALSE);                           /* Didn't process a message    */
  562.         UNREFERENCED_PARAMETER(lParam);
  563. }
  564.  
  565.  
  566. /****************************************************************************\
  567. *
  568. *     FUNCTION: OptionsProc(HWND, unsigned, WORD, LONG)
  569. *
  570. *     PURPOSE:  Processes messages for "Options" dialog box
  571. *
  572. *     MESSAGES:
  573. *
  574. *         WM_INITDIALOG - initialize dialog box
  575. *         WM_COMMAND    - Input received
  576. *
  577. \****************************************************************************/
  578.  
  579. BOOL APIENTRY OptionsProc(
  580.         HWND hDlg,                /* window handle of the dialog box */
  581.         UINT message,             /* type of message                 */
  582.         UINT wParam,              /* message-specific information    */
  583.         LONG lParam)
  584. {
  585.     int i;
  586.     int fRepaint = FALSE;
  587.  
  588.     switch (message) {
  589.     case WM_INITDIALOG:                /* message: initialize dialog box */
  590.         SendDlgItemMessage(hDlg, DLG_OPTIONS_EDITOR, EM_LIMITTEXT, MAX_PATH, 0);
  591.         SetDlgItemText(hDlg, DLG_OPTIONS_EDITOR, gszCursorEditor);
  592.         CheckRadioButton( hDlg,
  593.                           DLG_OPTIONS_RADIO_DESKCOL,
  594.                           DLG_OPTIONS_RADIO_WINCOL,
  595.                           garadColor[giradColor].id );
  596.         return (TRUE);
  597.  
  598.     case WM_COMMAND:                      /* message: received a command */
  599.         switch(LOWORD(wParam)) {
  600.         case IDOK:
  601.  
  602.             /*
  603.              * Get the new desk color
  604.              */
  605.             for( i = 0; garadColor[i].id != 0; i++ ) {
  606.                 if( IsDlgButtonChecked(hDlg, garadColor[i].id) ) {
  607.                     break;
  608.                 }
  609.             }
  610.  
  611.             if (i != giradColor ) {
  612.                 /* new color, make new brush and repaint */
  613.                 if (ghbrPrevBackgnd != NULL)
  614.                     DeleteObject(ghbrPrevBackgnd);
  615.  
  616.                 ghbrPrevBackgnd =
  617.                         CreateSolidBrush(GetSysColor(garadColor[i].idSys));
  618.                 giradColor = i;
  619.                 fRepaint = TRUE;
  620.             }
  621.  
  622.             /*
  623.              * Get new editor
  624.              */
  625.             GetDlgItemText(hDlg,DLG_OPTIONS_EDITOR,
  626.                     gszCursorEditor,COUNTOF(gszCursorEditor));
  627.  
  628.             for( i = 0; i < COUNTOF(gszCursorEditor); i++ ) {
  629.  
  630.                 if (gszCursorEditor[i] == TEXT('\0'))
  631.                     break;
  632.  
  633.                 if (gszCursorEditor[i] == TEXT('%') &&
  634.                         ++i < COUNTOF(gszCursorEditor) &&
  635.                         gszCursorEditor[i] == TEXT('1')) {
  636.                     break;
  637.                 }
  638. #if defined(DBCS) && !defined(UNICODE)
  639.                 if (IsDBCSLeadByte(gszCursorEditor[i])) {
  640.                     i++;
  641.                 }
  642. #endif
  643.             }
  644.  
  645.  
  646.             if (i >= COUNTOF(gszCursorEditor) ||
  647.                 gszCursorEditor[i] != TEXT('1')) {
  648.  
  649.                 if (i >= (COUNTOF(gszCursorEditor) - 4)) {
  650.                     i =  COUNTOF(gszCursorEditor) - 4;
  651.                 }
  652.  
  653.                 lstrcpy(&gszCursorEditor[i], TEXT(" %1"));
  654.             }
  655.  
  656.         case IDCANCEL:
  657.             EndDialog(hDlg, fRepaint);        /* Exits the dialog box        */
  658.             return (TRUE);
  659.  
  660.         default:
  661.             break;
  662.         }
  663.         break;
  664.     }
  665.     return (FALSE);                           /* Didn't process a message    */
  666.         UNREFERENCED_PARAMETER(lParam);
  667. }
  668.  
  669.  
  670. /****************************************************************************\
  671. *
  672. *     FUNCTION: ExitCommand(HWND)
  673. *
  674. *     PURPOSE:  Exit the program chekcing for dirty files etc.
  675. *
  676. *
  677. \****************************************************************************/
  678. VOID ExitCommand(HWND hWnd) {
  679.  
  680.     /* if file is dirty then prompt for save */
  681.     if(CheckDirty(hWnd))
  682.         AniEndDialog(hWnd, TRUE);
  683. }
  684.  
  685. /****************************************************************************\
  686. *
  687. *     FUNCTION: CheckDirty(HWND)
  688. *
  689. *     PURPOSE:  check for dirty files and return TRUE if it is OK to continue.
  690. *
  691. *
  692. \****************************************************************************/
  693. BOOL CheckDirty(HWND hWnd) {
  694.     int idRet;
  695.  
  696.     /* if file is dirty then prompt for save */
  697.     if (ganiAcon.fDirty) {
  698.         idRet = FmtMessageBox( hWnd, MSG_LITERAL, gszWindowTitle,
  699.                 MB_YESNOCANCEL | MB_ICONEXCLAMATION, TRUE, MSG_SAVEFILEQUEST,
  700.                 ganiAcon.szFile);
  701.  
  702.         switch( idRet ) {
  703.         case IDYES:
  704.             SaveFile(hWnd, FALSE);
  705.             break;
  706.  
  707.         case IDNO:
  708.             break;
  709.  
  710.         case IDCANCEL:
  711.             return FALSE;
  712.         }
  713.     }
  714.  
  715.     return TRUE;
  716. }
  717.  
  718.  
  719. /****************************************************************************\
  720. *
  721. *     FUNCTION: HWND ExecProgram(  HWND hwndCaller, LPTSTR pszCmdLine )
  722. *
  723. *     PURPOSE:  Creates a process and returns the new processes main window
  724. *
  725. *     RETURNS: NULL if the process could not be created, otherwise the
  726. *              processes main window handle.
  727. *
  728. *     SIDEEFFECT: This function will also start a thread that will block
  729. *               on the process handle until the process terminates.  At that
  730. *               time, the thread will post a message back to the calliers
  731. *               window.
  732. *
  733. *
  734. * History:
  735. *   22-Apr-1993 JonPa   Created it
  736. *
  737. \****************************************************************************/
  738. BOOL ExecProgram( HWND hwndCaller, LPTSTR pszCmdLine ) {
  739.     STARTUPINFO si;
  740.     PROCESS_INFORMATION pi;
  741.     HWND hwnd;
  742.     PTHDDATA pthd;
  743.     DWORD tid;
  744.     HANDLE hthrd;
  745.  
  746.     /*
  747.      * Create the monitor thread (suspened)
  748.      */
  749.     pthd = AllocMem(sizeof(THDDATA));
  750.  
  751.     if (pthd == NULL)
  752.         return FALSE;
  753.  
  754.     /* set thread data to be invalid incase we have to abort */
  755.     pthd->hprocMonitor = NULL;
  756.     pthd->hwndCaller = hwndCaller;
  757.  
  758.     if ((hthrd = CreateThread( NULL, 0, ProcWaitThread, pthd, CREATE_SUSPENDED,
  759.             &tid )) == NULL) {
  760.         /* could not create the monitor thread, return error */
  761.         FreeMem(pthd);
  762.         return FALSE;
  763.     }
  764.  
  765.     /*
  766.      * Create the process
  767.      */
  768.     ZeroMemory( &si, sizeof(si) );
  769.     si.cb = sizeof(si);
  770.     si.wShowWindow = SW_SHOW;
  771.     si.dwFlags = STARTF_USESHOWWINDOW;
  772.  
  773.     if (!CreateProcess( NULL, pszCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
  774.             &si, &pi)) {
  775.         ResumeThread(hthrd);    // make thread localfree the data and exit
  776.         return FALSE;
  777.     }
  778.  
  779.     DPRINT(("MT:Child IDs proc/thd: 0x%lx / 0x%lx\n", pi.dwProcessId, pi.dwThreadId));
  780.     DPRINT(("MT:Child Hnd proc/thd: 0x%lx / 0x%lx\n", pi.hProcess, pi.hThread));
  781.  
  782.     /*
  783.      * Wait for the main window to be created
  784.      */
  785.     if( WaitForInputIdle( pi.hProcess, CMS_WAIT_FOR_PROCESS ) != 0 ) {
  786.         ResumeThread(hthrd);    // make thread localfree the data and exit
  787.         return FALSE;
  788.     }
  789.  
  790.     DPRINT(("MT:Child is idle\n"));
  791.  
  792.     /*
  793.      * Enumerate the new processes main thread's windows and
  794.      * return the main one.
  795.      */
  796.     hwnd = NULL;
  797.     EnumThreadWindows( pi.dwThreadId, ETWProc, (LPARAM)&hwnd );
  798.  
  799. #if 0
  800.     if (hwnd != NULL) {
  801.         pthd->hprocMonitor = pi.hProcess;
  802.         pthd->hwndMonitor = hwnd;
  803.  
  804.         SendMessage(hwndCaller, AIM_SETCHILDAPP, 0, hwnd);
  805.     }
  806. #else
  807.     pthd->hprocMonitor = pi.hProcess;
  808.     pthd->hwndMonitor = hwnd;
  809.  
  810.     if (pthd->hprocMonitor != NULL)
  811.         SendMessage(hwndCaller, AIM_SETCHILDAPP, 0, (LPARAM)hwnd);
  812. #endif
  813.  
  814.     ResumeThread(hthrd);
  815.     CloseHandle(hthrd);
  816.     CloseHandle(pi.hThread);
  817.     return TRUE;
  818. }
  819.  
  820.  
  821. /****************************************************************************\
  822. *
  823. *     FUNCTION: BOOL CALLBACK ETWProc( HWND hwnd, LPARAM lParam )
  824. *
  825. *     PURPOSE:  Enumeration proc for ExecProgram.  It looks for the thread's
  826. *               top level window.
  827. *
  828. * History:
  829. *   22-Apr-1993 JonPa   Created it
  830. *
  831. \****************************************************************************/
  832. BOOL CALLBACK ETWProc( HWND hwnd, LPARAM lParam ) {
  833.     DWORD *pdw = (DWORD *)lParam;
  834.  
  835.     /*
  836.      * If this window has no parent, then it is a toplevel
  837.      * window for the thread.  Remember the last one we find since it
  838.      * is probably the main window.
  839.      */
  840.  
  841.     if (GetParent(hwnd) == NULL) {
  842.         DPRINT(("MT:EnumThdWin found 0x%lx\n", (DWORD)hwnd));
  843.         *pdw = (DWORD)hwnd;
  844.     }
  845.  
  846.     return TRUE;
  847. }
  848.  
  849. /****************************************************************************\
  850. *
  851. *     FUNCTION: DWORD ProcWaitThread( LPDWORD lpdw )
  852. *
  853. *     PURPOSE:  Thread to wait on a process and then post a message
  854. *
  855. *
  856. * History:
  857. *   22-Apr-1993 JonPa   Created it
  858. *
  859. \****************************************************************************/
  860. DWORD WINAPI ProcWaitThread( LPVOID lpv ) {
  861.     LPDWORD lpdw = lpv;
  862.     PTHDDATA pthd = (PTHDDATA)lpdw;
  863.     DWORD dwRet;
  864.  
  865.     if (pthd->hprocMonitor == NULL) {
  866.         /* something went wrong, just exit now */
  867.         DPRINT(("wt:Aborting\n"));
  868.         FreeMem( lpdw );
  869.         ExitThread(0);
  870.     }
  871.  
  872.     DPRINT(("wt:Waiting\n"));
  873.     dwRet = WaitForSingleObject( pthd->hprocMonitor, INFINITE );
  874.  
  875.     DPRINT(("wt:Send AIM_PROCESSTERM\n"));
  876.     SendMessage(pthd->hwndCaller, AIM_PROCESSTERM, (dwRet == WAIT_OBJECT_0),
  877.             (LPARAM)pthd->hwndMonitor);
  878.  
  879.     CloseHandle( pthd->hprocMonitor );
  880.     FreeMem( lpdw );
  881.     ExitThread(0);
  882.  
  883.     return 0;
  884. }
  885.  
  886.  
  887. /****************************************************************************\
  888. *
  889. *     FUNCTION: void NewAniCursor( HWND hwnd )
  890. *
  891. *     PURPOSE:  erase any used memory and init to a clean slate
  892. *
  893. *
  894. * History:
  895. *   22-Apr-1993 JonPa   Created it
  896. *
  897. \****************************************************************************/
  898. void NewAniCursor( HWND hwnd ) {
  899.     int i, cSteps;
  900.     LPTSTR psz;
  901.  
  902.     PausePreview(hwnd, DLG_MAIN_PREVIEW);
  903.  
  904.     /* Step through the list box, deleting all the lb entryies and everything
  905.      * that they point to (except the icons).
  906.      */
  907.     cSteps = GetStepCount(hwnd);
  908.  
  909.     if (cSteps != LB_ERR) {
  910.         for( i = 0; i < cSteps; i++ ) {
  911.             /*
  912.              * Delete the top item of the list.  Note that once that item
  913.              * (current index 0) is deleted, then the next item will move
  914.              * up and become index 0.
  915.              */
  916.             SendDlgItemMessage( hwnd, DLG_MAIN_FRAMELIST, LB_DELETESTRING,0,0);
  917.         }
  918.     }
  919.  
  920.  
  921.     /*
  922.      * Step through the icon list deleting them.  We don't need to call
  923.      * DestroyFrame since we are trashing the whole chain.
  924.      */
  925.  
  926. #if 0
  927.     pf = gpfrmFrames;
  928.     gpfrmFrames = NULL;
  929.  
  930.     DON'T DO THIS!!! it will wipe out the clip board accidentally!
  931.  
  932.     for(; pf != NULL; pf = pfrmNext ) {
  933.         pfrmNext = pf->pfrmNext;
  934.  
  935.         DestroyIcon( pf->hcur );
  936.         FreeMem(pf);
  937.     }
  938. #endif
  939.  
  940.     /*
  941.      * Init Ani header
  942.      */
  943.     ZeroMemory( &ganiAcon, sizeof(ganiAcon) );
  944.     ganiAcon.anih.cbSizeof = sizeof(ganiAcon);
  945.     ganiAcon.anih.cbSizeof = AF_ICON;
  946.     ganiAcon.anih.jifRate = 10;
  947.  
  948.     SetDlgItemTextA(hwnd, DLG_MAIN_TITLE, ganiAcon.azTitle);
  949.     SetDlgItemTextA(hwnd, DLG_MAIN_AUTHOR, ganiAcon.azCreator);
  950.  
  951.     SetDlgItemInt( hwnd, DLG_MAIN_RATE, ganiAcon.anih.jifRate, FALSE);
  952.  
  953.     PreviewCursor(hwnd, DLG_MAIN_PREVIEW);
  954.  
  955.     SetWindowFileTitle(hwnd, gpszUntitled );
  956.  
  957.     psz = FmtSprintf(MSG_NOFRAMESSEL);
  958.     SetDlgItemText(hwnd, DLG_MAIN_FRAMEGRP, psz);
  959.     FmtFree( psz );
  960. }
  961.  
  962. /****************************************************************************\
  963. *
  964. *     FUNCTION: BOOL GetCurrentSel( HWND hwnd, int id, int * paiSel,
  965. *                                                   int ciSel, int *pcSel );
  966. *
  967. *     PURPOSE:  Gets the selections and returns it's index
  968. *
  969. *
  970. * History:
  971. *   22-Apr-1993 JonPa   Created it
  972. *
  973. \****************************************************************************/
  974. BOOL GetCurrentSel( HWND hwnd, int id, int * paiSel, int ciSel, int *pcSel ) {
  975.  
  976. #ifdef MULTISEL
  977.     *pcSel = SendDlgItemMessage(hwnd,id, LB_GETSELITEMS, ciSel,(LPARAM)paiSel);
  978.  
  979.     if (*pcSel == LB_ERR) {
  980.         *pcSel = 0;
  981.     }
  982. #else
  983.  
  984.     *paiSel = SendDlgItemMessage(hwnd, id, LB_GETCURSEL, 0, 0);
  985.     *pcSel = 1;
  986.  
  987.     if (*paiSel == LB_ERR)
  988.         *pcSel = 0;
  989. #endif
  990.  
  991.     return TRUE;
  992. }
  993.  
  994. /****************************************************************************\
  995. *
  996. *     FUNCTION: VOID SetCurrentSel( HWND hwnd, int id, BOOL fExtend, int iSel);
  997. *
  998. *     PURPOSE:  Sets the selections and returns it's index
  999. *
  1000. *
  1001. * History:
  1002. *   29-Apr-1993 JonPa   Created it
  1003. *
  1004. \****************************************************************************/
  1005. VOID SetCurrentSel( HWND hwnd, int id, BOOL fExtend, int iSel) {
  1006. #ifdef MULTISEL
  1007.     if (!fExtend) {
  1008.         SendDlgItemMessage(hwnd, id, LB_SETSEL, FALSE, -1);
  1009.     }
  1010.  
  1011.     SendDlgItemMessage(hwnd, id, LB_SETSEL, TRUE, iSel);
  1012. #else
  1013.     SendDlgItemMessage(hwnd, id, LB_SETCURSEL, iSel, 0);
  1014. #endif
  1015.  
  1016.     UpdateStepSel( hwnd );
  1017. }
  1018.  
  1019.  
  1020. /****************************************************************************\
  1021. *
  1022. *     FUNCTION: VOID EditFrame(HWND hwnd, int iSel);
  1023. *
  1024. *     PURPOSE:  Runs ImagEdit on the frame indexed by iSel
  1025. *
  1026. *
  1027. * History:
  1028. *   27-Apr-1993 JonPa
  1029. *
  1030. \****************************************************************************/
  1031. VOID EditFrame(HWND hWnd, BOOL fEditFrame) {
  1032.     LPTSTR pszCmdLine = NULL;
  1033.     int cchCmdLine;
  1034.     HANDLE hf;
  1035.     DWORD cb;
  1036.     PBYTE pbIcon;
  1037.     DWORD cbIcon;
  1038.     int iSel;
  1039.     int cSel;
  1040.     BOOL fExeced;
  1041.  
  1042.     /* create a temp .cur file name */
  1043.     if( !GetTempCursorFileName( gszTempFile ) ) {
  1044.         FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
  1045.                 TRUE, MSG_OUTOFRESOUCES );
  1046.         return;
  1047.     }
  1048.  
  1049.  
  1050.     cSel = GetSelStepCount(hWnd);
  1051.  
  1052.     if ( (fEditFrame && (cSel != 1)) || cSel > 1 ) {
  1053.  
  1054.         FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
  1055.                 TRUE, fEditFrame ? MSG_MUSTEQONEFAME : MSG_LESSEQONEFRAME);
  1056.         return;
  1057.     }
  1058.  
  1059.     /* cache the currently selected item (Singluar) */
  1060.     GetCurrentSel( hWnd, DLG_MAIN_FRAMELIST, &iSel, 1, &cSel );
  1061.  
  1062.     /*
  1063.      * If edit, then write the frame to the file and save checksum
  1064.      * otherwise write the blank cursor to the file.
  1065.      */
  1066.  
  1067.     hf = CreateFile( gszTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  1068.             FILE_ATTRIBUTE_NORMAL, NULL );
  1069.  
  1070.  
  1071.     if (hf == INVALID_HANDLE_VALUE) {
  1072.         FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE,
  1073.             MSG_CANTCREATEFILE, gszTempFile );
  1074.         return;
  1075.     }
  1076.  
  1077.     if (fEditFrame || cSel != 0) {
  1078.         PSTEP ps = GetStep(hWnd, iSel);
  1079.  
  1080.         if( !IsValidPS(ps) ) {
  1081.             FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
  1082.                     TRUE, MSG_OUTOFRESOUCES );
  1083.             CloseHandle(hf);
  1084.             return;
  1085.         }
  1086.  
  1087.  
  1088.         pbIcon = ps->pfrmFrame->abIcon;
  1089.         cbIcon = ps->pfrmFrame->rtag.ckSize;
  1090.  
  1091.     } else {
  1092.  
  1093.         HRSRC hr = FindResource(hInst, MAKEINTRESOURCE(ID_BLANKCUR),
  1094.                 MAKEINTRESOURCE(RCT_RAWDATA));
  1095.  
  1096.         if (hr == NULL || (pbIcon =LockResource(LoadResource(hInst, hr))) ==
  1097.                 NULL) {
  1098.             FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
  1099.                     TRUE, MSG_OUTOFRESOUCES );
  1100.             CloseHandle(hf);
  1101.             return;
  1102.         }
  1103.  
  1104.         cbIcon = SizeofResource(hInst, hr);
  1105.     }
  1106.  
  1107.     WriteFile(hf, pbIcon, cbIcon, &cb, NULL);
  1108.  
  1109.     CloseHandle(hf);
  1110.  
  1111.     /*
  1112.      * change .tmp to .cur
  1113.      */
  1114.     { TCHAR szOldName[MAX_PATH];
  1115.  
  1116.         cchCmdLine = lstrlen(gszTempFile);
  1117.  
  1118.         lstrcpy( szOldName, gszTempFile );
  1119.         lstrcpy( &gszTempFile[cchCmdLine - 3], gpszCUR );
  1120.  
  1121.         if(!MoveFile(szOldName, gszTempFile))
  1122.             lstrcpy( gszTempFile, szOldName );
  1123.  
  1124.         cchCmdLine = (cchCmdLine + lstrlen(gszCursorEditor) + 1 + 1) *
  1125.                 sizeof(TCHAR);
  1126.  
  1127.         pszCmdLine = AllocMem(cchCmdLine);
  1128.     }
  1129.  
  1130.     if (pszCmdLine == NULL)
  1131.         return;
  1132.  
  1133.     {
  1134.         LPTSTR pszTempFile = gszTempFile;
  1135.  
  1136.         FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1137.                 gszCursorEditor, 0, 0, pszCmdLine, cchCmdLine, (va_list *)(DWORD)&pszTempFile);
  1138.     }
  1139.  
  1140.     /* spawn imagedit on the file */
  1141.     fExeced = ExecProgram( hWnd, pszCmdLine );
  1142.     DPRINT(("MT:Begin Defer to child\n"));
  1143.  
  1144.     FreeMem(pszCmdLine);
  1145.  
  1146.     if ( fExeced  ) {
  1147.         gfEditFrame = fEditFrame;
  1148.     } else {
  1149.         FmtMessageBox( hWnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
  1150.                     TRUE, MSG_NOIMAGEDIT, gszCursorEditor );
  1151.     }
  1152. }
  1153.  
  1154.  
  1155.  
  1156.  
  1157. /****************************************************************************\
  1158. *
  1159. *     FUNCTION: PSTEP NewStep( void );
  1160. *
  1161. *
  1162. *     PURPOSE:  Creates a new step and set's its pfrmFrame to NULL;
  1163. *
  1164. *
  1165. * History:
  1166. *   29-Apr-1993 JonPa   Created it
  1167. *
  1168. \****************************************************************************/
  1169. PSTEP NewStep( void ) {
  1170.     PSTEP ps;
  1171.  
  1172.     ps = AllocMem(sizeof(STEP));
  1173.  
  1174.     if (IsValidPS(ps))
  1175.         ps->pfrmFrame = NULL;
  1176.  
  1177.     return ps;
  1178. }
  1179.  
  1180. /****************************************************************************\
  1181. *
  1182. *     FUNCTION: VOID DestroyStep( PSTEP ps );
  1183. *
  1184. *
  1185. *     PURPOSE:  Deletes a step, and derefernces its frame, deleting it if
  1186. *               necessary.
  1187. *
  1188. * History:
  1189. *   29-Apr-1993 JonPa   Created it
  1190. *
  1191. \****************************************************************************/
  1192. VOID DestroyStep( PSTEP ps ) {
  1193.     LinkStepFrame(ps, NULL);
  1194.  
  1195.     FreeMem(ps);
  1196. }
  1197.  
  1198.  
  1199. /****************************************************************************\
  1200. *
  1201. *     FUNCTION: VOID CopyStep( PSTEP psDst, PSTEP psSrc );
  1202. *
  1203. *
  1204. *     PURPOSE:  Copyies a step, bumping the ref count of the frame if it
  1205. *               needs it.
  1206. *
  1207. * History:
  1208. *   07-May-1993 JonPa   Created it
  1209. *
  1210. \****************************************************************************/
  1211. VOID CopyStep( PSTEP psDst, PSTEP psSrc ) {
  1212.     *psDst = *psSrc;
  1213.  
  1214.     if( psDst->pfrmFrame != NULL ) {
  1215.         psDst->pfrmFrame->cRef += 1;
  1216.     }
  1217. }
  1218.  
  1219.  
  1220. /****************************************************************************\
  1221. *
  1222. *     FUNCTION: VOID LinkStepFrame( PSTEP ps, PFRAME pf );
  1223. *
  1224. *
  1225. *     PURPOSE:  Unlinks a step from its frame and then links the new
  1226. *               frame in its place.  If the old frame is an orphan, it
  1227. *               gets destroyed.
  1228. *
  1229. *
  1230. * History:
  1231. *   29-Apr-1993 JonPa   Created it
  1232. *
  1233. \****************************************************************************/
  1234. VOID LinkStepFrame(PSTEP ps, PFRAME pf ) {
  1235.     PFRAME pfOld = ps->pfrmFrame;
  1236.  
  1237.     if (pf != NULL)
  1238.         pf->cRef++;
  1239.  
  1240.     if (pfOld != NULL && --(pfOld->cRef) == 0)
  1241.         DestroyFrame(pfOld);
  1242.  
  1243.     ps->pfrmFrame = pf;
  1244. }
  1245.  
  1246. /****************************************************************************\
  1247. *
  1248. *     FUNCTION: VOID DestroyFrame( PFRAME pf );
  1249. *
  1250. *
  1251. *     PURPOSE:  Unlinks a frame from the list, deletes its hcur, and
  1252. *               Frees its memory.
  1253. *
  1254. *
  1255. * History:
  1256. *   28-Apr-1993 JonPa   Created it
  1257. *
  1258. \****************************************************************************/
  1259. VOID DestroyFrame( PFRAME pf ) {
  1260.     PFRAME pfList;
  1261.  
  1262.     if (pf == gpfrmFrames) {
  1263.         gpfrmFrames = pf->pfrmNext;
  1264.     } else {
  1265.  
  1266.         for( pfList = gpfrmFrames; pfList != NULL;
  1267.                 pfList = pfList->pfrmNext ) {
  1268.  
  1269.             if (pfList->pfrmNext == pf) {
  1270.                 break;
  1271.             }
  1272.         }
  1273.  
  1274.         if (pfList != NULL) {
  1275.             pfList->pfrmNext = pf->pfrmNext;
  1276.         }
  1277.     }
  1278.  
  1279.     DestroyIcon( pf->hcur );
  1280.     FreeMem(pf);
  1281. }
  1282.  
  1283. /****************************************************************************\
  1284. *
  1285. *     FUNCTION: PCLPBRDDAT NewClpBrdDat( void )
  1286. *
  1287. *
  1288. *     PURPOSE:  Creates a new clip board data struct
  1289. *
  1290. *
  1291. * History:
  1292. *   29-Apr-1993 JonPa   Created it
  1293. *
  1294. \****************************************************************************/
  1295. PCLPBRDDAT NewClpBrdDat( void ) {
  1296.     PCLPBRDDAT pcbd = AllocMem( sizeof(CLPBRDDAT) );
  1297.  
  1298.     if (pcbd != NULL)
  1299.         pcbd->stp.pfrmFrame = NULL;
  1300.  
  1301.     return pcbd;
  1302. }
  1303.  
  1304. /****************************************************************************\
  1305. *
  1306. *     FUNCTION: VOID DestroyClpBrdDat(PCLPBRDDAT pcbd)
  1307. *
  1308. *
  1309. *     PURPOSE:  Creates a new clip board data struct
  1310. *
  1311. *
  1312. * History:
  1313. *   29-Apr-1993 JonPa   Created it
  1314. *
  1315. \****************************************************************************/
  1316. VOID DestroyClpBrdDat(PCLPBRDDAT pcbd) {
  1317.     LinkStepFrame(&(pcbd->stp), NULL);
  1318.  
  1319.     FreeMem(pcbd);
  1320. }
  1321.  
  1322. /****************************************************************************\
  1323. *
  1324. *     FUNCTION: VOID SetWindowFileTitle(HWND hWnd, LPTSTR szFileTitle)
  1325. *
  1326. *
  1327. *     PURPOSE:  Sets the file title
  1328. *
  1329. *
  1330. * History:
  1331. *   30-Apr-1993 JonPa   Created it
  1332. *
  1333. \****************************************************************************/
  1334. VOID SetWindowFileTitle(HWND hWnd, LPTSTR szFileTitle) {
  1335.  
  1336.     /*
  1337.      * We use LocalAlloc here instead of AllocMem because we don't really
  1338.      * char if it fails
  1339.      */
  1340.     int cch = lstrlen( gszWindowTitle ) + lstrlen(szFileTitle);
  1341.     LPTSTR pszTitle = LocalAlloc(LPTR, (cch+4) * sizeof(TCHAR) );
  1342.  
  1343.     if (pszTitle != NULL) {
  1344.         wsprintf( pszTitle, "%s - %s", gszWindowTitle, szFileTitle );
  1345.         SetWindowText(hWnd, pszTitle);
  1346.  
  1347.         LocalFree(pszTitle);
  1348.     } else {
  1349.         SetWindowText(hWnd, gszWindowTitle);
  1350.     }
  1351. }
  1352.  
  1353. int __cdecl RevCompInts(const void *elm1, const void *elm2) {
  1354.     return *((int *)elm2) - *((int *)elm1);
  1355. }
  1356.  
  1357. /****************************************************************************\
  1358. *
  1359. *     FUNCTION: ClearStepSel
  1360. *
  1361. *
  1362. *     PURPOSE:  Clears all selections from the frame list
  1363. *
  1364. *
  1365. * History:
  1366. *   02-Jul-1993 JonPa   Created it
  1367. *
  1368. \****************************************************************************/
  1369. VOID ClearStepSel( HWND hWnd )  {
  1370.     int cItems = GetStepCount(hWnd);
  1371.  
  1372.     if (cItems != 0) {
  1373.         SendDlgItemMessage(hWnd, DLG_MAIN_FRAMELIST,
  1374.                 LB_SELITEMRANGE, (WPARAM)FALSE, MAKELPARAM(0, cItems - 1));
  1375.     }
  1376.  
  1377.     UpdateStepSel(hWnd);
  1378. }
  1379.