/*  Project Tec3270

	 SUBSYSTEM:    Tec3270.exe (Tec3270 application)
	 FILE:         alffnmdc.cpp
	 AUTHOR:       Alcindo Ferreira Filho

	 OVERVIEW:

    ALFFMDIClient Class Implementation, the Tec3270 MDI sessions,
    class manager. Sessions are childs of this class.

    COPYRIGHT:    © 1998-2007
                  Alcindo Ferreira Filho
                  <alcindo@inttec.com.br>

    LICENSE:      Tec3270_License (docs/Tec3270_License.txt)
*/
//#define DEBUG32    1

#include "alffnall.h"

// Diagnostics
DIAG_DEFINE_GROUP(ALFFMDIClient,1,0);

//{{ALFFMDIClient Implementation}}
//
// Build a response table for all messages/commands handled
// by ALFFMDIClient derived from TMDIClient.
//

DEFINE_RESPONSE_TABLE1(ALFFMDIClient, TMDIClient)
//{{ALFFMDIClientRSP_TBL_BEGIN}}
	 EV_WM_TIMER,
	 EV_COMMAND(CM_NEWSESSION, CmNewSession),
	 EV_COMMAND(CM_CLOSESESSION, CmCloseSession),
	 EV_COMMAND(CM_ALFFPRINT, CmPrint),
	 EV_COMMAND(CM_ALFFPRINTERSETUP, CmPrintSetup),
	 EV_COMMAND(CM_ALFFPRINTPREVIEW, CmPrintPreview),
	 EV_COMMAND(CM_CASCADECHILDREN, CmCascadeChildren),
	 EV_COMMAND(CM_TILECHILDREN, CmTileChildrenVert),
	 EV_COMMAND(CM_TILECHILDRENHORIZ, CmTileChildrenHoriz),
	 EV_COMMAND(CM_ARRANGEICONS, CmArrangeIcons),
	 EV_COMMAND(CM_CLOSECHILDREN, CmCloseChildren),
	 EV_COMMAND(CM_CHOOSEFONT, CmChooseFont),
	 EV_COMMAND(CM_CHOOSEPRTFONT, CmChoosePrtFont),
	 EV_COMMAND(CM_CHOOSECOLORS, CmChooseColors),
	 EV_COMMAND(CM_OPTIONSKEYBOARD, CmKeyboard),
	 EV_COMMAND(CM_OPTIONSKEYPAD, CmOptionsKeyPad),
	 EV_COMMAND(CM_OPTIONSCONFIGSESSIONS, CmOptionsConfigSessions),
	 EV_COMMAND(CM_OPTIONSAUTOMAT, CmOptionsAutomat),
	 EV_COMMAND(CM_TOOLSMONITOR,CmToolsMonitor),
    EV_COMMAND(CM_SECURITYADMINCERTS, CmSecurityAdminCerts),
    EV_COMMAND(CM_SECURITYOPTIONS, CmSecurityOptions),    
	 EV_COMMAND(CM_ALFFEXIT,CmExit),
	 EV_MESSAGE(MSG_KEYPAD_PRESSED, EvMsgKeyPad),
	 EV_MESSAGE(MSG_INIT_MDI, DoMDIInit),
	 EV_MESSAGE(MSG_CLOSE_IMMED, CloseChild),
	 EV_COMMAND_ENABLE(CM_NEWSESSION,CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_CLOSESESSION,CmOneChildEnable),
	 EV_COMMAND_ENABLE(CM_ALFFPRINT, CmPrintEnable),
	 EV_COMMAND_ENABLE(CM_ALFFPRINTERSETUP, CmPrintEnable),
	 EV_COMMAND_ENABLE(CM_ALFFPRINTPREVIEW, CmPrintPreviewEnable),
	 EV_COMMAND_ENABLE(CM_CASCADECHILDREN, CmTwoChildEnable),
	 EV_COMMAND_ENABLE(CM_TILECHILDREN, CmTwoChildEnable),
	 EV_COMMAND_ENABLE(CM_TILECHILDRENHORIZ, CmTwoChildEnable),
	 EV_COMMAND_ENABLE(CM_ARRANGEICONS, CmTwoChildEnable),
	 EV_COMMAND_ENABLE(CM_CLOSECHILDREN, CmOneChildEnable),
	 EV_COMMAND_ENABLE(CM_CHOOSEFONT, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_CHOOSEPRTFONT, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_CHOOSECOLORS, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_OPTIONSKEYBOARD, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_OPTIONSKEYPAD, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_OPTIONSCONFIGSESSIONS, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_OPTIONSAUTOMAT, CmMonitorEnable),
	 EV_COMMAND_ENABLE(CM_TOOLSMONITOR, CmToolsMonitorEnable),
//{{ALFFMDIClientRSP_TBL_END}}
END_RESPONSE_TABLE;


//////////////////////////////////////////////////////////
// ALFFMDIClient
// ================
// Construction/Destruction handling.
ALFFMDIClient::ALFFMDIClient (TModule* module)
 : TMDIClient (module),
   ALFFDdeServer("TEC3270 Server", "WHllApi"),
//   wHLLSessions(0,0,2),
	childList(0,0,2)
{
 ChildCount = 0;
 ChildActive = 0;
 Attr.H = 10000;
 Attr.W = 15000;
 prtData = NULL;
 pMsgs   = new ALFFMsgs(this);
 KeyPad  = NULL;
 sessName = NULL;
 monitoring = false;

#if (PORTUGUES == 1)
  dateFormat = ALFFDate::pt_BR;
#elif (ENGLISH == 1)
  dateFormat = ALFFDate::en_US;
#else
#error (ALFFNMDC.CPP) Language must be defined to PORTUGUES=1 or ENGLISH=1.
#endif

 // DDE for WHLLAPI controls
 advising = 0;
 // DdeString Inherited from ALFFDde that is
 // base class for ALFFDdeServer
 itemWHLLCommand = DdeString("WHllCommand");

 //Initialize WHLLSessions Controls List
 for (int i=0; i<MAXWHLLSESSIONS; i++)
  {
   hllSessions[i] = NULL;
   hllSessionName[i] = NULL;
   hllSessionPsShare[i] = PS_WRITE_NONE;
   ownerAppId[i] = NULL;
   ownerAppIndex[i] = -1;
   appsConnected[i] = 0;
  }

 //Initialize WHLL Applications Controls List
 for (int i=0; i<MAXWHLLAPPS; i++)
  {
   hllApp[i] = NULL;
   hllAppConnected[i] = false;
   hllSessionIndex[i] = -1;
   // WHLLAPI App Options (Set by SETSESSIONPARAMETERS function)
   // See struct constructor for default values
   wHllAppOptions[i] = NULL;
   outData[i] = NULL;
  }

 // Reserved HDDEDATA for returning data to apps that exceeded MAXWHLLAPPS
 outData[MAXWHLLAPPS+1] = NULL;

 // User Certificate FilePath and Password (it will be destructed after
 //  being used on CONNECTPS):
 hllCertPath = NULL;
 hllCertPwd = NULL;

 wHllSessionCount = 0;
}

ALFFMDIClient::~ALFFMDIClient()
{
 //Destroy();
 delete  pMsgs;
 if (prtData)
	delete prtData;

 // FreeString Inherited from ALFFDde that is
 // base class for ALFFDdeServer
 FreeString(itemWHLLCommand);

 // Delete  Sessions Controls List
 for (int i=0; i<MAXWHLLSESSIONS; i++)
  {
   // Do not need to delete child pointer as it is owned by
   // MDIClient that takes care of its destruction....
   if ( hllSessionName[i] != NULL )
     delete [] hllSessionName[i];
   ownerAppId[i] = NULL;
   ownerAppIndex[i] = -1;
  }
 // Delete  Applications Controls List
 for (int i=0; i<MAXWHLLAPPS; i++)
  {
   if ( wHllAppOptions[i] != NULL )
     delete wHllAppOptions[i];
  }
}

//////////////////////////////////////////////////////////
// ALFFMDIClient
// ===========
// MDIClient DDe Server methods.

bool
ALFFMDIClient::ProvidesItem(HSZ queryItem)
{
  bool stringsMatch = StringsMatch(itemWHLLCommand,queryItem);
#ifdef __WARN
  char queryText[strLength] = {0x00};
  char queryText2[strLength] = {0x00};
  WARNX(ALFFMDIClient, !stringsMatch, 0, "ALFFMDIClient:: Does not provide item -> <" << QueryString(itemWHLLCommand, queryText) << "> Not Equal <" << QueryString(queryItem, queryText2) << ">" );
#endif
  return stringsMatch;
}

bool
ALFFMDIClient::StartServerAdvise(HCONV /*convId*/, HSZ item)
{
#ifdef __WARN
  char queryText[strLength];
#endif
  TRACEX(ALFFMDIClient,0,"ALFFMDIClient:: Start Tec3270_WHllApi  advising " << QueryString(item,queryText));
  if (StringsMatch(itemWHLLCommand,item))
   {
    advising++;
    return TRUE;
   }
  else
   {
    TRACEX(ALFFMDIClient,0,"ALFFMDIClient:: Does not provide item to advise " << QueryString(item,queryText));
   }
  return FALSE;
}

bool
ALFFMDIClient::StopServerAdvise(HCONV /*convId*/, HSZ item)
{
#ifdef __TRACE
  char queryText[strLength];
  TRACEX(ALFFMDIClient,0,"ALFFMDIClient:: Stopping Tec3270_WHllApi advise " << QueryString(item,queryText));
#endif
  if (StringsMatch(itemWHLLCommand,item))
   {
    advising--;
    return TRUE;
   }
  else
   {
    #ifdef __TRACE
    char queryText[strLength];
    TRACEX(ALFFMDIClient,0,"ALFFMDIClient:: Does not provide item to stop advising" << QueryString(item,queryText));
    #endif
   }
  return FALSE;
}

HDDEDATA far
ALFFMDIClient::ReturnData(HCONV appId, HSZ item)
{
 //
 // Check that I do supply the item
 //
 if (!ProvidesItem(item))
   return (HDDEDATA)0;
 //
 // If there is any data from last command processed it should
 // be returned
 //
 else
  {
   int dataIndex = GetHLLAppPtr(appId);
   if (dataIndex)
     return outData[dataIndex-1];
   else if (outData[MAXWHLLAPPS+1] != NULL)
     return outData[MAXWHLLAPPS+1];
   // There isn't data to return
   else return (HDDEDATA)0;
  }
}

int
ALFFMDIClient::GetHLLSessionPtr(char* lpStrSessName)
{
 int index = 0;
 for (int i=0; i < MAXWHLLSESSIONS; i++)
  {
   if (hllSessionName[i] && lpStrSessName)
    {
     if (!strcmp(hllSessionName[i],lpStrSessName))
      {
       index = i+1;
       break;
      }
    }
  }
 return index;
}

int
ALFFMDIClient::GetHLLAppPtr(HCONV appId)
{
 int index = 0;
 for (int i=0; i < MAXWHLLAPPS; i++)
  {
   // appId may be NULL for getting index for
   // adding new app
   if (hllApp[i] == appId)
    {
     index = i+1;
     break;
    }
  }
 return index;
}


HDDEDATA far
ALFFMDIClient::ReceivedData(HCONV thisAppId, HSZ item, HDDEDATA hCommand)
{
#ifdef __TRACE
  char queryText[strLength];
  TRACEX(ALFFMDIClient,0,"ALFFMDIClient:: ReceivedData ..." );
#endif

 //
 // Check that I do supply the item
 //
 if (!ProvidesItem(item))
  {
#ifdef __TRACE
   TRACEX(ALFFMDIClient,0,"ALFFMDIClient:: Do not provide item ->"  << QueryString(item, queryText));
#endif
   return (HDDEDATA)0;
  }
 //
 // We should implement here all WHLLAPI process
 //
#ifdef __TRACE
 //pMsgs->StrMessage("Comando Recebido",0,IDS_ALFFSESSTITLE);
#endif

 // WHLLAPI Parms
 short commandCode;
 unsigned char* byString;
 short byStringLen;
 short returnCode;
 short psPosition;

 //Session Pointer Index
 int childIndex;

 // SETSESSIONPARAMETERS Function controls
#define MAXPARMS  22
#define MAXPARMLENGTH MAXPATH
 unsigned char parmDelimiter = ',';
 char *ptrDelimiter, *ptrString;
 char* sessionParms [MAXPARMS];
 unsigned char i, numParmOk;
 int numParms;
 bool  parmOk;
 string tempString;
 int    tempStringLen;

 // PAUSE controls
 bool isPSChanged;

 // Lets recover command received
 unsigned char*  commandBuffer;
 int    bufferLen;
 WORD   extendedError = 0;

 // Just for getting command length
 bufferLen = GetData(hCommand, 0, 0);
 commandBuffer = new unsigned char[bufferLen+1];
 GetData(hCommand, commandBuffer, bufferLen);
 memset (commandBuffer+bufferLen, NULL, 1);

 /*
  * Parsing Buffer
  */
 // Command Code is an 16 Bits integer (LL, HH)
 memcpy (&commandCode, commandBuffer+CCODEOFFSET, 2);

 // PS Position is sent over ReturnCode field
 memcpy (&psPosition, commandBuffer+RETCODEOFFSET, 2);

 // Skipping Extended Error code (+EXTDERROROFFSET)

 // String length is an 16 Bits integer (LL, HH)
 memcpy (&byStringLen, commandBuffer+DATALENOFFSET, 2);

 //String begins after command header (CC,RC,XErr,LL,String.....)
 byString = commandBuffer+DATAOFFSET;


 int currentHLLSession;
 int currentHLLApp = GetHLLAppPtr(thisAppId);
 // If thisAppId is already connected it was found on App list
 // and 'currentHLLApp' is greater than 0.
 // If thisAppId was not found 'currentHLLApp' is 0.
 if (currentHLLApp)
  {
   currentHLLApp -= 1;  // Set index related to 0(zero);
   currentHLLSession = hllSessionIndex[currentHLLApp];
   if ( (currentHLLSession >= 0)
      &&(ownerAppId[currentHLLSession] == NULL) )
    // thisAppId has an Session Options struct and its owner
    // is NULL. Certainly it is an session that had an owner
    // that is now disconnected and thisAppId is connected to it too.
    // In this case we must appropriate this session to thisAppId.
    ownerAppId[currentHLLSession] = thisAppId;
  }
 else
  {
   // try to get an valid new app index: if it is not available
   // GetHLLAppPtr will return 0, so currentHLLApp will be set
   // to -1 indicating no more app could be accepted.
   currentHLLApp =  GetHLLAppPtr(NULL)-1;
   if (currentHLLApp >= 0)
    {
     hllApp[currentHLLApp] = thisAppId;
     wHllAppOptions[currentHLLApp] = new TecWHLLAppParms();
    }
   currentHLLSession = -1;  // App not connected to any HLL session
  }

 // Session pointer used in functions
 ALFFMDIChild* child = NULL;

 TecWHLLAppParms*  wHllOpts;
 bool returnString = false;
 if (currentHLLApp >= 0)
  {
   // Get App/Session Parameters (Set by SETSESSIONPARAMETERS)
   wHllOpts =  wHllAppOptions[currentHLLApp];
   switch (commandCode)
   {
   case    CONNECTPS:
// ATTENTION....ATTENTION....ATTENTION....ATTENTION....ATTENTION....ATTENTION...
////////////////////////////////////////////////////////////////////////////////
//		KEY$/NOKEY session parameters are accepted and stored on session data
//		structure (wHllOpts), but are not used.  Someone should implemente
//    the code for checking password (if there is one) before connecting
//    to an already existing sessions that has sharing permissions.......
////////////////////////////////////////////////////////////////////////////////
           // Checking if session name is available
           if ((byStringLen) || (psPosition == CONNECTPSCHECK))
            {
             if (psPosition == CONNECTPSCHECK)
              {
               // This the second or more call for having effective return code
               // form connection that were asked for in first call
               //
               if (currentHLLSession >= 0)
                {
                 // Take the session pointer
                 child = (ALFFMDIChild*)hllSessions[currentHLLSession];
                 if (!child)
                  {
                   returnCode = WHLLSYSERROR;
                   extendedError = TEC3270_WHLLNO3270SESSION;
                   break;
                  }
                }
               // We have an session, so let's see what is going on
               if (child->IsSecureConnection())
                {
                 // This is an secure connection, check for user certificates,
                 // correcteness if it was not connected ok
                 if (child->IsSSLConnected())
                  {
                   if (child->GetTerminalPtr()->IsKeyboardLocked())
                    returnCode = WHLLINHIBITED;
                   else returnCode = CONNECTPSDONE;  // Same as WHLLOK but definitive
                   break;
                  }
                 else if (child->IsIdle())
                  {
                   if (child->GetLinePtr()->GetSSLError())
                    {
                     // SSL was not connected Ok, check client cert error
                     returnCode = child->GetLinePtr()->GetClientCertificateError();
                     if (returnCode == CERTIFICATEOK)
                       // SSL was not connected Ok, check Server cert error
                       returnCode = child->GetLinePtr()->GetServerCertificateError();

                     // Translate SSL Error to WHLL Certificate Errors
                     switch (returnCode)
                      {
                       case     NOCERTIFICATE:
                                returnCode = WHLLNOCERTIFICATE;
                                break;
                       case     CERTIFICATEISEXPIRED:
                                returnCode = WHLLEXPIREDCERT;
                                break;
                       case     CERTIFICATEISREVOKED:
                                returnCode = WHLLREVOKEDCERT;
                                break;
                       case     CERTIFICATEINVALIDPWD:
                                returnCode = WHLLCERTPWD;
                                break;
                       case     CERTIFICATENOISSUER:
                       case     CERTIFICATEISNOTVALID:
                       case     CERTIFICATENOTTRUSTED:
                                returnCode = WHLLINVALIDCERT;
                                break;
                       case     CERTIFICATECRLNOTAVAIL:
                                returnCode = WHLLNOCERTCRL;
                                break;
                       case     CERTIFICATEOK:
                       default: returnCode = WHLLSYSERROR;
                                extendedError = TEC3270_WHLLCONNECTIONSSLERROR;
                                break;
                      }
                     break;
                    }
                   else
                    {
                     returnCode = WHLLNOTCONNECTED;
                     break;
                    }
                  }
                 else
                  {
                   // Do nothing : wait for one of above session states or
                   // session connection timed out. We'll be called again.
                   returnCode = WHLLOK;
                   break;
                  }
                }
               else
                {
                 // This isn't an secure connection, so we need only to check,
                 // the connection to see if it is sure connected
                 if (child->IsConnected())
                  {
                    if (child->GetTerminalPtr()->IsKeyboardLocked())
                       returnCode = WHLLINHIBITED;
                    else returnCode = CONNECTPSDONE; // Same as WHLLOK but definitive
                    break;
                  }
                 else if (child->IsIdle())
                  {
                   returnCode = WHLLNOTCONNECTED;
                   break;
                  }
                 else
                  {
                   // Do nothing : wait for one of above session states or
                   // session connection timed out. We'll be called again.
                   returnCode = WHLLOK;
                   break;
                  }
                }
              }
             // This is the first call for connecting the session specified, so
             // there is an session name. Do initial checks.
             if (wHllSessionCount <= MAXWHLLSESSIONS)
              {
               if ((currentHLLSession >= 0)
                && (hllAppConnected[currentHLLApp]))
                {
                 // Applications is already connected to an session:
                 // For connecting to another session it must use
                 // DISCONNECTPS function before asking for connect...
                 returnCode = WHLLUNAVAILABLE;
                 break;
                }
               // The number of connected WHLL sessions is less then max available
               if (sessName)
                delete [] sessName;
             	sessName = new char [byStringLen+1];
             	memcpy(sessName, byString, byStringLen);
             	memset(sessName+byStringLen,NULL,1);

               // Verify if referred session exists
               ALFFConnData connData;
               ALFFConnectDlg connDlg(this, &connData, IDD_ALFFCONNECT);
               if ( (!connDlg.LoadConnection(sessName))
                  ||(!strcmp(connData.hostName,"Enter HostName")) )
                {
                 returnCode =  WHLLNOTCONNECTED;
                 break;
                }

#define  WHLLAPISESSION  true
               // GetHLLSessionPtr returns the number of element in WHLLSessions
               // list that corresponds to session name to be connected to.
               // if it returns 0(zero) no matched session was found.
               childIndex =  GetHLLSessionPtr(sessName);
               if (childIndex)
                {
                 childIndex -= 1; //Set index related to 0(zero)
                 // Session is already in WHLLSessions list
                 if (appsConnected[childIndex])
                  {
                   // Session has at least one app connected
                   int ownerIndex = ownerAppIndex[childIndex];
                   if ((ownerAppId[childIndex] != thisAppId)
                    && (hllSessionPsShare[childIndex] == PS_WRITE_NONE))
                    {
                     // The owner of this session isn't thisAppId and
                     // it has an PSShare that do not permit other apps
                     // to connect to it.
                     // So, this session cannot be shared by any other application !
                     returnCode = WHLLUNAVAILABLE;
                     break;
                    }
                   //else hllSessionPsShare[childIndex] contains the share mode
                   //     so it must be verified now about having KEY$ parameter
                   //     in order to compare to new client KEY$ parameter
                   //     to permit or not the connection...... See comment
                   //     that is immediately below "case CONNECTPS".
                  }
                 //else Session not app connected: may be connected by thisAppId !

                 // Take the session pointer
                 child = (ALFFMDIChild*)hllSessions[childIndex];

                 if ((child != NULL) && (child->IsIdle())
                    &&(ownerAppId[childIndex] == thisAppId) )
                   {
                    // Current Session was created before and is owned by thisAppId
                    //  but for some reason was disconnect from host, so try to
                    //  reconnect it
                    child->Connect(hllSessionName[childIndex], WHLLAPISESSION, hllCertPath, hllCertPwd);
                   }
                }
               else
                {
                 child = (ALFFMDIChild*)CreateSession(sessName, WHLLAPISESSION, hllCertPath, hllCertPwd);
                 /* This is an new session, so Add session to WHLLSession list.
                  * Session added will only be removed when application
                  * calls RESETSYSTEM. All connected sessions will stay
                  * conected to host even if DISCONNECTPS is used and so
                  * they will be on WHLL Session list and the MAXWHLLSESSIONS
                  * is the count limit of simultaneous sessions.
                  */
                 if (child)
                  {
                   // If there is an session associated previously with thisAppId
                   // and there is any session defined on it, we must use it,
                   // otherwise we should get an new session from list.
                   if ((currentHLLSession != -1)
                     &&(!hllSessionName[currentHLLSession]))
                       childIndex = currentHLLSession;
                   else childIndex = wHllSessionCount++;

                   // Do the session startup procedure

                   // Associate the Tec3270 session ptr to it
                   hllSessions[childIndex] = child;

                   // Creating and storing its name on Tec3270 sessions defined
                   hllSessionName[childIndex] = new char[strlen(sessName)+1];
                   strcpy(hllSessionName[childIndex], sessName);

                   // Inherit PS Share from APP Options
                   hllSessionPsShare[childIndex] = wHllOpts->psShare;

                   // This session is now owned by thisAppId app
                   ownerAppId[childIndex] = thisAppId;
                   ownerAppIndex[childIndex] = currentHLLApp;
                  }
                 else
                  {
                   returnCode =  WHLLSYSERROR;
                   extendedError = TEC3270_WHLLNO3270SESSION;
                   break;
                  }
                }

               // Set currentWHLLSession and App current Session indexes
               currentHLLSession = hllSessionIndex[currentHLLApp] = childIndex;

              	if (child)
              	 {
                  // Set one more app connected to this session
                  appsConnected[currentHLLSession]++;

                  // This app is now connected to above session
                  hllAppConnected[currentHLLApp] = true;

                  // Checking for foreground option
                  if (!wHllOpts->conLog)
                   {
                    child->ShowWindow(SW_SHOWMAXIMIZED);
                    ::SetForegroundWindow(GetApplication()->GetMainWindow()->HWindow);
                   }
               	returnCode = WHLLOK;
              	 }
             	else
                {
                 // There is no valid Tec3270 session to be connected to Host
                 child = (ALFFMDIChild*) GetActiveMDIChild();
                 if (child)
                  {
                   child->SetWHLLClosing(true);
                   CloseSession(child);
                  }
                 returnCode = WHLLNOTCONNECTED;
                }

             	delete [] sessName;
             	sessName = NULL;
              }
             else
              {
               // MAXWHLLSESSIONS reached
               returnCode =  WHLLSYSERROR;
               extendedError = TEC3270_WHLLMAXSESSEXCEEDED;
              }
            }
           else returnCode = WHLLNOTCONNECTED;

           break;

   case DISCONNECTPS:
           if (currentHLLSession >= 0)
            {
             //
             // Disconnect from current active session if it is connected.
             //
             if (hllAppConnected[currentHLLApp])
              {
               hllAppConnected[currentHLLApp] = false;
               // The session stay owned by app until it use the
               // RESETSYSTEM function, when all sessions are reset
               // and disconnected from app and from the host.
               appsConnected[currentHLLSession]--;
               returnCode = WHLLOK;
              }
             else returnCode = WHLLNOTCONNECTED;
            }
           else returnCode = WHLLNOTCONNECTED;
           byStringLen = 0;
           break;


   case    SETSESSIONPARAMETERS:
           /* STRLEN/STREOT:
            * Specify how the length of Data String is determined.
            *
            * Applies to Send Key (3), Search Presentation Space (6),
            * Copy String to Presentation Space (15), Search Field (30),
            * Copy String to Field (33), Send File (90) and Receive File (91).
            *
            *  STRLEN => Data Length explicitly defined.
            *            This is the default setting.
			   *  STREOT => Data Length not necessarily defined;
            *            Data String parameter on a function call ends
            *            in an EOT character.
            */

           /* EOT=c
            * When the STREOT session option is set, specify the
            * delimiter character to mark the end of the Data String
            * parameter on a function call (same as above).
            * The default EOT character is binary zero (NULL terminated string),
            * and it is adopted when STREOT is specified and no EOT=c is supplied.
            */

           /* SRCHALL/SRCHFROM
            * Determine how the Host session presentation space is to be searched.
            *
            * Applies to Search Presentation Space (6) and Search Field (30).
            *
            * SRCHALL	If using Search Presentation Space (6),
            *           search the entire Host session presentation space.
            *           If using Search Field (30), search the entire field.
            *           SRCHALL is the default setting.
            * SRCHFROM	If session option SRCHFRWD is set, start search at
            *           specified PS Position and stop at the end
            *           (of the field or Host session presentation space).
            *           If session option SRCHBKWD is set, start search at
            *           the end and stop at specified PS Position.
            */

           /* SRCHFRWD/SRCHBKWD
            * When the SRCHFROM session option is set, determine the direction
            * of the search.
            *
            * Applies to Search Presentation Space (6) and Search Field (30).
            *
            * SRCHFRWD	When session option SRCHFROM is set, start search
            *           at specified PS Position and stop at the end
            *           (of the field or Host session presentation space).
            *           This is the default setting.
				* SRCHBKWD	When session option SRCHFROM is set, start search
            *           at the end (of the field or Host session presentation
            *           space) and stop at specified PS Position.
            */

           /* NOATTRB/ATTRB
            * Determine how to translate attributes to your Windows HLLAPI
            * application.
            *
            * Applies to Copy Presentation Space (5),Copy Presentation Space
            * to String (8) and Copy Field to String (34).
            *
            * NOATTRB	Translate EBCDIC bytes that do not have ASCII equivalents
            *           to spaces (ASCII 20h). NOATTRB is the default setting.
				* ATTRB	   EBCDIC bytes that do not have ASCII equivalents are
            *           not translated, but are passed as their original
            *           EBCDIC values.
            */

           /* FPAUSE/IPAUSE
            * Determine the type of pause to use.
            *
            * Applies to Pause (18).
            *
            * FPAUSE	Full pause; pause for the length of time specified
            *        in Pause (function 18). FPAUSE is the default setting.
            * IPAUSE	Interruptible pause; once a Start Host Notification
            *        (function 23) call is made, any Host event ends the pause.
            */

           /* NOQUIET/QUIET
            * Determine whether the file transfer functions SEND FILE (90)
            * and RECEIVE FILE (91) will generate messages displayed to the user.
            *
            * NOQUIET	SEND and RECEIVE messages are displayed.
				* QUIET	SEND and RECEIVE messages are not displayed.
            *
            */

           /* TIMEOUT=0/TIMEOUT=c
            * Set the timeout interval to be used during file transfer operations.
            * If a timeout occurs, the file transfer aborts.
            *
            * TIMEOUT=0	Set the timeout to 30 seconds.
            *           There must not be a space on either side of the equal sign;
            *           the value is a zero. TIMEOUT=0 is the default setting.
            * TIMEOUT=c	Set the timeout to a specific period.
            *           A CTRL+BREAK is issued automatically after the specified
            *           period. There must not be a space on either side of the
            *           equal sign; c is a one-byte character that can  be only
            *           one of the following values:
            *           1	30 seconds (0.5 minutes
            *           2	60 seconds (1.0 minutes)
            *           3	90 seconds (1.5 minutes)
            *           4	120 seconds (2.0 minutes)
            *           5	150 seconds (2.5 minutes)
            *           6	180 seconds (3.0 minutes)
            *           7	210 seconds (3.5 minutes)
            *           8	240 seconds (4.0 minutes)
            *           9	270 seconds (4.5 minutes)
            *           J	300 seconds (5.0 minutes)
            *           K	330 seconds (5.5 minutes)
            *           L	360 seconds (6.0 minutes)
            *           M	390 seconds (6.5 minutes)
            *           N	420 seconds (7.0 minutes)
            */

           /* ESC=c
            * Specify the escape character to use for 3270 function key codes.
            *
            * Applies to Send Key (3) and Get Key (51).
            *
            * Set the escape character to use for 3270 function key codes to c
            * which is a one-byte literal character. There must not be a space
            * on either side of the equal sign ("space" is not a valid escape
            * character). The default escape character is the at sign (@).
            */

           /* AUTORESET/NORESET
            * Determine if Send Key (function 3) sends a reset prior to the
            * keystroke string or not.
            *
            * AUTORESET	A reset precedes the keystroke string specified with
            *           a Send Key (3), attempting to reset any states
            *           that can be reset (except input-inhibited).
            *           AUTORESET is the default setting.
            * NORESET 	A reset does not precede the keystroke string specified
            *           with a Send Key (3).
            */

           /* TWAIT/LWAIT/NWAIT
            * Determine the characteristics of a wait period.
            *
            * Applies to Wait (4) and Get Key(51).
            *
            * TWAIT	For Wait (4), wait up to 60 seconds before timing out
            *        on XCLOCK or XSYSTEM.
            *        For Get Key (function 51), wait until a keystroke is
            *        queued before returning. TWAIT is the default setting.
            * LWAIT 	For Wait (4), wait until the XCLOCK or XSYSTEM clears.
            *        This setting is not recommended because your Windows
            *        HLLAPI does not regain control until the Host is available.
            *        For Get Key (51), wait until a keystroke is queued before
            *        returning.
            * NWAIT	No wait period applies. Wait (4) and Get Key (51) calls
            *        each check their respective status and return immediately
            */

           /* TRON/TROFF
            * Determine whether to enable or disable Windows HLLAPI tracing.
            * The information in the trace is intended to help debug a Windows
            * HLLAPI program. Tracing is turned off when the Windows HLLAPI
            * program ends or when TROFF is specified.
            *
            * TROFF	Turn tracing off.
            * TRON	Turn tracing on. With tracing enabled, all executed Windows
            *        HLLAPI functions are traced.
            */

           /* EAB/NOEAB
            * Determine whether to include extended attributes (EABs) or not.
            *
            * Applies to Copy Presentation Space (5), Copy Presentation Space
            * to String (8), Copy String to Presentation Space (15),
            * Copy String to Field (33) and Copy Field to String (34).
            *
            * EAB	   Include extended attributes (EABs) with Data String.
            *        Since there is an EAB for every character that displays,
            *        you must define Data String to be twice the size of the Host
            *        session presentation space or field.
            * NOEAB	Do not include any extended attributes (EABs) with Data
            *        String (no EABs). This is the default setting.
            */


           /* XLATE/NOXLATE
            * Determine the translation of extended attributes (EABs).
            *
            * Applies to Copy Presentation Space (5), Copy Presentation Space to
            * String (8) and Copy Field to String (34).
            *
            * XLATE	   Translate extended attributes (EABs) into CGA colors.
				* NOXLATE	Do not translate extended attributes (EABs).
            */

           /* CONLOG/CONPHYS
            * Specify which application will be the foreground application
            * when connecting to a session.
            *
            * Applies to Connect Presentation Space (1).
            *
            * CONLOG	  After connection, your Windows HLLAPI application remains
            *          the foreground application. CONLOG is the default setting.
            * CONPHYS  After connection, the specified session becomes the
            *          foreground application, updating the session and accepting
            *          keyboard input. Your Windows HLLAPI application can still
            *          access the session (to monitor for a specific event,
            *          for example). To return foreground control to your
            *          Windows HLLAPI application, call Disconnect
            *          Presentation Space (2).
            */

           /* OLDOIA/NEWOIA
            * Specify the format for the data returned from Copy OIA (13).
            *
            * OLDOIA	Data returned in 3270 PC format.
				* NEWOIA	Data is returned in ASCII format.
            */

           /* NOCFGSIZE/CFGSIZE
            * Determine the presentation space size returned by Query Sessions (10).
            *
            * NOCFGSIZE	Returns the current size of the connected presentation space.
            * CFGSIZE	Returns the configured size of the presentation space
            *           thereby ignoring any override of the presentation space
            *           by the host.
            */

           /* DISPLAY/NODISPLAY
            * Specify whether nondisplay fields will be copied using
            * Copy Presentation Space (5), Copy Presentation Space to String (8),
            * Copy OIA (13), Copy String to Presentation Space (15),
            * Copy String to Field (33), and Copy Field to String (34).
            *
            * DISPLAY	Nondisplay fields are copied to the target buffer in
            *           the same manner as display fields.
				* NODISPLAY	Nondisplay fields are copied as a string of nulls
            *           to the target buffer. This allows applications to
            *           display the copied buffer in the presentation window
            *           without displaying confidential information,
            *           such as passwords.
            */

           /* WRITE_SUPER/WRITE_WRITE/WRITE_READ/
            * WRITE_NONE/SUPER_WRITE/READ_WRITE
            * Specify whether a Windows HLLAPI application can or will share
            * the presentation space to which it is connected with another
            * application using Connect Presentation Space (1) and
            * Connect PM Window Services (101).
            *
            * WRITE_SUPER	Set by a Windows HLLAPI application that requires write
            *              access and allows only supervisory applications
            *              to connect to its presentation space.
				* WRITE_WRITE	Set by a Windows HLLAPI application that requires write
            *              access and allows other applications that have
            *              predictable behavior to connect to its presentation space.
            * WRITE_READ	Set by a Windows HLLAPI application that requires write
            *              access and allows other applications to use read-only
            *              functions on its connected presentation space.
            * WRITE_NONE	Set by a Windows HLLAPI application that requires exclusive
            *              access to the connected presentation space.
            *              No other applications, not even supervisory,
            *              will have access to its presentation space.
            * SUPER_WRITE	Set by a Windows HLLAPI supervisory application allowing
            *              applications with write access to share the connected
            *              presentation space. The application setting this parameter
            *              will not cause errors for other application but provide
            *              only supervisory-type functions.
            * READ_WRITE	Set by a Windows HLLAPI application that requires read-only
            *              access and allows other applications that perform read-only
            *              functions to connect to its presentation space.
            */

           /* NOKEY/KEY$nnnnnnnn
            * Allow applications that have sharing requirements to limit access
            * to a partner application (i.e. an application developed to work
            * with it).
            *
            * NOKEY	      Allows the application to be compatible with existing
            *              applications that do not specify the KEY parameter.
            * KEY$nnnnnnn	Specify the keyword to restrict sharing of the presentation
            *              space. The keyword must be exactly 8-bytes long.
            */

           /* CERTPATH=
            * filepath     Especifica o caminho de arquivo que contém o certificado de
            *              usuário, necessário para estabelecer uma conexão segura com
            *              o "Host", que será solicitada a seguir.
				*				   Afeta a função CONNECTPS (função 1).
            *
            *              Este caminho deve conter a unidade de  disco (rígido,
            *              removível, "token" ou outra mídia), diretórios/subdiretórios
            *              e o nome do arquivo com extensão ".pfx" ou ".p12", onde está
            *              o certificado a ser utilizado na conexão. Não é permitido o
            *              uso de espaços precedendo ou seguindo o símbolo de igual ("=").
            */

           /* CERTPWD=
            * senha        Especifica a senha do arquivo que contém o certificado de
            *              usuário, cujo caminho foi informado pelo parâmetro anterior.
            *              Afeta a função CONNECTPS (função 1).
            *
            *              Deverá ser fornecida imediatamente antes do acionamento da
            *              função CONNECTPS.
				*				   Para maior segurança ela será destruída imediatamente após
            *              ter sido feito o acesso ao certificado (com sucesso ou não).
            *              Isto significa que a cada nova tentativa de conexão a senha
            *              deverá ser fornecida novamente.
            */


           memset (byString+byStringLen,NULL,1);
           numParms = 0;
           ptrString = (char*)byString;
           parmOk = false;

           // Parsing SESSIONPARAMETERS
           for (i=0; i < MAXPARMS; i++)
            {
             ptrDelimiter = strchr(ptrString,parmDelimiter);
             if (ptrDelimiter)
               bufferLen = ptrDelimiter-ptrString;
             else
              {
               bufferLen = byStringLen-(ptrString-(char*)byString);
               parmOk = true;
              }
             if (bufferLen)
              {
               sessionParms[i] = new char[bufferLen+1];
               strncpy(sessionParms[i],ptrString, bufferLen);
               sessionParms[i][bufferLen] = NULL;
               numParms++;
               ptrString = ptrDelimiter + 1;
               if (ptrString > ((char*)byString+byStringLen))
                parmOk = true;
              }
             if (parmOk)
              break;
            }

           // Checking each one parm received
           if (numParms)
            {
             // Checking for Parm Length integrity
             if (strlen(sessionParms[0]) > MAXPARMLENGTH )
               returnCode = WHLLPARAMETERERROR;
             else
              {
               // Parm Length is Ok

               //Reset command parm area
               parmOk = false;
               numParmOk = 0;
               for (i=0; i<numParms; i++)
                {
                 if (!strcmp(sessionParms[i], "STRLEN"))
                  {
                   //STRLEN parm
                   parmOk = true;
                   wHllOpts->strEOT = false;
                  }
                 else if (!strcmp(sessionParms[i], "STREOT"))
                  {
                   //STREOT parm
                   parmOk = true;
                   wHllOpts->strEOT = true;
                   wHllOpts->eotChar = NULL;
                  }
                 else if (!strncmp(sessionParms[i], "EOT=", 4))
                  {
                   //EOT=c parm
                   parmOk = true;
                   wHllOpts->strEOT = true;
                   wHllOpts->eotChar = sessionParms[i][4];
                  }
                 else if (!strcmp(sessionParms[i], "SRCHALL"))
                  {
                   //SRCHALL parm
                   parmOk = true;
                   wHllOpts->searchAll = true;
                  }
                 else if (!strcmp(sessionParms[i], "SRCHFROM"))
                  {
                   //SRCHFROM parm
                   parmOk = true;
                   wHllOpts->searchAll = false;
                  }
                 else if (!strcmp(sessionParms[i], "SRCHFRWD"))
                  {
                   //SRCHFRWD parm
                   parmOk = true;
                   wHllOpts->searchFwd = true;
                  }
                 else if (!strcmp(sessionParms[i], "SRCHBKWD"))
                  {
                   //SRCHBKWD parm
                   parmOk = true;
                   wHllOpts->searchFwd = false;
                  }
                 else if (!strcmp(sessionParms[i], "NOATTRB"))
                  {
                   //NOATTRB parm
                   parmOk = true;
                   wHllOpts->noAttrb = true;
                  }
                 else if (!strcmp(sessionParms[i], "ATTRB"))
                  {
                   //ATTRB parm
                   parmOk = true;
                   wHllOpts->noAttrb = false;
                  }
                 else if (!strcmp(sessionParms[i], "FPAUSE"))
                  {
                   //FPAUSE	parm
                   parmOk = true;
                   wHllOpts->fPause = true;
                  }
                 else if (!strcmp(sessionParms[i], "IPAUSE"))
                  {
                   //IPAUSE	parm
                   parmOk = true;
                   wHllOpts->fPause = false;
                  }
                 else if (!strcmp(sessionParms[i], "NOQUIET"))
                  {
                   //NOQUIET	parm
                   parmOk = true;
                   wHllOpts->xmitFileQuiet = false;
                  }
                 else if (!strcmp(sessionParms[i], "QUIET"))
                  {
                   //QUIET	parm
                   parmOk = true;
                   wHllOpts->xmitFileQuiet = true;
                  }
                 else if (!strncmp(sessionParms[i], "TIMEOUT=", 8))
                  {
                   //TIMEOUT=c parm
                   parmOk = true;
                   wHllOpts->timeOut = sessionParms[i][8];
                  }
                 else if (!strncmp(sessionParms[i], "ESC=", 4))
                  {
                   //ESC=c parm
                   parmOk = true;
                   wHllOpts->escapePFKChar = sessionParms[i][4];
                  }
                 else if (!strcmp(sessionParms[i], "AUTORESET"))
                  {
                   //AUTORESET	parm
                   parmOk = true;
                   wHllOpts->autoReset = true;
                  }
                 else if (!strcmp(sessionParms[i], "NORESET"))
                  {
                   //NORESET	parm
                   parmOk = true;
                   wHllOpts->autoReset = false;
                  }
                 else if (!strcmp(sessionParms[i], "TWAIT"))
                  {
                   //TWAIT	parm
                   parmOk = true;
                   wHllOpts->waitPeriod = TWAIT;
                  }
                 else if (!strcmp(sessionParms[i], "LWAIT"))
                  {
                   //LWAIT	parm
                   parmOk = true;
                   wHllOpts->waitPeriod = LWAIT;
                  }
                 else if (!strcmp(sessionParms[i], "NWAIT"))
                  {
                   //NWAIT	parm
                   parmOk = true;
                   wHllOpts->waitPeriod = NWAIT;
                  }
                 else if (!strcmp(sessionParms[i], "TRON"))
                  {
                   //TRON	parm
                   parmOk = true;
                   wHllOpts->traceOn = true;
                  }
                 else if (!strcmp(sessionParms[i], "TROFF"))
                  {
                   //TROFF	parm
                   parmOk = true;
                   wHllOpts->traceOn = false;
                  }
                 else if (!strcmp(sessionParms[i], "EAB"))
                  {
                   //EAB	parm
                   parmOk = true;
                   wHllOpts->noEAB = false;
                  }
                 else if (!strcmp(sessionParms[i], "NOEAB"))
                  {
                   //NOEAB	parm
                   parmOk = true;
                   wHllOpts->noEAB = true;
                  }
                 else if (!strcmp(sessionParms[i], "XLAT"))
                  {
                   //XLAT	parm
                   parmOk = true;
                   wHllOpts->eabXlat = true;
                  }
                 else if (!strcmp(sessionParms[i], "NOXLAT"))
                  {
                   //NOXLAT	parm
                   parmOk = true;
                   wHllOpts->eabXlat = false;
                  }
                 else if (!strcmp(sessionParms[i], "CONLOG"))
                  {
                   //CONLOG	parm
                   parmOk = true;
                   wHllOpts->conLog = true;
                  }
                 else if (!strcmp(sessionParms[i], "CONPHYS"))
                  {
                   //CONPHYS	parm
                   parmOk = true;
                   wHllOpts->conLog = false;
                  }
                 else if (!strcmp(sessionParms[i], "NEWOIA"))
                  {
                   //NEWOIA	parm
                   parmOk = true;
                   wHllOpts->newOIA = true;
                  }
                 else if (!strcmp(sessionParms[i], "OLDOIA"))
                  {
                   //OLDOIA	parm
                   parmOk = true;
                   wHllOpts->newOIA = false;
                  }
                 else if (!strcmp(sessionParms[i], "CFGSIZE"))
                  {
                   //CFGSIZE	parm
                   parmOk = true;
                   wHllOpts->cfgSize = true;
                  }
                 else if (!strcmp(sessionParms[i], "NOCFGSIZE"))
                  {
                   //NOCFGSIZE	parm
                   parmOk = true;
                   wHllOpts->cfgSize = false;
                  }
                 else if (!strcmp(sessionParms[i], "NODISPLAY"))
                  {
                   //NODISPLAY  parm
                   parmOk = true;
                   wHllOpts->noDisplay = true;
                  }
                 else if (!strcmp(sessionParms[i], "DISPLAY"))
                  {
                   //DISPLAY  parm
                   parmOk = true;
                   wHllOpts->noDisplay = false;
                  }
                 else if (!strcmp(sessionParms[i], "WRITE_SUPER"))
                  {
                   //WRITE_SUPER	parm
                   parmOk = true;
                   wHllOpts->psShare = PS_WRITE_SUPER;
                  }
                 else if (!strcmp(sessionParms[i], "WRITE_WRITE"))
                  {
                   //WRITE_WRITE	parm
                   parmOk = true;
                   wHllOpts->psShare = PS_WRITE_WRITE;
                  }
                 else if (!strcmp(sessionParms[i], "WRITE_READ"))
                  {
                   //WRITE_READ	parm
                   parmOk = true;
                   wHllOpts->psShare = PS_WRITE_READ;
                  }
                 else if (!strcmp(sessionParms[i], "WRITE_NONE"))
                  {
                   //WRITE_NONE	parm
                   parmOk = true;
                   wHllOpts->psShare = PS_WRITE_NONE;
                  }
                 else if (!strcmp(sessionParms[i], "SUPER_WRITE"))
                  {
                   //SUPER_WRITE	parm
                   parmOk = true;
                   wHllOpts->psShare = PS_SUPER_WRITE;
                  }
                 else if (!strcmp(sessionParms[i], "READ_WRITE"))
                  {
                   //READ_WRITE	parm
                   parmOk = true;
                   wHllOpts->psShare = PS_READ_WRITE;
                  }
                 else if (!strcmp(sessionParms[i], "NOKEY"))
                  {
                   //NOKEY	parm
                   parmOk = true;
                   wHllOpts->keyWord[0] = NULL;
                  }
                 else if (!strncmp(sessionParms[i], "KEY$", 4))
                  {
                   //KEY$nnnnnnnn parm:
                   
                   // See comments about password checking that
                   // is immediately below "case CONNECTPS"....

                   parmOk = true;
                   strcpy(wHllOpts->keyWord, &sessionParms[i][4]);
                  }
                 else if (!strncmp(sessionParms[i], "CERTPATH", 8))
                  {
                   //CERTPATH=filepath  certificate filepath parm
                   parmOk = true;
                   if (hllCertPath != NULL)
                    delete [] hllCertPath;
                   hllCertPath = new char[strlen(&sessionParms[i][9])+1];
                   strcpy(hllCertPath, &sessionParms[i][9]);
                  }
                 else if (!strncmp(sessionParms[i], "CERTPWD", 7))
                  {
                   //CERTWD=password   Certificate file password parm
                   parmOk = true;
                   if (hllCertPwd != NULL)
                    delete [] hllCertPwd;
                   hllCertPwd = new char[strlen(&sessionParms[i][8])+1];
                   strcpy(hllCertPwd, &sessionParms[i][8]);
                  }

                 else parmOk = false;

                 if (parmOk)
                   numParmOk++;

                 // Delete processed session parm
                 delete [] sessionParms[i];
                 sessionParms[i] = NULL;
                }

               if ((currentHLLSession >= 0)
                 &&(ownerAppId[currentHLLSession] == thisAppId))
                { hllSessionPsShare[currentHLLSession] = wHllOpts->psShare; }

               if (numParmOk != numParms)
                {
                 byStringLen = numParmOk;
                 returnCode = WHLLPARAMETERERROR;
                }
               else returnCode = WHLLOK;
              }
            }
           else returnCode = WHLLPARAMETERERROR;

           break;

   case    STARTHOSTNOTIFICATION:
           //  Parameter				Description
			  //  Data String				A 7-byte string in the following format:
           //          	Byte 1		Short name session ID of the desired Host session, or Space or null for the current Host session.
#define SESSIONID            0      // Byte offset
           //				Byte 2		Notification mode. "P" for presentation space update only, "O" for OIA update only, "B" for both presentation space and OIA updates. When calling WinHLLAPIAsync, this position can be "A".
#define NOTIFICATIONMODE     1      // Byte offset
           //				Bytes 3-6	Not used; no error occurs if an old Windows HLLAPI application uses these positions.
           //				Byte 7		Reserved or replace with one of the following if using WinHLLAPIAsync and "A" in byte 2:  "P" for presentation space update only, "O" for OIA update only, "B" for both presentation space and OIA updates
			  //	Data Length				Length of Host event buffer (256 recommended).
           //	PS Position				NA

           // Data Length must be greater than 0
           if (byStringLen < 2)
            {
             returnCode =  WHLLPARAMETERERROR;
             break;
            }

           // Verify correctness of notifyMode informed
           unsigned char notifyMode;
           if (byString[NOTIFICATIONMODE] ==  'P')
              notifyMode = PSUPDATED;
           else if (byString[NOTIFICATIONMODE] ==  'O')
              notifyMode = PSOIAUPDATED;
           else if (byString[NOTIFICATIONMODE] ==  'B')
              notifyMode = PSBOTHUPDATED;
           else
             {
              returnCode =  WHLLPARAMETERERROR;
              break;
             }

           // On this implementation Notification is only supported
           // if referred to current session or to an short session ID (one byte name)
           if ((byString[SESSIONID] !=  0x00)
             &&(byString[SESSIONID] !=  ASCIIBLANK) )
            {
               // GetHLLSessionPtr returns the number of element in WHLLSessions
               // list that corresponds to session name to be connected to.
               // if it returns 0(zero) no matched session was found.
               char shortId[2];
               memcpy (&shortId[0],&byString[SESSIONID],1);
               memset (&shortId[1],NULL,1);
               strupr(shortId);
               childIndex =  GetHLLSessionPtr(shortId);
               if (childIndex)
                {
                 childIndex -= 1; //Set index related to 0(zero)
                 // Get Session pointer
                 child = (ALFFMDIChild*)hllSessions[childIndex];
                }
               else
                {
                 // Verify if referred session exists
                 ALFFConnData connData;
                 ALFFConnectDlg connDlg(this, &connData, IDD_ALFFCONNECT);
	              if ( (!connDlg.LoadConnection(shortId))
                    ||(!strcmp(connData.hostName,"Enter HostName")) )
                  {
                   returnCode =  WHLLNOTCONNECTED;
                   break;
                  }
                 else
                  {
                   // Session is defined: create child session but not connected to host
                   if (wHllSessionCount < MAXWHLLSESSIONS)
                    {
                     childIndex = wHllSessionCount++;
                     child = (ALFFMDIChild*)CreateSession(NULL, WHLLAPISESSION);
                     if (child)
                      {
                       // Session was created ok, so associate the Tec3270 session ptr to it
                       hllSessions[childIndex] = child;

                       // Creating and storing its name on Tec3270 sessions defined
                       hllSessionName[childIndex] = new char[strlen(shortId)+1];
                       strcpy(hllSessionName[childIndex], shortId);

                       // Inherit PS Share from APP Options
                       hllSessionPsShare[childIndex] = wHllOpts->psShare;

                       // This session is now owned by thisAppId app
                       ownerAppId[childIndex] = thisAppId;
                       ownerAppIndex[childIndex] = currentHLLApp;

                       // Assure that child is an WHLL session, because it is
                       // normally done on CONNECTPS.
                       child->SetWHLLSession(true);

                       // Do not need to set App current Session index
                       // It will be done when CONNECTPS is executed (if not executed yet)
                      }
                     else
                      {
                       returnCode =  WHLLSYSERROR;
                       extendedError = TEC3270_WHLLNO3270SESSION;
                       break;
                      }
                    }
                   else
                    {
                     returnCode =  WHLLSYSERROR;
                     extendedError = TEC3270_WHLLMAXSESSEXCEEDED;
                     break;
                    }
                  } // else ....LoadConnection
                } // else if childIndex
            }
           else child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           if (child)
             child->SetWHLLHostNotification(notifyMode);
           else
            {
             returnCode =  WHLLSYSERROR;
             extendedError = TEC3270_WHLLNO3270SESSION;
             break;
            }
           returnCode = WHLLOK;

           break;

   case    STOPHOSTNOTIFICATION:
           // Data Length must be greater than 0
           if (!byStringLen)
            {
             returnCode =  WHLLPARAMETERERROR;
             break;
            }

           // On this implementation Notification is only supported
           // if referred to current session or to an short session ID (one byte name)
           // for what all validations was done and STARTHOSTNOTIFICATION was already executed.
           if ((byString[SESSIONID] !=  0x00)
             &&(byString[SESSIONID] !=  ASCIIBLANK) )
            {
               // GetHLLSessionPtr returns the number of element in WHLLSessions
               // list that corresponds to session name to be connected to.
               // if it returns 0(zero) no matched session was found.
               char shortId[2];
               memcpy (&shortId[0],&byString[SESSIONID],1);
               memset (&shortId[1],NULL,1);
               strupr(shortId);
               childIndex =  GetHLLSessionPtr(shortId);
               if (childIndex)
                 childIndex -= 1; //Set index related to 0(zero)
               else
                {
                 returnCode =  WHLLNOTCONNECTED;
                 break;
                }
            }
           else childIndex = currentHLLSession;

           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[childIndex];

           if ( (child)
              &&(child->IsWHLLHostNotifying()) )
            {
              child->SetWHLLHostNotification(PSNONOTIFY);
              returnCode = WHLLOK;
            }
           else returnCode = WHLLNOTAVAILABLE;

           break;

   case    QUERYHOSTUPDATE:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
            {
             returnCode = WHLLNOTCONNECTED;
             break;
            }

           // Data Length must be greater than 0
           if (!byStringLen)
            {
             returnCode =  WHLLPARAMETERERROR;
             break;
            }

           // On this implementation Notification is only supported
           // if referred to current session or to an short session ID (one byte name)
           if ((byString[SESSIONID] !=  0x00)
             &&(byString[SESSIONID] !=  ASCIIBLANK) )
            {
               // GetHLLSessionPtr returns the number of element in WHLLSessions
               // list that corresponds to session name to be connected to.
               // if it returns 0(zero) no matched session was found.
               char shortId[2];
               memcpy (&shortId[0],&byString[SESSIONID],1);
               memset (&shortId[1],NULL,1);
               strupr(shortId);
               childIndex =  GetHLLSessionPtr(shortId);
               if (childIndex)
                 childIndex -= 1; //Set index related to 0(zero)
               else
                {
                 returnCode =  WHLLNOTCONNECTED;
                 break;
                }
            }
           else childIndex = currentHLLSession;

           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[childIndex];

           if ( (child)
              &&(child->IsWHLLHostNotifying()) )
            {
              int notifyType = child->GetWHLLPSChangeType();
              if (notifyType == PSUPDATED)
                returnCode = WHLLPSUPDATE;
              else if (notifyType == PSOIAUPDATED)
                returnCode = WHLLOIAUPDATE;
              else if (notifyType == PSBOTHUPDATED)
                returnCode = WHLLBOTHUPDATE;
              else returnCode = WHLLOK;

              // Reset PS or OIA Changes flag
              child->SetWHLLPSChanged(PSNOTCHANGED);
            }
           else returnCode = WHLLNOTAVAILABLE;

           break;

   case    RESETSYSTEM:
           // Set App Connected to not connected
           hllAppConnected[currentHLLApp] = false;
           hllSessionIndex[currentHLLApp] = -1;

		     // We must decrement the number of apps connected to this session, but
		     // only if it is not owned by thisAppId, otherwise it will be deleted ahead.

           if ( (currentHLLSession >= 0)
              &&(appsConnected[currentHLLSession])
              &&(ownerAppId[currentHLLSession] != thisAppId) )
        		 { appsConnected[currentHLLSession]--; }

           // Verify if there is any session owned by this app
           // and in this case Free it
           for (i=0; i<MAXWHLLSESSIONS; i++)
            {
             // Close all sessions owned by disconnected Application
             // All other apps connected to it will be affected !!
             if ( ownerAppId[i] == thisAppId )
               {
                 CleanupHLLSession(i);
                 wHllSessionCount--;
               }
            }

           // Reset WHLLAPI App Options
           delete wHllAppOptions[currentHLLApp];
           wHllAppOptions[currentHLLApp] = new TecWHLLAppParms();

           // thisAppId has no more sessions available;
           currentHLLSession = -1;

           returnCode = WHLLOK;
           break;

   case    COPYPS:
           psPosition = 1;  //Assume first screen position

   case    COPYPSTOSTR:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
            {
             returnCode = WHLLNOTCONNECTED;
             break;
            }

           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           // Data Length must be greater than 0
           if (commandCode == COPYPSTOSTR)
            {
             if (!byStringLen)
              {
               returnCode =  WHLLPARAMETERERROR;
               break;
              }
            }
           else  // it is COPYPS, so assume length = screenSize
            {
             // GetScrNumLines must be decremented by one for discounting status line
             byStringLen = (child->GetTerminalPtr()->GetScrNumLines()-1) *
                            child->GetTerminalPtr()->GetScrLineSize();
            }

           // PS position must be greater or equal than 0 and
           // less then session 3270 Buffer Size (this is verified on child session).
           if (psPosition >= 0)
            {

             // PS to "byString"
             returnCode = child->CopyPSToString(&byString, byStringLen, psPosition,
                                                wHllOpts->noAttrb,    // 3270 Attribute (true = translate to space, false = don't translate)
                                                wHllOpts->noEAB,      // EAB options  (true = Extended attribute bytes are not copied to the string, false = yes, they are copied)
                                                wHllOpts->eabXlat,    // EAB translation (true  = Extended attribute bytes are copied and translated into CGA colors.
                                                                      //                  false = Extended attribute bytes are returned with no changes. )
                                                wHllOpts->noDisplay); // Non display fields (true = Data in non-display fields is copied as null characters to the target buffer.
                                                                      //                     false = Data in non-display fields is copied to the target buffer.)
             if (returnCode == WHLLSYSERROR)
               extendedError = TEC3270_WHLLNO3270BUFSTR;
             else if ((returnCode == WHLLOK)
                    ||(returnCode == WHLLPSBUSY)
                    ||(returnCode == WHLLINHIBITED) )
               returnString = true;
            }
           else
            {
              returnCode = WHLLPOSITIONERROR;
              break;
            }
           break;

   // Write on Screen Buffer
   case    COPYSTRTOPS:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
           {
             returnCode = WHLLNOTCONNECTED;
             break;
           }

           // Data Length must be greater than 0
           if(!byStringLen)
            {
             returnCode =  WHLLPARAMETERERROR;
             break;
            }

           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           // PS position must be greater or equal than 0 and
           // less then session 3270 Buffer Size (this is verified on child session).           if (psPosition >= 0)
           if (psPosition >= 0)
            {
             // PS to "byString"
             returnCode = child->CopyStringToPS(byString, byStringLen, psPosition);
             if (returnCode == WHLLSYSERROR)
               extendedError = TEC3270_WHLLNO3270BUFSTR;
            }
           else
            {
              returnCode = WHLLPOSITIONERROR;
              break;
            }
           break;

   // Send Keystrokes to PS
   case    SENDKEY:
           // Data Length must be greater than 0
           if(!byStringLen)
            {
             returnCode =  WHLLPARAMETERERROR;
             break;
            }

           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
           {
             returnCode = WHLLNOTCONNECTED;
             byStringLen = 0;
             break;
           }

           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           if (child)
            {
             if (psPosition == SENDKEYNEXT)
              {
               if (child->IsWaitingHostResponse())
                {
                 byStringLen = 0;
                 returnCode = WHLLPSBUSY;
                 break;
                }
               else if (child->GetTerminalPtr()->IsKeyboardLocked())
                {
                 byStringLen = 0;
                 returnCode = WHLLINHIBITED;
                 break;
                }
              }

             // Send Key strokes until next AID (an keystroke sequence)
             returnCode = child->SendKeyStrokes(byString, byStringLen,
                                                wHllOpts->autoReset,
                                                wHllOpts->escapePFKChar);
             if (returnCode == WHLLSYSERROR)
               extendedError = TEC3270_WHLLNO3270SESSION;
            }
           else
            {
              returnCode = WHLLSYSERROR;
              extendedError = TEC3270_WHLLNO3270SESSION;
            }
           break;

   // Query Client or Server Certificate on Secured Connections
   case    QUERYCLIENTCERTIFICATE:
   case    QUERYSERVERCERTIFICATE:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
           {
             returnCode = WHLLNOTCONNECTED;
             break;
           }

           // Data Length must be greater than 0
           if (!byStringLen)
            {
             returnCode =  WHLLPARAMETERERROR;
             break;
            }

           bool isClient;
           if (commandCode == QUERYCLIENTCERTIFICATE)
             isClient = true;
           else isClient = false;

           // Locate Session pointer for asking about the cert info
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           // Checking if this session is an secured connection
           if (!child->IsSSLConnected() )
            {
             returnCode =  WHLLUNAVAILABLE;
             break;
            }

           // PS position must be one of the following "query types".
           switch (psPosition)
            {
             case    WHLL_QUERY_CERTIFICATE_ISSUER:
                     tempString = child->QueryCertInfo(isClient, QUERYCERTISSUER);
                     break;
             case    WHLL_QUERY_CERTIFICATE_SUBJECT:
                     tempString = child->QueryCertInfo(isClient, QUERYCERTSUBJECT);
                     break;
             case    WHLL_QUERY_CERTIFICATE_NOTBEFORE:
                     tempString = child->QueryCertInfo(isClient, QUERYCERTNOTBEFORE);
                     break;
             case    WHLL_QUERY_CERTIFICATE_NOTAFTER:
                     tempString = child->QueryCertInfo(isClient, QUERYCERTNOTAFTER);
                     break;
             case    WHLL_QUERY_CERTIFICATE_SUBJECTALTNAMES:
                     tempString = child->QueryCertInfo(isClient, QUERYCERTSUBJECTALTNAME);
                     break;
             default : returnCode = WHLLPOSITIONERROR;
                       break;
            }
           tempStringLen = tempString.length();
           if (tempStringLen)
            {
             returnString = true;
             if (byStringLen >= tempStringLen)
              {
               memcpy (byString, tempString.c_str(), tempStringLen);
               byStringLen = (WORD)tempStringLen;
               returnCode = WHLLOK;
              }
             else
              {
               memcpy (byString, tempString.c_str(), byStringLen);
               returnCode = WHLLTRUNCATED;
              }
            }
           else returnCode = WHLLNOFIELD;

           break;

   case    PAUSE:
           // Pause function timeout is processed on WHLLApi client
           // Here, on server, we need just to inform if PS was changed or
           // not, depending upon STARTHOSTNOTIFICATION function have been called before.
           if ((wHllOpts) && (!wHllOpts->fPause) )
            {
             //This is an interruptible pause, so we to to verify host notification
             //if there is any session active
             ALFFMDIChild* sessionPtr = (ALFFMDIChild*)hllSessions[currentHLLSession];
             if ((sessionPtr)
               &&(sessionPtr->IsWHLLPSChanged()) )
              // If STARTHOSTNOTIFICATION was not called before,
              // following parameter (isPSChanged) will be always false;
              {
               isPSChanged = true;
               returnCode = WHLLPSCHANGED;
              }
             else
              {
               isPSChanged = false;
               returnCode  = WHLLOK;
              }
            }
           else
            {
             isPSChanged = false;
             returnCode  = WHLLOK;
            }
           break;

   case    WAIT:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
           {
             returnCode = WHLLNOTCONNECTED;
             break;
           }
           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           if (child)
            {
             if (!child->GetTerminalPtr()->IsMode3270())
              {
               returnCode = WHLLNOTCONNECTED;
               break;
              }
             else if (child->IsWaitingHostResponse())
              {
               returnCode = WHLLPSBUSY;
               break;
              }
             else if (child->GetTerminalPtr()->IsKeyboardLocked())
              {
               returnCode = WHLLINHIBITED;
               break;
              }
             else
              {
               returnCode = WHLLOK;
               break;
              }
            }
           else
            {
              returnCode = WHLLSYSERROR;
              extendedError = TEC3270_WHLLNO3270SESSION;
            }
           break;

   case    SETCURSOR:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
           {
             returnCode = WHLLNOTCONNECTED;
             break;
           }
           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           if (child)
            {
             if (child->IsWaitingHostResponse())
              {
               returnCode = WHLLPSBUSY;
               break;
              }
             // GetScrNumLines must be decremented by one for discounting status line
             int screenSize = (child->GetTerminalPtr()->GetScrNumLines()-1) *
                              child->GetTerminalPtr()->GetScrLineSize();
             if ((psPosition > 0) && (psPosition <= screenSize))
              {
               // PSPosition is relative to 1, and SetCursor expects relative to 0,
               // so subtract 1 from it.
#define SETCURSORONSCREEN true
               child->GetTerminalPtr()->SetCursorPos(psPosition-1, SETCURSORONSCREEN);
               returnCode = WHLLOK;
              }
             else returnCode = WHLLPOSITIONERROR;
            }
           else
            {
             returnCode = WHLLSYSERROR;
             extendedError = TEC3270_WHLLNO3270SESSION;
            }
           break;

   case    QUERYCURSORLOC:
           // PS must be connect prior to using this function
           if ((!hllAppConnected[currentHLLApp])
             ||(currentHLLSession == -1))
           {
             returnCode = WHLLNOTCONNECTED;
             break;
           }
           // Locate Session pointer
           child = (ALFFMDIChild*)hllSessions[currentHLLSession];

           if (child)
            {
             // GetCursorPos returns cursor position relative to 0, so add 1.
             byStringLen = LOWORD(child->GetTerminalPtr()->GetCursorPos()+1);
             returnCode = WHLLOK;
            }
           else
            {
             returnCode = WHLLSYSERROR;
             extendedError = TEC3270_WHLLNO3270SESSION;
            }
           break;

   default:returnCode = WHLLNOTAVAILABLE;
           byStringLen = 0;
           break;
  }
 }
else
 {
  returnCode = WHLLSYSERROR;
  extendedError = TEC3270_WHLLMAXAPPEXCEEDED;
 }

 /*
  * Buffer Layout for exchanging data with client:
  *
  *   Field Name:  Comm  Ret   Extd  Data      Data
  *                Code  Code  Error Length    Buffer Bytes
  *               |LL,HH|LL,HH|LL,HH|LL,HH|___________..........._|
  *               |-----|-----|-----|-----|-----------------------|
  *   Byte Pos.:  0     2     4     6     8                       n
  */
 int bufLen;
 if ((commandCode == SETSESSIONPARAMETERS)
   ||(commandCode == PAUSE))
  {
   // We need to reserve space on commandOutBuffer to receive AppOptions struct
   bufLen = RETURNEDPARMSLEN + DATAOFFSET;
   //If any parameter is bad byStringlen will contain number of parms ok !!
   //byStringLen = RETURNEDPARMSLEN;
   returnString = true;
  }
 else if (returnString)
   bufLen = byStringLen+DATAOFFSET;
 else
  {
    bufLen = DATAOFFSET;
    //byStringLen = 0;  // Some functions return data on byStringLen (QUERYCURSORLOC is one)
  }

 // Initialize Output Buffer
 unsigned char* commandBufferOut = new unsigned char[bufLen];
 memset (commandBufferOut, NULL, bufLen);

 // Building Output Buffer
 memcpy (commandBufferOut+CCODEOFFSET, &commandCode, 2);
 memcpy (commandBufferOut+RETCODEOFFSET, &returnCode, 2);
 memcpy (commandBufferOut+EXTDERROROFFSET, &extendedError, 2);
 memcpy (commandBufferOut+DATALENOFFSET, &byStringLen, 2);
 if (returnString)
  {
   if ( commandCode == SETSESSIONPARAMETERS)
    {
     // We need to send AppOptions to be updated on WHLLAPI client
     // Trace Option
     if (wHllOpts->traceOn)
       commandBufferOut[DATAOFFSET+TRACEOFFSET] = 0x01;
     else commandBufferOut[DATAOFFSET+TRACEOFFSET] = 0x00;

     // Pause Option
     if (wHllOpts->fPause)
       commandBufferOut[DATAOFFSET+PAUSEOFFSET] = 0x01;
     else commandBufferOut[DATAOFFSET+PAUSEOFFSET] = 0x00;

     // STRLEN/STREOT Option
     if (wHllOpts->strEOT)
       commandBufferOut[DATAOFFSET+STREOTOFFSET] = 0x01;
     else commandBufferOut[DATAOFFSET+STREOTOFFSET] = 0x00;

     // EOT Char Option
     if (wHllOpts->strEOT)
       commandBufferOut[DATAOFFSET+EOTCHAROFFSET] = wHllOpts->eotChar;
     else commandBufferOut[DATAOFFSET+EOTCHAROFFSET] = 0x00;

     // TWAIT / LWAIT / NWAIT options
     commandBufferOut[DATAOFFSET+WAITOFFSET] = wHllOpts->waitPeriod;
    }
   else if ( commandCode == PAUSE)
    {
     if (isPSChanged)
       commandBufferOut[DATAOFFSET+PSCHANGEDOFFSET] = 0x01;
     else commandBufferOut[DATAOFFSET+PSCHANGEDOFFSET] = 0x00;
    }
   else memcpy (commandBufferOut+DATAOFFSET, byString, byStringLen);
  }

 // Save Data for further retrieving on ReturnData Method
 if (currentHLLApp >= 0)
    outData[currentHLLApp] = MakeData(commandBufferOut, bufLen, itemWHLLCommand);
 else outData[MAXWHLLAPPS+1] = MakeData(commandBufferOut, bufLen, itemWHLLCommand);

 if (commandBuffer != NULL)
   delete [] commandBuffer;

 delete [] commandBufferOut;

 return (HDDEDATA)DDE_FACK;
}


void
ALFFMDIClient::NotifyDisconnect(HCONV disconnectedAppId)
{
  int disconnectedApp = GetHLLAppPtr(disconnectedAppId);
  if (disconnectedApp)
   {
    disconnectedApp -= 1;  // Set index related to 0(zero);
    // Set AppId to none
    hllApp[disconnectedApp] = NULL;

    // Set App Connected to not connected
    hllAppConnected[disconnectedApp] = false;

    int appHLLSession = hllSessionIndex[disconnectedApp];

    // We must decrement the number of apps connected to this session, but
    // only if it is not owned by thisAppId, otherwise it will be deleted ahead.
    if ((appHLLSession >=0)
      &&(appsConnected[appHLLSession]) )
       appsConnected[appHLLSession]--;

    // Set App Session Index to none
    hllSessionIndex[disconnectedApp] = -1;

    // Delete WHLLAPI App Options (Set by SETSESSIONPARAMETERS function)
    delete wHllAppOptions[disconnectedApp];
    wHllAppOptions[disconnectedApp] = NULL;

    // Verify if there is any session owned by this app
    // and in this case Free it
    for (int i=0; i<MAXWHLLSESSIONS; i++)
     {
      // Close all sessions owned by disconnected Application
      // All other apps connected to it will be affected !!
      if (ownerAppId[i] == disconnectedAppId)
        {
         CleanupHLLSession(i);
         wHllSessionCount--;
        }
     }
   }
  ALFFDdeServer::NotifyDisconnect(disconnectedAppId);
}

void
ALFFMDIClient::CleanupHLLSession(int appHLLSession)
{
 if (appHLLSession >= 0)
  {
   // Close the Tec3270 session associated if there is any
   if (hllSessions[appHLLSession])
    {
     ALFFMDIChild* child = (ALFFMDIChild*)hllSessions[appHLLSession];
     child->SetWHLLClosing(true);
     CloseSession(child);
     hllSessions[appHLLSession] = NULL;
    }

   // Deleting Tec3270 sessions defined name
   if (hllSessionName[appHLLSession])
    {
     delete hllSessionName[appHLLSession];
     hllSessionName[appHLLSession] = NULL;
    }

   // Reset session controls to its initial values
   hllSessionPsShare[appHLLSession] = PS_WRITE_NONE;
   ownerAppId[appHLLSession] = NULL;
   ownerAppIndex[appHLLSession] = -1;
   appsConnected[appHLLSession] = 0;
  }
}

//////////////////////////////////////////////////////////
// ALFFMDIClient
// ===========
// MDIClient site initialization.
void
ALFFMDIClient::SetupWindow ()
{
 // Default SetUpWindow processing.
 TMDIClient::SetupWindow ();

 // Set Message for further MDI Initializations;
 PostMessage(MSG_INIT_MDI,0,0);
}

LRESULT
ALFFMDIClient::DoMDIInit(WPARAM,LPARAM)
{
#ifdef DEBUG32
 MessageBox("Iniciando DoMDIInit","Tec3270 Debug",MB_OK);
#endif
 char iniSection[36];
 /* Get the Application IniFile Pointer*/
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(),Tec3270App);
 ALFFIniFile* iniFile = theApp->GetIniFile();

 /* Get Sessions Automation From Ini File and Start All of It */
 strcpy(iniSection,"AUTOMATIC CONNECTIONS");
 int autoInact = iniFile->GetInt(iniSection,"STATUS",1);

#ifdef DEBUG32
 MessageBox("Obtendo Status do Auto Connect ","Tec3270 Debug",MB_OK);
#endif

 /* If Sessions Automations Are not Inactive */
 if (!autoInact)
  {
	int lenList = MAXSESSIONS*(SESSNAMELEN+1);
	char* autoList = new char[lenList];
	memset(autoList,NULL,lenList);
	/******************************************************
	 * Getting All Automated Connections already defined  *
	 ******************************************************/

#ifdef DEBUG32
	MessageBox("Obtendo Automacoes ... ","Tec3270 Debug",MB_OK);
#endif

	if (iniFile->GetString(iniSection,NULL," ",
								 autoList,MAXSESSIONS*(SESSNAMELEN+1)) )
	 {
	  /* Process all connections that was read and build an access index */
	  sessName = new char [SESSNAMELEN+1];
	  char* pList = autoList;
	  int i = 0;
	  while (strlen(pList))
		{

#ifdef DEBUG32
		 MessageBox(pList,"Tec3270 Debug",MB_OK);
#endif

		 if (strcmp(pList,"STATUS"))
		  {
			iniFile->GetString(iniSection,pList,"---",sessName,SESSNAMELEN);

			/* Start the Conection and conect it to "sessName"  */
			i++;

#ifdef DEBUG32
			MessageBox("Abrindo Conexao...","Tec3270 Debug",MB_OK);
#endif
			CreateSession(sessName);
		  }
		 pList += strlen(pList)+1;
		}
	  delete [] sessName;
	  sessName = NULL;

	  /*
		* If there is more then one Automatic Started Session
		* put them side by side, else we must maximize the only one
		*/
	  if (i > 1)
		 CmTileChildrenVert();
	  else
		{
		  ALFFMDIChild *curChild = (ALFFMDIChild *)GetActiveMDIChild();
		  if (curChild)
			 curChild->ShowWindow(SW_SHOWMAXIMIZED);
		}
	 }

   delete [] autoList;

  }

 /* Get KeyPad Status From Ini File and Initialize it if status is active */
 char format[21];
 char status[21];
 TPoint kPadPos;
 strcpy(iniSection,"KEYPAD");

 iniFile->GetString(iniSection,"STATUS","",status, 21);
 iniFile->GetString(iniSection,"FORMAT","",format, 21);
 kPadPos.x = iniFile->GetInt(iniSection,"X",0);
 kPadPos.y =  iniFile->GetInt(iniSection,"Y",0);

 if (!strcmp(status,"ACTIVE"))
  {
	/* KeyPad Status At Last Execution Was Active, So Take it Back */
	int  kPadType = 0;
	if (!strcmp(format,"HORIZONTAL"))
	 kPadType = HORIZKPAD;
	else if (!strcmp(format,"VERTICAL"))
			 kPadType = VERTKPAD;
	else throw (TXOwl(IDS_ALFFINIERROR));
	TRect mRect = GetApplication()->GetMainWindow()->GetWindowRect();
	TPoint wCenter = TPoint(mRect.left+(mRect.Width()/2),
								  (mRect.top + mRect.Height()));
	ALFFChooseKeyPad(this, TResId(IDD_ALFFCHOOSEKEYPAD),&KeyPad,kPadType).
						  GetKeyPad(&kPadPos);
	if (KeyPad)
	 {
	  KeyPad->Create();
	  KeyPad->Parent->SetFocus();
    }
  }

 return 1L;
}

// MDIClient KeyPad Movement to follow MainWindow Movement
void
ALFFMDIClient::CmMove(bool maximized, bool iconic)
{
 TPoint wCenter;
 TRect mRect = GetApplication()->GetMainWindow()->GetWindowRect();
 if (KeyPad)
  {
	KeyPad->ShowWindow(SW_HIDE);
	if (!maximized)
	 {
	  if (!iconic)
		{
		 if (KeyPad->IsHorizontal())
		  {
			wCenter = TPoint(mRect.left+(mRect.Width()/2),mRect.bottom);
			KeyPad->MoveTopToCenter(&wCenter);
		  }
		 else
		  {
			wCenter = TPoint(mRect.right,(mRect.top+mRect.Height()/2));
			KeyPad->MoveLeftToCenter(&wCenter);
		  }
		}
		else return;
	 }
	else
	 {
	  if (KeyPad->IsHorizontal())
		{
		 wCenter = TPoint(mRect.left+(mRect.Width()/2),
								(mRect.bottom-GetSystemMetrics(SM_CYCAPTION)));
		 KeyPad->MoveBottomToCenter(&wCenter);
		}
	  else
		{
		 wCenter = TPoint(mRect.right-GetSystemMetrics(SM_CXFRAME),
							  (mRect.top+mRect.Height()/2));
		 KeyPad->MoveRightToCenter(&wCenter);
		}
	 }
	KeyPad->ShowWindow(SW_SHOW);
	KeyPad->Parent->SetFocus();
  }
}

//////////////////////////////////////////////////////////
// ALFFMDIClient
// ===========
// Menu File Open Function
//
void
ALFFMDIClient::CmNewSession()
{
  CreateSession(sessName);
}

TMDIChild*
ALFFMDIClient::CreateSession(char *sessionName, bool isWHLL,
                                char* certPath, char* certPwd)
{
	char title[255];
	char sessHdr[STRINGMSGLEN];

	// Generate a title for the MDI child window.
	pMsgs->LoadString(IDS_SESSHEADER,sessHdr,STRINGMSGLEN-1);
	wsprintf(title, sessHdr, ++ChildCount);

#ifdef DEBUG32
	MessageBox(title,"Tec3270 Debug",MB_OK);
#endif

#ifdef DEBUG32
	MessageBox("Criando MDIChild...","Tec3270 Debug",MB_OK);
#endif

	ALFFMDIChild* child = new ALFFMDIChild(*this, title, dateFormat, 0, ChildCount);
	if (child) // Child Was Created Ok ?
	 {

#ifdef DEBUG32
	MessageBox("Executando SetIcon...","Tec3270 Debug",MB_OK);
#endif

	  ChildActive++;
	  // Associate ICON w/ this child window.
	  child->SetIconSm(GetApplication(), IDI_ALFFCONNECTIONBRK);

#ifdef DEBUG32
	MessageBox("Obtendo Active Child...","Tec3270 Debug",MB_OK);
#endif

	  // If there is any active MDI child MAXIMIZED then it should be restored.
	  ALFFMDIChild *curChild = (ALFFMDIChild *)GetActiveMDIChild();

	  /* If there is any child already maximized we need to resize it */
	  if (curChild)
	  {
#ifdef DEBUG32
	MessageBox("Executando curChild->ShowWindow...","Tec3270 Debug",MB_OK);
#endif
		long windowLong =  curChild->GetWindowLong(GWL_STYLE);
		if (windowLong & WS_MAXIMIZE)
		  curChild->ShowWindow(SW_SHOWNORMAL);
	  }
#ifdef DEBUG32
	MessageBox("Executando child->Create...","Tec3270 Debug",MB_OK);
#endif
	  child->Create();
	  //child->EnableWindow(true);

	  /* If automated sessions are being created they must be connected */
	  if (sessionName)
		{
#ifdef DEBUG32
		  MessageBox("Sessao criada. Iniciando Conexao...","Tec3270 Debug",MB_OK);
#endif
		  if (child->Connect(sessionName, isWHLL, certPath, certPwd))
         return child;
        else return NULL;
      }
     else return child;
	 }
   else
	 {
		// Child Cannot be created: Generate a message.
		pMsgs->LoadString(IDS_SESSHEADER,sessHdr,STRINGMSGLEN-1);
		wsprintf(title, sessHdr, ChildCount--);
		pMsgs->StrMessage(title,IDS_SESSCANNOTCREATE,IDS_ALFFSESSTITLE);
      return NULL;
	 }
}

// Menu File Close command
void
ALFFMDIClient::CmCloseSession()
{
 TMDIChild* curChild = GetActiveMDIChild();
 CloseSession(curChild);
}

bool
ALFFMDIClient::CloseSession(TMDIChild* oneChild)
{
 ALFFMDIChild* child = (ALFFMDIChild *) oneChild;
 if (child)
  {
	//ChildActive--;
	child->CloseWindow();
	if (!child->HWindow)
	  delete child;
   return true;
  }
 else return false;
}

LRESULT
ALFFMDIClient::CloseChild(WPARAM, LPARAM)
{
 ALFFMDIChild* curChild = (ALFFMDIChild *)GetActiveMDIChild();
 if (curChild)
  {
	curChild->Destroy();
	if (!curChild->HWindow)
	  delete curChild;
   ChildActive--;
  }
 return 1L;
}

void
ALFFMDIClient::SaveKeyPadStatus()
{
 // Save KeyPad Status and Format
 char iniSection[36];
 char format[21];
 char status[21];
 strcpy(iniSection,"KEYPAD");
 /* Get the Application IniFile Pointer*/
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(),Tec3270App);
 ALFFIniFile* iniFile = theApp->GetIniFile();

 TRect kPadPos;
 /* Save KeyPad Format And Options */
 if (KeyPad)
  {
	if (KeyPad->IsHorizontal())
	  strcpy(format,"HORIZONTAL");
	else strcpy(format,"VERTICAL");
	strcpy(status,"ACTIVE");
	kPadPos = KeyPad->GetWindowRect();
  }
 else
  {
	strcpy(format,"HORIZONTAL");
	strcpy(status,"INACTIVE");
	kPadPos = TRect(0,0,0,0);
  }
 iniFile->WriteString(iniSection,"STATUS",status);
 iniFile->WriteString(iniSection,"FORMAT",format);
 iniFile->WriteInt(iniSection,"X",kPadPos.left);
 iniFile->WriteInt(iniSection,"Y",kPadPos.top);
}

// Tec3270 Exit
void
ALFFMDIClient::CmExit()
{
 ALFFMDIChild* curChild = (ALFFMDIChild *)GetActiveMDIChild();
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
 if (curChild)
  {
	if (pMsgs->StrMessage(Title, IDS_ALFFCOMMCLOSEALL, IDS_ALFFEXITTITLE,true)
			 == IDOK )
	 {
     theApp->SetAppEnded();
     if (!CloseChildren())
      {
		  if (!(pMsgs->Message(IDS_ALFFCOMMCANNOTCLOSE,IDS_ALFFEXITTITLE,true)
         == IDOK ) )
          return;
        else
         {
          while (ChildActive)
            CloseChild(0,0);
         }
      }
	  //theApp->SetAppEnded();
	  SaveKeyPadStatus();
	  if (KeyPad)
		{
		 KeyPad->Destroy(KEYPADCLOSED);
		 delete KeyPad;
		 KeyPad = NULL;
		}
     Destroy();
	  theApp->GetMainWindow()->Destroy();
	 }
	 else return;
  }
 else
  {
	theApp->SetAppEnded();
	SaveKeyPadStatus();
	if (KeyPad)
	 {
	  KeyPad->Destroy(KEYPADCLOSED);
	  delete KeyPad;
	  KeyPad = NULL;
	 }
	Destroy();
	theApp->GetMainWindow()->Destroy();
  }
}

// Menu File Close Enabler
void
ALFFMDIClient::CmOneChildEnable (TCommandEnabler &ce)
{
 if (GetActiveMDIChild() && !monitoring)
	ce.Enable(true);
  else
	ce.Enable(false);
}


//////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Menu File Print command
void
ALFFMDIClient::CmPrint ()
{
  /* Get Application Ptr to get an Reference to App's Printer */
  Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
  /* Get Current Screen Child Pointer */
  ALFFMDIChild* curChild = (ALFFMDIChild*)GetActiveMDIChild();

#ifdef DEBUG32
	MessageBox("CmPrint: Inicio...","Tec3270 Debug",MB_OK);
#endif
  if (!theApp->Printing)
	{
		/* Create Printer object if not already created. */
		if (!theApp->Printer)
		 {
#ifdef DEBUG32
	MessageBox("CmPrint: CreatePrinter...","Tec3270 Debug",MB_OK);
#endif
		  if (!CreatePrinter())
			 return;
		 }
		if (theApp->Printer->GetSetup().Error)
		 {
#ifdef DEBUG32
	MessageBox("CmPrint: Printer->Setup...","Tec3270 Debug",MB_OK);
#endif
			theApp->Printer->Setup(this);
			if (theApp->Printer->GetSetup().Error)
			 {
				pMsgs->Message(IDS_ALFFPRTNOTAVAIL,IDS_ALFFPRTTITLE, true);
				return;
			 }
		 }

#ifdef DEBUG32
	MessageBox("CmPrint: Iniciando Impressao...","Tec3270 Debug",MB_OK);
#endif
		/* Get the Most Updated Printer Font */
		prtData->currPrtFont = theApp->GetPrtFont();

		/* Create Printout window and set characteristics */
		char prtTitle[TITLELEN];
		pMsgs->LoadString(IDS_ALFFPRINTOUTTITLE,prtTitle,TITLELEN-1);
#ifdef DEBUG32
	MessageBox("CmPrint: Criando ALFFPrintOut...","Tec3270 Debug",MB_OK);
#endif
      /*
	    * Verify if printer buffer is already available.
	    * If it is not available then it will be created just here
	    */
      if (!CreatePrinterBuffer())
       {
	     pMsgs->StrMessage("CmPrint-Printer Buffer",IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
	     return;
	    }


		ALFFPrintOut* printout;
		try {
		printout = new ALFFPrintOut(theApp->Printer,
                                  theApp->printerBuf,
                                  prtTitle,
											 curChild->GetClientWindow(),
											 prtData,
                                  NULL,   //connData not available here
                                          // (this is done out of session level)
                                          // (used to preview printed screens)
                                  true);
		}
		catch (TXOwl* erro)
		{
		 pMsgs->Message(IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
		 return;
		}

    /* Do need to call ALFFPrintout Paginate method  for updating page number
     * on printer buffer, because it is need on Printing Screen Dialog.
     */
#ifdef DEBUG32
	MessageBox("CmPrint: Paginando Printout...","Tec3270 Debug",MB_OK);
#endif
		printout->Paginate();
		prtData->FromPage = prtData->MinPage;
		prtData->ToPage   = prtData->MaxPage;

		/* Showing Print Screen Dialog to Get User Options */
#ifdef DEBUG32
	MessageBox("CmPrint: Acionando dialogo de impressao...","Tec3270 Debug",MB_OK);
#endif
		int printDialogRC;
		try {
		 printDialogRC = ALFFPrintDialog(this, theApp->Printer,
								  prtData, IDD_ALFFPRINT).Execute();
		}
		catch (xalloc)
		{
		 pMsgs->StrMessage("ALFFPrintDialog",IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
		 delete printout;
		 return;
		}
		if ( printDialogRC == IDOK)
		  {
         char iniSection[21];
         strcpy(iniSection,"SCREEN PRINTER DEVICE");

         /* Save the user printing on color option */
         ALFFIniFile* iniFile = theApp->GetIniFile();
         iniFile->WriteInt(iniSection,"PRINTCOLOR",prtData->printOnColor);

			theApp->Printing = true;
			if (prtData->hdrText)
			 {
			  if (prtData->fdHdr)
				 DeletePageHdr();
			  StorePrtPageHdr(prtData->hdrText,
									  curChild->GetTerminalPtr()->GetScrLineSize());
			  prtData->hdrStored = true;
			 }
			 else if (prtData->hdrStored)
					 {
					  DeletePageHdr();
					  prtData->hdrStored = false;
					 }

			/* Do printing as user asked for    */
			switch(prtData->printOption)
			 {
				case    PO_STORESCR: /*
											 * User asks just to save current screen or
											 * selected text on printer buffer.
											 */
											prtData->numScreens += 1;
											if(prtData->printWholeScr)
											 {
											  /* Store entire screen in printer buffer */
											  StorePrtFields(curChild->GetTerminalPtr(),
																  curChild->GetNVTBufPtr(),
																  curChild->Get3270BufPtr());
											 }
											 else
											  {
												/* Get Screen Selected Lines and store it */
												StorePrtSelText(curChild->GetTerminalPtr(),
																	 curChild->GetNVTBufPtr(),
																	 curChild->Get3270BufPtr());
											  }

											break;

				case PO_PRINTSTORED: /*
											 * Now it's time to print entire
											 * printer buffer or selected pages !!
											 */
											if (!prtData->printToFile)
											  {
												theApp->Printer->Print(GetWindowPtr(GetActiveWindow()),
													 *printout, false);
											  }
											else theApp->printerBuf->PrintToFile(this, prtData, pMsgs);
											break;

				case    PO_PRINTSCR: /*
											 * User asks to save current screen or
											 * selected text on printer buffer and
											 * print it immediately
											 */
											prtData->numScreens += 1;
											if(prtData->printWholeScr)
											 {
											  /* Store entire screen in printer buffer */
											  StorePrtFields(curChild->GetTerminalPtr(),
																  curChild->GetNVTBufPtr(),
																  curChild->Get3270BufPtr());
											 }
											 else
											  {
												/* Get Screen Selected Lines and store it */
												StorePrtSelText(curChild->GetTerminalPtr(),
																	 curChild->GetNVTBufPtr(),
																	 curChild->Get3270BufPtr());
											  }

											/* Now it's time to print entire
											 * printer buffer !!
											 */
											if (!prtData->printToFile)
											  {
												theApp->Printer->Print(GetWindowPtr(GetActiveWindow()),
													 *printout, false);
											  }
											 else theApp->printerBuf->PrintToFile(this, prtData, pMsgs);

											break;

				case PO_CLEARSTORED: if (theApp->printerBuf)
											  {theApp->printerBuf->Flush();}
                                 prtData->numScreens = 0;
											break;

						default      : pMsgs->Message(IDS_ALFFPRTERROR,
																IDS_ALFFPRTTITLE, true);
											break;
			  }
			theApp->Printing = false;
		  }
	 /* Delete printout as it is not needed ahead ....  */
	 if (printout)
		 delete printout;
	}
	else
	 {
	  if (pMsgs->Message(IDS_ALFFPRTINPROGRESS, IDS_ALFFPRTTITLE, true) == IDOK)
		{
		 theApp->Printer->SetUserAbort();
		 theApp->Printing = false;
		}
	 }
}

//////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Menu File Print Setup command
void
ALFFMDIClient::CmPrintSetup ()
{
	 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
	 if (theApp)
	  {
		  if (!theApp->Printer)
			CreatePrinter();
		  //
		  // Bring up the Print Setup dialog.
		  //
#ifdef DEBUG32
	MessageBox("CmPrintSetup: Iniciando Dialogo...","Tec3270 Debug",MB_OK);
#endif

		 /* Bring up the Print Setup dialog. */
  		 ALFFPrinterSetup*  setupDlg =
           new ALFFPrinterSetup(GetApplication()->GetMainWindow(),
                                NULL,
                                theApp->Printer, prtData, false);
                                                          //Screen Printer
		 bool endSetup = false;
		 while (!endSetup)
        {
         setupDlg->Execute();
         int setupErr = theApp->Printer->GetSetup().Error;
         int setupErr2 = theApp->Printer->GetError();
         if (/*setupErr ||*/ setupErr2)
	       {
           TPrintDialog::TData* tPrintData = &theApp->Printer->GetSetup();
           const char* printerName = tPrintData->GetOutputName();
           int button = -1;
           if (printerName)
	             button = pMsgs->StrMessage(printerName,
                         IDS_ALFFPRTNOTAVAIL,IDS_TIT3270PRTERR, true);
           else button = pMsgs->StrMessage("??????",
                         IDS_ALFFPRTNOTAVAIL,IDS_TIT3270PRTERR, true);
          /* Let User change the printer */
          if (button == IDOK)
              endSetup = true;
	       }
         else endSetup = true;
        }
       delete setupDlg;
	  }
}


//////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Menu File Print Preview command

void
ALFFMDIClient::CmPrintPreview ()
{
	 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
	 ALFFMDIChild* curChild = (ALFFMDIChild *)GetActiveMDIChild();
	 if (theApp)
	  {
		  if (!theApp->Printer)
			 CreatePrinter();

		  /* Get the Most Updated Printer Font */
		  prtData->currPrtFont = theApp->GetPrtFont();

		  ALFFPreviewWindow *prevW =
			 new ALFFPreviewWindow(Parent,
											  theApp->Printer,
											  curChild->GetClientWindow(),
											  prtData,
											  " ",
											  new ALFFLayoutWindow(0));
		  prevW->Create();

        // Disable main window and start printpreview messageloop
		  GetApplication()->BeginModal(GetApplication()->GetMainWindow(), MB_APPLMODAL);

		  /* We must destroy the preview window explicitly.
			* Otherwise, the window will not be destroyed until
			* it's parent, the MainWindow is destroyed.
			*/
		  prevW->Destroy();
		  delete prevW;
	 }
}

///////////////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Menu enabler used to disable all comands qhen monitoring is on
void
ALFFMDIClient::CmMonitorEnable (TCommandEnabler &tce)
{
 tce.Enable(!monitoring);
}

//////////////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Menu enabler used by Print & Print Setup
void
ALFFMDIClient::CmPrintEnable (TCommandEnabler &tce)
{
	 if (GetActiveMDIChild() && !monitoring)
	  {
		  Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
		  if (theApp)
		  {
				// If we have a Printer already created just test if all is okay.
				// Otherwise create a Printer object and make sure the printer
				// really exists and then delete the Printer object.
				//if (!theApp->Printer)
				//{ CreatePrinter(); }
				//tce.Enable(theApp->Printer->GetSetup().Error == 0);
            tce.Enable(true);
		  }
	  }
	  else tce.Enable(false);
}

// Menu enabler used by Print Preview
void
ALFFMDIClient::CmPrintPreviewEnable (TCommandEnabler &tce)
{
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
 bool printerPagesAvail = false;
 if (theApp && !monitoring)
	{
	 /* If we have a printer buffer active, that is, with screens added,
	  * print preview can be activated. */
	 if (theApp->printerBuf != NULL)
	  {
		if (theApp->printerBuf->GetItemsInContainer())
		 { printerPagesAvail = true; }
	  }
	}
 tce.Enable(printerPagesAvail);
}

//////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Choose Application Font to any fixedpitch font available
void
ALFFMDIClient::CmChooseFont()
{
 TFont* actualFont;
 char fontTitle[TITLELEN+1];

 /* Load Tec3270 Choose Font Dialog Title */
 pMsgs->LoadString(IDS_ALFFCHOOSEFONT,fontTitle, TITLELEN);

 /* Access Tec3270App Application */
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
 actualFont = theApp->GetAppFont();
#ifdef DEBUG32A
  MessageBox("Preparando Dialogo Fontes Comum","Tec3270 DEBUG 32",MB_OK);
#endif
 // Declare common dialog data structure
 ALFFChooseFontDialog::TData fontData;

 /* Font specifications and Automatic Font & Window Behaviors */
 fontData.DC = 0;
 fontData.PointSize = 10;
 fontData.Style = 0;
 fontData.FontType = SCREEN_FONTTYPE;
 fontData.SizeMin = 6;
 fontData.SizeMax = 16;
 fontData.Color = 0;
 fontData.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS
						| CF_LIMITSIZE | CF_FIXEDPITCHONLY;
 fontData.AutomaticWindowSizing = theApp->IsAutomaticWindowSizing();
 fontData.AutomaticFontSizing = theApp->IsAutomaticFontSizing();

 // If we already have a font, initialise the dialog with it.
 if (actualFont)
  {
	actualFont->GetObject(fontData.LogFont);
	// Tell the dialog to go initialise itself
	fontData.Flags |= CF_INITTOLOGFONTSTRUCT;
	TScreenDC dc;
	fontData.PointSize =
		 MulDiv(-fontData.LogFont.lfHeight,72,dc.GetDeviceCaps(LOGPIXELSY));
  }

#ifdef DEBUG32A
  MessageBox("Acionando Dialogo Fontes Comum","Tec3270 DEBUG 32",MB_OK);
#endif

 // Make the dialog
 ALFFChooseFontDialog* chooseFont;
 chooseFont = new ALFFChooseFontDialog(this,	fontData, fontTitle, true);
 if (chooseFont->Execute() == IDOK)
	 {
	  /*
		* Process and Set up new font
		*/
	  theApp->SetAppFont(fontData.LogFont,
								fontData.AutomaticWindowSizing,
								fontData.AutomaticFontSizing);
	  Tec3270MainWindow *theAppWindow =
		 TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(),Tec3270MainWindow);
	  theAppWindow->SetFontMetrics();
	  //if (theApp->IsAutomaticWindowSizing())
		 //theAppWindow->ResizeWindow();

	  /* Notify All Childs to Change Font */
	  ChildBroadcastMessage(MSG_CHANGE_FONT,0,0);

	 } // end if IDOK
 delete chooseFont;
}

//////////////////////////////////////////////////////////
// ALFFMDIClient
// ==========
// Choose Printer Font to any fixedpitch font available on Printer
void
ALFFMDIClient::CmChoosePrtFont()
{
 TFont* actualFont;
 TScreenDC pdc;
 char fontDlgTitle[TITLELEN+1];

 /* Load Tec3270 Choose Printer Font Dialog Title */
 pMsgs->LoadString(IDS_ALFFCHOOSEPRTFONT,fontDlgTitle, TITLELEN);

 /* Access Tec3270App Application */
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
 actualFont = theApp->GetPrtFont();

 // Declare common dialog data structure
 ALFFChooseFontDialog::TData fontData;

 // Flags - Allow no color or effects
 fontData.Flags = CF_FORCEFONTEXIST | CF_TTONLY | CF_SCREENFONTS
						| CF_LIMITSIZE | CF_FIXEDPITCHONLY;

 // The following are not used
 fontData.PointSize = 11;
 fontData.Style = 0;
 fontData.FontType = 0;
 fontData.SizeMin = 6;
 fontData.SizeMax = 16;
 fontData.Color = 0;

 // If we already have a font, initialise the dialog with it.
 if (actualFont)
  {
	actualFont->GetObject(fontData.LogFont);
	// Tell the dialog to go initialise itself
	fontData.Flags |= CF_INITTOLOGFONTSTRUCT;
  }

 fontData.PointSize =
		 MulDiv(-fontData.LogFont.lfHeight,72,pdc.GetDeviceCaps(LOGPIXELSY));
 fontData.DC = (HDC)pdc;

 ALFFChooseFontDialog chooseFont(this, fontData, fontDlgTitle);
 if (chooseFont.Execute() == IDOK)
  {
	 /*
	  * Process and Set up new font
	  */
	 theApp->SetPrtFont(fontData.LogFont);
  }   // end if IDOK
}


// Choose Base Terminal and 3270 Terminal Colors
void
ALFFMDIClient::CmChooseColors()
{
 /* Access the Application Object */
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(),Tec3270App);
 ALFFMDIChild* curChild = (ALFFMDIChild *)GetActiveMDIChild();

 if (curChild)
  {
	// Set Connection Data Up
	ALFFConnData* connData = curChild->GetChildConnData();

	/* Show All Colors and Permit To Change All of Them */
	if (ALFFColorSelect(theApp->GetMainWindow(),
							  connData,IDD_ALFFCOLORS,false).Execute() == IDOK)
	 {
	  /* Notify Active Child to Change Color */
	  curChild->GetTerminalPtr()->SetColors(connData);
	 }
  }
 else
  {
	/* There is no Session Active */
	ALFFConnData connData;

	/* Take Standard Color Definitions */
	char defaultColors[21];
	strcpy(defaultColors,"DEFAULT COLORS");

	ALFFIniFile* iniFile = theApp->GetIniFile();
	connData.scrCharColor = iniFile->GetLong(defaultColors,"TEXTCOLOR",TERMCHAR);
	connData.scrBkgdColor = iniFile->GetLong(defaultColors,"BKGDCOLOR",TERMBKGD);
	connData.scr3270BkgdColor = iniFile->GetLong(defaultColors,"BKGD3270COLOR",BKGD3270);
	connData.scrNormalUnprotTextColor = iniFile->GetLong(defaultColors,"NORMNPRTTEXT",NORMALUNPROT);
	connData.scrHighlightUnprotTextColor = iniFile->GetLong(defaultColors,"HIGHNPRTTEXT",HIGHUNPROT);
	connData.scrNormalProtTextColor = iniFile->GetLong(defaultColors,"NORMPROTTEXT",NORMALPROT);
	connData.scrHighlightProtTextColor = iniFile->GetLong(defaultColors,"HIGHPROTTEXT",HIGHPROT);
	connData.neutral = iniFile->GetLong(defaultColors,"NEUTRAL",DEFNEUTRAL);
	connData.blue = iniFile->GetLong(defaultColors,"BLUE",DEFBLUE);
	connData.red = iniFile->GetLong(defaultColors,"RED",DEFRED);
	connData.pink = iniFile->GetLong(defaultColors,"PINK",DEFPINK);
	connData.green = iniFile->GetLong(defaultColors,"GREEN",DEFGREEN);
	connData.turquoise = iniFile->GetLong(defaultColors,"TURQUOISE",DEFTURQUOISE);
	connData.yellow = iniFile->GetLong(defaultColors,"YELLOW",DEFYELLOW);
	connData.inverseNeutral =  iniFile->GetLong(defaultColors,"INVERSENEUTRAL",DEFINVNEUTRAL);
	connData.black = iniFile->GetLong(defaultColors,"BLACK",DEFBLACK);
	connData.deepBlue = iniFile->GetLong(defaultColors,"DEEPBLUE",DEFDEEPBLUE);
	connData.orange = iniFile->GetLong(defaultColors,"ORANGE",DEFORANGE);
	connData.purple = iniFile->GetLong(defaultColors,"PURPLE",DEFPURPLE);
	connData.paleGreen = iniFile->GetLong(defaultColors,"PALEGREEN",DEFPALEGREEN);
	connData.paleTurquoise = iniFile->GetLong(defaultColors,"PALETURQUOISE",DEFPALETURQUOISE);
	connData.gray = iniFile->GetLong(defaultColors,"GRAY",DEFGRAY);
	connData.white = iniFile->GetLong(defaultColors,"WHITE",DEFWHITE);

	/* Show All Colors and Permit To Change All of Them */
	ALFFColorSelect(theApp->GetMainWindow(),
						 &connData,IDD_ALFFCOLORS,false).Execute();
  }
}

void
ALFFMDIClient::CmKeyboard()
{
#ifdef STACKINFO
 // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
	char buf[128];
	wsprintf(buf,"\nStack Available: %u", stackavail());
	strcat(buf,"  <Before Keyboard Definition>");
	MessageBox(buf,"Stack Info",MB_OK);
 // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
#endif
 /* Access the Application Scope */
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);

 /* Access Tec3270 Ini File */
 char iniSection[16];
 ALFFIniFile* iniFile = theApp->GetIniFile();

 /* Get Current Keyboard Type and Configuration (IRMA or PC) */
 int keybId;
 strcpy(iniSection,"KEYBOARD");
 keybId = iniFile->GetInt(iniSection,"CONFIG TYPE",KEYBOARDBRPC);
#if DEBUG32
 MessageBox("ALFFMDIClient::CmKeyboard - Criando KeyBoard","Tec3270 DEBUG32",MB_OK);
#endif
 ALFFKeyboard* pKeyboard;
 pKeyboard = new ALFFKeyboard(this,keybId,REMAPKEY);

#if DEBUG32
 MessageBox("ALFFMDIClient::CmKeyboard - RemapKeyBoard","Tec3270 DEBUG32",MB_OK);
#endif
 keybId = pKeyboard->RemapKeyboard();
 if (keybId)
  {
	/* Save New Keyboard Id (or the Old Type) if it was changed */
	iniFile->WriteInt(iniSection,"CONFIG TYPE",keybId);

	/* Notify All Childs (if at least one exists) to Change Keyboard */
	if (GetActiveMDIChild())
		ChildBroadcastMessage(MSG_CHANGE_KEYBOARD,keybId,0);
  }
 delete pKeyboard;
}

void
ALFFMDIClient::CmOptionsKeyPad()
{
 if (!KeyPad)
  {
	TRect mRect = GetApplication()->GetMainWindow()->GetWindowRect();
	TPoint wCenter = TPoint(mRect.left+(mRect.Width()/2),
								  (mRect.top + mRect.Height()));
	ALFFChooseKeyPad* kPadDlg = new ALFFChooseKeyPad(this, TResId(IDD_ALFFCHOOSEKEYPAD),
																	  &KeyPad);
	kPadDlg->Execute();
	if (KeyPad)
	  KeyPad->Create();
	GetApplication()->GetMainWindow()->SetFocus();
	delete kPadDlg;
  }
  else
	{
	 if (pMsgs->Message(IDS_ALFFKEYPADCLOSE,IDS_ALFFKPADTIT,true)==IDOK)
	  {
#ifdef DEBUG32
		  pMsgs->StrMessage("Keypad sendo destruido !!",IDS_ALFFKEYPADCLOSE,IDS_ALFFKPADTIT);
#endif
		KeyPad->Destroy(KEYPADCLOSED);
		delete KeyPad;
		KeyPad = NULL;
	  }
	}
}

LRESULT
ALFFMDIClient::EvMsgKeyPad(WPARAM command, LPARAM)
{
 ALFFVirtualTerm* pTerminal;

 /* User wants to deactivate Smart Pad */
 if (command == KEYPADCLOSED)
  {
	CmOptionsKeyPad();
	return 1L;
  }

 // Get current active MDI child for starting key pad command //
 ALFFMDIChild *curChild = (ALFFMDIChild *)GetActiveMDIChild();

 /* If there is no child available there is nothing to do ...  */
 if (curChild)
  {
	 pTerminal = curChild->GetTerminalPtr();
	 if (pTerminal->IsConnected())
		pTerminal->ProcessCommand(command);
	 pTerminal->SetFocus();
  }
 else GetApplication()->GetMainWindow()->SetFocus();
 return 1L;
}

void
ALFFMDIClient::CmOptionsConfigSessions()
{
	 // Set Connection Data Up - Consctructor do set all initial values...
	 ALFFConnData* connData = new ALFFConnData();

	 /* We Must construct dialog before its execution for deleting it after
		 execution-> */
	 ALFFConnectDlg* configSession =
					  new ALFFConnectDlg(GetApplication()->GetMainWindow(),
												connData,
												IDD_ALFFCONNECT,
												SESSCONFIG);
	 /* Executing the Dialog */
	 configSession->Execute();

	 /* Deleting Dialog and auxiliary connection struct data */
	 delete configSession;

	 delete connData;
}

void
ALFFMDIClient::CmOptionsAutomat()
{
	 /* We Must construct dialog before its execution for deleting it after
		 execution. */
	 ALFFAutoConnect* automaticConnection =
							new ALFFAutoConnect(//this,
                                         GetApplication()->GetMainWindow(),
													  TResId(IDD_ALFFAUTOCONN));
	 /* Executing the Dialog */
	 automaticConnection->Execute();

	 /* Deleting Dialog and auxiliary connection struct data */
	 delete automaticConnection;
}

void
ALFFMDIClient::CreateChildList(TWindow* win)
{
 ALFFMDIChild* child = TYPESAFE_DOWNCAST((TWindow*)win, ALFFMDIChild);
 if (child)
	childList.Add((long)win);
}

static void
CreateChildList(TWindow* win, void*)
{
 Tec3270App *theApp =
	TYPESAFE_DOWNCAST(win->GetApplication(), Tec3270App);
 ALFFMDIClient *theMDI =
	TYPESAFE_DOWNCAST(theApp->GetMDIClient(), ALFFMDIClient);
 theMDI->CreateChildList(win);
}

void
ALFFMDIClient::Monitor(long win) //TWindow* win)
{
 long childWin = win;
 bool endMonitor = false;

 while (!endMonitor)
  {
	ALFFMDIChild* child = TYPESAFE_DOWNCAST((TWindow*)childWin, ALFFMDIChild);
	monitorTimeOut = child->GetChildConnData()->monTime * 1000;
	if (monitorTimeOut)
	 {
     SetToolsMonitorMenu(true, child);
	  child->GetTerminalPtr()->LockKeyboard();
	  child->GetTerminalPtr()->PaintScreen();
     child->Show(SW_SHOWMAXIMIZED);

	  /* Set the TIMER with correct value */
	  if (monitorTimeOut > MAXTIMEOUT)
		 SetTimer(9999,MAXTIMEOUT);
	  else SetTimer(9999,(UINT)monitorTimeOut);
	  return;
	 }
	else
	 {
	  if (childPtr < childList.GetItemsInContainer())
		childWin = childList[childPtr++];
	  else
		{
		 monitoring = false;
		 endMonitor = true;
		}
	 }
  }
  pMsgs->Message(IDS_ALFFSESSMONERR,IDS_ALFFMONTITLE);
}

void
ALFFMDIClient::EvTimer(uint timerId)
{
 if (timerId==9999)
  {
	KillTimer(timerId);
	if (monitorTimeOut > MAXTIMEOUT)
	  monitorTimeOut -= MAXTIMEOUT;
	else monitorTimeOut = 0;

	/* monitorTimeout contains the remaining time to wait until some action is done */
	if (monitorTimeOut)
	{
	 /* Connection Timer Must Be Restarted */
	 if (monitorTimeOut > MAXTIMEOUT)
		SetTimer(9999, MAXTIMEOUT);
	 else SetTimer(9999, (UINT)monitorTimeOut);
	}
	else /* Timer is Over: Do the correct action ! */
	 {
     ALFFMDIChild* curChild = (ALFFMDIChild *)GetActiveMDIChild();
     SetToolsMonitorMenu(false, curChild);

	  if (monitoring) //This boolean control is set by CmToolsMonitor//
		{
		 if (childPtr < childList.GetItemsInContainer())
		  Monitor(childList[childPtr]);
		 else
		  {
			childPtr = 0;
			Monitor(childList[0]);
		  }
		 childPtr++;
		}
     else
      {
       ALFFMDIChild* curChild = (ALFFMDIChild *)GetActiveMDIChild();
	    curChild->GetTerminalPtr()->UnlockKeyboard();
	    curChild->Show(SW_SHOWNORMAL);
      }
	 }
  }
}

void
ALFFMDIClient::CmToolsMonitorEnable(TCommandEnabler &ce)
{
 ce.Enable(ChildActive>1);
}

void
ALFFMDIClient::SetToolsMonitorMenu(bool onstatus, TMDIChild* curChild)
{
  unsigned int menuTextId;
  char menuText[STRINGMSGLEN];

  TMenuDescr* theMenu = new TMenuDescr(*curChild->GetMenuDescr());

  if (onstatus)
    menuTextId = IDS_ALFFSTOPMON;
  else
    menuTextId = IDS_ALFFSTARTMON;

  pMsgs->LoadString(menuTextId, menuText, STRINGMSGLEN);
  theMenu->ModifyMenu(CM_TOOLSMONITOR,MF_BYCOMMAND | MF_UNCHECKED, CM_TOOLSMONITOR, menuText);

  curChild->SetMenuDescr(*theMenu);

  GetApplication()->GetMainWindow()->MergeMenu(*theMenu);

  delete theMenu;
}

void
ALFFMDIClient::CmToolsMonitor()
{
 if (!monitoring)
  {
	if (ChildActive>1)
	 {
	  monitoring = true;
     childList.Flush();
	  ForEach(::CreateChildList);
	  childPtr = 0;
	  Monitor(childList[childPtr++]);
	 }
  }
 else
  {
	monitoring = false;
  	KillTimer(9999);
   childPtr = 0;
   ALFFMDIChild* curChild = (ALFFMDIChild*)GetActiveMDIChild();
   SetToolsMonitorMenu(false, curChild);
	curChild->GetTerminalPtr()->UnlockKeyboard();
   curChild->Show(SW_SHOWNORMAL);
   curChild->SetFocus();
  }
}

bool
ALFFMDIClient::IsMonitoring()
{
 return monitoring;
}

void
ALFFMDIClient::CmTwoChildEnable(TCommandEnabler &ce)
{
 if ((ChildActive>1) && !monitoring)
	ce.Enable(true);
  else
	ce.Enable(false);
}

void
ALFFMDIClient::CmSecurityAdminCerts()
{
  Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
  if (!theApp->GetSecurityObj()->IsSecurityOn())
    theApp->SetSecurityOn();
  ALFFCertAdminDlg certAdmin(this,theApp->GetSecurityObj(), dateFormat);
  certAdmin.Execute();
}

void
ALFFMDIClient::CmSecurityOptions()
{
 ALFFSecurityOptions secOptDlg(this);
 if (secOptDlg.Execute() == IDOK)
   /* Notify All Childs to Change Security Options */
	ChildBroadcastMessage(MSG_CHANGE_SECURITY_OPTIONS,0,0);
}

void
ALFFMDIClient::CmCascadeChildren()
{
 CascadeChildren();
}

void
ALFFMDIClient::CmTileChildrenVert()
{
 TileChildren();
}

void
ALFFMDIClient::CmTileChildrenHoriz()
{
 TileChildren(MDITILE_HORIZONTAL);
}

void
ALFFMDIClient::CmArrangeIcons()
{
 ArrangeIcons();
}

void
ALFFMDIClient::CmCloseChildren()
{
 CloseChildren();
}

bool
ALFFMDIClient::DeletePageHdr()
{
  if (prtData->fdHdr)
	{
    if (prtData->fdHdr->fdText)
      delete [] prtData->fdHdr->fdText;
	 delete prtData->fdHdr;
	 prtData->fdHdr = NULL;
	 prtData->scrPageOffset = 0;
	 return true;
	}
	else return false;
}

bool
ALFFMDIClient::StorePrtPageHdr(const char * hdrText, int lineSize)
{
 if (!prtData->fdHdr)
  {
	prtData->fdHdr = new PrtField();
	prtData->fdHdr->fdFormatted = false;
	prtData->fdHdr->fdPosition.x  = 0;
	prtData->fdHdr->fdPosition.y  = 0;
	prtData->fdHdr->fdTextColor = COLORREF(TColor::Black);
	prtData->fdHdr->fdBkgdColor = COLORREF(TColor::White);
	prtData->fdHdr->fdEffects = NULL;
	prtData->fdHdr->fdBkgdTransparency = NULL;
	prtData->fdHdr->fdValidation = NULL;
	prtData->fdHdr->fdOutlining = NULL;

	/* Page Header Text */
	prtData->fdHdr->fdText      = new char[strlen(hdrText)+1];
	strcpy(prtData->fdHdr->fdText,hdrText);

	/* Printer SubFields */
	prtData->fdHdr->scrLineSize = lineSize - PAGETEXTLEN - 1;
	prtData->fdHdr->scrPrtBegLine  = 0;
	prtData->fdHdr->scrPrtEndLine = (strlen(hdrText)/
												prtData->fdHdr->scrLineSize);
	prtData->fdHdr->scrNumber   = 0;

	prtData->hdrStored = true;

	/*
	 * Calculate page offset in order to skip at least one line between
	 * header and first screen on the page.
	 */
	prtData->scrPageOffset = (strlen(hdrText)/lineSize)+ 2;

  }
 return true;
}

bool
ALFFMDIClient::StorePrtFields(ALFFVirtualTerm* pTerminal,
											ALFFNvt*   pNVTBuf,
											ALFF3270*  p3270Buf)
{
  Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
#ifdef DEBUG32
	MessageBox("CmPrint: Iniciando Salvar Tela...","Tec3270 Debug",MB_OK);
#endif
  /*
	* Verify if printer buffer is already available.
	* If it is not available then it will be created just here
	*/
  if (!CreatePrinterBuffer())
   {
	 pMsgs->StrMessage("StorePrtFields-Printer Buffer",IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
	 return false;
	}

  /* Store All Screen Fields in correct Printer Coordinates */
  PrtField fdStore;
  bool endStoring = false;
  bool firsTime = true;
  int  firstFd = -1;
  int  scrLineSize = pTerminal->GetScrLineSize();
  int  fromPos = 0;
  int  addRC = 0;
  try
  {
	while (!endStoring)
	{
	 /*
	  * Get a field from 3270 Screen Buffer if in 3270 Mode
	  * or get a field from NVT Screen Buffer if not.
	  */
	 if (pTerminal->IsMode3270())
	  {
		fdStore = *p3270Buf->DataToScreen(fromPos,REGULARFIELD);
		if (firsTime)
		 {
		  firsTime = false;
		  firstFd  = (fdStore.fdPosition.y*scrLineSize)+fdStore.fdPosition.x;
		 }
		fdStore.scrLineSize = scrLineSize;
		fdStore.scrPrtBegLine = 0;
		fdStore.scrPrtEndLine = pTerminal->GetScrNumLines() - 1;
		fdStore.scrNumber   = prtData->numScreens;

      addRC = theApp->printerBuf->StorePrtField(&fdStore);
		if (addRC)
       {
		  pMsgs->Message(addRC, IDS_ALFFPRINTOUTTITLE);
		  return false;
       }

		if (fromPos == firstFd)
		endStoring = true;
	  }
    else
	  {
		 fdStore = *pNVTBuf->DataToScreen(fromPos,REGULARFIELD);
		 if (firsTime)
		  {
			firsTime = false;
			firstFd  = (fdStore.fdPosition.y*scrLineSize)+fdStore.fdPosition.x;
		  }
		 fdStore.scrLineSize = scrLineSize;
		 fdStore.scrPrtBegLine = 0;
		 fdStore.scrPrtEndLine = pTerminal->GetScrNumLines() - 1;
		 fdStore.scrNumber   = prtData->numScreens;
       addRC = theApp->printerBuf->StorePrtField(&fdStore);
		 if (addRC)
        {
		   pMsgs->Message(addRC, IDS_ALFFPRINTOUTTITLE);
		   return false;
        }
		 if (fromPos == firstFd)
			endStoring = true;
	  }
	} // while (!endStoring)
 }
 catch (xalloc)
	{
	 char xallocMsg [80];
	 sprintf(xallocMsg,"StorePrtFields Add RC=%i",addRC);
	 pMsgs->StrMessage(xallocMsg,IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
	 return false;
	}
 return true;
}

bool
ALFFMDIClient::StorePrtSelText(ALFFVirtualTerm* /*pTerminal*/,
										 ALFFNvt*  /*pNVT*/,
										 ALFF3270* /*p3270*/)
{
 return false;
}

bool
ALFFMDIClient::CreatePrinterBuffer()
{
  Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);
  if (!theApp->printerBuf)
	{
#ifdef DEBUG32
	MessageBox("CreatePrinterBuffer: Criando Printer Buffer...","Tec3270 Debug",MB_OK);
#endif
	  try {
	  theApp->printerBuf = new ALFFPrinterBuffer(6*MAXSCRFIELDS,0,MAXSCRFIELDS);
	  }
	  catch (xalloc)
	  {
		//pMsgs->StrMessage("New Printer Buffer",IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
      theApp->printerBuf = NULL;
		return false;
	  }
	}
  return true;
}

bool
ALFFMDIClient::CreatePrinter()
{
 Tec3270App *theApp = TYPESAFE_DOWNCAST(GetApplication(), Tec3270App);

 prtData = new ALFFPrtData();

 // Set current font
 prtData->currPrtFont = theApp->GetPrtFont();

 // Get printer options from ini File
 ALFFIniFile* iniFile = theApp->GetIniFile();
 char iniSection[21];
 strcpy(iniSection,"SCREEN PRINTER DEVICE");
 iniFile->GetString(iniSection,"DRIVER", "", prtData->prtDriver, 64);
 iniFile->GetString(iniSection,"DEVICE", "", prtData->prtDevice, 128);
 iniFile->GetString(iniSection,"OUTPUT", "", prtData->prtOutput, 128);
 prtData->defaultPrt = iniFile->GetInt(iniSection,"DEFAULT",0);
 iniFile->GetString(iniSection,"PRINTERFILENAME", "", prtData->printerFileName, MAXPATH);
 prtData->printOnColor  = iniFile->GetInt(iniSection,"PRINTCOLOR",0);
 prtData->printToFile = iniFile->GetInt(iniSection,"PRINTTOFILE",0);
 prtData->printToSeparateFiles = iniFile->GetInt(iniSection,"PRINTTOSEPARATEFILES",0);

 /* Should create Printer from saved user options */
 if (!theApp->Printer)
  {
   /* As an Network Printer access may lasts a while, user should be advised ...*/
   char barTitle[STRINGMSGLEN+1];
   pMsgs->LoadString(IDS_REMPRTBARTITLE, barTitle, STRINGMSGLEN);
   ALFFProgressBar* pBar = new ALFFProgressBar(GetApplication()->GetMainWindow(),
                                                    barTitle,20);
   pBar->Create();
   pBar->ShowWindow(SW_SHOW);

	try
    {
	  theApp->Printer = new ALFFPrinter(GetApplication());
     if (!prtData->defaultPrt)
       theApp->Printer->InitPrinter(prtData->prtDriver, prtData->prtDevice, prtData->prtOutput);
	 }
	catch (TXOwl* erro)
	 {
	  pMsgs->Message(IDS_OUTOFMEMORY, IDS_ALFFPRINTOUTTITLE);
     theApp->Printer = NULL;
	  return false;
	 }

   pBar->SetPosition(100);
   // Wait for 1 second and delete the progress bar
   long tickCount = ::GetTickCount();
   long tickNovo = tickCount;
   while ((tickNovo-tickCount)<1000)
   tickNovo = ::GetTickCount();
   delete pBar;
  }

 /* Reset the Printer Buffer    */
 if (theApp->printerBuf)
   theApp->printerBuf->Flush();

 return true;
}

