/*****************************************************************************/
/*                                                                           */
/*  Copyright Notice: IBM Personal Communication/3270 Version 4.2            */
/*                    (C) COPYRIGHT IBM CORP. 1997 - PROGRAM PROPERTY        */
/*                    OF IBM ALL RIGHTS RESERVED                             */
/*                                                                           */
/*****************************************************************************/
//
// This sample application can be built with IBM VisualAge C++ using the
// MAKEFILE provided, or with Microsoft Visual C++ V4.2 Developer Studio
// using the supplied project workspace file (ECLMON.MDP).
//
// Updated for PComm Version 4.3: Changed to use new PS update event on the
// ECLPS object, and OIA event on the OIA object (rather than the combined
// events on the ECLSession object).
//
// Updated for PComm Version 5.7.1: Added PageSetup and PrinterSetup panes
//
//-----------------------------------------------------------------------------
//
// This ECL sample application implements a simple "system monitor".  It
// displays the status of all PComm sessions in a color-coded matrix.  Any
// session can be selected and the contents of that session's screen will be
// displayed.  Tabs on the notebook are used to examine various aspects of
// the currently selected session (e.g. examine properties of individual
// fields, connection characteristics, etc).  All pages of the notebook are
// updated dynamically as the session data changes, and the status matrix
// is updated dynamically as sessions start, stop, connect, and disconnect.
//
// This sample demonstrates one possible use of almost all the ECL objects
// and events.  Some basic design points to help understand this application:
//
// -- Only one copy of the event objects are created.  The same object is
//    reused over and over to handle events on different sessions.
//
// -- There is only one ECLSession object pointer.  When the user changes
//    sessions by clicking on a status button, the current session object
//    is deleted.  A new object is then created for the selected session.
//    All the other objects (PS, OIA, etc.) are retrieved from the session
//    object.
//
// -- The "Session" object pointer is a global variable.  It is only
//    accessed by the main window thread -- it is not accessed directly
//    by the event objects (which run on a different thread), so we 
//    don't have to worry about serializing access to it.
//
// -- The event objects execute as quickly as possible.  When they need
//    to have work done, they post a message to the appropriate window
//    and continue.  Thus all the work is done on the main thread and the
//    events run as quickly as possible.
//
// -- The status matrix is an array of owner-draw buttons with a series
//    of IDs from IDC_SESSOIN1 through IDC_SESSION1+25.
//
// -- The main window is a dialog, so WinMain just runs a simple
//    DialogBox() call to run the application.
//
// -- The ConnList[] array is an array of data structures, one for each
//    possible PComm session.  It is fixed allocated at 26 since that is
//    the max number of sessions currently supported by PComm (V4.2).  
//    This fixed array would not be a good idea for supporting an
//    arbitrary number of sessions.  "CurrConn" is the index into this
//    array of the currently selected session.
//
// -- Each tab of the notebook is a seperate dialog with its own dialog
//    procedure.  The tab dialogs are notified when events occure (such as
//    the session disconnecting, or the presentation space being updated).
//    "CurrTab" is the index of the currently displayed tab.
//
//-----------------------------------------------------------------------------
// for MS VC++ compiler, this sample enumerates fonts, installed printers and
// adds them to the dropdown list for selection. But for Visual Age C++ compiler,
// enumeration is not done in this sample. So provide the FontName and PrinterName
// in the editable combo boxes. The browse button next to Prt2Dsk - Append, 
// Prt2Dsk - Separate and PDT file helps in selecting the files through OpenFile
// dialog. But for Visual Age C++, the file name should be typed in the edit boxes
// NO_PRTR_API should be defined for VAC++. So uncomment while compiling with VAC++
//#define NO_PRTR_API

#define STRICT

#ifndef NO_PRTR_API
#include "..\..\..\include\\eclall.hpp"       // Emulator Class Library
#endif

#ifdef NO_PRTR_API
#include "eclall.hpp"
#endif

#include <windows.h>        // Windows header
#include <commctrl.h>       // Common controls
#include <process.h>        // Thread support
#include <stdio.h>          // C language header
#include "resource.h"


//---------------------------------------------------------------------------------------------
// File Scope Variable Declarations
//---------------------------------------------------------------------------------------------

//Application instance handle
HINSTANCE hInst;

#define CONNSTATUS_STOPPED 0         // Status codes stored in ConnList[] array
#define CONNSTATUS_READY   1
#define CONNSTATUS_DISCONN 2
#define CONNSTATUS_NOAPI   3

// Application defined window messages
#define CHANGED_CONN       WM_APP+0  // Sent to each dialog tab -- changed connection or status
#define CHANGED_PS         WM_APP+1  // Sent to each dialog tab -- PS updated
#define CHANGED_OIA        WM_APP+2  // Sent to each dialog tab -- OIA updated
#define CHANGED_STATUS     WM_APP+3  // Send to main dialog -- status of conn changed
#define CLEAR_FIELDINFO    WM_APP+4  // Used internally by FIELD dialog
#define STARTEVENT_ERROR   WM_APP+5  // Posted by start/stop event handler
#define UPDATE_CONNINFO    WM_APP+6  // Used internally by CONNECTION dialog
#define CHANGED_PG_CONF    WM_APP+7  // Sent to page conf dialog tab
#define CHANGED_PRT_CONF   WM_APP+8  // Sent to print conf dialog tab
#define UPDATE_PG_CONF     WM_APP+9  // Used internally by Page conf dialog
#define UPDATE_PRT_CONF    WM_APP+10 // Used internally by Prt conf dialog


static HFONT MonoFont;            // Monospaced font for PS display
static HFONT SmallFont;           // Small font
#define MAX_TABS 5                // Number of tabs on the notebook control

static TC_ITEM TabList[MAX_TABS] = {
  {TCIF_TEXT, 0, 0, "Screen",     sizeof("Screen"),        -1, NULL},
  {TCIF_TEXT, 0, 0, "Fields",     sizeof("Fields"),        -1, NULL},
  {TCIF_TEXT, 0, 0, "Connection", sizeof("Connection"),    -1, NULL},

  // These items are not implemented in this sample
//{TCIF_TEXT, 0, 0, "Metrics",    sizeof("Metrics"),       -1, NULL},
//{TCIF_TEXT, 0, 0, "File Xfer",  sizeof("File Xfer"),     -1, NULL},
  {TCIF_TEXT, 0, 0, "Page Configuration", sizeof("Page Configuration"),    -1, NULL},
  {TCIF_TEXT, 0, 0, "Printer Configuration", sizeof("Printer Configuration"),    -1, NULL},
  };

typedef struct _ConnInfo {        // Structure describing one connection
  ECLConnection *ConnObj;         // Ptr to ECLConnection object
  long          ConnHandle;       // Handle of the connection
  HWND          StatusButton;     // Handle of status window
  int           ConnStatus;       // Last known status (CONNSTATUS_* value)
} ConnInfo;

ConnInfo ConnList[26];            // Array of all connection descriptions

static ECLConnMgr *ConnMgr;       // Connection Manager object
static ECLSession *Session=NULL;  // Session object for current connection
static HWND MainHwnd;             // Main window handle
static HWND TabHwnd;              // Main window tab control handle
static int  CurrTab;              // Index of currently displayed tab
static int  CurrConn;             // Current index into ConnList array


//---------------------------------------------------------------------------------------------
// Helper macros (assume dialog handle is "hwnd")
//---------------------------------------------------------------------------------------------
#define ENABLECONTROL(id) EnableWindow(GetDlgItem(hwnd, id), TRUE)
#define DISABLECONTROL(id) EnableWindow(GetDlgItem(hwnd, id), FALSE)
#define FOCUSCONTROL(id) SetFocus(GetDlgItem(hwnd, id))
#define SETCHECK(id) SendMessage(GetDlgItem(hwnd, id), BM_SETCHECK, (WPARAM)BST_CHECKED, 0)
#define CLEARCHECK(id) SendMessage(GetDlgItem(hwnd, id), BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0)
#define SETTEXT(id,str) SetWindowText(GetDlgItem(hwnd, id), str)
#define GETTEXT(id,str,len) GetWindowText(GetDlgItem(hwnd,id),str,len)
#define GETINT(id, i) i=GetDlgItemInt(hwnd, id, NULL, FALSE)
#define GETLONG(id, i) i=((long)GetDlgItemInt(hwnd, id, NULL, FALSE))
#define QUERYCHECK(id) ((BOOL)SendMessage(GetDlgItem(hwnd, id), BM_GETCHECK, 0, 0))
#define CLEARLIST(id)  SendDlgItemMessage(hwnd, id, LB_RESETCONTENT, 0, 0)
#define QUERYSELECTION(id) SendDlgItemMessage(hwnd, id, LB_GETCURSEL, 0, 0)
#define ERRBOX(h,title,msg) MessageBoxA(h, msg, title, MB_OK|MB_ICONERROR)
#define ADDSTRING2COMBO(id,str)  SendMessage (GetDlgItem(hwnd, id), CB_ADDSTRING, 0, (LPARAM) str)
#define SELECTINCOMBO(id,str)    SendMessage (GetDlgItem(hwnd, id), CB_SELECTSTRING, -1, (LPARAM) str)
#define CLR_BLACK                       RGB(0,0,0)
#define CLR_DARKBLUE                    RGB(0,0,128)
#define CLR_DARKGREEN                   RGB(0,128,0)
#define CLR_DARKCYAN                    RGB(0,128,128)
#define CLR_DARKRED                     RGB(128,0,0)
#define CLR_DARKPINK                    RGB(128,0,128)
#define CLR_BROWN                       RGB(128,128,0)
#define CLR_PALEGRAY                    RGB(192,192,192)
#define CLR_DARKGRAY                    RGB(128,128,128)
#define CLR_BLUE                        RGB(0,0,255)
#define CLR_GREEN                       RGB(0,255,0)
#define CLR_CYAN                        RGB(0,255,255)
#define CLR_RED                         RGB(255,0,0)
#define CLR_PINK                        RGB(255,0,255)
#define CLR_YELLOW                      RGB(255,255,0)
#define CLR_WHITE                       RGB(255,255,255)


#define MIN_MPL            2
#define MIN_MPP            2
#define MAX_MPL            255
#define MAX_MPP            255
#define MAX_STRING_LEN     256
#define GET_DEFAULT        0
#define ENUMERATE_ALL      1
#define PRT2DSK_APPEND     "Print to Disk - Append"
#define PRT2DSK_SEPARATE   "Print to Disk - Separate"
#define ON_STRING          " on "
#define BLANK_ITEM         " "
#define SET_PDT            "Set PDT"
#define RESET_PDT          "Reset PDT"
#define DONT_SEND_THIS     "Don't send this"
#define DONT_SHOW_B4_PRINT "Don't show"
#define SHOW_B4_PRINT      "Show before print"
#define NOTHING_SELECTED   "Nothing selected for sending to session"
#define MSG_SUCCESSFUL     "Successful"

#define TRY_EHLLAPI()      try \
                          {

#define CATCH_EHLLAPI(a)    } \
                          catch (ECLErr Err) \
                          {SETTEXT(a, Err.GetMsgText());}

#define SESSION_CHECK(a) {if (Session == NULL){SETTEXT(a,"No sessions are active"); \
                          return;}}



// Macro to post a message to all the notebook pages
#define POSTTOALL(msg,mp1,mp2) {int i; \
                                for (i=0; i<MAX_TABS; i++) \
                                  PostMessage((HWND)TabList[i].lParam, msg, (WPARAM)mp1, (LPARAM)mp2); \
                               }


//---------------------------------------------------------------------------------------------
// Prototypes
//---------------------------------------------------------------------------------------------
BOOL WINAPI DlgMainProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
void DrawSessionButton(DRAWITEMSTRUCT *DrawData, LONG Color, LONG ColorBorder, char SessID);
BOOL WINAPI ScreenDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI FieldsDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI ConnDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI MetricsDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI XferDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI DlgStartConnection(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI PgConfDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
BOOL WINAPI PrtConfDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2);
void InitializePgConfTab(HWND hwnd);
void InitializePrtConfTab(HWND hwnd);
void OpenPrt2DskPDTFile(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2, int iID);
int CALLBACK AddFace2Combo(CONST LOGFONT *lplf, CONST TEXTMETRIC *lptm,DWORD dwType,LPARAM hwnd);
void ClearPrtConfPage(HWND hwnd);
void ClearPgConfPage(HWND hwnd);
void ListPrinters(HWND hwnd);
void DPGetDefaultPrinter(HWND hwnd);        
void SetInPageConfTab(HWND hwnd);
void RestoreDefaultPageValues(HWND hwnd);
void SendPageConfValuesToSession(HWND hwnd);
void ReceivePrinterConfFromSession(HWND hwnd);
void SendPrinterConfToSession(HWND hwnd);

//---------------------------------------------------------------------------------------------
// Connection Start/Stop Event Handler
//---------------------------------------------------------------------------------------------

// Define a class derivied from ECLStartNotify

class MyStartEvents: public ECLStartNotify
{
public:
  // We only override these two functions
  void	NotifyEvent(ECLConnMgr *CMObj, long ConnHandle, BOOL Started);
  void  NotifyError(ECLConnMgr *CMObj, long ConnHandle, ECLErr ErrObj);
};

// Implement the overriden class functions

void MyStartEvents::NotifyEvent(ECLConnMgr *CMObj, long ConnHandle, BOOL Started)
{
  // This function is called whenever a connection starts or stops.

  // Tell the main window to update the status display
  PostMessage(MainHwnd, CHANGED_STATUS, 0, (LPARAM)ConnHandle);
}

void MyStartEvents::NotifyError(ECLConnMgr *CMObj, long ConnHandle, ECLErr ErrObj)
{
  // This function is called whenever an error occures during
  // connection start/stop.  Note this might happen a long while
  // after we tried to start or stop a new connection.  We will
  // be called here if, for example, an invalid profile name is
  // given when we try to start a new connection.

  ECLErr *ErrCopy;

  ErrCopy = new ECLErr(ErrObj);  // Make a copy to pass

  // Tell the main window and pass a pointer to the error object.
  // The main window will delete the copy.
  PostMessage(MainHwnd, STARTEVENT_ERROR, 0, (LPARAM)ErrCopy);
}

//---------------------------------------------------------------------------------------------
// Comm Link Event Handler
//---------------------------------------------------------------------------------------------

// Define a class derivied from ECLCommNotify

class MyCommEvents: public ECLCommNotify
{
public:
  // We only override this one function
  void	NotifyEvent(ECLConnection *ConnObj, BOOL Connected);
};

// Implement the overriden class function

void MyCommEvents::NotifyEvent(ECLConnection *ConnObj, BOOL Connected)
{
  // This function is called whenever the comm link changes state.
  PostMessage(MainHwnd, CHANGED_STATUS, 0, (LPARAM)ConnObj->GetHandle());

}

//---------------------------------------------------------------------------------------------
// PS Updated Event Handler
//---------------------------------------------------------------------------------------------

// Define a class derivied from ECLPSNotify

class MyPSEvents: public ECLPSNotify
{
public:
  // We only override this one function
  void	NotifyEvent(ECLPS *PSObj);
};

// Implement the overriden class function

void MyPSEvents::NotifyEvent(ECLPS *PSObj)
{

  // This function is called whenever the PS changes.

  // Make sure the connection on which this happended is still the
  // current session (could have changed while we were getting
  // this notification).
  if (PSObj->GetHandle() != ConnList[CurrConn].ConnHandle)
    return;

  // Post messages to all the dialog pages
  POSTTOALL(CHANGED_PS, 0, 0);
}

//---------------------------------------------------------------------------------------------
// OIA Updated Event Handler
//---------------------------------------------------------------------------------------------

// Define a class derivied from ECLOIANotify

class MyOIAEvents: public ECLOIANotify
{
public:
  // We only override this one function
  void	NotifyEvent(ECLOIA *OIAObj);
};

// Implement the overriden class function

void MyOIAEvents::NotifyEvent(ECLOIA *OIAObj)
{

  // This function is called whenever the OIA changes.

  // Make sure the connection on which this happended is still the
  // current session (could have changed while we were getting
  // this notification).
  if (OIAObj->GetHandle() != ConnList[CurrConn].ConnHandle)
    return;

  // Post messages to all the dialog pages
  POSTTOALL(CHANGED_OIA, 0, 0);
}

//---------------------------------------------------------------------------------------------
// Keystroke Event Handler
//---------------------------------------------------------------------------------------------

// Define a class derivied from ECLKeyNotify

class MyKeyEvents: public ECLKeyNotify
{
public:
  // We only override this one function
  int	NotifyEvent(ECLPS *PSObj, char const KeyType[2], const char * const KeyString);
};

// Implement the overriden class function

int MyKeyEvents::NotifyEvent(ECLPS *PSObj, char const KeyType[2], const char * const KeyString)
{
#define KEY_PROCESS 0
#define KEY_FILTER  1

  // This function is called whenever the user presses a key
  // in the current connection.

  // Make sure the connection on which this happended is still the
  // current session (could have changed while we were getting
  // this notification).
  if (PSObj->GetHandle() != ConnList[CurrConn].ConnHandle)
    return KEY_PROCESS;

  // Just display the keystroke on the SCREEN tab dialog page and continue
  // to process it normally.
  SetWindowText(GetDlgItem((HWND)TabList[0].lParam, IDC_KEYMON), KeyString);
  return KEY_PROCESS;

}

MyStartEvents *StartEvents;    // Ptr to my start/stop event handler
MyCommEvents *CommEvents;      // Ptr to my comm link event handler
MyPSEvents *PSEvents;          // Ptr to my PS update event handler
MyOIAEvents *OIAEvents;        // Ptr to my OIA update event handler
MyKeyEvents  *KeyEvents;       // Ptr to my keystroke event handler

//---------------------------------------------------------------------------------------------
// Main dialog window procedure
//---------------------------------------------------------------------------------------------
BOOL WINAPI DlgMainProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
{
  int i;

  try { // Capture any misc ECL errors

  switch (msg) {

  case WM_INITDIALOG: {
    RECT Rect, RectDlg;

    TabHwnd = GetDlgItem(hwnd, IDC_TAB);  // Keep some key window handles
    MainHwnd = hwnd;

    // Create main window tabs setting instance data to dlg window handles
    TabList[0].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_SCREEN), TabHwnd, ScreenDlgProc);
    TabList[1].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_FIELDS), TabHwnd, FieldsDlgProc);
    TabList[2].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_CONN),   TabHwnd, ConnDlgProc);
    TabList[3].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_PAGESETUP),   TabHwnd, PgConfDlgProc);
    TabList[4].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_PRINTERSETUP),   TabHwnd, PrtConfDlgProc);

  // These items are not implemented in this sample
//    TabList[3].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_METRICS),TabHwnd, MetricsDlgProc);
//    TabList[4].lParam = (long)CreateDialog(hInst, MAKEINTRESOURCE(IDD_XFER),   TabHwnd, XferDlgProc);
    for (i=0; i<MAX_TABS; i++) {
      SendMessage(TabHwnd, TCM_INSERTITEM, (WPARAM)i, (LPARAM)&(TabList[i]));
    }

    // Get info about tab control including it's display area
    GetWindowRect(TabHwnd, &Rect);
    OffsetRect(&Rect, -Rect.left, -Rect.top);
    SendMessage(TabHwnd, TCM_ADJUSTRECT, (WPARAM)FALSE, (LPARAM)&Rect);

    for (i=0; i<MAX_TABS; i++) {
      // Move dialogs into the tab display area and size to fit
      GetWindowRect(TabHwnd, &RectDlg);
      SetWindowPos((HWND)TabList[i].lParam, HWND_TOP, 
        Rect.left,
        Rect.top,
        Rect.right-Rect.left,
        Rect.bottom-Rect.top,
        SWP_NOACTIVATE|SWP_NOZORDER);
    }

    // Select tab 0 to start
    CurrTab = 0;
    ShowWindow((HWND)TabList[0].lParam, SW_SHOW);

    // Create my notifcation object handlers
    StartEvents = new MyStartEvents();  // Connection start/stop
    CommEvents  = new MyCommEvents();   // Comm link connect/disconnect
    PSEvents    = new MyPSEvents();     // PS updates
    OIAEvents   = new MyOIAEvents();    // OIA updates
    KeyEvents   = new MyKeyEvents();    // Keystroke events

    // Create connection manager and register for start/stop events
    ConnMgr = new ECLConnMgr();
    ConnMgr->RegisterStartEvent(StartEvents);

    // Build ConnList array of connection information and register
    // for comm link events on each one.  Note same event object is
    // used for all connections.  Initial event will cause comm status
    // change of 'A' connection which will trigger rest of initialization.
    CurrConn = 0;
    memset(ConnList, 0x00, sizeof(ConnList));
    for (i=0; i<26; i++) {
      ConnList[i].StatusButton = GetDlgItem(hwnd, IDC_SESSION1+i);
      ConnList[i].ConnObj = new ECLConnection((char)('A'+i));
      ConnList[i].ConnHandle = ConnList[i].ConnObj->GetHandle();
      ConnList[i].ConnObj->RegisterCommEvent(CommEvents, TRUE);
    }

    break;
  }

  case WM_DESTROY:     
    // Cleanup any current session object
    if (Session != NULL) {
      //Session->UnregisterUpdateEvent(UpdtEvents);
      Session->GetPS()->UnregisterKeyEvent(KeyEvents);
      Session->GetPS()->UnregisterPSEvent(PSEvents);
      Session->GetOIA()->UnregisterOIAEvent(OIAEvents);
      delete Session;
      Session = NULL;
    }

    // Cleanup the connection manager
    ConnMgr->UnregisterStartEvent(StartEvents);
    delete ConnMgr;

    // Cleanup all the connection objects
    for (i=0; i<26; i++) {
      ConnList[i].ConnObj->UnregisterCommEvent(CommEvents);
      delete ConnList[i].ConnObj;
    }

    // Cleanup event handlers
    delete StartEvents;
    delete CommEvents ;
    delete PSEvents ;
    delete OIAEvents;
    delete KeyEvents  ;

    break;

  case WM_NOTIFY:
    switch (((NMHDR *)mp2)->idFrom) {
    case IDC_TAB:  //------------------- Notification from tab control
      switch (((NMHDR *)mp2)->code) {
      case TCN_SELCHANGE: //------------ User changed tabs, swap dialogs
        ShowWindow((HWND)TabList[CurrTab].lParam, SW_HIDE);
        CurrTab = (int)SendMessage(TabHwnd, TCM_GETCURSEL, 0, 0);
        ShowWindow((HWND)TabList[CurrTab].lParam, SW_SHOW);
      }
    }
    break;

  case CHANGED_STATUS: 
    // The status of a connection has changed.  mp2 is the handle of
    // the connection.  We will update the visual status display.
    int Index;

    for (Index=0; Index<26; Index++) {  // Look for connection that changed
      if ((long)mp2 == ConnList[Index].ConnHandle) {  // Found it
        if (ConnList[Index].ConnObj->IsReady() == TRUE) 
          ConnList[Index].ConnStatus = CONNSTATUS_READY;
        else if (!ConnList[Index].ConnObj->IsStarted()) 
          ConnList[Index].ConnStatus = CONNSTATUS_STOPPED;
        else if (!ConnList[Index].ConnObj->IsCommStarted())
          ConnList[Index].ConnStatus = CONNSTATUS_DISCONN;
        else 
          ConnList[Index].ConnStatus = CONNSTATUS_NOAPI;

        // Update the visual display
        InvalidateRect(ConnList[Index].StatusButton, NULL, TRUE);

        // If the current connection was the one that changed, fake a
        // click on the connection button to (re)create the Session
        // object or delete it as needed for the new status.

        if (Index == CurrConn)
          SendMessage(hwnd, WM_COMMAND, (WPARAM)IDC_SESSION1+CurrConn, 0);

        break;
      }
    }
    return 0;  // CHANGED_STATUS

  case WM_COMMAND: 

    // First, look for any of the session status buttons

    if ((LOWORD(mp1) >= IDC_SESSION1) && (LOWORD(mp1) <= IDC_SESSION1+26-1)) {
      // Connection button was selected... switch connections
      int OldConn;

      OldConn = CurrConn;
      CurrConn = LOWORD(mp1) - IDC_SESSION1;

      // Repaint buttons w/updated inset emphasis
      InvalidateRect(ConnList[OldConn].StatusButton, NULL, TRUE);
      InvalidateRect(ConnList[CurrConn].StatusButton, NULL, TRUE);

      // Cleanup Session object for prior connection
      if (Session != NULL) {
        //Session->UnregisterUpdateEvent(UpdtEvents);
        Session->GetPS()->UnregisterPSEvent(PSEvents);
        Session->GetOIA()->UnregisterOIAEvent(OIAEvents);
        delete Session;
        Session = NULL;
      }

      // Create new session object only if connection is READY
      if (ConnList[CurrConn].ConnStatus == CONNSTATUS_READY) {
        Session = new ECLSession(ConnList[CurrConn].ConnHandle);
        try {
          //Session->RegisterUpdateEvent(PSOIAUpdate, UpdtEvents, TRUE);
          Session->GetPS()->RegisterPSEvent(PSEvents, TRUE);
          Session->GetOIA()->RegisterOIAEvent(OIAEvents, TRUE);
        } catch (ECLErr Err) {
          ERRBOX(hwnd,  "ECL Error registering for update events:", Err.GetMsgText());
        }
      }

      // Setup connection control buttons based on current status
      switch (ConnList[CurrConn].ConnStatus) {
      case CONNSTATUS_READY:
        ENABLECONTROL(IDC_START);
        ENABLECONTROL(IDC_CONNECT);
        SETTEXT(IDC_START, "Stop");
        SETTEXT(IDC_CONNECT, "Disconn");
        break;
      case CONNSTATUS_STOPPED:
        ENABLECONTROL(IDC_START);
        DISABLECONTROL(IDC_CONNECT);
        SETTEXT(IDC_START, "Start");
        SETTEXT(IDC_CONNECT, "Connect");
        break;
      case CONNSTATUS_DISCONN:
        ENABLECONTROL(IDC_START);
        ENABLECONTROL(IDC_CONNECT);
        SETTEXT(IDC_START, "Stop");
        SETTEXT(IDC_CONNECT, "Connect");
        break;
      case CONNSTATUS_NOAPI:
        DISABLECONTROL(IDC_START);
        DISABLECONTROL(IDC_CONNECT);
        SETTEXT(IDC_START, "Start");
        SETTEXT(IDC_CONNECT, "Connect");
        break;
      }

      // Tell current dialog page about the change (others will find
      // out when they become visible).
      PostMessage((HWND)TabList[CurrTab].lParam, CHANGED_CONN, 0, 0);
      //POSTTOALL(CHANGED_CONN, 0, 0);

      return 0;
    }

    // Other normal buttons on the main dialog

    switch (LOWORD(mp1)) {
    case IDC_START: //----------------- Start/Stop button
      if (ConnList[CurrConn].ConnObj->IsStarted()) {
        ConnMgr->StopConnection(ConnList[CurrConn].ConnHandle, "");
      } else {
        DialogBox(hInst, MAKEINTRESOURCE(IDD_STARTCONNECTION), hwnd, (DLGPROC)DlgStartConnection);
      }
      return 0;
    case IDC_CONNECT: //--------------- Connect/Disconnect button
      if (ConnList[CurrConn].ConnObj->IsCommStarted())
        ConnList[CurrConn].ConnObj->StopCommunication();
      else
        ConnList[CurrConn].ConnObj->StartCommunication();
    }

    return FALSE;

  case WM_DRAWITEM: { /* Draw color session buttons */
    DRAWITEMSTRUCT *DrawData;
    ULONG           BorderColor, FillColor;

    DrawData = (DRAWITEMSTRUCT *)mp2;
    if (DrawData->itemState & ODS_FOCUS)
      BorderColor = CLR_BLACK;
      else BorderColor = CLR_DARKGRAY;

    i = mp1 - IDC_SESSION1;            // Index into ConnList array
    switch (ConnList[i].ConnStatus) {
    case CONNSTATUS_READY:             // Select color based on status
      FillColor = CLR_GREEN;
      break;
    case CONNSTATUS_STOPPED:
      FillColor = CLR_PALEGRAY;
      break;
    case CONNSTATUS_DISCONN:
      FillColor = CLR_YELLOW;
      break;
    default:
      FillColor = CLR_RED;
      break;
    }

    // Draw the custom button face
    DrawSessionButton(DrawData, FillColor, BorderColor, 'A'+i);

    return TRUE;
  }

  case STARTEVENT_ERROR:
    // Error interface of start/stop event handler was called.
    // mp2 is a pointer to an ECLErr object.  We just display
    // the error message.
    ERRBOX(hwnd,"Connection start/stop error:", ((ECLErr *)mp2)->GetMsgText());
    delete (ECLErr *)mp2;
    return 0;

  case WM_CLOSE:
    EndDialog(hwnd, 0);
    PostQuitMessage(0);
    break;


  } // switch msg

} catch (ECLErr Err) {
  ERRBOX(hwnd,  "ECL Error (main dialog):", Err.GetMsgText());
}

  return FALSE;
  
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI ScreenDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
// Dialog procedure for the "Screen" tab of the notebook
//---------------------------------------------------------------------------------------------
{

  try { // Capture any misc ECL errors

  switch (msg) {

  case WM_INITDIALOG: {
    // Set PS display to small monospaced font
    SendDlgItemMessage(hwnd, IDC_PSTEXT, WM_SETFONT, (WPARAM)MonoFont, (LPARAM)TRUE);
    break;
    }

  case CHANGED_CONN: {
    // Changed connections (or status of current connection).
    // If there is no Session object, disable everything.

    if (Session == NULL) {
      DISABLECONTROL(IDC_SENDKEYS);
      DISABLECONTROL(IDC_SEND);
      SETTEXT(IDC_SENDKEYS, "");
      SETTEXT(IDC_KEYMON, "");
      DISABLECONTROL(IDC_OIAINHIBIT);
      DISABLECONTROL(IDC_OIAINSERT);
      DISABLECONTROL(IDC_OIACAPS);
      DISABLECONTROL(IDC_OIANUM);
      DISABLECONTROL(IDC_OIAAPL);
      DISABLECONTROL(IDC_OIACAPSLOCK);
      DISABLECONTROL(IDC_OIADBCS);
      DISABLECONTROL(IDC_OIACOMMERR);
      DISABLECONTROL(IDC_OIAMSGWAIT);

      switch (ConnList[CurrConn].ConnStatus) {
      case CONNSTATUS_DISCONN:
        SETTEXT(IDC_PSTEXT, "<CONNECTION DISCONNECTED>");
        break;
      case CONNSTATUS_NOAPI:
        SETTEXT(IDC_PSTEXT, "<CONNECTION API DISABLED>");
        break;
      case CONNSTATUS_STOPPED:
        SETTEXT(IDC_PSTEXT, "<CONNECTION IS STOPPED>");
        break;
      default:
        SETTEXT(IDC_PSTEXT, "");
        break;
      }
    } else { 
      // Enable everything.  We will get PS and OIA updates
      // when the event is registered to update those fields.
      ENABLECONTROL(IDC_SENDKEYS);
      ENABLECONTROL(IDC_SEND);
      SETTEXT(IDC_KEYMON, "");
      SETTEXT(IDC_SENDKEYS, "");
      SendMessage(hwnd, WM_COMMAND, IDC_MONITOR, 0); // Set key monitor if checked
    }
    return 0;
  } // msg CHANGED_CONN

  case WM_SHOWWINDOW:
    if ((BOOL)mp1 == TRUE) { // This dialog becoming visible
      // Force update
      SendMessage(hwnd, CHANGED_CONN, 0, 0);
      if (Session != NULL) {
        SendMessage(hwnd, CHANGED_OIA, 0, 0);
        SendMessage(hwnd, CHANGED_PS,  0, 0);
      }
    }
    break;


  case CHANGED_OIA: 
    if(Session != NULL)
    {
    // OIA has been updated... update visual status
    ULONG   Status;

    if (CurrTab != 0)         // Ignore if not displaying this dialog
      return 0; 

    // We get all the status flags in one call which is much
    // faster than making a call for each one.

    Status = Session->GetOIA()->GetStatusFlags();

    switch (Status & OIAFLAG_INHIBMASK) {
    case NotInhibited:
      SETTEXT(IDC_OIAINHIBIT, "Uninhib");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    case SystemWait:
      SETTEXT(IDC_OIAINHIBIT, "System");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    case CommCheck:
      SETTEXT(IDC_OIAINHIBIT, "CommChk");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    case ProgCheck:
      SETTEXT(IDC_OIAINHIBIT, "ProgChk");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    case MachCheck:
      SETTEXT(IDC_OIAINHIBIT, "MachChk");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    case OtherInhibit:
      SETTEXT(IDC_OIAINHIBIT, "X");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    default:
      SETTEXT(IDC_OIAINHIBIT, "?");
      ENABLECONTROL(IDC_OIAINHIBIT);
      break;
    } // Inhibit switch

    // Update static text controls based on OIA status
    if (Status & OIAFLAG_INSERT)
      ENABLECONTROL(IDC_OIAINSERT);
    else
      DISABLECONTROL(IDC_OIAINSERT);

    if (Status & OIAFLAG_UPSHIFT)
      ENABLECONTROL(IDC_OIACAPS);
    else
      DISABLECONTROL(IDC_OIACAPS);

    if (Status & OIAFLAG_NUMERIC)
      ENABLECONTROL(IDC_OIANUM);
    else
      DISABLECONTROL(IDC_OIANUM);

    if (Status & OIAFLAG_APL)
      ENABLECONTROL(IDC_OIAAPL);
    else
      DISABLECONTROL(IDC_OIAAPL);

    if (Status & OIAFLAG_CAPSLOCK)
      ENABLECONTROL(IDC_OIACAPSLOCK);
    else
      DISABLECONTROL(IDC_OIACAPSLOCK);

    if (Status &OIAFLAG_DBCS)
      ENABLECONTROL(IDC_OIADBCS);
    else
      DISABLECONTROL(IDC_OIADBCS);

    if (Status & OIAFLAG_COMMERR)
      ENABLECONTROL(IDC_OIACOMMERR);
    else
      DISABLECONTROL(IDC_OIACOMMERR);

    if (Status & OIAFLAG_MSGWAIT)
      ENABLECONTROL(IDC_OIAMSGWAIT);
    else
      DISABLECONTROL(IDC_OIAMSGWAIT);

  } // OIA changed
  return 0;

  case CHANGED_PS: 
    if(Session != NULL)
    {
    // PS has been updated... update visual PS display
    ECLPS  *PS;               // Ptr to current session PS object
    ULONG  i;

    char *Screen;             // Character plane buffer
    ULONG Size;               // Size of PS, plus 3
    ULONG LineLen, Rows;      // Dimensions of the PS
    char Save1, Save2, Save3; // Temp character stores
    char *Ptr;                // Ptr into screen buffer

    if (CurrTab != 0)         // Ignore if this dialog is not visible
      return 0; 

    PS = Session->GetPS();                    // Get ptr to PS object
    PS->GetSize(&Rows, &LineLen);             // Get dimensions of PS
    Size = (Rows * LineLen) + 3;              // Calc reqd buffer size

    Screen = new char[Size];                  // Allocate buffer
    PS->GetScreen(Screen, Size, TextPlane);   // Get text plane

    // For each line, terminate it w/CR+LF+NULL and insert
    // into the multiline edit box control.

    SETTEXT(IDC_PSTEXT, "");                  // Clear edit box
    for (Ptr = Screen, i=0;                   // Start on 1st row
         i < Rows;                            // Until end of screen
         Ptr = Ptr+LineLen, i++) {            // Move ptr and counter

      Save1 = *(Ptr+LineLen);                 // Save 1st 3 chars of next row
      Save2 = *(Ptr+LineLen+1);
      Save3 = *(Ptr+LineLen+2);

      strcpy(Ptr+LineLen, "\r\n");            // Terminate line w/CR+LF+NULL
      SendDlgItemMessage(hwnd, IDC_PSTEXT, EM_REPLACESEL, FALSE, (LPARAM)Ptr);

      *(Ptr+LineLen) = Save1;                 // Restore next row
      *(Ptr+LineLen+1) = Save2;
      *(Ptr+LineLen+2) = Save3;
    } // for each line

    delete []Screen;                          // Cleanup buffer
  }  // msg CHANGED_PS

  case WM_COMMAND: 
    switch (LOWORD(mp1)) {
    case IDC_SEND: // Send keystrokes to the current connection, catch errors
      char SendBuff[255];
      GETTEXT(IDC_SENDKEYS, SendBuff, sizeof(SendBuff));
      try {
        Session->GetPS()->SendKeys(SendBuff);
      } catch (ECLErr Err) {
        ERRBOX(hwnd, "ECL Error sending keystrokes:", Err.GetMsgText());
      }
      break;

    case IDC_MONITOR: // Toggle keystroke monitor
      SETTEXT(IDC_KEYMON, "");
      if (Session == NULL)
        break;
      if (QUERYCHECK(IDC_MONITOR))
        Session->GetPS()->RegisterKeyEvent(KeyEvents);
      else
        Session->GetPS()->UnregisterKeyEvent(KeyEvents);
      break;

    }
    return FALSE;


  } // Switch on msg

} catch (ECLErr Err) {
  ERRBOX(hwnd,  "ECL Error (screen tab):", Err.GetMsgText());
}

  return FALSE;
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI FieldsDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
// Dialog procedure for the "Fields" tab of the notebook.
//---------------------------------------------------------------------------------------------
{
  int i;
  ECLField      *Fld;         // Ptr to one field object

  switch (msg) {

  case WM_INITDIALOG: {
    // Set column width of multicolumn listbox for 4 columns
    RECT Rect;

    GetWindowRect(GetDlgItem(hwnd, IDC_FIELDLIST), &Rect);
    SendDlgItemMessage(hwnd, IDC_FIELDLIST, LB_SETCOLUMNWIDTH, (Rect.right-Rect.left)/4, 0);

    break;
    }

  case WM_SHOWWINDOW:
    if ((BOOL)mp1 == TRUE) { // We are becoming visible
      SendMessage(hwnd, CHANGED_PS, 0, 0);  // Refresh list
    }
    break;

  case CLEAR_FIELDINFO: {
    // Reset all the GUI controls to empty values
    CLEARLIST(IDC_FIELDLIST);       
    SETTEXT(IDC_FLDSTARTROW, "");
    SETTEXT(IDC_FLDENDROW, "");
    SETTEXT(IDC_FLDSTARTCOL, "");
    SETTEXT(IDC_FLDENDCOL, "");
    SETTEXT(IDC_FLDLEN, "");
    SETTEXT(IDC_FIELDTEXT, "");
    CLEARCHECK(IDC_FLDMOD);
    CLEARCHECK(IDC_FLDPROTECT);
    CLEARCHECK(IDC_FLDHIGH);
    CLEARCHECK(IDC_FLDDISPLAY);
    CLEARCHECK(IDC_FLDNUM);
    CLEARCHECK(IDC_FLDPEN);
    return 0;
    } // msg CLEAR_FIELDINFO

  case CHANGED_CONN:
    // Changed connections (or status of current connection).
    SendMessage(hwnd, CHANGED_PS, 0, 0);      // Refresh if required
    return 0;

  case CHANGED_PS: {
    ECLFieldList  *Fields;      // Ptr to current session FieldList object
    char          Buff[20] = "Field n";

    // PS has been updated.  We only update the field display
    // if this is the current dialog tab (since it takes some
    // time to build the field list objects).
    if (CurrTab != 1)
      return 0;

    SendMessage(hwnd, CLEAR_FIELDINFO, 0, 0);  // Clear current GUI fields
    if (Session == NULL)                       // Stop if no current Sesion obj
      return 0;

    Fields = Session->GetPS()->GetFieldList(); // Get ptr to field list object
    Fields->Refresh();                         // Rebuild the list from current PS
    for (Fld = Fields->GetFirstField(), i=1;   // Insert each field in the listbox
         Fld != NULL;
         Fld = Fields->GetNextField(Fld), i++) {
      itoa(i, Buff+6, 10);
      SendDlgItemMessage(hwnd, IDC_FIELDLIST, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)Buff);
    }
    return 0;

    } // CHANGED_PS

  case WM_COMMAND: 
    switch (LOWORD(mp1)) {
    case IDC_FIELDLIST: //------------------- Message from listbox
      if (HIWORD(mp1) == LBN_SELCHANGE) { //- User selected a field 
        // Process selected field of the listbox
        i = QUERYSELECTION(IDC_FIELDLIST);
        if (i<0)  // No selection
          return 0;

        // Walk field list to get to selected field
        Fld = Session->GetPS()->GetFieldList()->GetFirstField();
        for (; i>0; i--)
          Fld = Session->GetPS()->GetFieldList()->GetNextField(Fld);

        //------------- Field attributes
        if (Fld->IsModified())
          SETCHECK(IDC_FLDMOD);
        else
          CLEARCHECK(IDC_FLDMOD);

        if (Fld->IsProtected())
          SETCHECK(IDC_FLDPROTECT);
        else
          CLEARCHECK(IDC_FLDPROTECT);
        
        if (Fld->IsHighIntensity())
          SETCHECK(IDC_FLDHIGH);
        else
          CLEARCHECK(IDC_FLDHIGH);
        
        if (Fld->IsDisplay())
          SETCHECK(IDC_FLDDISPLAY);
        else
          CLEARCHECK(IDC_FLDDISPLAY);
        
        if (Fld->IsNumeric())
          SETCHECK(IDC_FLDNUM);
        else
          CLEARCHECK(IDC_FLDNUM);
        
        if (Fld->IsPenDetectable())
          SETCHECK(IDC_FLDPEN);
        else
          CLEARCHECK(IDC_FLDPEN);

        //------------- Field text
        char *Buff;
        Buff = new char[Fld->GetLength() + 1];
        Fld->GetScreen(Buff, Fld->GetLength() + 1, TextPlane);
        SETTEXT(IDC_FIELDTEXT, Buff);
        delete []Buff;

        //------------- Field position
        ULONG Srow, Scol, Erow, Ecol, Len;
        Fld->GetStart(&Srow, &Scol);
        Fld->GetEnd(&Erow, &Ecol);
        Len = Fld->GetLength();

        SetDlgItemInt(hwnd, IDC_FLDSTARTROW, Srow, FALSE);
        SetDlgItemInt(hwnd, IDC_FLDSTARTCOL, Scol, FALSE);
        SetDlgItemInt(hwnd, IDC_FLDENDROW,   Erow, FALSE);
        SetDlgItemInt(hwnd, IDC_FLDENDCOL,   Ecol, FALSE);
        SetDlgItemInt(hwnd, IDC_FLDLEN   ,   Len , FALSE);
      }
    }
    return FALSE;


  } // Switch on msg

  return FALSE;
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI ConnDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
{

  switch (msg) {

  case WM_INITDIALOG: {
    break;
    }

  case WM_SHOWWINDOW:
    if ((BOOL)mp1 == TRUE) { // We are becoming visible
      SendMessage(hwnd, UPDATE_CONNINFO, 0, 0);  // Refresh GUI
    }
    break;

  case CHANGED_CONN:
    // Changed connections (or status of current connection).

    if (IsWindowVisible(hwnd))  // Only update if we are visible
      SendMessage(hwnd, UPDATE_CONNINFO, 0, 0);
    return 0;

  case UPDATE_CONNINFO:
    // Update GUI with current connection status
    char Buff[21];

    // Connection name
    Buff[0] = ConnList[CurrConn].ConnObj->GetName();
    Buff[1] = 0x00;
    SETTEXT(IDC_CONNNAME, Buff);

    // Connection handle
    sprintf(Buff, "0x%08lX", ConnList[CurrConn].ConnObj->GetHandle());
    SETTEXT(IDC_CONNHAND, Buff);

    // Connection type (converted to string)
    ECLBase::ConvertTypeToString(ConnList[CurrConn].ConnObj->GetConnType(), Buff);
    SETTEXT(IDC_CONNTYPE, Buff);

    // Host code page
    itoa(ConnList[CurrConn].ConnObj->GetCodePage(), Buff, 10);
    SETTEXT(IDC_CONNCP, Buff);

    // Ready flag
    if (ConnList[CurrConn].ConnObj->IsReady() == CONNSTATUS_READY)
      SETCHECK(IDC_CONNREADY);
    else
      CLEARCHECK(IDC_CONNREADY);

    // Started flag
    if (ConnList[CurrConn].ConnObj->IsStarted())
      SETCHECK(IDC_CONNSTARTED);
    else
      CLEARCHECK(IDC_CONNSTARTED);

    // Connected
    if (ConnList[CurrConn].ConnObj->IsCommStarted())
      SETCHECK(IDC_CONNCONNECTED);
    else
      CLEARCHECK(IDC_CONNCONNECTED);

    // API enabled
    if (ConnList[CurrConn].ConnObj->IsAPIEnabled())
      SETCHECK(IDC_CONNAPI);
    else
      CLEARCHECK(IDC_CONNAPI);

    return 0;

  } // Switch on msg

  return FALSE;
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI MetricsDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
{

  switch (msg) {

  case WM_INITDIALOG: {
    break;
    }

  } // Switch on msg

  return FALSE;
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI XferDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
{

  switch (msg) {

  case WM_INITDIALOG: {
    break;
    }

  } // Switch on msg

  return FALSE;
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI DlgStartConnection(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
// Dialog procedure for "Start Connection" dialog.
//---------------------------------------------------------------------------------------------
{
  static char ProfName[255] = "";  // Keep across instances of this dialog

  switch (msg) {

  case WM_INITDIALOG: {
    char Name[2];

    // Recall last used profile
    SETTEXT(IDC_STARTPROFILE, ProfName);
    // Set connection name on the GUI
    Name[0] = ConnList[CurrConn].ConnObj->GetName();
    Name[1] = 0x00;
    SETTEXT(IDC_STARTCONN, Name);

    SETCHECK(IDC_STARTREST);
    FOCUSCONTROL(IDC_STARTPROFILE);
    break;
    }

  case WM_COMMAND:
    switch (LOWORD(mp1)) {
    case IDOK: { //--------------------- (OK) Start connection button
      char *WinState;
      char Buff[sizeof(ProfName)+50];

      GETTEXT(IDC_STARTPROFILE, ProfName, sizeof(ProfName));
      if ((ProfName[0] == 0x00) || (ProfName[0] == ' ')) {
        ERRBOX(hwnd, "Invalid Profile Name","You must enter a workstation profile name with or without a '.WS' file type.");
        return 0;
      }
      if (QUERYCHECK(IDC_STARTMIN))
        WinState = "min";
      else if (QUERYCHECK(IDC_STARTMAX))
        WinState = "max";
      else if (QUERYCHECK(IDC_STARTMAX))
        WinState = "max";
      else if (QUERYCHECK(IDC_STARTREST))
        WinState = "restore";
      else if (QUERYCHECK(IDC_STARTHIDE))
        WinState = "hide";

      // Build ECLConnMgr::StartConnection config string
      sprintf(Buff, "profile=\"%s\" connname=%c winstate=%s",
              ProfName,
              ConnList[CurrConn].ConnObj->GetName(),
              WinState);

      // Start the new connection.  Note that control returns
      // here immediately and the connection will start sometime
      // later (our StartEvent object will be notified).

      try {
        ConnMgr->StartConnection(Buff);
      }
      catch (ECLErr Err) {
        ERRBOX(NULL, "Connection start failed.", Err.GetMsgText());
      }

      EndDialog(hwnd, IDOK);  // End this dialog
      return 0;
    } // IDOK

    case IDCANCEL:
      EndDialog(hwnd, IDCANCEL);
      return 0;

    } // switch on command ID

    return FALSE;

  } // Switch on msg

  return FALSE;
}
  
/*----------------------------------------------------------------------------*/
void DrawSessionButton(DRAWITEMSTRUCT *DrawData, LONG Color, LONG ColorBorder, char SessID)
/*----------------------------------------------------------------------------*/
/* Draw one of the connection buttons.  If it is the current connection,      */
/* hilight it with an inset double-border.                                    */
/*----------------------------------------------------------------------------*/
{
HBRUSH NewBrush, OldBrush;
HPEN   NewPen,   OldPen;

  NewBrush = CreateSolidBrush(Color);
  NewPen   = CreatePen(PS_SOLID, 1, CLR_DARKGRAY);

  if ((NewBrush) && (NewPen)) {
    OldBrush = (HBRUSH)SelectObject(DrawData->hDC, NewBrush);
    OldPen   = (HPEN)SelectObject(DrawData->hDC, NewPen);

    Rectangle(DrawData->hDC,       
             (DrawData->rcItem).left, (DrawData->rcItem).top,
             (DrawData->rcItem).right,(DrawData->rcItem).bottom);

    SetBkMode(DrawData->hDC, TRANSPARENT);
    SelectObject(DrawData->hDC, OldPen);
    DeleteObject(NewPen);
    NewPen = CreatePen(PS_SOLID, 1, CLR_BLACK);
    SelectObject(DrawData->hDC, NewPen);
    if ((SessID - 'A') == CurrConn) { // Hilight current connection
      int i;
      for (i=0; i<2; i++) {
      MoveToEx(DrawData->hDC, (DrawData->rcItem).left, (DrawData->rcItem).bottom, NULL);
      LineTo(DrawData->hDC, (DrawData->rcItem).left, (DrawData->rcItem).top);
      LineTo(DrawData->hDC, (DrawData->rcItem).right, (DrawData->rcItem).top);
      SelectObject(DrawData->hDC, OldPen);
      DeleteObject(NewPen);
      NewPen = CreatePen(PS_SOLID, 1, CLR_WHITE);
      SelectObject(DrawData->hDC, NewPen);
      InflateRect(&(DrawData->rcItem), -1, -1);
      MoveToEx(DrawData->hDC, (DrawData->rcItem).right, (DrawData->rcItem).top, NULL);
      LineTo(DrawData->hDC, (DrawData->rcItem).right, (DrawData->rcItem).bottom);
      LineTo(DrawData->hDC, (DrawData->rcItem).left, (DrawData->rcItem).bottom);
      SelectObject(DrawData->hDC, OldPen);
      DeleteObject(NewPen);
      NewPen = CreatePen(PS_SOLID, 1, CLR_BLACK);
      SelectObject(DrawData->hDC, NewPen);
      }
    }

    DrawText(DrawData->hDC, &SessID, 1, &(DrawData->rcItem), DT_CENTER|DT_VCENTER|DT_SINGLELINE);

    SelectObject(DrawData->hDC,OldPen);
    SelectObject(DrawData->hDC,OldBrush);
    DeleteObject(NewPen);
    DeleteObject(NewBrush);
  }

}

//---------------------------------------------------------------------------------------------
BOOL WINAPI PgConfDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
{

  switch (msg) {

  case WM_INITDIALOG: {
    //add CPI, LPI, MPL, MPP, Font info
    InitializePgConfTab(hwnd);
    break;
    }

  case WM_SHOWWINDOW:
    if ((BOOL)mp1 == TRUE) { // We are becoming visible
      SendMessage(hwnd, UPDATE_PG_CONF, 0, 0);  // Refresh GUI
    }
    break;

  case CHANGED_PG_CONF:
    // Changed connections (or status of current connection).

    if (IsWindowVisible(hwnd))  // Only update if we are visible
      SendMessage(hwnd, UPDATE_PG_CONF, 0, 0);
    return 0;

  case CHANGED_CONN:
    // Changed connections (or status of current connection).

    if (IsWindowVisible(hwnd))  // Only update if we are visible
      SendMessage(hwnd, UPDATE_PG_CONF, 0, 0);
    return 0;

  case UPDATE_PG_CONF:
    SETTEXT(IDC_EDIT_ERR_PAGESETUP,"");
    SetInPageConfTab(hwnd);
    break;

   case WM_COMMAND: 
    switch (LOWORD(mp1)) {
      //clear button pressed in Page configuration
    case IDC_BUTTON_PAGE_CLEAR:
      ClearPgConfPage(hwnd);
      break;

      // get values from session and propagate in GUI
    case IDC_BUTTON_PAGE_GET_VAL:
      SETTEXT(IDC_EDIT_ERR_PAGESETUP,"");
      SetInPageConfTab(hwnd);
      break;

      //set IBM default values in the session and update GUI
    case IDC_BUTTON_PAGE_SEND_DEF_VAL:
      SETTEXT(IDC_EDIT_ERR_PAGESETUP,"");
      RestoreDefaultPageValues(hwnd);
      //SetInPageConfTab(hwnd);
      break;

      //send values selected in GUI to session
    case IDC_BUTTON_PAGE_SET_VAL:
      SETTEXT(IDC_EDIT_ERR_PAGESETUP,"");
      SendPageConfValuesToSession(hwnd);
      break;
    case IDC_CHK_FONT_CPI:
      //ERRBOX(hwnd,  "IDC_CHK_FONT_CPI", "IDC_CHK_FONT_CPI");
      if(QUERYCHECK(IDC_CHK_FONT_CPI))
        DISABLECONTROL(IDC_COMBO_CPI);
      else
        ENABLECONTROL(IDC_COMBO_CPI);
      break;

    case IDC_CHK_FONT_LPI:
      //ERRBOX(hwnd,"IDC_CHK_FONT_LPI", "IDC_CHK_FONT_LPI");
      if(QUERYCHECK(IDC_CHK_FONT_LPI))
        DISABLECONTROL(IDC_COMBO_LPI);
      else
        ENABLECONTROL(IDC_COMBO_LPI);
      break;
      
    }
  } // Switch on msg

  return FALSE;
}

//---------------------------------------------------------------------------------------------
BOOL WINAPI PrtConfDlgProc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
//---------------------------------------------------------------------------------------------
{
  switch (msg) {

  case WM_INITDIALOG: {
    InitializePrtConfTab(hwnd);
    break;
    }

  case WM_SHOWWINDOW:
    if ((BOOL)mp1 == TRUE) { // We are becoming visible
      SendMessage(hwnd, UPDATE_PRT_CONF, 0, 0);  // Refresh GUI
    }
    break;

  case CHANGED_PRT_CONF:
    // Changed connections (or status of current connection).

    if (IsWindowVisible(hwnd))  // Only update if we are visible
      SendMessage(hwnd, UPDATE_PRT_CONF, 0, 0);
    return 0;

  case UPDATE_PRT_CONF:
    SETTEXT(IDC_EDIT_ERR_PRINTER,"");
    ClearPrtConfPage(hwnd);
    ReceivePrinterConfFromSession(hwnd);
    break;

  case WM_COMMAND: 
    switch (LOWORD(mp1)) {
      //opening Prt2Dsk - Append filename
    case IDC_BUTTON_BROWSE_PRT2DSK_APPEND:
      OpenPrt2DskPDTFile(hwnd, msg, mp1, mp2, IDC_EDIT_PRT2DISK_APPEND);
      break;

      //opening Prt2Dsk - Separate filename
    case IDC_BUTTON_BROWSE_PRT2DSK_SEPARATE:
      OpenPrt2DskPDTFile(hwnd, msg, mp1, mp2, IDC_EDIT_PRT2DISK_SEPARATE);
      break;

      //opening PDT file name
    case IDC_BUTTON_BROWSE_PDTFILE:
      OpenPrt2DskPDTFile(hwnd, msg, mp1, mp2, IDC_EDIT_PDTFILE);
      break;
      //clear button pressed
    case IDC_BUTTON_PRT_CLEAR :
      ClearPrtConfPage(hwnd);
      break;

    //send values to session
    case IDC_BUTTON_PRT_SET_VAL:
      SETTEXT(IDC_EDIT_ERR_PRINTER,"");
      SendPrinterConfToSession(hwnd);
     break;

    //send values to session
    case IDC_BUTTON_PRT_GET_VAL:
      SETTEXT(IDC_EDIT_ERR_PRINTER,"");
      ClearPrtConfPage(hwnd);
      ReceivePrinterConfFromSession(hwnd);
      break;
    }
  } // Switch on msg

  return FALSE;
}

void InitializePgConfTab(HWND hwnd)
{
  int i;
  char szStr[256];
  HDC  hDC;
  
  //get printer dc. we should get this from Printer Conf tab (?) 
  // or from session. right now list all fonts of Display
    hDC = CreateDC("DISPLAY", NULL, NULL, NULL);

    //add CPI values
    ADDSTRING2COMBO(IDC_COMBO_CPI,"10");
    ADDSTRING2COMBO(IDC_COMBO_CPI,"12");
    ADDSTRING2COMBO(IDC_COMBO_CPI,"17");
    ADDSTRING2COMBO(IDC_COMBO_CPI,BLANK_ITEM);

    //add LPI values
    ADDSTRING2COMBO(IDC_COMBO_LPI,"2");
    ADDSTRING2COMBO(IDC_COMBO_LPI,"3");
    ADDSTRING2COMBO(IDC_COMBO_LPI,"4");
    ADDSTRING2COMBO(IDC_COMBO_LPI,"6");
    ADDSTRING2COMBO(IDC_COMBO_LPI,"8");
    ADDSTRING2COMBO(IDC_COMBO_LPI,BLANK_ITEM);

    //add MPL values
    for(i = MIN_MPL; i <= MAX_MPL; i++)
    {
      sprintf(szStr,"%d",i);
      ADDSTRING2COMBO(IDC_COMBO_MPL,szStr);
    }
    ADDSTRING2COMBO(IDC_COMBO_MPL,BLANK_ITEM);
    //add MPP values
    for(i = MIN_MPP; i <= MAX_MPP; i++)
    {
      sprintf(szStr,"%d",i);
      ADDSTRING2COMBO(IDC_COMBO_MPP,szStr);
    }
    ADDSTRING2COMBO(IDC_COMBO_MPP,BLANK_ITEM);

#ifndef NO_PRTR_API
     //add font information
    EnumFonts(hDC,NULL,AddFace2Combo,(LPARAM) hwnd);
#endif 
    ADDSTRING2COMBO(IDC_COMBO_FONT, BLANK_ITEM);

    //select default values
    SELECTINCOMBO(IDC_COMBO_CPI,"10");
    SELECTINCOMBO(IDC_COMBO_LPI,"6");
    SELECTINCOMBO(IDC_COMBO_MPL,"66");
    SELECTINCOMBO(IDC_COMBO_MPP,"132");

    DeleteDC(hDC);
}

int CALLBACK AddFace2Combo(
  CONST LOGFONT *lplf,     // logical-font data
  CONST TEXTMETRIC *lptm,  // physical-font data
  DWORD dwType,            // font type
  LPARAM mp           // application-defined data
)
{
  HWND hwnd;
  hwnd = (HWND)mp;

  ADDSTRING2COMBO(IDC_COMBO_FONT, lplf->lfFaceName);
  return (1);
}

void InitializePrtConfTab(HWND hwnd)
{
  ListPrinters(hwnd);
  DPGetDefaultPrinter(hwnd);

  //PDT mode selection
  ADDSTRING2COMBO(IDC_COMBO_PDT_MODE, SET_PDT);
  ADDSTRING2COMBO(IDC_COMBO_PDT_MODE, RESET_PDT);
  ADDSTRING2COMBO(IDC_COMBO_PDT_MODE, DONT_SEND_THIS);

  //Show Printer Setup Dialog before every print
  ADDSTRING2COMBO(IDC_COMBO_DEF_SHOW_DLG, SHOW_B4_PRINT);
  ADDSTRING2COMBO(IDC_COMBO_DEF_SHOW_DLG, DONT_SHOW_B4_PRINT);
  ADDSTRING2COMBO(IDC_COMBO_DEF_SHOW_DLG, DONT_SEND_THIS);

  SELECTINCOMBO(IDC_COMBO_PDT_MODE, DONT_SEND_THIS);
  SELECTINCOMBO(IDC_COMBO_DEF_SHOW_DLG, DONT_SEND_THIS);

  return;
}

void ListPrinters(HWND hwnd)
{
#ifndef NO_PRTR_API
  //for VisualAge C++ compiler, enumerate the printers and add to list
  //for MS VC++ compiler, this function lists the installed printers
  int i;
  DWORD  Flags, Level, cbBuf, cbNeeded, cReturned;
  LPSTR          Name         = NULL;
  LPBYTE         pPrinterEnum = NULL;
  char           entry[MAX_STRING_LEN];
  PRINTER_INFO_2 *pPrinterInfo2;
  
  Level        = 2;
  cbBuf        = 0;
  cbNeeded     = 0;
  cReturned    = 0;
  
  Flags = PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL;
  
  // Get required memory buffer size
  EnumPrinters(Flags,
               Name,
               Level,
               pPrinterEnum,
               cbBuf,
               &cbNeeded,
               &cReturned);
  
  if (cbNeeded && 
    (pPrinterEnum = (LPBYTE)GlobalAlloc(GPTR, cbNeeded)) != NULL)
  {
    // Get all installed printer information
    cbBuf = cbNeeded;
    EnumPrinters(Flags,
                 Name,
                 Level,
                 pPrinterEnum,
                 cbBuf,
                 &cbNeeded,
                 &cReturned);
    
    // Put all information to listbox
    pPrinterInfo2 = (PRINTER_INFO_2 *)pPrinterEnum;
    for (i = 0; i < (int)cReturned; i++, pPrinterInfo2++)
    {
      lstrcpy(entry, pPrinterInfo2->pPrinterName);
      lstrcat(entry, ON_STRING);
      lstrcat(entry, pPrinterInfo2->pPortName);
      ADDSTRING2COMBO(IDC_COMBO_PRINTER,entry);
    }
    GlobalFree((HGLOBAL)pPrinterEnum);
  }
  ADDSTRING2COMBO(IDC_COMBO_PRINTER,BLANK_ITEM);

#endif  //for MS VC++ compiler
  return;
}

void OpenPrt2DskPDTFile(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2, int iID)
{
#ifndef NO_PRTR_API

  OPENFILENAME ofn;       // common dialog box structure
  char szFile[260];       // buffer for file name
  
  GETTEXT(iID, szFile, sizeof(szFile));

  // Initialize OPENFILENAME
  ZeroMemory(&ofn, sizeof(ofn));
  ofn.lStructSize = sizeof(ofn);
  ofn.hwndOwner = hwnd;
  ofn.lpstrFile = szFile;
  //
  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
  // use the contents of szFile to initialize itself.
  //
  ofn.lpstrFile[0] = '\0';
  ofn.nMaxFile = sizeof(szFile);
  ofn.lpstrFilter = "All\0*.*\0";
  ofn.nFilterIndex = 1;
  ofn.lpstrFileTitle = NULL;
  ofn.nMaxFileTitle = 0;
  ofn.lpstrInitialDir = NULL;
  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  
  // Display the Open dialog box. 
  if(GetOpenFileName(&ofn) == TRUE)
    SETTEXT(iID, szFile);
#endif
  return;
}

void ClearPrtConfPage(HWND hwnd)
{
  //clear printer type radio buttons
  CLEARCHECK(IDC_RADIO_PRT2DSK_APPEND);
  CLEARCHECK(IDC_RADIO_PRT2DSK_SEPARATE);
  CLEARCHECK(IDC_RADIO_DEF_PRINTER);
  CLEARCHECK(IDC_RADIO_NON_DEF_PRINTER);

  //clear edit boxes of printer type
  SETTEXT(IDC_EDIT_PRT2DISK_APPEND,"");
  SETTEXT(IDC_EDIT_PRT2DISK_SEPARATE,"");

  //clear PDT file edit box
  SETTEXT(IDC_EDIT_PDTFILE,"");

  //clear non-default windows printer combo
  SELECTINCOMBO(IDC_COMBO_PRINTER,BLANK_ITEM);
  SETCHECK(IDC_RADIO_NONE_PRINTER);

  //clear Set PDT and Show dialog before every print
  SELECTINCOMBO(IDC_COMBO_PDT_MODE, DONT_SEND_THIS);
  SELECTINCOMBO(IDC_COMBO_DEF_SHOW_DLG, DONT_SEND_THIS);

  //clear the Error edit box
  SETTEXT(IDC_EDIT_ERR_PRINTER,"");

  return;
}

void ClearPgConfPage(HWND hwnd)
{
  //clear Set PDT and Show dialog before every print
  CLEARCHECK(IDC_CHK_FONT_CPI);
  CLEARCHECK(IDC_CHK_FONT_LPI);

  ENABLECONTROL(IDC_COMBO_CPI);
  ENABLECONTROL(IDC_COMBO_LPI);

  //clear all the page configuration combo boxes
  SELECTINCOMBO(IDC_COMBO_CPI,BLANK_ITEM);
  SELECTINCOMBO(IDC_COMBO_LPI,BLANK_ITEM);
  SELECTINCOMBO(IDC_COMBO_MPP,BLANK_ITEM);
  SELECTINCOMBO(IDC_COMBO_MPL,BLANK_ITEM);
  SELECTINCOMBO(IDC_COMBO_FONT,BLANK_ITEM);

  SETTEXT(IDC_EDIT_ERR_PAGESETUP,"");

  return;
}

void DPGetDefaultPrinter(HWND hwnd)
{
#ifndef NO_PRTR_API
  //for VisualAge C++ compiler, enumerate the printers and add to list
  //for MS VC++ compiler, this function lists the installed printers
  BOOL bFlag;
  OSVERSIONINFO osv;
  TCHAR cBuffer[256];
  PRINTER_INFO_2 *ppi2 = NULL;
  DWORD dwNeeded = 0;
  DWORD dwReturned = 0;
  HMODULE hWinSpool = NULL;
  PROC fnGetDefaultPrinter = NULL;
  char szPrinterName[256];
  DWORD dwBufferSize;
  BOOL  bErr = FALSE;
  
  // What version of Windows are you running?
  osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  GetVersionEx(&osv);
  
  // If Windows 95 or 98, use EnumPrinters.
  do
  {
    if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
    {
      // The first EnumPrinters() tells you how big our buffer must
      // be to hold ALL of PRINTER_INFO_2. Note that this will
      // typically return FALSE. This only means that the buffer (the 4th
      // parameter) was not filled in. You do not want it filled in here.
      SetLastError(0);
      bFlag = EnumPrinters(PRINTER_ENUM_DEFAULT, NULL, 2, NULL, 0, &dwNeeded, &dwReturned);
      {
        if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (dwNeeded == 0))
        {
          bErr= TRUE; break;
        }
      }
      
      // Allocate enough space for PRINTER_INFO_2.
      ppi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, dwNeeded);
      if (!ppi2)
      {
        bErr = TRUE; break;
      }
      
      // The second EnumPrinters() will fill in all the current information.
      bFlag = EnumPrinters(PRINTER_ENUM_DEFAULT, NULL, 2, (LPBYTE)ppi2, dwNeeded, &dwNeeded, &dwReturned);
      if (!bFlag)
      {
        GlobalFree(ppi2);
        bErr = TRUE; break;
      }
      
      // If specified buffer is too small, set required size and fail.
      if ((DWORD)lstrlen(ppi2->pPrinterName) >= dwBufferSize)
      {
        dwBufferSize = (DWORD)lstrlen(ppi2->pPrinterName) + 1;
        GlobalFree(ppi2);
        bErr = TRUE; break;
      }
      
      // Copy printer name into passed-in buffer.
      lstrcpy(szPrinterName, ppi2->pPrinterName);
      lstrcat(szPrinterName, ppi2->pPortName);
      
      // Set buffer size parameter to minimum required buffer size.
      dwBufferSize = (DWORD)lstrlen(ppi2->pPrinterName) + 1;
    }
    
    // If Windows NT, use the GetDefaultPrinter API for Windows 2000,
    // or GetProfileString for version 4.0 and earlier.
    else if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
      // Retrieve the default string from Win.ini (the registry).
      // String will be in form "printername,drivername,portname".
      if (GetProfileString("windows", "device", ",,,", cBuffer, 256) <= 0)
      {
        bErr = TRUE;
        break;
      }
      
      // Printer name precedes first "," character.
      strtok(cBuffer, ",");
      
      // If specified buffer is too small, set required size and fail.
      if ((DWORD)lstrlen(cBuffer) >= dwBufferSize)
      {
        dwBufferSize = (DWORD)lstrlen(cBuffer) + 1;
        bErr = TRUE;
        break;
      }
      
      // Copy printer name into passed-in buffer.
      lstrcpy(szPrinterName, cBuffer);
      
      // Set buffer size parameter to minimum required buffer size.
      dwBufferSize = (DWORD)lstrlen(cBuffer) + 1;
    }
    
    // Clean up.
    if (ppi2)
      GlobalFree(ppi2);
  }while(0);
  
  if(bErr)
    lstrcpy(szPrinterName, "");
  
  SETTEXT(IDC_EDIT_DEF_PRINTER,szPrinterName);

#endif   //for MS VC++

  return;
}

void SetInPageConfTab(HWND hwnd)
{
    char szTemp[MAX_STRING_LEN + 1]="\0";

    SESSION_CHECK(IDC_EDIT_ERR_PAGESETUP)
    TRY_EHLLAPI()
    ECLPageSettings *pTestPgSet = Session->GetPageSettings();

    //check or uncheck fontCPI
    if(pTestPgSet->IsFontCPI())
    {
      SETCHECK(IDC_CHK_FONT_CPI);
      DISABLECONTROL(IDC_COMBO_CPI);
    }
    else
    {
      CLEARCHECK(IDC_CHK_FONT_CPI);
      ENABLECONTROL(IDC_COMBO_CPI);
    }

    //check or uncheck fontLPI
    if(pTestPgSet->IsFontLPI())
    {
      SETCHECK(IDC_CHK_FONT_LPI);
      DISABLECONTROL(IDC_COMBO_LPI);
    }
    else
    {
      CLEARCHECK(IDC_CHK_FONT_LPI);
      ENABLECONTROL(IDC_COMBO_LPI);
    }

    int c = pTestPgSet->GetCPI();
    int l = pTestPgSet->GetLPI();
    
    //other selections
    SELECTINCOMBO(IDC_COMBO_CPI, _itoa(pTestPgSet->GetCPI(),szTemp,10));
    SELECTINCOMBO(IDC_COMBO_LPI, _itoa(pTestPgSet->GetLPI(),szTemp,10));
    SELECTINCOMBO(IDC_COMBO_MPL, _itoa(pTestPgSet->GetMaxCharsPerLine(),szTemp,10));
    SELECTINCOMBO(IDC_COMBO_MPP, _itoa(pTestPgSet->GetMaxLinesPerPage(),szTemp,10));
    SETTEXT(IDC_COMBO_FONT, pTestPgSet->GetFontFaceName());
    CATCH_EHLLAPI(IDC_EDIT_ERR_PAGESETUP)

    GETTEXT(IDC_EDIT_ERR_PAGESETUP, szTemp, MAX_STRING_LEN);
    if(szTemp[0] == '\0') //No error. Successful
      SETTEXT(IDC_EDIT_ERR_PAGESETUP, MSG_SUCCESSFUL);

}

void RestoreDefaultPageValues(HWND hwnd)
{
  ULONG nTabs = PAGE_TEXT;
  ECLPageSettings *pTestPgSet;
  char szErr[MAX_STRING_LEN + 1]="\0";

  SESSION_CHECK(IDC_EDIT_ERR_PAGESETUP)
  TRY_EHLLAPI()
  pTestPgSet = Session->GetPageSettings();
  pTestPgSet->RestoreDefaults(nTabs);
  CATCH_EHLLAPI(IDC_EDIT_ERR_PAGESETUP);

  GETTEXT(IDC_EDIT_ERR_PAGESETUP, szErr, MAX_STRING_LEN);
  if(szErr[0] == '\0') //No error. Successful
    SETTEXT(IDC_EDIT_ERR_PAGESETUP, MSG_SUCCESSFUL);

  return;
}

#define CATCH_EHLLAPI_ERR(str)  } \
                               catch (ECLErr Err) \
                              {strcat(szErr,str);}


void SendPageConfValuesToSession(HWND hwnd)
{
  BOOL bNothingSet = TRUE;
  int   iVal;
  ULONG nTabs = PAGE_TEXT;
  ECLPageSettings *pTestPgSet;
  char szTemp[MAX_STRING_LEN + 1]="\0";
  char szErr[MAX_STRING_LEN + 1]="\0";
  char *szErrMsg[5]={" CPI","  LPI","  MaxCharsPerLine","  MaxCharsPerPage","  FontFaceName"};

  SESSION_CHECK(IDC_EDIT_ERR_PAGESETUP)
  TRY_EHLLAPI()
  pTestPgSet = Session->GetPageSettings();
  CATCH_EHLLAPI(IDC_EDIT_ERR_PAGESETUP);

  TRY_EHLLAPI()
  //send CPI to session
  if(QUERYCHECK(IDC_CHK_FONT_CPI))
  {
    pTestPgSet->SetCPI();
    bNothingSet = FALSE;
  }
  else
  {
    GETTEXT(IDC_COMBO_CPI,szTemp,MAX_STRING_LEN);
    iVal = atoi(szTemp);
    if(iVal)
    {
     pTestPgSet->SetCPI(iVal);
     bNothingSet = FALSE;
    }
  }
  CATCH_EHLLAPI_ERR(szErrMsg[0]);
    
  //send LPI to session
  TRY_EHLLAPI()
  if(QUERYCHECK(IDC_CHK_FONT_LPI))
  {
    pTestPgSet->SetLPI();
    bNothingSet = FALSE;
  }
  else
  {
    GETTEXT(IDC_COMBO_LPI, szTemp, MAX_STRING_LEN);
    iVal = atoi(szTemp);
    if(iVal)
    {
      pTestPgSet->SetLPI(iVal);
      bNothingSet = FALSE;
    }
  }
  CATCH_EHLLAPI_ERR(szErrMsg[1]);

  //send MPL to session
  TRY_EHLLAPI()
  GETTEXT(IDC_COMBO_MPP, szTemp, MAX_STRING_LEN);

  iVal = atoi(szTemp);
  if(iVal)
  {
    pTestPgSet->SetMaxLinesPerPage(iVal);
    bNothingSet = FALSE;
  }
  CATCH_EHLLAPI_ERR(szErrMsg[2]);

  //send MPL to session
  TRY_EHLLAPI()
  GETTEXT(IDC_COMBO_MPL, szTemp, MAX_STRING_LEN);
  iVal = atoi(szTemp);
  if(iVal)
  {
    pTestPgSet->SetMaxCharsPerLine(iVal);
    bNothingSet = FALSE;
  }
  CATCH_EHLLAPI_ERR(szErrMsg[3]);

  //send font to session
  TRY_EHLLAPI()
  GETTEXT(IDC_COMBO_FONT, szTemp, MAX_STRING_LEN);
  if(strcmp(szTemp, BLANK_ITEM))
  {
    pTestPgSet->SetFontFaceName(szTemp); 
    bNothingSet = FALSE;
  }
  CATCH_EHLLAPI_ERR(szErrMsg[4]);

  iVal = strlen(szErr);

  if(iVal)            //some error sent from session
  {
    sprintf(szErr,"%s  is/are invalid. %c%c Please Enter correct Values",szErr,13,10);
    SETTEXT(IDC_EDIT_ERR_PAGESETUP,szErr);
  }
  else if(bNothingSet)     //nothing is set for sending to session
     SETTEXT(IDC_EDIT_ERR_PAGESETUP, NOTHING_SELECTED);
  
  else                     //successfully sent to session
    SETTEXT(IDC_EDIT_ERR_PAGESETUP, MSG_SUCCESSFUL);

  return;
}

void SendPrinterConfToSession(HWND hwnd)
{
  ECLPrinterSettings *pTestPrtSet;
  const char * const szTemp2 = "test";
  char szTemp[MAX_STRING_LEN + 1];
  BOOL bSelected;
  int  iSel;
  BOOL bNothingSet = TRUE;

  SESSION_CHECK(IDC_EDIT_ERR_PRINTER)
  TRY_EHLLAPI()
  pTestPrtSet = Session->GetPrinterSettings();
  CATCH_EHLLAPI(IDC_EDIT_ERR_PRINTER);

  //send PDT selection to session
  GETTEXT(IDC_COMBO_PDT_MODE, szTemp, MAX_STRING_LEN);
  if(!strcmp(szTemp, RESET_PDT))
    iSel = 0;
  else if(!strcmp(szTemp, SET_PDT))
    iSel = 1;
  else
    iSel = -1;

  if(iSel >=0)
  {
    TRY_EHLLAPI()
    bSelected = iSel ? TRUE : FALSE;
    GETTEXT(IDC_EDIT_PDTFILE,szTemp,MAX_STRING_LEN);
    pTestPrtSet->SetPDTMode(bSelected,szTemp);
    CATCH_EHLLAPI(IDC_EDIT_ERR_PRINTER);

    bNothingSet = FALSE;
  }

  //send Showdialog to session
  GETTEXT(IDC_COMBO_DEF_SHOW_DLG, szTemp, MAX_STRING_LEN);
  if(!strcmp(szTemp, DONT_SHOW_B4_PRINT))
    iSel = 0;
  else if(!strcmp(szTemp, SHOW_B4_PRINT))
    iSel = 1;
  else
    iSel = -1;

  if(iSel >=0)
  {
    TRY_EHLLAPI()
    bSelected = iSel ? TRUE : FALSE;
    pTestPrtSet->SetPromptDialog(bSelected);
    CATCH_EHLLAPI(IDC_EDIT_ERR_PRINTER);

    bNothingSet = FALSE;
  }

  //sending printer type
  TRY_EHLLAPI()
  if(QUERYCHECK(IDC_RADIO_PRT2DSK_APPEND))
  {
    GETTEXT(IDC_EDIT_PRT2DISK_APPEND,szTemp,MAX_STRING_LEN);
    pTestPrtSet->SetPrtToDskAppend(szTemp);
	bNothingSet = FALSE;
  }
  else if(QUERYCHECK(IDC_RADIO_PRT2DSK_SEPARATE))
  {
    GETTEXT(IDC_EDIT_PRT2DISK_SEPARATE,szTemp,MAX_STRING_LEN);
    pTestPrtSet->SetPrtToDskSeparate(szTemp);
	bNothingSet = FALSE;
  }
  else if(QUERYCHECK(IDC_RADIO_DEF_PRINTER))
  {
    pTestPrtSet->SetWinDefaultPrinter();
	bNothingSet = FALSE;
  }
  else if(QUERYCHECK(IDC_RADIO_NON_DEF_PRINTER))
  {
    GETTEXT(IDC_COMBO_PRINTER,szTemp,MAX_STRING_LEN);
    pTestPrtSet->SetSpecificPrinter(szTemp);
	bNothingSet = FALSE;
  }
  CATCH_EHLLAPI(IDC_EDIT_ERR_PRINTER);

  if(bNothingSet)     //nothing is set in session
     SETTEXT(IDC_EDIT_ERR_PRINTER, NOTHING_SELECTED);
  else
  {
    GETTEXT(IDC_EDIT_ERR_PRINTER,szTemp,MAX_STRING_LEN);
    if(strlen(szTemp) == 0)  //Successful. No errors
      SETTEXT(IDC_EDIT_ERR_PRINTER, MSG_SUCCESSFUL);
  }
  return;
}

void ReceivePrinterConfFromSession(HWND hwnd)
{
  ECLPrinterSettings *pTestPrtSet;
  int iMode;
  char szTemp[MAX_STRING_LEN + 1];

  SESSION_CHECK(IDC_EDIT_ERR_PRINTER);
  TRY_EHLLAPI()

  pTestPrtSet = Session->GetPrinterSettings();

  //PDT mode
  if(pTestPrtSet->IsPDTMode())
    SELECTINCOMBO(IDC_COMBO_PDT_MODE, SET_PDT);
  else
    SELECTINCOMBO(IDC_COMBO_PDT_MODE, RESET_PDT);

  //Show Printer Setup dialog before every print
  if(pTestPrtSet->IsPromptDialogEnabled())
    SELECTINCOMBO(IDC_COMBO_DEF_SHOW_DLG, SHOW_B4_PRINT);
  else
    SELECTINCOMBO(IDC_COMBO_DEF_SHOW_DLG, DONT_SHOW_B4_PRINT);

  //update PDT file name
  SETTEXT(IDC_EDIT_PDTFILE,pTestPrtSet->GetPDTFile());

  //update Prt2Dsk - Append file name
  SETTEXT(IDC_EDIT_PRT2DISK_APPEND,pTestPrtSet->GetPrtToDskAppendFile());

  //update Prt2Dsk - Separate file name
  SETTEXT(IDC_EDIT_PRT2DISK_SEPARATE,pTestPrtSet->GetPrtToDskSeparateFile());

  //clear printer type radio buttons
  CLEARCHECK(IDC_RADIO_PRT2DSK_APPEND);
  CLEARCHECK(IDC_RADIO_PRT2DSK_SEPARATE);
  CLEARCHECK(IDC_RADIO_DEF_PRINTER);
  CLEARCHECK(IDC_RADIO_NON_DEF_PRINTER);
  CLEARCHECK(IDC_RADIO_NONE_PRINTER);

 //select printer type radio button
  iMode = pTestPrtSet->GetPrintMode();
  switch(iMode)
  {
  case ECLPrinterSettings::PrtToDskAppend:
    SETCHECK(IDC_RADIO_PRT2DSK_APPEND);
    break;
  case ECLPrinterSettings::PrtToDskSeparate:
    SETCHECK(IDC_RADIO_PRT2DSK_SEPARATE);
    break;
  case ECLPrinterSettings::SpecificPrinter:
    SETCHECK(IDC_RADIO_NON_DEF_PRINTER);
    break;
  case ECLPrinterSettings::WinDefaultPrinter:
    SETCHECK(IDC_RADIO_DEF_PRINTER);
    break;
  default :
    SETCHECK(IDC_RADIO_NONE_PRINTER);
  }

  //update Printer name only for non-default printer
  if(iMode == 3)
    SETTEXT(IDC_COMBO_PRINTER,pTestPrtSet->GetPrinterName());

  CATCH_EHLLAPI(IDC_EDIT_ERR_PRINTER)

  GETTEXT(IDC_EDIT_ERR_PRINTER, szTemp, MAX_STRING_LEN);
  if(szTemp[0] == '\0') //successfully received from session
    SETTEXT(IDC_EDIT_ERR_PRINTER, MSG_SUCCESSFUL);

  return;
}


//---------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hinstInst, 
                   HINSTANCE hinstPrevInstance, 
                   LPSTR lpszCmdLine, 
                   int nCmdShow)
//---------------------------------------------------------------------------------------------
//  Main routine                                                                   
//---------------------------------------------------------------------------------------------
{
LOGFONT lFont;

   //Save app instance for later use
   hInst = hinstInst;

   InitCommonControls();

   // Make 6 point monospaced font
   lFont.lfHeight = -MulDiv(6, GetDeviceCaps(GetDC(GetDesktopWindow()), LOGPIXELSY), 72);
   lFont.lfWidth = 0;
   lFont.lfEscapement = 0;
   lFont.lfOrientation = 0;
   lFont.lfWeight = FW_NORMAL;
   lFont.lfItalic = 0;
   lFont.lfUnderline = 0;
   lFont.lfStrikeOut = 0;
   lFont.lfCharSet = ANSI_CHARSET;
   lFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
   lFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
   lFont.lfQuality = DEFAULT_QUALITY;
   lFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
   strcpy(lFont.lfFaceName, "Courier New");
   MonoFont = CreateFontIndirect(&lFont);

 
   // To set a dialog control font:
   //SendDlgItemMessage(hwnd, CTR_ID, WM_SETFONT, (WPARAM)MonoFont, (LPARAM)TRUE);

   // The main dialog is the main application window.
   DialogBox(hinstInst, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)DlgMainProc);

   DeleteObject(MonoFont);

   return(0);
}


