// Copyright distributed.net 1997-1999 - All Rights Reserved
// For use in distributed.net projects only.
// Any other distribution or use of this source violates copyright.
//
// $Log: w32cons.cpp,v $
// Revision 1.22.2.4  1999/01/30 16:16:02  remi
// Synced with :
//
//  Revision 1.37  1999/01/29 18:43:53  jlawson
//  fixed formatting.  fixed possible problem in the win16 sleep when
//  tickcount becomes less than its previous value.
//
//  Revision 1.36  1999/01/15 00:38:04  cyp
//  uh. SetForegroundWindow() is win32 only.
//
//  Revision 1.35  1999/01/12 16:41:11  cyp
//  Fixed tray/popup.
//
//  Revision 1.34  1999/01/11 23:40:25  michmarc
//  Added casts required to make VC happy
//
//  Revision 1.33  1999/01/09 03:04:52  cyp
//  save last used window position/size for use when restarting.
//
// Revision 1.22.2.3  1999/01/04 02:55:12  remi
// Synced with :
//
//  Revision 1.32  1999/01/02 07:29:30  silby
//  Change so code compiles on msvc.  Thanks for the tip, cow.
//
//  Revision 1.31  1999/01/01 02:45:18  cramer
//  Part 1 of 1999 Copyright updates...
//
// Revision 1.22.2.2  1998/12/29 20:13:00  remi
// Synced with :
//
//  Revision 1.30  1998/12/28 17:18:50  silby
//  USE_NATIVE_CONSOLEIO works again.
//
//  Revision 1.29  1998/12/26 20:53:40  cyp
//  Added minimize-to-taskbar and popup code. Added long and short versions of
//  benchmark.
//
//  Revision 1.28  1998/12/20 07:12:11  cyp
//  adjusted WM_ENDSESSION for win32 service.
//
//  Revision 1.27  1998/12/20 03:36:54  cyp
//  Changed background color to RGB(0,0,128) instead of RGB(0,0,127). I have
//  no idea whether this is a better representation of blue (or whether
//  this will solve Blast's problem) but its worth a shot.
//
//  Revision 1.26  1998/12/16 07:23:41  silby
//  changed MoveTo() to MoveToEx()
//
//  Revision 1.25  1998/12/16 07:13:37  cyp
//  win16 changes. La, la join the dots.
//
//  Revision 1.24  1998/12/05 22:28:46  cyp
//  Added -kill/-hup support.
//
//  Revision 1.23  1998/12/01 00:16:54  cyp
//  win16 endsession is now handled 'correctly'. Version check for win32
//  service start fixed.
//
// Revision 1.22.2.1  1998/11/16 10:02:19  remi
// Removed unused code.
//
// Revision 1.22  1998/11/14 19:35:51  cyp
// Font problem (aka "1024x768") fixed. Restart problem fixed. Screen destroy
// problem fixed. Slow exit fixed.
//
// Revision 1.21  1998/11/14 13:48:19  cyp
// Fixed win16 instance protection. Fixed clear screen.
//
// Revision 1.20  1998/11/11 05:37:21  cyp
// Added single-client-instance protection for win16; created w32ConGetPos(),
// w32ConSetPos(), w32ConGetWinVersion() [returns DOS style ver (>=20 for NT)]
//
// Revision 1.19  1998/11/11 01:21:44  cyp
// IDM_UPDATE not IDM_FETCH
//
// Revision 1.18  1998/11/10 10:51:10  silby
// RC5 benchmark was being triggered instead of DES benchmark; fixed.
//
// Revision 1.17  1998/11/08 20:11:07  cyp
// Added w32ConGetSize()
//
// Revision 1.16  1998/11/02 06:10:36  cyp
// urgh! 'fixed' the debug functions I had left in.
//
// Revision 1.15  1998/11/02 05:33:39  cyp
// win32 creation/message-loop now runs on its own thread; iconize-before-close
// problem resolved; color problem fixed; added a pop up menu (primarily for
// win16 that can do these things only with progman's/fileman's run command);
// mutex creation for win32 moved to WinMain()/realmain(); window title is
// standardized so that a gui controller can find it; Client is now restartable.
//
// Revision 1.14  1998/10/26 04:32:58  cyp
// Both win16 and win32 work fine. Some speed tweaking in w16Yield() is
// needed.
//
// Revision 1.11  1998/10/20 07:41:16  silby
// Changed win32 to use win32 sleeping and yielding instead of 
// win16 equiv of those two.
//
// Revision 1.10  1998/10/19 13:21:12  cyp
// win16 changes
//
// Revision 1.9  1998/10/11 05:50:42  cyp
// Lots of fixes.
//
// Revision 1.8  1998/10/11 00:34:15  cyp
// Removed indentx/y and implemented smoothsizing.
//
// Revision 1.7  1998/10/08 00:02:30  silby
// Commented out some code called only for the gui that 
// was setting console attributes
//
// Revision 1.6  1998/10/07 18:19:27  silby
// Finished AutoClose support.  Seems to work well.
//
// Revision 1.5  1998/10/07 12:45:45  silby
// Added in microsoft prescribed delay so that hwnd could be properly 
// determined (we weren't waiting long enough for the title to change.)
//
// Revision 1.4  1998/10/05 05:11:35  cyp
// Implemented: (a) conditional destruction, ala Press any key..., of the
// client's window on deinit (b) to activate the client's window from WinMain.
//
// Revision 1.3  1998/10/04 17:53:50  silby
// Reinits signal handlers now when console is created.
//
// Revision 1.2  1998/10/04 01:31:33  silby
// Removed direct paths to platforms/win32cli, letting makefile handle it
//
// Revision 1.1  1998/10/03 12:24:43  cyp
// Created.
//
#if (!defined(lint) && defined(__showids__))
const char *w32cons_cpp(void) {
return "@(#)$Id: w32cons.cpp,v 1.22.2.4 1999/01/30 16:16:02 remi Exp $"; }
#endif

#include "cputypes.h"
#include "baseincs.h"
#include "w32svc.h"   //win9x win32CliInitializeService()
#include "w32cons.h"  //ourselves
#include "console.h"  //for CLICONS_[SHORT|LONG]NAME, ConOut, ConInKey
#include "triggers.h" // for clisetupsignals
#include "setprio.h"  // SetGlobalPriority();
#include "cpucheck.h" // GetProcessorType(); for MMX detection
#include "modereq.h"  // lauch options

/* ---------------------------------------------------- */
#define SLEEP_FACTOR 1

//define this for win32 native console i/o
//#define USE_NATIVE_CONSOLEIO


// define to the dimensions of the virtual screen
#define W16CONS_WIDTH       80
#define W16CONS_HEIGHT      25

// undefine the following to allow the window to be resized
//#define W16CONS_FIXEDSIZE

// define to the font type (must be fixed width)
#define W16CONS_FONT        ANSI_FIXED_FONT //OEM_FIXED_FONT, SYSTEM_FIXED_FONT

// define to maximum keyboard buffer size
#define W16CONS_KEYBUFF     16

// command message constants
#define W16CONS_CMD_CLEARSCREEN   0x01
#define W16CONS_CMD_PRINTSTR      0x02
#define W16CONS_CMD_ISKBHIT       0x03
#define W16CONS_CMD_GETCH         0x04
#define W16CONS_CMD_SETPOS        0x05
#define W16CONS_CMD_GETPOS        0x06
#define W16CONS_CMD_GETSIZE       0x07
#define W16CONS_CMD_SHUTDOWN      0x08

#define W32CONS_CMD_NOTIFYICON    (WM_USER+10)

#if 0
#ifndef WM_SIZING /* not available in win16 headers. but is called under w32 */
#define WM_SIZING      0x0214  /* real win32 message number */
#define WMSZ_LEFT           1  /*  wParam for WM_SIZING message  */
#define WMSZ_RIGHT          2
#define WMSZ_TOP            3
#define WMSZ_TOPLEFT        4
#define WMSZ_TOPRIGHT       5
#define WMSZ_BOTTOM         6
#define WMSZ_BOTTOMLEFT     7
#define WMSZ_BOTTOMRIGHT    8
#endif
#endif

/* ---------------------------------------------------- */

//#if (!defined(__LARGE__) && !defined(__FLAT__))
//  #error memory model must be large or flat
//#endif
#if (CLIENT_OS != OS_WIN32) && defined(USE_NATIVE_CONSOLEIO)
  #undef USE_NATIVE_CONSOLEIO
#endif

/* ---------------------------------------------------- */

// data structure associated with the window
struct W16ConsoleStruc
{
  HWND hwnd;
  char buff[W16CONS_HEIGHT][W16CONS_WIDTH];
  int currow, curcol;
  int keybuff[W16CONS_KEYBUFF];
  int keycount;
  HFONT hfont;
  int fontisstock;
  int fontx, fonty;
  int indentx, indenty;
  int dispcols, disprows;
  int painting;
  int smoothsizing;
};

static char szClassName[32] = {0};
static unsigned int openWinCount = 0;
static HWND hwndList[1];

static struct
{
HWND    hwnd;
HANDLE  hmutex;
int     hidden;
FILE    *fstdout;
FILE    *fstdin;
int     iconisstock;
HICON   hIcon;     
int     createflag;
int     errorcode;
int     asthread;
int     debugon;
Client *client;
RECT    lastpos;
} constatics = {NULL,NULL,0,NULL,NULL,0,NULL,0,0,0,0,NULL,{0,0,0,0}};

typedef struct W16ConsoleStruc * W16CONP;

#define W16CONS_ERR_CREATETHREAD 1
#define W16CONS_ERR_NOFONT       2
#define W16CONS_ERR_NOMEM        3
#define W16CONS_ERR_CREATEWIN    4
#define W16CONS_ERR_REGCLASS     5
#define W16CONS_ERR_GETINST      6
#define W16CONS_ERR_NOSLOT       7
#define W16CONS_ERR_NCCREATE     8

/* ---------------------------------------------------- */

int w32ConSetClientPointer( Client *client )
{
  constatics.client = client;
  return 0;
}

#include "client.h"   //client class, LoadSaveProblems()
class Problem;
#include "probman.h"  //GetProblemPointerFromIndex()
#include "probfill.h" //PROBFILL_UNLOADALL

void __w16ClientHardStop( void )
{
  Client *client = constatics.client;
  unsigned int load_problem_count;
  
  if (client)
    {
    load_problem_count = 0;
    while (GetProblemPointerFromIndex(load_problem_count) != NULL)
      load_problem_count++;
    if (load_problem_count != 0)
      client->LoadSaveProblems(load_problem_count+1, PROBFILL_UNLOADALL );
    }
  return;
}

/* ---------------------------------------------------- */

#if (CLIENT_OS == OS_WIN32)
void __w16showerror(const char *caption)
{
  LPVOID lpMsgBuf;
  FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
     GetLastError(),  0 /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, 
     (LPTSTR) &lpMsgBuf, 0, NULL );// Process any inserts in lpMsgBuf.
  MessageBox( NULL, (LPCTSTR)lpMsgBuf, caption, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL );
  LocalFree( lpMsgBuf );
  return;
}  
#endif

void __w16writelog( const char *format, ... )
{
  va_list argptr;
  va_start(argptr, format);
  char buffer[128];
  vsprintf( buffer, format, argptr );
  va_end(argptr);
  FILE *f = fopen("debug.log","a+");
  if (!f) f = fopen("debug.log","w");
  if (f)
    {
    strcat(buffer,"\n");
    fwrite(buffer,strlen(buffer),1,f);
    fflush(f);
    fclose(f);
    }
  return;
}  

/* ---------------------------------------------------- */


static W16CONP __win16GetHwndConsole( HWND hwnd )
{
  #if (CLIENT_OS == OS_WIN32) || (CLIENT_OS == OS_WIN32S)
  return (W16CONP)GetWindowLong(hwnd, GWL_USERDATA);
  #else
  return (W16CONP)GetWindowLong(hwnd, 0);
  #endif
}

static W16CONP __win16SetHwndConsole( HWND hwnd, W16CONP console )
{
  #if (CLIENT_OS == OS_WIN32) || (CLIENT_OS == OS_WIN32S)
  return (W16CONP)SetWindowLong(hwnd, GWL_USERDATA, (LONG)console);
  #else
  return (W16CONP)SetWindowLong(hwnd, 0, (LONG)console);
  #endif
}

/* ---------------------------------------------------- */

#if 0
static int __win16AssertHidden(HWND hwnd)
{
  if (constatics.hidden && (IsWindowVisible(hwnd) || IsWindowEnabled(hwnd)))
    {
    SetWindowPos(hwnd,HWND_BOTTOM,0,0,0,0,
        (SWP_HIDEWINDOW|SWP_NOREDRAW|SWP_NOACTIVATE));
    RECT rect;
    GetWindowRect(hwnd,&rect);
    rect.right-=rect.left;
    rect.bottom-=rect.top;
    SetWindowPos(hwnd, NULL,-rect.right, -rect.bottom, 
       rect.right, rect.bottom, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
    #if 0
    hwnd = GetTopWindow(GetDesktopWindow());
    if (hwnd) 
      {
      EnableWindow(hwnd,1);
      SetActiveWindow(hwnd);
      }
    #endif
    return 1;
    }
  return 0;
}
#endif



/* ---------------------------------------------------- */

#if ((CLIENT_OS == OS_WIN32) && !defined(USE_NATIVE_CONSOLEIO))

static char w32cons_tipstr[64] = "distributed.net RC5DES client";

#include <shellapi.h>

static int my_Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid )
{
  OFSTRUCT ofstruct;
  ofstruct.cBytes = sizeof(ofstruct);

  #ifndef OF_SEARCH
  #define OF_SEARCH 0x0400
  #endif
  if ( OpenFile( "shell32.dll", &ofstruct, OF_EXIST|OF_SEARCH) < 0 )
    return -1;

  HINSTANCE hinst = LoadLibrary( ofstruct.szPathName );
  if (hinst < (HINSTANCE)32)
    return -1;

  HMODULE hmod = GetModuleHandle("SHELL32");
  int retcode = -1;
  if (hmod)
    {
    FARPROC proc = GetProcAddress(hmod, "Shell_NotifyIconA");
    if (proc)
      {
      retcode = ((BOOL (WINAPI *)(DWORD, PNOTIFYICONDATA)) proc)
      (dwMessage, pnid) != 0 ? (0) : (+1);
      }
    }
  FreeLibrary(hinst);
  return retcode;
}  

static int __DoTrayStuff(DWORD action, HWND hwnd)
{
  static int intray=0, verasst=0;
  int retcode = 0;

  if (constatics.hidden || verasst < 0)
    return -1;

  NOTIFYICONDATA tnd;
  tnd.cbSize    = sizeof(NOTIFYICONDATA);
  tnd.hWnd      = hwnd;
  tnd.uID       = 1; /* icon identifier */
  tnd.uFlags    = NIF_TIP|NIF_ICON|NIF_MESSAGE;
  tnd.uCallbackMessage= W32CONS_CMD_NOTIFYICON;
  tnd.hIcon     = constatics.hIcon;
  strncpy(tnd.szTip,w32cons_tipstr,(sizeof(tnd.szTip)-1));
  tnd.szTip[sizeof(tnd.szTip)-1]=0;

  #if 0
  if (constatics.client)
    //do fancy stuff here...
  #endif

  HICON hIcon = NULL;

  #if 0  //do more fancy stuff here
  HINSTANCE hmyinst = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
  if (hmyinst) 
    {
    hIcon = (HICON)LoadImage(hmyinst, MAKEINTRESOURCE(1), 
                                            IMAGE_ICON, 16, 16, 0 );
    if (hIcon != NULL)
      tnd.hIcon = constatics.hIcon;
    }
  #endif
      
  if (action >= 0 && IsIconic(hwnd) && intray == 0)
    {
    retcode = my_Shell_NotifyIcon(NIM_ADD, &tnd);
    if (retcode == 0)
      {
      intray = 1;
      ShowWindow(hwnd, SW_HIDE);
      retcode = 0;
      verasst = 1;
      }
    else
      {
      if (retcode < 0 && verasst == 0)
        verasst = -1;
      retcode = -1;
      }
    }
  else if (intray != 0)
    {
    retcode = my_Shell_NotifyIcon(NIM_DELETE, &tnd);
    if (retcode == 0)
      {
      intray = 0;
      ShowWindow(hwnd, SW_SHOW);
      SetForegroundWindow(hwnd);
      retcode = 0;
      verasst = 1;
      }
    else
      {
      if (retcode < 0 && verasst == 0)
        verasst = -1;
      retcode = -1;
      }
    }
    
  if (hIcon)
    DestroyIcon(hIcon);

  return retcode;
}          
#endif

/* ---------------------------------------------------- */

#if !defined(USE_NATIVE_CONSOLEIO)

static LRESULT __w16AdjustRect( W16CONP console, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  int width = LOWORD(lParam);  //assume this is a WM_SIZE message
  int height = HIWORD(lParam);
  int adjx = (GetSystemMetrics(SM_CXFRAME) << 1);
  int adjy = (GetSystemMetrics(SM_CYFRAME) << 1) + 
              GetSystemMetrics(SM_CYCAPTION);

  #if (CLIENT_OS == OS_WIN32)
    __DoTrayStuff(1,hwnd);
  #endif

  console->disprows = W16CONS_HEIGHT;
  console->dispcols = W16CONS_WIDTH;
  wParam = wParam; //not used if not WM_SIZING

  #if defined(WM_SIZING)
  RECT *rectp = NULL;
  if (message == WM_SIZING)
    {
    rectp  = (RECT *) lParam;
    height = (rectp->bottom - rectp->top) - adjy;
    width  = (rectp->right - rectp->left) - adjx;

    message = WM_SIZE;
    //wParam specifies the edge of window being sized 
    }
  #endif

  if (message == WM_CREATE)
    {
    width = console->fontx * console->dispcols;
    height = console->fonty * console->disprows;
    }
    
  if (message == WM_SIZE || message == WM_PAINT || message == WM_CREATE)
    {
    RECT rect;
    GetWindowRect(hwnd, &rect);

    if (message == WM_PAINT) //dummy meaning wParam and lParam are invalid
      {                      
      width = (rect.right-rect.left) - adjx;
      height = (rect.bottom-rect.top) - adjy;
      }

    if (console->fontisstock == 0 || console->hfont == NULL) //_can_ adjust size
      {
      int newfonty  = ((height + (W16CONS_HEIGHT/2))/W16CONS_HEIGHT);
      int newfontx  = ((width + (W16CONS_WIDTH/2))/W16CONS_WIDTH);

      if (console->smoothsizing)
        {
        if ((newfonty * W16CONS_HEIGHT) != height)
          newfonty  = ((height+W16CONS_HEIGHT)/W16CONS_HEIGHT);
        if ((newfontx * W16CONS_WIDTH) != width)
          newfontx  = ((width+W16CONS_WIDTH)/W16CONS_WIDTH);
        }

      //if (console->hfont == NULL || newfontx != console->fontx || newfonty == console->fontx)
        {
        SIZE size;
        HFONT hfont = NULL;
        int isstock = 0;
        int i;
      
        for (i=0; (hfont == NULL && i<=5); i++)
          {
          if (i==0) //try to avoid a change of typeface if we can help it
            {
            if (console->hfont)
              {
              LOGFONT lfont;
              GetObject( console->hfont, sizeof(LOGFONT), (LPSTR) &lfont);
              lfont.lfHeight = newfonty; 
              lfont.lfWidth = newfontx;
              hfont = CreateFontIndirect(&lfont);
              isstock = 0;
              }
            }
          else if (i<4)
            {
            hfont = CreateFont( newfonty, newfontx, 0,0,300,0,0,0, 0, 
              ((i==3)?(0):(OUT_TT_PRECIS)), 
              ((i==2 || i==3)?(0):(CLIP_CHARACTER_PRECIS)), 
              ((i==1)?(PROOF_QUALITY):(0)), 
              FIXED_PITCH|FF_MODERN, "Courier New" );
            isstock = 0;
            }
          else if (i==4)
            {
            hfont = CreateFont( newfonty, newfontx,  0,0,0,0,0,0, 0, 
                            0, 0, 0, FIXED_PITCH|FF_MODERN, NULL );
            isstock = 0;
            }
          else //if (i==5) 
            {
            if (console->hfont == NULL)
              {
              hfont = (HFONT)GetStockObject(W16CONS_FONT);
              isstock = 1;
              }
            }
          if (hfont != NULL)
            {
            HDC hdc = GetDC(hwnd);
            HFONT hOldfont = (HFONT)SelectObject(hdc, hfont);
            GetTextExtentPoint(hdc, "X", 1, &size);
            SelectObject(hdc,hOldfont);
            ReleaseDC(hwnd, hdc);
            if (message != WM_CREATE &&  (size.cx != newfontx || 
                                          size.cy != newfonty))
              {
              if (!isstock)
                DeleteObject(hfont);
              hfont = NULL;
              }
            else
              {
              if (console->hfont && !console->fontisstock)
                DeleteObject(console->hfont);
              console->fontisstock = isstock;
              console->hfont = hfont;
              console->fontx = size.cx;
              console->fonty = size.cy;
              }
            }
          } /* for (i=0; (hfont == NULL && i<=5); i++) */
        }

      }
    if (console->hfont == NULL)
      return FALSE;

    //make width and height the adjusted window (not client) dimensions
    width  = console->dispcols * console->fontx + adjx;
    height = console->disprows * console->fonty + adjy;

    InvalidateRect(hwnd,NULL,TRUE);
 
    //if this a WM_SIZING message, then adjust the new size and return
    #if defined(WM_SIZING) 
    if (rectp != NULL && console->smoothsizing == 0) 
      {
      if (wParam == WMSZ_TOP || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)
        rectp->top = rectp->bottom - height;
      if (wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMRIGHT || wParam == WMSZ_BOTTOMLEFT)
        rectp->bottom = rectp->top + height;
      if (wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT || wParam == WMSZ_RIGHT)
        rectp->right = rectp->left + width;
      if (wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_LEFT)
        rectp->left = rectp->right - width;
      return TRUE;
      }
    #endif

    if (message == WM_CREATE || console->smoothsizing == 0)
      MoveWindow(hwnd, rect.left, rect.top, width, height, TRUE );

    if (message != WM_PAINT)
      UpdateWindow( hwnd );
      
    GetWindowRect(hwnd,&constatics.lastpos);

    return TRUE;
    }
  return FALSE;
}    

/* ---------------------------------------------------- */

int __win16AdjustCaret(HWND hwnd, W16CONP console, int destroy_first )
{
  //if (hwnd == GetFocus())
    {
    if (destroy_first)
      DestroyCaret();

    if (console->smoothsizing == 0)
      {
      CreateCaret( hwnd, NULL, console->fontx, console->fonty / 6);
      SetCaretPos( console->indentx + console->curcol * console->fontx,
        console->indenty + (console->currow + 1) * console->fonty -(console->fonty / 6) );
      ShowCaret( hwnd );
      }
    else
      {
      RECT clirect;
      GetClientRect( hwnd, &clirect );
    
      int col = ( ((unsigned long)(clirect.right-clirect.left)) *
          ((unsigned long)(console->curcol)) ) / console->dispcols;
      int row = ( ((unsigned long)(clirect.bottom-clirect.top)) *
          ((unsigned long)(console->currow)) ) / console->disprows;
      int cwidth = (clirect.right-clirect.left) / console->dispcols;
      int cheight = (clirect.bottom-clirect.top) / console->disprows;
    
      CreateCaret( hwnd, NULL, cwidth, cheight / 6);
      SetCaretPos( col, row+(cheight-cheight/6) );
      ShowCaret( hwnd );
      }
    }
  return 0;
}

/* ---------------------------------------------------- */



LRESULT CALLBACK __w16WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{
  W16CONP console = __win16GetHwndConsole( hwnd );

  //__w16writelog( "msg: 0x%04x, wParam: 0x%04x, lParam: 0x%08x", message, wParam, lParam );
    
  switch (message)
    {
    case WM_NCCREATE:
      {
      if ( DefWindowProc(hwnd, message, wParam, lParam) != 0)
        {
        constatics.createflag = 0;
        constatics.errorcode = W16CONS_ERR_NCCREATE;
        return -1;
        }
      return 0;
      }
    case WM_CREATE:
      {
      console = new W16ConsoleStruc;
      if (console)
        {
        // initialize our private structure
        memset((void *)console, 0, sizeof(W16ConsoleStruc));
        memset((void *)(&(console->buff[0][0])),' ',sizeof(console->buff));

        console->hwnd = hwnd;
        console->disprows = W16CONS_HEIGHT;
        console->dispcols = W16CONS_WIDTH;
        console->smoothsizing = 1;
        
        if ((winGetVersion()%2000) < 400)
          console->smoothsizing = 0;

        #ifdef DEBUG_SIZING
        console->smoothsizing = 0;
        #endif

        console->fontx = (int)GetSystemMetrics(SM_CXSCREEN);
        if (console->fontx < 700) /* 640x480 */ 
          { console->fontx =  6; console->fonty = 12; }
        else if (console->fontx < 900) /* 800x600 */  
          { console->fontx =  7; console->fonty = 15; }
        else                                 
          { console->fontx =  8; console->fonty = 18; }

        __w16AdjustRect( console, hwnd, WM_CREATE, 0, 0 );

        if (console->hfont == NULL)
          {
          delete console;
          constatics.createflag = 0;
          constatics.errorcode = W16CONS_ERR_NOFONT;
          return -1;
          }

        __win16SetHwndConsole( hwnd, console );

        constatics.createflag = 1;
        break;
        }
      else
        {
        constatics.createflag = 0;
        constatics.errorcode = W16CONS_ERR_NOMEM;
        // fail to create
        return -1;
        }
      }
    case WM_CLOSE:
      {
      SendMessage( hwnd, WM_CHAR, 0x03, 0 );
      return -1;
      }
    case WM_QUERYENDSESSION:
      {
      return TRUE; /* yes, we can terminate */
      }
    case WM_ENDSESSION:
      {
      if (wParam) /* yes, we are terminating */
        {
        #if (CLIENT_OS == OS_WIN32)
        if (((lParam & ENDSESSION_LOGOFF)!=0) && win32CliServiceRunning()) 
          return 1;  /* if we are running as a service. don't exit */
        #endif
        __w16ClientHardStop();
        SendMessage( hwnd, WM_CHAR, 0x03, 0 ); /* useless */
        }
      break;
      }
    case WM_DESTROY:
      {
      #if (CLIENT_OS == OS_WIN32)
        __DoTrayStuff(-1,hwnd);
      #endif
      if (console)
        {
        if (console->hfont && !console->fontisstock)
          DeleteObject(console->hfont);
        delete console;
        }
      __win16SetHwndConsole( hwnd, NULL );
      PostQuitMessage(0);
      break;
      }
    case WM_ERASEBKGND:
      return 0; /* do it in WM_PAINT (sets ps.fErase)  */
    case WM_PAINT:
#if 0 /* testing */
      {
      RECT clirect;
      if (GetUpdateRect(hwnd, &clirect, 1)!= 0) /* something needs updating */
        {
        int done_paint=0;
        if (console)
          __w16AdjustRect( console, hwnd, WM_PAINT, 0, 0);
        if (console && console->hfont)
          {
          PAINTSTRUCT ps;
          HDC paintdc = BeginPaint(hwnd, &ps);
          if (paintdc)
            {
            #define W16CONS_FORECOLOR RGB( 255,255,255 ) //GetSysColor(COLOR_HIGHLIGHTTEXT)
            #define W16CONS_BACKCOLOR RGB(   0,  0,128 ) //GetSysColor(COLOR_HIGHLIGHT)

            COLORREF oldTClr = SetTextColor(paintdc, W16CONS_FORECOLOR );
            COLORREF oldBClr = SetBkColor(paintdc, W16CONS_BACKCOLOR );

            GetClientRect(hwnd, &clirect);
        
            HFONT oldFont = (HFONT)SelectObject(paintdc, console->hfont);
            RECT workrect;
            SIZE size;
            GetTextExtentPoint(paintdc, "X", 1, &size);
            console->fontx = size.cx;
            console->fonty = size.cy;
            workrect.top = workrect.left = 0;
            workrect.right = console->fontx * console->dispcols;
            workrect.bottom = console->fonty * console->disprows;
            SelectObject(paintdc, oldFont);

            HDC hdc = NULL;
            HBITMAP newbmp = NULL;
            HBITMAP oldbmp = NULL;
            
            if (console->smoothsizing != 0)
              {
              hdc = CreateCompatibleDC( paintdc );
              if (hdc)
                {
                SetTextColor(hdc, W16CONS_BACKCOLOR ); /* note: reversed */
                SetBkColor(hdc, W16CONS_FORECOLOR );

                newbmp = CreateCompatibleBitmap( hdc, 
                         workrect.right, workrect.bottom );
                if (newbmp)
                  {
                  oldbmp = (HBITMAP)SelectObject(hdc, newbmp );
                  /*
                  HBRUSH hbrush = CreateSolidBrush( RGB(0,0,0) );
                  if (hbrush)
                    {
                    UnrealizeObject(hbrush);
                    HBRUSH hbrOld = (HBRUSH)SelectObject(hdc, hbrush);
                    Rectangle(hdc, workrect.left, workrect.top,
                                   workrect.right, workrect.bottom);
                    DeleteObject(SelectObject(hdc,hbrOld));
                    }
                  */
                  }
                else
                  {
                  DeleteDC( hdc );
                  hdc = NULL;
                  }
                }
              }
            if (hdc == NULL)
              hdc = paintdc;


            int offsetrow = GetScrollPos(hwnd, SB_VERT);
            int offsetcol = GetScrollPos(hwnd, SB_HORZ);
            int row;
 
            oldFont = (HFONT)SelectObject(hdc, console->hfont);
            for (row = 0; row < console->disprows; row++)
              {
              TextOut(hdc, console->indentx,
                             console->indenty + row * console->fonty,
                             &console->buff[offsetrow + row][offsetcol],
                             console->dispcols);
              }
            SelectObject(hdc, oldFont);


            if (newbmp == NULL) /* paintdc == hdc */
              {
              HPEN hpen = CreatePen(PS_SOLID, 1, GetBkColor(hdc) );
              if (hpen)
                {
                HPEN oldpen = (HPEN)SelectObject( hdc, hpen );
                MoveTo( hdc, workrect.left, workrect.bottom );
                LineTo( hdc, workrect.right, workrect.bottom );
                SelectObject( hdc, oldpen );
                DeleteObject( hpen );
                }
              }
            else
              {
              if (clirect.right == workrect.right && 
                  clirect.bottom == workrect.bottom)
                {
                BitBlt(paintdc, 0, 0, clirect.right, clirect.bottom, 
                                              hdc, 0, 0, SRCCOPY);
                }
              else
                {
                int oldbltmode = SetStretchBltMode( paintdc, STRETCH_ORSCANS );
                StretchBlt( paintdc, 0, 0, clirect.right, clirect.bottom, 
                      hdc, 0, 0, workrect.right, workrect.bottom, SRCCOPY);
                SetStretchBltMode( paintdc, oldbltmode );
                }
              SelectObject( hdc, oldbmp );
              DeleteObject( newbmp );
              DeleteDC( hdc );
              }

            SetBkColor  ( paintdc, oldBClr );
            SetTextColor( paintdc, oldTClr );

            EndPaint(hwnd, &ps);
            done_paint = 1;
            }
          if (hwnd == GetFocus())
            __win16AdjustCaret(hwnd, console, 1);
          } /* if (console && console->hfont) */
        if (!done_paint) /* don't send more paint msgs if paint fails */
          ValidateRect(hwnd, NULL); 
        }
      break;
      }
#else
      {
      RECT clirect;
      if (GetUpdateRect(hwnd, &clirect, 1)!= 0) /* something needs updating */
        {
        int done_paint=0;
        if (console)
          __w16AdjustRect( console, hwnd, WM_PAINT, 0, 0);
        if (console && console->hfont)
          {
          PAINTSTRUCT ps;
          HDC paintdc = BeginPaint(hwnd, &ps);
          if (paintdc)
            {
            HDC hdc = paintdc;
            if (console->smoothsizing)
              hdc = CreateCompatibleDC( paintdc );
            if (hdc)
              {
              HFONT oldFont = (HFONT)SelectObject(hdc, console->hfont);
  
              RECT workrect;
              GetClientRect(hwnd, &clirect);
        
              SIZE size;
              GetTextExtentPoint(hdc, "X", 1, &size);
              console->fontx = size.cx;
              console->fonty = size.cy;
              workrect.top = workrect.left = 0;
              workrect.right = console->fontx * console->dispcols;
              workrect.bottom = console->fonty * console->disprows;
              if (console->smoothsizing == 0)
                workrect.bottom--;
 
              HBITMAP newbmp = NULL;
              
              if (console->smoothsizing)
                newbmp = CreateCompatibleBitmap( hdc, 
                         workrect.right, workrect.bottom );
              if (console->smoothsizing == 0 || newbmp)
                {
                HBITMAP oldbmp = NULL;
                if (console->smoothsizing)
                  oldbmp = (HBITMAP)SelectObject( hdc, newbmp );
 
                #define W16CONS_FORECOLOR RGB( 255,255,255 ) //GetSysColor(COLOR_HIGHLIGHTTEXT)
                #define W16CONS_BACKCOLOR RGB(   0,  0,127 ) //GetSysColor(COLOR_HIGHLIGHT)
 
                COLORREF oldTClr = SetTextColor(hdc, W16CONS_FORECOLOR );
                COLORREF oldBClr = SetBkColor(hdc, W16CONS_BACKCOLOR );
                int offsetrow = GetScrollPos(hwnd, SB_VERT);
                int offsetcol = GetScrollPos(hwnd, SB_HORZ);
                int row;
                for (row = 0; row < console->disprows; row++)
                  {
                  TextOut(hdc, console->indentx,
                             console->indenty + row * console->fonty,
                             &console->buff[offsetrow + row][offsetcol],
                             console->dispcols);
                  }

                if (console->smoothsizing == 0)
                  {
                  HPEN hpen = CreatePen(PS_SOLID, 1, GetBkColor(hdc) );
                  if (hpen)
                    {
                    HPEN oldpen = (HPEN)SelectObject( hdc, hpen );
                    MoveToEx( hdc, workrect.left, workrect.bottom-1, NULL);
                    LineTo( hdc, workrect.right, workrect.bottom-1 );
                    SelectObject( hdc, oldpen );
                    DeleteObject( hpen );
                    }
                  }

                SetBkColor  ( hdc, oldBClr );
                SetTextColor( hdc, oldTClr );

                if (console->smoothsizing)
                  {
                  oldTClr = SetTextColor(paintdc, W16CONS_BACKCOLOR);
                  oldBClr = SetBkColor(paintdc, W16CONS_FORECOLOR);
                  if (clirect.right == workrect.right && 
                      clirect.bottom == workrect.bottom)
                    {
                    BitBlt(paintdc, 0, 0, clirect.right, clirect.bottom, 
                                                hdc, 0, 0, SRCCOPY);
                    }
                  else
                    {
                    int oldbltmode = SetStretchBltMode( paintdc, STRETCH_ORSCANS );
                    StretchBlt( paintdc, 0, 0, clirect.right, clirect.bottom, 
                             hdc, 0, 0, workrect.right, workrect.bottom, SRCCOPY );
                    SetStretchBltMode( paintdc, oldbltmode );
                    }
                  SetBkColor  ( paintdc, oldBClr );
                  SetTextColor( paintdc, oldTClr );
 
                  SelectObject( hdc, oldbmp );
                  DeleteObject( newbmp );
                  }
                done_paint = 1;
                }
              SelectObject( hdc, oldFont );
              if (console->smoothsizing)
                DeleteDC( hdc );
              }
            EndPaint(hwnd, &ps);
            }
          if (hwnd == GetFocus())
            __win16AdjustCaret(hwnd, console, 1);
          } /* if (console && console->hfont) */
        if (!done_paint) /* don't send more paint msgs if paint fails */
          ValidateRect(hwnd, NULL); 
        }
      break;
      }
#endif
    case WM_GETMINMAXINFO:
      {
      MINMAXINFO FAR * lpmmi = (MINMAXINFO FAR *) lParam;
      #if defined(__WINDOWS_386__) /* convert 16:16 pointer to 16:32 */
         lpmmi = (MINMAXINFO FAR *)MK_FP32( (void *)lpmmi ); 
      #endif

#if 0
      if (console && console->smoothsizing == 0)
        {
        lpmmi->ptMaxSize.x = 
        lpmmi->ptMaxTrackSize.x = 
        lpmmi->ptMinTrackSize.x = (W16CONS_WIDTH * console->fontx +
                                  2 * GetSystemMetrics(SM_CXFRAME));
        lpmmi->ptMaxSize.y = 
        lpmmi->ptMaxTrackSize.y = 
        lpmmi->ptMinTrackSize.y = (W16CONS_HEIGHT * console->fonty +
                                  2 * GetSystemMetrics(SM_CYFRAME) + 
                                  GetSystemMetrics(SM_CYCAPTION));
        }
      else
#endif
        {
        lpmmi->ptMinTrackSize.x = (W16CONS_WIDTH * 2 +
                                  2 * GetSystemMetrics(SM_CXFRAME));
        lpmmi->ptMinTrackSize.y = (W16CONS_HEIGHT * 4 +
                                  2 * GetSystemMetrics(SM_CYFRAME) + 
                                  GetSystemMetrics(SM_CYCAPTION));

        lpmmi->ptMaxTrackSize.x = (W16CONS_WIDTH * 12 +
                                  2 * GetSystemMetrics(SM_CXFRAME));
        if (lpmmi->ptMaxTrackSize.x > lpmmi->ptMaxSize.x)
          lpmmi->ptMaxTrackSize.x = lpmmi->ptMaxSize.x;
        else
          lpmmi->ptMaxSize.x = lpmmi->ptMaxTrackSize.x;
                          
        lpmmi->ptMaxTrackSize.y = (W16CONS_HEIGHT * 29 +
                                  2 * GetSystemMetrics(SM_CYFRAME) + 
                                  GetSystemMetrics(SM_CYCAPTION));
        if (lpmmi->ptMaxTrackSize.y > lpmmi->ptMaxSize.y)
          lpmmi->ptMaxTrackSize.y = lpmmi->ptMaxSize.y;
        else
          lpmmi->ptMaxSize.y = lpmmi->ptMaxTrackSize.y;

        }
      break;
      }
    //case WM_WINDOWPOSCHANGED:
    case WM_WINDOWPOSCHANGING:
      {
      WINDOWPOS FAR *pwp = (WINDOWPOS FAR *)lParam;
      #if defined(__WINDOWS_386__)
        pwp = (WINDOWPOS FAR *)(MK_FP32((void *)pwp));
      #endif
      if (constatics.hidden && (pwp->flags & SWP_SHOWWINDOW)!=0) 
        { 
        if (message == WM_WINDOWPOSCHANGING)
          {
          pwp->flags ^= SWP_SHOWWINDOW; 
          pwp->flags |= SWP_HIDEWINDOW; 
          }
        else
          ShowWindow(hwnd, SW_HIDE);
        return 0;
        }
      return DefWindowProc(hwnd, message, wParam, lParam);
      }
    #ifdef WM_SIZING
    case WM_SIZING:
    #endif
    case WM_SIZE:
      {
      #if (CLIENT_OS == OS_WIN32)
        __DoTrayStuff(1,hwnd);
      #endif
      if (message == WM_SIZE && wParam == SIZE_MINIMIZED)
        {
        return DefWindowProc(hwnd, message, wParam, lParam);
        }
      if (console)
        {
        #if defined(WM_SIZING) && defined(__WINDOWS_386__)
        if (message == WM_SIZING)
          lParam = (LPARAM)(MK_FP32((void *)lParam));
        #endif
        return __w16AdjustRect( console, hwnd, message, wParam, lParam);
        }
      break;
      }
    case W32CONS_CMD_NOTIFYICON:
      {
      if (lParam == WM_RBUTTONUP)
        {
        SendMessage(hwnd,WM_RBUTTONUP,0,(LPARAM)0xFEDCCDEFL);
        }
      else if (lParam == WM_LBUTTONDBLCLK)
        {
        ShowWindow(hwnd,SW_RESTORE);
        }
      break;
      }
    case WM_RBUTTONUP:
      {
      if (!CheckExitRequestTriggerNoIO())
        {
        HMENU hmenu = CreatePopupMenu();
        if (hmenu)
          {
          POINT ptPos; 
          int intray = 0;
          ptPos.x = LOWORD(lParam); ptPos.y = HIWORD(lParam);
          if (lParam != (LPARAM)0xFEDCCDEFL)
            ClientToScreen(hwnd, &ptPos);
          else
            {
            GetCursorPos(&ptPos);
            intray = 1;
            }

          //IDM_defines are in w32cons.h
          UINT showmode = ((CheckPauseRequestTrigger())?(MF_GRAYED):(MF_ENABLED));
          
          HMENU hbench = NULL;
          
          if (intray == 0)
            {
            hbench = CreatePopupMenu();
            if (hbench)
              {
              AppendMenu(hbench, (ModeReqIsSet(MODEREQ_BENCHMARK_RC5)?(MF_GRAYED):(showmode)),
                                IDM_BENCHRC5_SHORT, "RC5 short block" );
              AppendMenu(hbench, (ModeReqIsSet(MODEREQ_BENCHMARK_RC5)?(MF_GRAYED):(showmode)),
                                IDM_BENCHRC5_LONG, "RC5 long block" );
              AppendMenu(hbench, (ModeReqIsSet(MODEREQ_BENCHMARK_DES)?(MF_GRAYED):(showmode)),
                                IDM_BENCHDES_SHORT, "DES short block" );
              AppendMenu(hbench, (ModeReqIsSet(MODEREQ_BENCHMARK_DES)?(MF_GRAYED):(showmode)),
                                IDM_BENCHDES_LONG, "DES long block" );
              }
            }
          if (intray == 0)
            {
            AppendMenu(hmenu, MF_SEPARATOR, 0, "" );
            if (hbench)                  
              AppendMenu(hmenu, MF_POPUP, (UINT)hbench, "Benchmark" );
            else
              AppendMenu(hmenu, MF_GRAYED, IDM_BENCHDES_LONG, "Benchmark" );
            #if 0
            AppendMenu(hmenu, (ModeReqIsSet(MODEREQ_BENCHMARK_RC5)?(MF_GRAYED):(showmode)),
                              IDM_BENCHRC5, "Benchmark RC5 core" );
            AppendMenu(hmenu, (ModeReqIsSet(MODEREQ_BENCHMARK_DES)?(MF_GRAYED):(showmode)),
                              IDM_BENCHDES, "Benchmark DES core" );
            #endif
            }
          AppendMenu(hmenu, MF_SEPARATOR, 0, "" );
          AppendMenu(hmenu, MF_ENABLED, IDM_PAUSE, 
                 ((CheckPauseRequestTriggerNoIO())?("Continue"):("Pause")));
          AppendMenu(hmenu, MF_ENABLED, IDM_RESTART, "Restart");
          AppendMenu(hmenu, MF_ENABLED, IDM_SHUTDOWN, "Shutdown");
          #if (CLIENT_OS == OS_WIN32) 
          SetForegroundWindow(hwnd);  //needed for tray popup
          #endif
          TrackPopupMenu(hmenu, TPM_LEFTALIGN, ptPos.x, ptPos.y, 0, hwnd, NULL);
          PostMessage(hwnd, WM_NULL, 0, 0);
          if (hbench)
            DestroyMenu(hbench);
          DestroyMenu(hmenu);
          }
        }
      break;
      }
    case WM_COMMAND:
      {
      if (wParam == IDM_BENCHRC5_SHORT)
        ModeReqSet(MODEREQ_BENCHMARK_RC5|MODEREQ_BENCHMARK_QUICK);
      else if (wParam == IDM_BENCHRC5_LONG)
        ModeReqSet(MODEREQ_BENCHMARK_RC5);
      else if (wParam == IDM_BENCHDES_LONG || wParam == IDM_BENCHDES_SHORT)
        {
        if (constatics.asthread && (GetProcessorType(1) & 0x100)==0)
          {
          MessageBox(NULL, 
            "Interactive DES Benchmark is only available when running\n"
            "on Win16 or when MMX instructions are available. Please run the\n"
            "DES Benchmark from the command line instead.", "DES Benchmark",
            MB_OK | MB_ICONINFORMATION );
          }
        else if (wParam == IDM_BENCHDES_SHORT)
          ModeReqSet(MODEREQ_BENCHMARK_DES|MODEREQ_BENCHMARK_QUICK);
        else
          ModeReqSet(MODEREQ_BENCHMARK_DES);
        }  
      else if (wParam == IDM_SHUTDOWN)
        SendMessage( hwnd, WM_CHAR, 0x03, 0 );
      else if (wParam == IDM_RESTART)
        RaiseRestartRequestTrigger();
      else if (wParam == IDM_PAUSE)
        {
        if (CheckPauseRequestTriggerNoIO())
          ClearPauseRequestTrigger();
        else
          RaisePauseRequestTrigger();
        }
      break;
      }
    case WM_CHAR:
      {
      if (console)
        {
        if (((int)(wParam)) == 0x03)
          {
          #if 0
          if (console->keycount >= W16CONS_KEYBUFF)
            console->keycount = W16CONS_KEYBUFF - 1;
          if (console->keycount > 0)
            memmove(&console->keybuff[1], &console->keybuff[0],
              console->keycount * sizeof(int));
          console->keybuff[0] = (int) wParam;
          #endif
          RaiseExitRequestTrigger();
          }
        else if (console->keycount < W16CONS_KEYBUFF)
          {
          console->keybuff[console->keycount++] = (int) wParam;
          }
        else
          {
          // beep, keyboard buffer full
          MessageBeep(MB_OK);
          }
        }
      break;
      }
    case WM_SETFOCUS:
      {
      if (console)
        {
        __win16AdjustCaret(console->hwnd, console, 0 );
        }
      break;
      }
    case WM_KILLFOCUS:
      {
      if (console)
        DestroyCaret();
      break;
      }
    case (WM_USER+0):
      {
      if (!console)
        {
        //__w16writelog("(WM_USER+0) 0x%04x called when no console.", (int)wParam);
        return -1;
        }
      switch (wParam)
        {
        case W16CONS_CMD_SHUTDOWN:
          {
          DestroyWindow(hwnd);
          return 0;
          }
        case W16CONS_CMD_CLEARSCREEN:
          {
          memset((void *)(&(console->buff[0][0])),' ',sizeof(console->buff));
          console->currow = 0;
          console->curcol = 0;
   
          InvalidateRect(hwnd, NULL, TRUE);
          UpdateWindow(hwnd);
          break;
          }
        case W16CONS_CMD_PRINTSTR:
          {
          char ch;
          const char *text = (const char *)lParam;
          
          do{
            // check the validity of the current
            // cursor position, scrolling the window if necessary.
    
            if (console->currow < 0)
              console->currow = console->curcol = 0;
            else if (console->curcol < 0)
              console->curcol = 0;
            if (console->curcol >= W16CONS_WIDTH)
              {
              console->curcol = 0;
              console->currow++;
              }
            if (console->currow >= W16CONS_HEIGHT)
              {
              memmove( &(console->buff[0][0]), 
                      (&(console->buff[0][0])) + W16CONS_WIDTH, 
                        sizeof(console->buff) - W16CONS_WIDTH );
              //for (len = 0; len < W16CONS_HEIGHT - 1; len++)
              //  memmove(console->buff[len], console->buff[len+1], W16CONS_WIDTH);
              memset( &(console->buff[W16CONS_HEIGHT-1][0]),' ',W16CONS_WIDTH);
              console->currow = W16CONS_HEIGHT - 1;
              console->curcol = 0;
              }
                
            //update the screen buffer
              
            ch = *text++;
            if (!ch)
              break;
            if (ch == 0x0A)         /* \n  new-line */
              { console->currow++; console->curcol = 0; }
            else if (ch == 0x0D)   /* \r    carriage return */
              console->curcol = 0;
            else if (ch == '\t')   /* \t    horizontal tab  */
              console->curcol += (console->curcol%8);
            else if (ch == '\a')   /* \a  bell (alert)      */
              MessageBeep(MB_OK);
            else if (ch == '\f')   /* \f    form-feed       */
              {
              memset((void *)(&(console->buff[0][0])),' ',sizeof(console->buff));
              console->currow = 0;
              console->curcol = 0;
              }
            else if (ch == '\b')   /* \b  backspace         */
              { if (console->curcol > 0) console->curcol--; }
            else if (ch == '\v')   /* \v  vertical tab      */
              console->currow++;
            else if (ch <= 26  )   /* don't print other ctrl-chars */
              ;
            else
              {
              console->buff[console->currow][console->curcol++] = ch;
              }
            } while (ch); /* always true */
  
          // force repaint
          InvalidateRect(hwnd, NULL, TRUE);
          UpdateWindow(hwnd);
          break;
          }
        case W16CONS_CMD_ISKBHIT:
          {
          return ((console->keycount > 0)?(1):(0));
          }
        case W16CONS_CMD_GETSIZE:
          {
          return MAKELRESULT(W16CONS_HEIGHT,W16CONS_WIDTH);
          }
        case W16CONS_CMD_GETPOS:
          {
          return MAKELRESULT(console->currow,console->curcol);
          }
        case W16CONS_CMD_SETPOS:
          {
          int row = LOWORD(lParam);
          int col = HIWORD(lParam);
    
          if (row < 0)                       
            row = 0;
          else if (row >= W16CONS_HEIGHT)    
            row = W16CONS_HEIGHT-1;
          if (col < 0)                       
            col = 0;
          else if (col >= W16CONS_WIDTH)     
            col = W16CONS_WIDTH-1;

          console->currow = row;
          console->curcol = col;
          
          if (hwnd == GetFocus())
            __win16AdjustCaret(hwnd, console, 1 );
          break;
          }
        case W16CONS_CMD_GETCH:
          {
          LRESULT keyval = 0;
          if (console->keycount > 0)
            {
            keyval = (LRESULT)console->keybuff[0];
            if ((--console->keycount) > 0)
            memmove(&console->keybuff[0], &console->keybuff[1],
                console->keycount * sizeof(console->keybuff[0]));
            }
          return keyval;
          }
        } /* switch (wParam) */
      break;
      }
    default:
      {
      return DefWindowProc(hwnd, message, wParam, lParam);
      }
    }
  return 0;
}

#endif

/* ------------------------------------------------ */

void w16Yield(void)
{
  #if (CLIENT_OS == OS_WIN32)
  if (constatics.asthread)
    {
    Sleep(SLEEP_FACTOR);
    return;
    }
  #endif

  static int yielding = 0;
  int did_yield = 0, doclose = 0;
  MSG msg;
  ++yielding;
    {
    HWND hwnd = NULL;
    //#if (CLIENT_OS == OS_WIN32)
    //  hwnd = hwndList[0];
    //#endif
    while (openWinCount && PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE ))
      {
      doclose = (msg.message == WM_CLOSE || msg.message == WM_DESTROY || 
                (msg.message == WM_ENDSESSION && msg.wParam!=0) ||
                (msg.message == WM_CHAR && msg.wParam == 0x03));
      if (doclose && yielding==1)
        {
        RaiseExitRequestTrigger();
        CheckExitRequestTrigger();
        }
      TranslateMessage(&msg);
      DispatchMessage(&msg);
      did_yield = 1;
      if (doclose)
        break;
      #if (CLIENT_OS == OS_WIN32)
        Sleep(SLEEP_FACTOR);
      #endif
      }
    }
  --yielding;
  if (!did_yield && !doclose)
    {
    #if (CLIENT_OS == OS_WIN32)
      Sleep(SLEEP_FACTOR);
    #else
      Yield();
    #endif
    }
  return;
}

/* ------------------------------------------------ */

void w16Sleep(unsigned int millisecs)
{
  #if (CLIENT_OS == OS_WIN32)
  if (constatics.asthread)
  {
    Sleep(millisecs);
    return;
  }
  #endif

  DWORD next, diff, last = GetTickCount();
  do
  {
    w16Yield();
    next = diff = GetTickCount();
    if (next < last)
      diff = last - next;
    else
      diff -= last;
    last = next;
    if (diff > millisecs)
      diff = millisecs;
    millisecs -= diff;
  } while (millisecs);
}

/* ------------------------------------------------ */

struct helperArg
{
  int nCmdShow;
  int nSuccess;
  int asthread;
  HWND hwnd;
  HINSTANCE hInstance;
};
  
/* ------------------------------------------------ */

static void __win16WinCreateHelper( void *xarg )
{
  struct helperArg *arg = (struct helperArg *)(xarg);

  int nCmdShow = arg->nCmdShow;
  int asthread = arg->asthread;
  HINSTANCE hInstance = arg->hInstance;
  LPCSTR wintitle;
  HWND hwnd;  
  MSG msg;

  wintitle = "console";
  if (winGetInstanceArgv())
    wintitle = (LPCSTR)(winGetInstanceArgv()[0]);

  constatics.createflag = -1;
  constatics.errorcode = 0;
  
  int top=constatics.lastpos.top, left=constatics.lastpos.left;
  if (constatics.lastpos.right==0 && constatics.lastpos.bottom==0)
    top = left = CW_USEDEFAULT;
  
  /* create a window using that class */
  hwnd = CreateWindow( szClassName, wintitle, WS_OVERLAPPEDWINDOW,
         left, top, constatics.lastpos.right, constatics.lastpos.bottom, 
         HWND_DESKTOP, NULL, hInstance, NULL );

  if (hwnd == NULL)
    {
    if (constatics.errorcode == 0)
      constatics.errorcode = W16CONS_ERR_CREATEWIN;
    arg->nSuccess = 0;
    return;
    }

  /* display the window */
  ShowWindow(hwnd, nCmdShow /* SW_SHOW */);
  UpdateWindow(hwnd);

  while (constatics.createflag == -1)
    {
    #if (CLIENT_OS == OS_WIN32)
    Sleep(SLEEP_FACTOR);
    #else
    Yield();
    #endif
    }
    
  if (constatics.createflag == 0)
    {
    DestroyWindow(hwnd);
    arg->nSuccess = 0;
    return;
    }
    
  arg->hwnd = hwnd;
  arg->nSuccess = 1;

  if (asthread)
    {
    #if (CLIENT_OS == OS_WIN32)
      {
      //SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS );
      //SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL );
      SetGlobalPriority(9);
      }
    #endif
    while (GetMessage(&msg, (HWND) NULL, 0, 0)) 
      {
      if ((msg.message == WM_CHAR && msg.wParam == 0x03))
        RaiseExitRequestTrigger();
      else
        {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        }
      }
    }

  return;
}

/* ------------------------------------------------ */

#if !defined(USE_NATIVE_CONSOLEIO)

HWND w16ConsoleCreate(int nCmdShow)
{
  struct helperArg arg;
  WNDCLASS wcl;
  
  constatics.errorcode = 0;
  arg.hInstance = winGetInstanceHandle(); /* w32pre.cpp */

  if (!arg.hInstance)
    {
    constatics.errorcode = W16CONS_ERR_GETINST;
    return 0;
    }
  if (openWinCount == (sizeof(hwndList)/sizeof(hwndList[0])))
    {
    constatics.errorcode = W16CONS_ERR_NOSLOT;
    return 0;
    }

  if (szClassName[0]==0)
    {
    constatics.hIcon = LoadIcon(arg.hInstance, MAKEINTRESOURCE(1));
    constatics.iconisstock = 0;
    if (!constatics.hIcon)
      {
      LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
      constatics.iconisstock = 1;
      }

    strcpy(szClassName,"DCTICLI");
    #ifdef __WINDOWS_386__ //win16 pmode - cannot share memory
    sprintf( szClassName, "DCTI%u", arg.hInstance );
    #endif

    /* define a window class */
    wcl.hInstance = arg.hInstance;
    wcl.lpszClassName = szClassName;
    wcl.lpfnWndProc = (WNDPROC)__w16WindowFunc; 
    wcl.style = 0; //( CS_HREDRAW | CS_VREDRAW | CS_SAVEBITS |
                  ///*CS_BYTEALIGNCLIENT |*/ CS_BYTEALIGNWINDOW );
                /*((((winGetVersion()%2000) >= 4)?(0): */
    wcl.hIcon = constatics.hIcon;
    wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcl.lpszMenuName = NULL;
    wcl.cbClsExtra = 0;
    wcl.cbWndExtra = sizeof(void *); /* we need space for a pointer */
    wcl.hbrBackground = NULL; /* winproc does the background painting */

    /* register the window class */
    if (!RegisterClass(&wcl)) 
      {
      szClassName[0]=0;
      if (!constatics.iconisstock)
        DestroyIcon( constatics.hIcon );
      constatics.hIcon = NULL;
      constatics.errorcode = W16CONS_ERR_REGCLASS;
      return 0;
      }
    }
  
  arg.nSuccess = -1;
  arg.nCmdShow = nCmdShow;
  arg.asthread = 0;

  #if (CLIENT_OS == OS_WIN32)
  constatics.asthread = arg.asthread = 1;
  if (_beginthread( __win16WinCreateHelper, 512, (void *)&arg  ) == NULL)
    {
    constatics.errorcode = W16CONS_ERR_CREATETHREAD;
    arg.nSuccess = 0;
    }
  #endif
  if (arg.asthread == 0)
    __win16WinCreateHelper( (void *)&arg );

  while (arg.nSuccess == -1)
    w16Yield();

  if (arg.nSuccess == 0)    
    {
    if (openWinCount == 0 && szClassName[0])
      {
      if (UnregisterClass( szClassName, arg.hInstance ) == 0)
        {
        szClassName[0] = 0;
        if (constatics.hIcon && !constatics.iconisstock)
          DestroyIcon( constatics.hIcon );
        constatics.hIcon = NULL;
        }
      }
    constatics.asthread = 0;
    return 0;
    }

  hwndList[openWinCount++] = arg.hwnd;
  return arg.hwnd;
}    

/* ------------------------------------------------ */

int w16ConsoleDestroy(void)
{
  HINSTANCE hInstance;
  
  if (openWinCount)
    {
    hInstance = winGetInstanceHandle(); /* w32pre.cpp */
    if (hInstance)
      {
      openWinCount--;
      HWND hwnd = hwndList[openWinCount];
      if (hwnd && szClassName[0])
        {
        hwndList[openWinCount] = NULL;
        SendMessage( hwnd, (WM_USER+0), W16CONS_CMD_SHUTDOWN, 0 );

        #if 0 //this does not work! (and causes a restart to fail)
        if (openWinCount == 0 && szClassName[0])
          {
          if (UnregisterClass( szClassName, hInstance ) == 0)
            {
            szClassName[0] = 0;
            if (constatics.hIcon && !constatics.iconisstock)
              DestroyIcon( constatics.hIcon );
            constatics.hIcon = NULL;
            }
          }
        #endif
        }
      return 1;
      }
    }
  return 0;
}  

/* ------------------------------------------------ */

void w16SetConsoleTitle(const char *name)
{
  w16Yield();
  if (openWinCount == 0 || hwndList[0] == NULL)
    return;

  SetWindowText( hwndList[0], (LPSTR)name );
}  

/* ------------------------------------------------ */

int w16ConsoleClear(void)
{
  w16Yield();
  if (openWinCount == 0 || hwndList[0] == NULL)
    return -1;
  SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_CLEARSCREEN, 0 );
  return 0;
}

/* ------------------------------------------------ */

int w16ConsolePrint(const char *text)
{
  unsigned int len;
  w16Yield();
  if (openWinCount == 0 || hwndList[0] == NULL)
    return -1;
  if (!text)
    return -1;
  if ((len = strlen(text)) == 0)
    return 0;
  SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_PRINTSTR, (LPARAM)(text) );
  return len;
}  

/* ------------------------------------------------ */

int w16ConSetPos(int col, int row)
{
  w16Yield();
  if (openWinCount == 0 || hwndList[0] == NULL)
    return -1;
  SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_SETPOS, MAKELONG(row, col));
  return 0;
}

/* ------------------------------------------------ */

int w16ConGetPos(int *col, int *row)
{
  w16Yield();
  if (openWinCount == 0 || hwndList[0] == NULL)
    return -1;
  LRESULT cr = SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_GETPOS, 0);
  if (col) *col = HIWORD(cr);
  if (row) *row = LOWORD(cr);
  return 0;
}

/* ------------------------------------------------ */

int w16ConGetSize( int *width, int *height)
{
  if (openWinCount == 0 || hwndList[0] == NULL)
    return -1;
  LRESULT wh = SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_GETSIZE, 0);
  if (width)  *width  = HIWORD(wh);
  if (height) *height = LOWORD(wh);
  return 0;
}  

/* ------------------------------------------------ */

int w16ConsoleKbhit(void)
{
  w16Yield();
  if (openWinCount == 0 || hwndList[0] == NULL)
    return 0;
  return SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_ISKBHIT, 0 );
}

/* ------------------------------------------------ */

int w16ConsoleGetch(void)
{
  LRESULT keyval = 0; 

  do{
    w16Yield();
    if (openWinCount == 0 || hwndList[0] == NULL) 
      break;
    keyval = SendMessage( hwndList[0], (WM_USER+0), W16CONS_CMD_GETCH, 0 );
    } while (keyval == 0);

  if (keyval == -1) /* no console */
    keyval = 0;
  
  return (int)keyval;
}  
      
#endif

/* ===================================================== */

int w32DeinitializeConsole(void)
{
  #if !defined(NEEDVIRTUALMETHODS)
    {
    #ifdef USE_NATIVE_CONSOLEIO
      {
      if (constatics.hwnd)
        FreeConsole();
      constatics.hwnd = NULL;
      if (constatics.fstdout)
        fclose(constatics.fstdout);
      constatics.fstdout = NULL;
      if (constatics.fstdin)
        fclose(constatics.fstdin);
      constatics.fstdin = NULL;
      }
    #else
      {
      if (constatics.hwnd)
        w16ConsoleDestroy();
      constatics.hwnd = NULL;
      }
    #endif
    }
  #endif
  
  #if (CLIENT_OS == OS_WIN32)
  if (constatics.hmutex != NULL)
    {
    ReleaseMutex( constatics.hmutex );
    CloseHandle( constatics.hmutex );
    }
  #endif
 
  return 0;
}

/* ---------------------------------------------------- */

const char *wintitle = "distributed.net RC5DES client"; //CLICONS_LONGNAME; //we need this often

int w32InitializeConsole(int runhidden, int runmodes)
{
  int retcode = 0;

  //ensure only one instance if not running modes.
  if (runmodes == 0)
    {
    HWND otherguy = FindWindow( NULL, wintitle );
    if ( otherguy != NULL)
      {
      if (!runhidden)
        ShowWindow(otherguy, SW_SHOW);
      retcode = -1;
      }
    #if (CLIENT_OS == OS_WIN32) /* also check for gui */
    else if (constatics.hmutex == NULL)
      {
      SetLastError(0);
      constatics.hmutex = CreateMutex(NULL, TRUE, "Bovine RC5/DES Win32 Client");
      if (GetLastError() != 0)
        {
        retcode = -1;
        ReleaseMutex( constatics.hmutex );
        CloseHandle( constatics.hmutex );
        }
      }
    #endif
    }

  #if (CLIENT_OS == OS_WIN32)
  if (retcode == 0)
    {
    if (winGetVersion() >= 400 && winGetVersion()<2000)
      win32CliInitializeService(0,NULL); //initializes if we are a win9x svc
    }
  #endif

  if (retcode == 0)
    {
    constatics.hidden = runhidden;

    //the win32 console client is really a GUI client without a GUI - cyrus
    #ifndef USE_NATIVE_CONSOLEIO
      {
      int nCmdShow = winGetInstanceShowCmd();
      if (runhidden)
        nCmdShow = SW_HIDE | WS_DISABLED;
      if ((constatics.hwnd = w16ConsoleCreate(nCmdShow)) == NULL)
        {
        if (!runhidden)
          {
          char buffer[100];
          char *errmsg = NULL;
          if (constatics.errorcode == W16CONS_ERR_CREATETHREAD) 
            errmsg = "create console thread";
          else if (constatics.errorcode == W16CONS_ERR_NOFONT) 
           errmsg = "assign font";
          else if (constatics.errorcode == W16CONS_ERR_NOMEM) 
            errmsg = "create window data area";
          else if (constatics.errorcode == W16CONS_ERR_CREATEWIN) 
            errmsg = "create window client area";
          else if (constatics.errorcode == W16CONS_ERR_NCCREATE) 
            errmsg = "create window non-client area";
          else if (constatics.errorcode == W16CONS_ERR_REGCLASS) 
            errmsg = "register class";
          else if (constatics.errorcode == W16CONS_ERR_GETINST) 
            errmsg = "get instance handle";
          else if (constatics.errorcode == W16CONS_ERR_NOSLOT) 
            errmsg = "find a window slot";
          sprintf(buffer,"Unable to create console window.%s%s)",
                ((errmsg == NULL)?(" (Unknown error"):("\n(Failed to ")),
                ((errmsg == NULL)?(""):(errmsg)) );
          MessageBox( NULL, buffer, wintitle, MB_OK | MB_TASKMODAL);
          }
        retcode = -1;
        }
      else
        {
        w16SetConsoleTitle(wintitle);
        }
      }
    #elif (!defined(NEEDVIRTUALMETHODS))
      {
      if (runhidden)
        {
        //nothing - console won't be created
        retcode = 0;
        }
      else if (!AllocConsole())
        {
        retcode = -1;
        MessageBox( NULL, "Unable to create console window.",
                              wintitle, MB_OK | MB_TASKMODAL);
        }
      else
        {
        retcode = 0;
        SetConsoleTitle(wintitle);
        Sleep(40); //Delay needed for title to update
        constatics.hwnd = FindWindow( NULL, wintitle );
          
        // Now re-map the C Runtime STDIO handles
        #define _IOINIT_METHOD 2

        #if (_IOINIT_METHOD == 1)
          {
          //microsoft method - 
          //http://support.microsoft.com/support/kb/articles/q105/3/05.asp
          //fails on win98 (_fdopen fails)
   
          int hCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
          FILE *hf = _fdopen(hCrt, "w");
          *stdout = *hf;
          setvbuf(stdout, NULL, _IONBF, 0);         
          hCrt = _open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
          hf = _fdopen(hCrt, "w");
          *stderr = *hf;
          setvbuf(stderr, NULL, _IONBF, 0);         
          hCrt = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
          hf = _fdopen(hCrt, "r");
          *stdin = *hf;
          setvbuf(stdin, NULL, _IONBF, 0);
          }
        #elif (_IOINIT_METHOD == 2)
          {
          //this is my own pudding - cyrus
          //works on win98 (at least when the compiler is from watcom)
   
          FILE *hf;
          hf = fopen("CONOUT$", "w+t");
          if (!hf)
            {
            MessageBox( NULL, "Unable to open console for write.",
                      wintitle, MB_OK | MB_TASKMODAL | MB_ICONERROR);
            retcode = -1;
            }
          else
            {
            constatics.fstdout = hf;
 
            *stdout = *hf;
            setvbuf(stdout, NULL, _IONBF, 0);
            *stderr = *hf;
            setvbuf(stderr, NULL, _IONBF, 0);
               
            hf = fopen("CONIN$", "rt");
            if (!hf)
              {
              MessageBox( NULL, "Unable to open console for read.",
                 wintitle, MB_OK | MB_TASKMODAL | MB_ICONERROR);
              retcode = -1;
              }
            else
              {
              constatics.fstdin = hf;
 
              *stdin = *hf;
              setvbuf(stdin, NULL, _IONBF, 0);
              }
            } 
          }
        #elif (_IOINIT_METHOD == 3)
          {
          SECURITY_ATTRIBUTES sa;
          sa.nLength      = sizeof(SECURITY_ATTRIBUTES);
          sa.lpSecurityDescriptor = NULL;
          sa.bInheritHandle   = TRUE;
   
          HANDLE hIFile = CreateFile( "CONIN$", GENERIC_READ /*dwDesiredAccess*/, 
          FILE_SHARE_READ /*dwShareMode*/, &sa /*lpSecurityAttributes*/,
          OPEN_EXISTING /*dwCreationDistribution*/, 0 /*dwFlagsAndAttributes*/,
          0 /*hTemplateFile*/ );
          HANDLE hOFile = CreateFile( "CONOUT$", GENERIC_WRITE /*dwDesiredAccess*/, 
          FILE_SHARE_WRITE /*dwShareMode*/, &sa /*lpSecurityAttributes*/,
          OPEN_EXISTING /*dwCreationDistribution*/, 0 /*dwFlagsAndAttributes*/,
          0 /*hTemplateFile*/ );
   
          SetStdHandle( STD_OUTPUT_HANDLE, hOFile );
          SetStdHandle( STD_ERROR_HANDLE, hOFile );
          SetStdHandle( STD_INPUT_HANDLE, hIFile );
          }
        #endif
        } //runhidden or not
      if (retcode == 0)
        CliSetupSignals(); // Need to rehook the console control handler
      }
    #else // defined(NEEDVIRTUALMETHODS)
      {
      #if 0
      SetConsoleTitle(wintitle);
 
      constatics.hwnd = FindWindow( NULL, wintitle );
           
      if (!runhidden)
        {
        //nothing - screen is already visible
        }
      else if (constatics.hwnd)
        {
        RECT rc;
        GetClientRect( GetDesktopWindow(), &rc );
        SetWindowPos( hwnd, HWND_BOTTOM, 0, 
                             rc.bottom+1, 0, 0, SWP_HIDEWINDOW);
        }
      #endif
      }
    #endif
    } //if (retcode == 0)


  return (retcode);
}
 
/* ---------------------------------------------------- */

int w32ConShowWindow(void)  /* activate client window if not -hidden */
{
  if (!constatics.hwnd || constatics.hidden)
    return -1;
  ShowWindow(constatics.hwnd, SW_SHOW);
  return 0;
}

/* ---------------------------------------------------- */

int w32ConKbhit(void)
{
  #ifdef USE_NATIVE_CONSOLEIO
  return (kbhit());
  #else
  return w16ConsoleKbhit();
  #endif
}  

/* ---------------------------------------------------- */

int w32ConGetch(void)
{
  #ifdef USE_NATIVE_CONSOLEIO
  return (kbhit());
  #else
  return w16ConsoleGetch();
  #endif
}

/* ---------------------------------------------------- */

int w32ConOut(const char *text)
{
  #ifdef USE_NATIVE_CONSOLEIO
  int i = fwrite( text, sizeof(char), strlen(text), stdout);
  fflush(stdout);
  return i;
  #else
  return w16ConsolePrint(text);
  #endif
}

/* ---------------------------------------------------- */

int w32ConIsScreen(void)
{
  if (constatics.hwnd && !constatics.hidden)
    {
    #ifdef NEEDVIRTUALMETHODS
    return 1;
    #elif defined(USE_NATIVE_CONSOLEIO)
    return (isatty(fileno(stdout)) && isatty(fileno(stdin)));
    #else
    return 1;
    #endif
    }
  return 0;
}

/* ---------------------------------------------------- */

void w32Yield(void)
{
  #ifdef USE_NATIVE_CONSOLEIO    
    Sleep(SLEEP_FACTOR);
  #else
    w16Yield();
  #endif
  return;
}

/* ---------------------------------------------------- */

void w32Sleep(unsigned int millisecs)
{
  #ifdef USE_NATIVE_CONSOLEIO    
    Sleep(millisecs);
  #else
    w16Sleep(millisecs);
  #endif
}

/* ---------------------------------------------------- */

int w32ConGetSize( int *width, int *height)
{
  if (constatics.hwnd && !constatics.hidden)
    {
    #ifdef USE_NATIVE_CONSOLEIO
      {
      HANDLE hStdout;
      CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

      hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
      if (hStdout == INVALID_HANDLE_VALUE) 
        return -1;
      if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) 
        return -1;
      if (height) *height=csbiInfo.srWindow.Bottom - csbiInfo.srWindow.Top + 1;
      if (width) *width = csbiInfo.srWindow.Right - csbiInfo.srWindow.Left + 1;
      return 0;
      }
    #else
      {
      return w16ConGetSize( width, height );
      }
    #endif
    }
  return -1;
}

/* ---------------------------------------------------- */

int w32ConClear(void)
{
  if (constatics.hwnd && !constatics.hidden)
    {
    #ifdef USE_NATIVE_CONSOLEIO    
      {
      HANDLE hStdout;
      CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
      DWORD nLength;
      COORD topleft = {0,0};
      DWORD temp;
      hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
      if (hStdout == INVALID_HANDLE_VALUE) 
        return -1;
      if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) 
        return -1;
      nLength = csbiInfo.dwSize.X * csbiInfo.dwSize.Y;
      SetConsoleCursorPosition(hStdout, topleft);
      FillConsoleOutputCharacter(hStdout, (TCHAR) ' ', nLength, topleft, &temp);
      FillConsoleOutputAttribute(hStdout, csbiInfo.wAttributes, nLength, topleft, &temp);
      SetConsoleCursorPosition(hStdout, topleft);
      return 0;
      }
    #else
      {
      return w16ConsoleClear();
      }
    #endif
    }
  return -1;
}

/* ---------------------------------------------------- */

int w32ConSetPos(int col, int row)
{
  if (constatics.hwnd && !constatics.hidden)
    {
    #ifdef USE_NATIVE_CONSOLEIO    
      HANDLE hStdout;
      COORD pos = {col,row};
      hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
      if (hStdout == INVALID_HANDLE_VALUE) 
        return -1;
      SetConsoleCursorPosition(hStdout, pos);
      return 0;
    #else
      return w16ConSetPos(col, row);
    #endif
    }
  return -1;
}  

/* ------------------------------------------------ */

int w32ConGetPos(int *col, int *row)
{
  if (constatics.hwnd && !constatics.hidden)
    {
    #ifdef USE_NATIVE_CONSOLEIO    
//      #error function missing
    #else
      return w16ConGetPos(col,row);
    #endif
    }
  return -1;
}

/* ------------------------------------------------ */

int w32ConSendIDMCommand( int cmd )
{
  HWND otherguy = FindWindow( NULL, wintitle );
  if ( otherguy == NULL)
    return -1;
  SendMessage( otherguy, WM_COMMAND, cmd, 0 );
  return 0;
}  
