ANICMD.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:38k
源码类别:

Windows编程

开发平台:

Visual C++

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