//------------------------------------------------------------------------------------------------------
// Name       : tsample_.c
// Date       : 23.05.1996     Author : SM           System : Win32
//------------------------------------------------------------------------------------------------------
// This file contains the language-independent implementation of the module TSAMPLE_.DLL. All texts and
// resources that are language-dependent are located in an additional TSAMPLE.DLL, whose sources can be
// found in the subdirectories \E (for English) and \D (for German).
//------------------------------------------------------------------------------------------------------

#define USER_DATA_ID          "1.00-1995-08-10"

//------------------------------------------------------------------------------------------------------

#include        "windows.h"
#include        "windowsx.h"
#include        "stdlib.h"
#include        "stdio.h"
#include        "math.h"

#include        "e:\release4\toso40.h"          // Toso Interface 4.0 Definitions
#include        "dialog.h"

//-----------------------------------------------------------------------------------------------------

#define STAR_INDENT_MIN         3       // Minimum number of indents
#define STAR_INDENT_MAX         100     // Maximum number of indents

//-----------------------------------------------------------------------------------------------------

typedef struct {
  STR32         TimeStamp;

  int           StarIndentNum;
  double        StarRotation;
} INF_HEADER;

//------ Language-dependent texts in TSAMPLE.DLL -------------------------------------------------------

DLL_IMPORT LPSTR
        eStartUpText    [],
        eDialogText     [],
        eMessageText    [],
        eCommandName    [],
        eCommandEntry   [],
        eNewPoint       [];

//------------------------------------------------------------------------------------------------------

static  HINSTANCE       hInstDLL,               // Instance handle of the main DLL
                        hLanguage,              // Instance handle of the language DLL
                        hGlobalInst;            // Instance handle of the serving application
static  HWND            hGlobalWnd;             // Main window handle of the serving application

//------Dialog Window Handling -------------------------------------------------------------------------

static  DUMMYSTR        gCaption;               // Current dialog window caption
static  int             gExitDialog;            // Button with which the dialog was canceled
static  INF_HEADER      gCopyHeader;            // Temporary copy of INFHeader

//------ Command Processing ----------------------------------------------------------------------------

static  INF_HEADER      INFHeader;              // Settings

static  DPOINT          gPoint[3];              // Points entered by the user
static  int             gCommandID;             // Current Command's ID
static  HBITMAP         hBitmap;                // Handle of command icon bitmap

static  MODULE_COMMAND_DATA     CommandData[TVG_MODULE_SUBMENU_MAX];

//------ Command Description ---------------------------------------------------------------------------
// The structure COMMAND_DATA contains a command description. It lists the points to be entered by the
// user and their types. Each point description consists of three values: The point type (POINT_???),
// the index of "related point", i.e. the point to which this point is relative, and a textual
// description of that point.
// The following command required exactly 3 points to be entered (COMMAND_FIXED = number of point to be
// entered is known in advance, "3" says that this known number is three).
// Following a description of those three points to be entered:
// 1) POINT_CENTER = center of a circle, ellipse, etc.
//    "-1"         = no "related point"
//    NULL         = default description
// 2) POINT_RADIUS = radius of a circle
//    "0"          = relative to the point with the index zero (the center point)
//    NULL         = default description
// 3) POINT_RADIUS = radius of a circle
//    "0"          = relative to the point with the index zero (the center point)
//    NULL         = default description
// Please note that the description strings of the points 2) and 3) will be overwritten before passed
// to the serving application in order to change the description to "Enter Radius 1" and "Enter Radius 2"
// (see end of procedure TosoModuleInit()).

static  COMMAND_DATA    gInfo[] = {             // Command description structure
        { COMMAND_FIXED,
          3,
          { POINT_CENTER, POINT_RADIUS, POINT_RADIUS },
          { -1, 0, 0 },
          { NULL, NULL, NULL }
        }
};

//------------------------------------------------------------------------------------------------------

BOOL ModuleLoadSettings( void )
{
  BOOL          Result = FALSE;

  if( TosoProfileReadKeyOpen( "TSAMPLE", FALSE ) ) {
    if( TosoProfileReadData( "Init", (LPBYTE) &INFHeader, sizeof( INFHeader ) ) )
      Result = TRUE;
    TosoProfileReadKeyClose();

    INFHeader.TimeStamp[31] = 0x00;
    if( lstrcmp( INFHeader.TimeStamp, USER_DATA_ID ) )
      Result = FALSE;
  }

  if( !Result ) {
    INFHeader.StarIndentNum = 6;
    INFHeader.StarRotation  = REAL_05PI;
  }
  return( Result );
}

//------------------------------------------------------------------------------------------------------

BOOL ModuleSaveSettings( void )
{
  BOOL          Result = FALSE;

  if( TosoProfileWriteKeyOpen( "TSAMPLE", FALSE ) ) {
    lstrcpy( INFHeader.TimeStamp, USER_DATA_ID );
    if( TosoProfileWriteData( "Init", (LPBYTE) &INFHeader, sizeof( INFHeader ) ) )
      Result = TRUE;
    TosoProfileWriteKeyClose();
  }
  return( Result );
}

//------------------------------------------------------------------------------------------------------
// Callback procedure for dialog box handling of DialogEditParamaters(). This procedure handles all
// messages sent to the dialog window.

BOOL CALLBACK DialogEditParametersManage( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
  static HWND   hOldFocus;
  DUMMYSTR      DummyStr, UnitStr;
  int           DummyInt;
  double        DummyDouble;

  switch( message ) {
    case WM_INITDIALOG:                         // Initialize dialog box
      TosoDialogCenter( hDlg );
      SetWindowText( hDlg, gCaption );

// Convert the current indent number to a string that can be set to an edit field.

      wsprintf( DummyStr, "%d", gCopyHeader.StarIndentNum );
      SetDlgItemText( hDlg, IDD_EDIT0, DummyStr );

// Convert the current rotation angle to a string that can be set to an edit field. A conversion made
// by means of TosoConvertAngleString() automatically uses the current coordinate system and its
// parameters like current unit, number diplay, etc. for the conversion.

      TosoConvertAngleString( DummyStr, gCopyHeader.StarRotation, UnitStr );
      SetDlgItemText( hDlg, IDD_EDIT1, DummyStr );
      SetDlgItemText( hDlg, IDD_UNIT1, UnitStr );

// Set the focus to the first edit field and highlight the complete content of that edit field.

      Edit_SetSel( GetDlgItem( hDlg, IDD_EDIT0 ), 0, -1 );
      hOldFocus = SetFocus( GetDlgItem( hDlg, IDD_EDIT0 ) );    
      return( FALSE );


    case WM_COMMAND:
      switch( GET_WM_COMMAND_ID( wParam, lParam ) ) {
        case IDD_OK:                            // OK

// Read the indent number from the edit field and convert it to an integer value.

          GetDlgItemText( hDlg, IDD_EDIT0, DummyStr, NAME_LENGTH_EDIT );
          if( sscanf( DummyStr, "%d", &DummyInt ) != 1 ) {
            MessageBox( hDlg, eMessageText[3], eDialogText[0], MB_OK );

            Edit_SetSel( GetDlgItem( hDlg, IDD_EDIT0 ), 0, -1 );
            SetFocus( GetDlgItem( hDlg, IDD_EDIT0 ) );    
            return( TRUE );
          }

// Check wether the stated indent number is within range. If not, display a message and set the
// focus to the according edit field.

          if( DummyInt < STAR_INDENT_MIN || DummyInt > STAR_INDENT_MAX ) {
            MessageBox( hDlg, eMessageText[3], eDialogText[0], MB_OK );

            Edit_SetSel( GetDlgItem( hDlg, IDD_EDIT0 ), 0, -1 );
            SetFocus( GetDlgItem( hDlg, IDD_EDIT0 ) );    
            return( TRUE );
          }
          gCopyHeader.StarIndentNum = DummyInt;

// Read the rotation angle rom the edit field and convert it to a double with unit [rad]. A conversion
// made by TosoConvertStringAngle() automatically resolves any term or unit stated in that string. If
// an error occurs, display a message and set the focus to the according edit field.

          GetDlgItemText( hDlg, IDD_EDIT1, DummyStr, NAME_LENGTH_EDIT );
          if( !TosoConvertStringAngle( &DummyDouble, DummyStr, hDlg ) ) {
            MessageBox( hDlg, eMessageText[2], eDialogText[0], MB_OK );

            Edit_SetSel( GetDlgItem( hDlg, IDD_EDIT1 ), 0, -1 );
            SetFocus( GetDlgItem( hDlg, IDD_EDIT1 ) );    
            return( TRUE );
          }
          gCopyHeader.StarRotation = DummyDouble;

          gExitDialog = IDD_OK;
          SetFocus( hOldFocus );
          EndDialog( hDlg, TRUE );
          return( TRUE );

        case IDD_CANCEL:
          gExitDialog = IDD_CANCEL;
          SetFocus( hOldFocus );
          EndDialog( hDlg, TRUE );
          return( TRUE );
      }
      break;

// Help message detection and processing

    case WM_ENTERIDLE:
      return( TosoDialogEnterIdle( hDlg, wParam, lParam ) );

    default:
      if( message == TosoDialogHelpMessage() ) {
        WinHelp( hDlg, "TSAMPLE.HLP", HELP_CONTEXT, gCommandID );
        return( TRUE );
      }
      break;
  }
  return( FALSE );
}

//------------------------------------------------------------------------------------------------------
// This procedure displays and manages the parameter dialog for the command "Star" that this module
// offers to the user.

BOOL DialogEditParameters( HWND hMainWnd, LPSTR Caption, int* IndentNum, double* Rotation )
{
  lstrcpy( gCaption, Caption );

// Copy the current settings to the temporary copy in order to be able to restore the values if
// the user cancels the dialog.

  gCopyHeader.StarIndentNum = *IndentNum;
  gCopyHeader.StarRotation  = *Rotation;

// Call and process the dialog window.

  if( DialogBox( hLanguage, "EDITPARAM", hMainWnd, DialogEditParametersManage ) == -1 ) {
    MessageBox( hMainWnd, eMessageText[1], eDialogText[0], MB_OK );
    return( FALSE );
  }

// Check whether the user canceled the dialog or not. If he pressed OK, copy the new values to
// the current settings.

  if( gExitDialog == IDD_CANCEL ) {
    return( FALSE );
  }
  else {
    *IndentNum = gCopyHeader.StarIndentNum;
    *Rotation  = gCopyHeader.StarRotation;
    return( TRUE );
  }
}

//------------------------------------------------------------------------------------------------------
// This procedure is used to calculate the polygon corner points of a star based on the current values
// of INFHeader.StarIndentNum and INFHeader.StarRotation.

int CommandCalculateStar( DPOINT* p1, DPOINT* p2, DPOINT* p3, DPOINT* Result )
{
  double        dx, dy, r1, r2, Angle1, Angle2, Step;
  int           Count, Index;

// Calculation of the first radius (distance p1 - p2)

  dx = p2->x - p1->x;
  dy = p2->y - p1->y;
  r1 = sqrt( dx * dx + dy * dy );

// Calculation of the second radius (distance p1 - p3)

  dx = p3->x - p1->x;
  dy = p3->y - p1->y;
  r2 = sqrt( dx * dx + dy * dy );

// Step angle

  Step = REAL_2PI / INFHeader.StarIndentNum;

// Calculation of point pairs with an offset of 1/2 step

  Angle1 = INFHeader.StarRotation;
  Angle2 = INFHeader.StarRotation + 0.5 * Step;

  Index = 0;
  for( Count = 0; Count < INFHeader.StarIndentNum; Count++ ) {
    Result[Index  ].x = p1->x + cos( Angle1 ) * r2;
    Result[Index++].y = p1->y + sin( Angle1 ) * r2;
    Result[Index  ].x = p1->x + cos( Angle2 ) * r1;
    Result[Index++].y = p1->y + sin( Angle2 ) * r1;
    Angle1 += Step;
    Angle2 += Step;
  }

// Number of calculated points

  return( Index );
}

//------------------------------------------------------------------------------------------------------
// This procedure creates an object of types "Surface" and fills it with required definition points to
// build a star.

BOOL CommandFinishStar( void )
{
  int           Total, Count;
  BOOL          Result = TRUE;

// Room to store the polygon point of the calculated star.

  DPOINT        Poly[STAR_INDENT_MAX*2];

// Fill the array Poly[] with a list of point coordinates

  Total = CommandCalculateStar( gPoint + 0, gPoint + 1, gPoint + 2, Poly );

// Open an object of "Surface"

  TosoObjectOpen( OBJ_SURFACE );

// Add the start-point of the polygon

  TosoObjectAddPoint( DB_POINT_START, Poly[0].x, Poly[0].y );

// Add all further points as end-point

  for( Count = 1; Count < Total; Count++ )
    TosoObjectAddPoint( DB_POINT_END, Poly[Count].x, Poly[Count].y );

// Close the object, initialize its properties and insert it into the current drawing

  if( !TosoObjectFastInsert() )
    Result = FALSE;

  return( Result );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called each time the entry of a new point is about to start.

int TosoInputPointInitProc( int CommandID, int PointIndex, double XPos, double YPos )
{

// There is no need to initialize anything, so return immediately.

  return( INPUT_OK );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called at least once each time the user move the cursor.

BOOL TosoInputPointMoveProc( int CommandID, int PointIndex, double XPos, double YPos )
{

// The only action required is to store the current point's coordinates. These coordinate will be used
// to draw the "rubber lines" within the procedure TosoInputDisplayProc() and later on to create the
// object within the procedure TosoInputFinishProc().
// It will suffice if the coordinate are only stored at this one location since TosoInputPointMoveProc()
// will at least be called once with the final coordinate of each point.

  gPoint[PointIndex].x = XPos;
  gPoint[PointIndex].y = YPos;

  return( TRUE );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called each time the entry of a point is to be finished.

int TosoInputPointExitProc( int CommandID, int PointIndex, double XPos, double YPos )
{

// There is no need to do anything, so return immediately. The final point coordinate that are passed
// in XPos and YPos should have already been saved in the TosoInputPoitMoveProc(), so there is no need
// to do it here again.

  return( INPUT_OK );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called each time the module has to update the "rubber lines" displaying the
// current input status on the screen.
// Since the given hDrawDC is using an reversing pen, both "display" and "hide" require the same
// drawing operations.

void TosoInputDisplayProc( int CommandID, int PointIndex, HDC hDrawDC, BOOL DrawFixed, BOOL DrawVariable )
{
  int           Total, Count;

// Room to store the polygon point of the calculated star.

  DPOINT        Poly[STAR_INDENT_MAX*2];

  switch( CommandID ) {
    case 1:                             // Star

// First step: draw all rubber lines that do not change due to mouse movement. Since the complete star
// changes when the mouse position changes, this case is empty here.

      if( DrawVariable ) {


      }

// Second step: draw all rubber lines that do change due to mouse movement. Since the complete star
// changes when the mouse position changes, everything is drawn in this case.

      if( DrawVariable ) {

// Point index 0: No rubber lines visible during entry of first point (center).

        if( PointIndex == 0 ) {

        }

// Point index 1: Display a circle defined by point index 0 (center) and point index 1 (radius 1)

        if( PointIndex == 1 ) {
          TosoInputDrawCircle( hDrawDC, gPoint[0].x, gPoint[0].y, gPoint[1].x, gPoint[1].y );
        }

// Point index 2: Calculate and display a complete star based on point index 0 (center), point
//                index 1 (radius 1) and point index 2 (radius 2).

        if( PointIndex == 2 ) {
          Total = CommandCalculateStar( gPoint + 0, gPoint + 1, gPoint + 2, Poly );

          for( Count = 1; Count < Total; Count++ )
            TosoInputDrawLine( hDrawDC, Poly[Count-1].x, Poly[Count-1].y, Poly[Count].x, Poly[Count].y );

          TosoInputDrawLine( hDrawDC, Poly[Total-1].x, Poly[Total-1].y, Poly[0].x, Poly[0].y );
        }
      }
      break;
  }
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called each time the user wants to edit the parameters of the currently active
// command.

BOOL TosoInputParameterProc( int CommandID )
{
  gCommandID = CommandID;

  switch( CommandID ) {
    case 1:                             // Star

// Display the parameter dialog window. If the parameters are changed (i.e. if DialogEditParameters()
// return TRUE, do also return TRUE to indicate the serving application that parameters of the
// currently active command have changed, i.e. this command should be re-initialised.

      return( DialogEditParameters( hGlobalWnd, eCommandName[0], &INFHeader.StarIndentNum, &INFHeader.StarRotation ) );
  }
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called each time the user explicity canceles the currently active command
// by pressing the right mouse button. If the current command were a command that requires a non-fixed
// number of point entries, this is the place to terminate the command by returning INPUT_FINISH. If
// the current allowed parameters to be editing DURING its execution (like the serving application's
// DRAW > CURVE command), this is the right place to display a corresponding dialog window.

int TosoInputCancelProc( int CommandID, int PointCount )
{
  return( INPUT_CANCEL );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called by the serving application during the execution of the module-supplied
// command "Star". It is called each time the user has successfully enteres all required points, i.e.
// the command is finished and the resulting actions are to be performed.

void TosoInputFinishProc( int CommandID, int PointCount )
{
  BOOL          Result = TRUE;

// Tell the interface that some objects are to be created.

  if( !TosoCreationStart() )
    return;

// Start a new undo level. All objects created since now can either now be inserted to the drawing by
// calling TosoUndoFinishProcess() or can be deleted by calling TosoUndoCancelProcess().

  TosoUndoInitProcess();

// Execute the command, i.e. calculate the resulting polygon and create an object of type "Surface"
// based on that calculation.

  switch( CommandID ) {
    case 1:                             // Star
      Result = CommandFinishStar();
      break;
  }

// If creation was successful, end the newly created undo level (which inserts all objects to the
// current drawing) and draw all newly created objects. Else, delete all newly created objects by
// canceling the undo level.
  
  if( Result ) {
    TosoUndoFinishProcess();
    TosoDrawNewObjects();
  }
  else
    TosoUndoCancelProcess();

// Tell the interface that the object creation was ended.

  TosoCreationEnd();
}

//------------------------------------------------------------------------------------------------------
// This DLL entry procedure must exist in any DLL to be used in Win32. Since our DLL does all necessary
// initialization in its TosoModuleInit() procedure, this procedure is quite empty.

BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD Reason, LPVOID Dummy )
{
  switch( Reason ) {
    case DLL_PROCESS_ATTACH:
      hInstDLL = hInstance;
      break;

    case DLL_PROCESS_DETACH:
      hInstDLL = NULL;
      break;
  }
  return( TRUE );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called when the module is loaded by the serving application. Its main tasks are:
// - Checking whether it is compatible with the given InterfaceVersion
// - Checking whether it is licensed to the given serial number (optional)
// - Storing of the serving application's instance and main windows handle for further use
// - Loading of the language-dependent library
// - Filling in the module ID structure whose address is passed in ModuleID
// - Loading of options from the registry database
// - Loading profiles
// - Allocating any static memory required

DLL_EXPORT BOOL TosoModuleInit( const LPSTR SerialNumber, HINSTANCE hMainInst, HWND hMainWnd,
                                                          int InterfaceVersion, MODULE_ID* ModuleID )
{
  int           Count;

  if( InterfaceVersion < TOSO_INTERFACE_VERSION ) {
    MessageBox( hMainWnd, eMessageText[0], eDialogText[0], MB_OK );
    return( FALSE );
  }
  hGlobalInst = hMainInst;
  hGlobalWnd  = hMainWnd;

// Load the command icon bitmap from the language DLL.

  hLanguage = LoadLibrary( "TSAMPLE.DLL" );
  hBitmap = LoadBitmap( hLanguage, "IDB_COMMAND" );

// Fill the module information data block

  ModuleID->OwnerID    = DB_OWNER_TOSO;
  ModuleID->ModuleID   = 0x0000;
  ModuleID->ModuleCTRL = MODULECTRL_ALL;

  ModuleID->ModuleProc.InputPointInitProc = (TOSOINPUTPOINTINIT_PROC) TosoInputPointInitProc;
  ModuleID->ModuleProc.InputPointMoveProc = (TOSOINPUTPOINTMOVE_PROC) TosoInputPointMoveProc;
  ModuleID->ModuleProc.InputPointExitProc = (TOSOINPUTPOINTEXIT_PROC) TosoInputPointExitProc;
  ModuleID->ModuleProc.InputDisplayProc   = (TOSOINPUTDISPLAY_PROC)   TosoInputDisplayProc;
  ModuleID->ModuleProc.InputParameterProc = (TOSOINPUTPARAMETER_PROC) TosoInputParameterProc;
  ModuleID->ModuleProc.InputCancelProc    = (TOSOINPUTCANCEL_PROC)    TosoInputCancelProc;
  ModuleID->ModuleProc.InputFinishProc    = (TOSOINPUTFINISH_PROC)    TosoInputFinishProc;

  ModuleID->ModuleData.Type = MODULETYPE_DRAW;

  ModuleID->ModuleData.InputData.CommandMode = COMMAND_DIRECT;
  ModuleID->ModuleData.MenuData.MenuEntry   = eStartUpText[1];
  ModuleID->ModuleData.MenuData.Description = eStartUpText[2];

  ModuleID->ModuleData.IconHandle  = hBitmap;
  ModuleID->ModuleData.IconXOffset = 0;
  ModuleID->ModuleData.IconYOffset = 0;
  ModuleID->ModuleData.IconMode    = 0;

  ModuleID->CommandData = CommandData;

// Fill in the commands' names and the accompanying information.

  Count = 0;
  while( eCommandEntry[Count] == NULL || eCommandEntry[Count][0] != END_CHAR ) {
    CommandData[Count].InputData.CommandMode = COMMAND_DIRECT;
    CommandData[Count].MenuData.MenuEntry   = eCommandEntry[Count];
    CommandData[Count].MenuData.Description = eCommandName [Count];

    CommandData[Count].IconHandle  = hBitmap;
    CommandData[Count].IconXOffset = 0;
    CommandData[Count].IconYOffset = ( Count + 1 ) * 48;
    CommandData[Count].IconMode    = 0;

    if( eCommandEntry[Count] )
      CommandData[Count].Type = IDM_ENTRY;
    else
      CommandData[Count].Type = IDM_ENTRY | IDM_SEPARATOR;

    Count++;
  }
  CommandData[Count].Type = IDM_END;

// Fill the command description structure with the predefined global structure gInfo.

  CommandData[0].InputData = gInfo[0];
  CommandData[0].InputData.PointNames[1] = eNewPoint[0];
  CommandData[0].InputData.PointNames[2] = eNewPoint[1];

// Read the current settings (set to their default values if not found)

  ModuleLoadSettings();

  return( TRUE );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called when the module is removed by the serving application. Its main tasks are:
// - Checking whether anything is to be saved. If so, it should display a message information the user
//   about it and allowing him to save those changes.
// - Freeing of all statically allocated memory.
// If this procedure return FALSE, the serving application will not be able to terminate. So please, do
// only return FALSE if shutting down the module now would severely damage or destroy user data.

DLL_EXPORT BOOL TosoModuleExit( void )
{
  ModuleSaveSettings();

  DeleteBitmap( hBitmap );

  return( TRUE );
}

//------------------------------------------------------------------------------------------------------
// This procedure is called when a module's command is chosen by the user. For a command module, its
// main tasks are:
// - If requested, display the help topic for the given command
// - Execute the chosen command (if it is a "direct" command that does not require point entry)
// - Register an external command (if it is a "indirect" command that does require point entry)
// - Error handling and display

DLL_EXPORT BOOL TosoModuleCommand( int CommandID, int ExecMode )
{
  BOOL          Result = FALSE;

// Check whether a help topic is to be displayed instead of starting a command.

  if( ExecMode == MODULEEXEC_HELP ) {
    switch( CommandID ) {
      case 1:
      case 3:
        WinHelp( hGlobalWnd, "TSAMPLE.HLP", HELP_CONTEXT, CommandID );
        break;
    }
    return( FALSE );
  }

// Execute the command chosen by the user.

  switch( CommandID ) {
    case 1:
      Result = TRUE;

// If the user has first selected the command from the menu, allow him to edit the parameters first.
// If the command does only use seldomly-modified parameters, this is NOT necessary.

      if( ExecMode == MODULEEXEC_USER ) {
        gCommandID = CommandID;
        if( !DialogEditParameters( hGlobalWnd, eCommandName[0], &INFHeader.StarIndentNum, &INFHeader.StarRotation ) )
          Result = FALSE;
      }
      break;

    case 3:
      MessageBox( hGlobalWnd, eStartUpText[0], eDialogText[0], MB_OK );
      Result = TRUE;
      break;

    default:
      Result = FALSE;
      break;
  }
  return( Result );
}
