
/******************************************************************************\
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
\******************************************************************************/

#include "porttool.h"
#include "port.h"

/* forward declarations of helper functions in this module */
HWND   WINAPI StartInteractive (HANDLE, char *, int);
HANDLE WINAPI StartBackground (HANDLE, HWND, char *);
VOID   WINAPI InitializeMenu (HWND, HANDLE);
LONG   WINAPI CommandHandler (HWND, UINT, LONG);
int    WINAPI SetWrap (HWND);
BOOL   WINAPI GetCmdLine (char *, char *, BOOL *);
int    WINAPI Save_YNC (HWND);
VOID   WINAPI SetWindowTitle (HWND, char*);
VOID   WINAPI GetEditSubString (HWND, PUINT, PUINT, char *);

UINT    uSearchMsg;
HWND    hDlgPortStatus;
HWND    hDlgPort;


/* test case static variables for background porting */
HANDLE              hEvents[nBKPORTEVENTS];
BKPORTFILESTRUCT    BkPort;



/* entry point ot this executable */
int WINAPI WinMain (hInstance, hPrevInstance, lpCmdLine, nCmdShow)
    HINSTANCE hInstance;
    HINSTANCE hPrevInstance;
    LPSTR  lpCmdLine;
    int    nCmdShow;
{
    MSG        msg;
    HWND       hWnd;
    HANDLE     hAccel;
    BOOL       bBkgnd = 0;
    char       *lpszBuff = NULL;
    char       *lpszCmdLine = NULL;
    char       *lpCL;


    /* previous instances do not exist in Win32 */
    if (hPrevInstance)
    return 0;

    /* parse and copy command line parameters to local memory */
    lpCL = GetCommandLine ();
    if (lpszCmdLine = (char *)LocalAlloc (LPTR, strlen (lpCL) + 1))
    GetCmdLine (lpCL, lpszCmdLine, &bBkgnd);

    /* if /b switch, start background porting session */
    if (bBkgnd)
    {
    /* invoke background port status dialog */
    if (!(hDlgPortStatus = StartBackground (hInstance, NULL, lpszCmdLine)))
        return FALSE;
    }

    /* start interactive porting session */
    else
    {
    if (!(hWnd = StartInteractive (hInstance, lpszCmdLine, nCmdShow)))
        return FALSE;
    }

    /* free memory allocated for pCmdLine */
    if (lpszCmdLine)
    LocalFree ((HLOCAL)lpszCmdLine);

    /* load main accelerator table */
    hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE (IDA_PORTTOOL));

    /* main window message loop */
    while (GetMessage (&msg, NULL, 0, 0))
    {
    if ((!hDlgSearch     || !IsDialogMessage (hDlgSearch, &msg))     &&
        (!hDlgPort       || !IsDialogMessage (hDlgPort, &msg))       &&
        (!hDlgPortStatus || !IsDialogMessage (hDlgPortStatus, &msg)) &&
        (!TranslateAccelerator (hWnd, hAccel, &msg)))
        {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
        }
    }

    /* return success of application */
    return TRUE;
}




/* start background port status dialog */
HANDLE WINAPI StartBackground (
    HANDLE    hModule,
    HWND      hWndParent,
    char      *lpszCmdLine)
{
    return (CreateDialogParam (hModule,
                   IDD_BKPORTDIALOG,
                   hWndParent,
                   BkPortDlgProc,
                   (LPARAM)lpszCmdLine));
}




/* start interactive version of app */
HWND WINAPI StartInteractive (
    HANDLE    hInstance,
    char      *lpszCmdLine,
    int       nCmdShow)
    {
    WNDCLASS   wc;
    char       lpszClass[MAX_PATH];
    HWND       hWnd;

    /* load resources strings */
    LoadString (hInstance, IDS_APPNAME, lpszClass, sizeof (lpszClass));

    /* Register the frame class */
    wc.style         = 0;
    wc.lpfnWndProc   = (WNDPROC)MainWndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = CBWNDEXTRA;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon (hInstance, IDPortTool);
    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = IDPortTool;
    wc.lpszClassName = lpszClass;

    if (!RegisterClass (&wc) )
    return FALSE;

    /* Create the frame */
    hWnd = CreateWindow (lpszClass,
             "Win32 Port",
             WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | DS_LOCALEDIT,
             CW_USEDEFAULT,
             0,
             CW_USEDEFAULT,
             0,
             NULL,
             NULL,
             hInstance,
             (*lpszCmdLine ? lpszCmdLine : 0));

    /* make sure window was created */
    if (!hWnd)
    return FALSE;

    /* register search/replace message for common dialog use */
    uSearchMsg = RegisterWindowMessage ((char *)FINDMSGSTRING);

    /* show and update main window */
    ShowWindow (hWnd, nCmdShow);
    UpdateWindow (hWnd);

    return hWnd;
}



/* main window procedure */
LONG WINAPI MainWndProc (
    HWND    hWnd,
    UINT    uMsg,
    UINT    uParam,
    LONG    lParam)
{
    LONG    lRet = 1;
    int     nResult;
    RECT    rc;

    switch (uMsg)
    {
    case WM_CREATE:
        {
        HWND              hWndEdit;
        LPCREATESTRUCT    lpcs = (LPCREATESTRUCT)lParam;
        char              lpszBuff[MAX_PATH];
        LOGFONT           lfEditFont;
        HFONT             hFont;
        HCURSOR           hOldCursor;

        /* put hourglass cursor up */
        hOldCursor = (HCURSOR)SetClassLong (hWnd, GCL_HCURSOR, 0);
        SetCursor (LoadCursor (NULL, IDC_WAIT));

        /* Create an edit control */
        GetClientRect (hWnd, &rc);
        hWndEdit = CreateWindow ("edit",
                     " ",
                     WS_CHILD | WS_VISIBLE | DS_LOCALEDIT |
                     WS_HSCROLL | WS_VSCROLL |
                     ES_AUTOHSCROLL | ES_AUTOVSCROLL |
                     ES_MULTILINE | ES_NOHIDESEL,
                     rc.left,
                     rc.top,
                     rc.right-rc.left,
                     rc.bottom-rc.top,
                     hWnd,
                     (HMENU)IDC_EDIT,
                     (HANDLE)GetModuleHandle (NULL),
                     0);

        /* if edit control failed, abort aplication */
        if (!IsWindow (hWndEdit))
        {
        ErrorNotify (hWnd, IDS_EDITWNDFAILED);
        return FALSE;
        }

        /* increase edit control max character limit beyond 30,000 default */
        SendMessage (hWndEdit, EM_LIMITTEXT, 0x0FFFFFFF, 0);

        /* save edit window handle and init state variables */
        SetWindowLong (hWnd, WL_HWNDEDIT, (LONG) hWndEdit);
        SetWindowWord (hWnd, WW_SCROLL, TRUE);
        SetWindowWord (hWnd, WW_UNTITLED, TRUE);
        SetWindowWord (hWnd, WW_SEARCHCASE, TRUE);
        SetWindowWord (hWnd, WW_SEARCHDN, TRUE);
        SetWindowLong (hWnd, WL_HPTRDEVNAMES, 0);

        /* get printer configuration */
        if (!GetPrinterConfig (hWnd))
           ErrorNotify (hWnd, IDS_PTRCONFIGFAILED);

        /* if initialization file passed, load file now */
        if (lpcs->lpCreateParams)
        {
        /* load filename passed at initialization */
        if ((nResult = LoadFile (hWnd, lpcs->lpCreateParams)) == TRUE )
            {
            /* save filename and path in global string */
            strcpy (lpszFilePath, lpcs->lpCreateParams);

            /* The file has a title, so reset the UNTITLED flag. */
            SetWindowWord(hWnd, WW_UNTITLED, FALSE);

            /* extract filename from path */
            GetFileFromPath (lpszFilePath, lpszBuff);

            /* set window text title to be "AppName - filename" */
            SetWindowTitle (hWnd, lpszBuff);
            }
        else
            {
            /* notify user of error */
            ErrorNotify (hWnd, nResult);

            /* set window title to "AppName - Untitled" */
            LoadString ((HANDLE)GetModuleHandle (NULL),
                IDS_UNTITLED,
                lpszBuff,
                sizeof (lpszBuff));
            SetWindowTitle (hWnd, lpszBuff);
            }
        }
        else
        {
        /* set window title to "AppName - Untitled" */
        LoadString ((HANDLE)GetModuleHandle (NULL),
                IDS_UNTITLED,
                lpszBuff,
                sizeof (lpszBuff));
        SetWindowTitle (hWnd, lpszBuff);

        /* set global file and path variables to null */
        *lpszFilePath = 0;
        }

        /* create fixed pitch font as default font */
        lfEditFont.lfHeight = 16;
        lfEditFont.lfWidth = 0;
        lfEditFont.lfEscapement = 0;
        lfEditFont.lfOrientation = 0;
        lfEditFont.lfWeight = 400;
        lfEditFont.lfItalic = FALSE;
        lfEditFont.lfUnderline = FALSE;
        lfEditFont.lfStrikeOut = FALSE;
        lfEditFont.lfCharSet = ANSI_CHARSET;
        lfEditFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
        lfEditFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
        lfEditFont.lfQuality = DEFAULT_QUALITY;
        lfEditFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
        *lfEditFont.lfFaceName = 0;

        /* make scroll bars initially visible */
        SetScrollRange (hWndEdit, SB_VERT, 0, 100, TRUE);
        SetScrollRange (hWndEdit, SB_HORZ, 0, 100, TRUE);

        /* create the logical font */
        if (hFont = CreateFontIndirect (&lfEditFont))
        SendMessage (hWndEdit, WM_SETFONT, (UINT)hFont, 0);
        else
        ErrorNotify (hWnd, IDS_FONTFAILEDTOCREATE);

        /* remove hourglass cursor */
        SetClassLong (hWnd, GCL_HCURSOR, (LONG)hOldCursor);
        SetCursor (hOldCursor);

        /* set focus to edit window */
        SetFocus (hWndEdit);
        }
        break;

    case WM_SIZE:
        {
        RECT    rc;
        HWND    hWndEdit;

        /* resize the edit control to match the client area */
        hWndEdit = (HWND)GetWindowLong (hWnd, WL_HWNDEDIT);
        GetClientRect (hWnd, &rc);
        MoveWindow (hWndEdit,
            rc.left,
            rc.top,
            rc.right-rc.left,
            rc.bottom-rc.top,
            TRUE);
        }
        break;

    case WM_SETFOCUS:
        SetFocus ((HWND)GetWindowLong (hWnd, WL_HWNDEDIT));
        break;

    case WM_INITMENU:
        /* initialize menuitems */
        InitializeMenu (hWnd, (HMENU)uParam);
        break;

    case WM_WININICHANGE:
    case WM_DEVMODECHANGE:
        /* get printer configuration */
        GetPrinterConfig (hWnd);
        break;

    case WM_COMMAND:
        /* handle all command messages in a localized function */
         lRet = CommandHandler (hWnd, uParam, lParam);
        break;

    case WM_CLOSE:
    case WM_QUERYENDSESSION:
        {
        HWND    hWndEdit = (HWND)GetWindowLong (hWnd, WL_HWNDEDIT);

        /* check if there are changes to the edit contents, and offer to save first */
        if (SendMessage (hWndEdit, EM_GETMODIFY, 0, 0))
        {
        switch (Save_YNC (hWnd))
            {
            case IDCANCEL:
            /* abort exit */
            return FALSE;
            case IDYES:
            /* save data then continue */
            if (!SendMessage (hWnd, WM_COMMAND, (UINT)UM_SAVEFILE, 0))
                return FALSE;
            case IDNO:
            /* just fall through */
            break;
            }
        }

        /* call destroy window to cleanup and go away */
        DestroyWindow (hWnd);
        }
        break;

    case WM_DESTROY:
        {
        HFONT    hFont = (HFONT)SendMessage ((HWND)GetWindowLong (hWnd, WL_HWNDEDIT),
                         WM_GETFONT,
                         0,
                         0);

        /* destroy font handle from edit control if exists */
        if (hFont)
        DeleteObject (hFont);

        PostQuitMessage (0);
        }
        break;

    default:
        /* process common dialog search message here, then break */
        if (uMsg == uSearchMsg)
        {
        LPFINDREPLACE    lpfr = (LPFINDREPLACE)lParam;

        if (lpfr->Flags & FR_DIALOGTERM)
            {
            /* save case and direction */
            SetWindowWord (hWnd, WW_SEARCHCASE, (WORD)(lpfr->Flags & FR_MATCHCASE));
            SetWindowWord (hWnd, WW_SEARCHDN, (WORD)(lpfr->Flags & FR_DOWN));
            hDlgSearch = NULL;
            }

        else if (lpfr->Flags & FR_FINDNEXT)
            if (!LocateText (hWnd,
                     (WORD)(lpfr->Flags & FR_MATCHCASE),
                     (WORD)(lpfr->Flags & FR_DOWN),
                     lpszSearch))
            ErrorNotify (hWnd, IDS_STRINGNOTFOUND);
        break;
        }

        /* pass all unhandled messages to DefWindowProc */
        lRet = DefWindowProc (hWnd, uMsg, uParam, lParam);
        break;
    }

    /* return 1 if handled message, 0 if not */
    return lRet;
}



/* about box dialog procedure */
BOOL WINAPI AboutDlgProc (
    HWND    hwnd,
    UINT    uMsg,
    UINT    uParam,
    LONG    lParam)
{
    BOOL    bRet = TRUE;

    switch (uMsg)
    {
    case WM_COMMAND:
        switch (LOWORD (uParam))
        {
        /* end dialog with TRUE or FALSE for OK or CANCEL */
        case IDOK:
        case IDCANCEL:
            EndDialog(hwnd, (LOWORD (uParam) == IDOK));
            break;

        default:
            bRet = FALSE;
        }
        break;

    default:
        bRet =  FALSE;
        break;
    }
    return bRet;
}



/* initialize menu function */
VOID WINAPI InitializeMenu (
    HWND    hWnd,
    HANDLE  hMenu)
{
    WORD    mfStatus;
    DWORD   dwSel;
    HWND    hWndEdit = (HWND)GetWindowLong (hWnd, WL_HWNDEDIT);
    WORD    wScroll;

    /* see if edit control can undo last command */
    if (SendMessage (hWndEdit, EM_CANUNDO, 0, 0L))
    mfStatus = MF_ENABLED;
    else
    mfStatus = MF_GRAYED;
    EnableMenuItem (hMenu, IDM_EDITUNDO, mfStatus);

    /* enable menuitems CUT, COPY and CLEAR if selected text */
    dwSel = SendMessage (hWndEdit, EM_GETSEL, 0, 0);
    mfStatus = (WORD)((LOWORD(dwSel) == HIWORD(dwSel))?MF_GRAYED:MF_ENABLED);
    EnableMenuItem (hMenu, IDM_EDITCUT, mfStatus);
    EnableMenuItem (hMenu, IDM_EDITCOPY, mfStatus);
    EnableMenuItem (hMenu, IDM_EDITCLEAR, mfStatus);

    /* if text allow for new file, enable menuitem */
    if (SendMessage (hWndEdit, WM_GETTEXTLENGTH, 0, 0))
    EnableMenuItem (hMenu, IDM_FILENEW, MF_ENABLED);
    else
    EnableMenuItem (hMenu, IDM_FILENEW, MF_GRAYED);

    /* if CF_TEXT format data is available in clipboard */
    if (OpenClipboard (hWnd) & IsClipboardFormatAvailable (CF_TEXT))
    EnableMenuItem (hMenu, IDM_EDITPASTE, MF_ENABLED);
    else
    EnableMenuItem (hMenu, IDM_EDITPASTE, MF_GRAYED);
    CloseClipboard ();

    /* set the scroll bars menuitem */
    wScroll = GetWindowWord (hWnd, WW_SCROLL);
    CheckMenuItem (hMenu, IDM_EDITSCROLL, (UINT)(wScroll ? MF_CHECKED : MF_UNCHECKED));

    /* set the word wrap state for the window */
    dwSel = GetWindowLong (hWndEdit, GWL_STYLE);
    CheckMenuItem (hMenu,
           IDM_EDITWRAP,
           (UINT)((dwSel & ES_AUTOHSCROLL) ? MF_UNCHECKED : MF_CHECKED));

    /* enable search menuitems if a search string exists */
    if (*lpszSearch)
    {
    EnableMenuItem (hMenu, IDM_SEARCHNEXT, MF_ENABLED);
    EnableMenuItem (hMenu, IDM_SEARCHPREV, MF_ENABLED);
    }
    else
    {
    EnableMenuItem (hMenu, IDM_SEARCHNEXT, MF_GRAYED);
    EnableMenuItem (hMenu, IDM_SEARCHPREV, MF_GRAYED);
    }

    /* enable Print menuitems if a printer is available */
    if (GetWindowLong (hWnd, WL_HPTRDEVNAMES))
    {
    EnableMenuItem (hMenu, IDM_FILEPRINT, MF_ENABLED);
    EnableMenuItem ( hMenu, IDM_FILESETUP, MF_ENABLED);
    }
    else
    {
    EnableMenuItem (hMenu, IDM_FILEPRINT, MF_GRAYED);
    EnableMenuItem ( hMenu, IDM_FILESETUP, MF_GRAYED);
    }

    /* menuitems that are always enabled */
    EnableMenuItem(hMenu, IDM_EDITSCROLL, MF_ENABLED);
    EnableMenuItem(hMenu, IDM_EDITSELECT, MF_ENABLED);
    EnableMenuItem(hMenu, IDM_EDITWRAP, MF_ENABLED);
    EnableMenuItem(hMenu, IDM_SEARCHFIND, MF_ENABLED);
}



/* handle all WM_COMMAND messages here */
LONG WINAPI CommandHandler (
    HWND    hWnd,
    UINT    uParam,
    LONG    lParam)
{
    int     nResult;
    HWND    hWndEdit = (HWND)GetWindowLong (hWnd, WL_HWNDEDIT);

    switch (LOWORD(uParam))
    {
    case IDM_FILENEW:
        {
        char    lpszMsg[MAX_PATH];

        /* check if there are changes, and offer to save first */
        if (SendMessage (hWndEdit, EM_GETMODIFY, 0, 0))
        {
        switch (Save_YNC (hWnd))
            {
            case IDCANCEL:
            /* abort operation */
            return FALSE;
            case IDYES:
            /* save data then continue if successful */
            if (!SendMessage (hWnd, WM_COMMAND, (UINT)UM_SAVEFILE, 0))
                return FALSE;
            case IDNO:
            /* just fall through */
            break;
            }

        /* reset edit changes flag */
        SendMessage (hWndEdit, EM_SETMODIFY, FALSE, 0);
        }

        /* clear edit control */
        SetWindowText (hWndEdit, "");

        /* set window title to "Untitled" */
        LoadString ((HANDLE)GetModuleHandle (NULL),
            IDS_UNTITLED,
            lpszMsg,
            sizeof (lpszMsg));
        SetWindowTitle (hWnd, lpszMsg);
        SetWindowWord (hWnd, WW_UNTITLED, TRUE);

        /* reset caret position by sending WM_KILLFOCUS/WM_SETFOCUS messages */
        SetFocus (NULL);
        SetFocus (hWndEdit);
        }
        break;

    case IDM_FILEOPEN:
        {
        char    lpszFileName[MAX_PATH];
        int     nResult;

        /* if changes to current file, ask to save first */
        if (SendMessage (hWndEdit, EM_GETMODIFY, 0, 0))
        {
        switch (Save_YNC (hWnd))
            {
            case IDCANCEL:
            /* abort operation */
            return FALSE;
            case IDYES:
            /* save data then continue */
            if (!SendMessage (hWnd, WM_COMMAND, (UINT)UM_SAVEFILE, 0))
                return FALSE;
            case IDNO:
            /* just fall through */
            break;
            }

        /* reset edit changes flag */
        SendMessage (hWndEdit, EM_SETMODIFY, FALSE, 0);
        }

        /* get new filename and load into edit control */
        if (GetFileName (hWnd, lpszFileName, lpszFilePath))
        {
        if ((nResult = LoadFile (hWnd, lpszFilePath)) != TRUE )
            /* notify user of error */
            ErrorNotify (hWnd, nResult);
        else
            {
            /* update window text */
            SetWindowTitle (hWnd, lpszFileName);
            SetWindowWord (hWnd, WW_UNTITLED, FALSE);
            }
        }
        else
        return FALSE;
        }
        break;

    case IDM_FILESAVEAS:
        {
        char    lpszFileTitle[MAX_PATH];
        int     nResult;

        /* get a valid filename and path */
        if (SaveAsFileName (hWnd, lpszFileTitle, lpszFilePath))
        {
        /* if file saves okay */
        if ((nResult = SaveFile (hWnd, lpszFilePath)) > 0)
            {
            /* reset changed flag, and window title */
            SendMessage (hWndEdit, EM_SETMODIFY, FALSE, 0);
            SetWindowTitle (hWnd, lpszFileTitle);
            SetWindowWord (hWnd, WW_UNTITLED, FALSE);
            }
        else
            {
            /* unable to save file, return error */
            ErrorNotify (hWnd, nResult);
            return FALSE;
            }
        }
        else
        return FALSE;
        }
        break;

    case IDM_FILESAVE:
        {
        char    lpszFileTitle[MAX_PATH];
        int     nResult;

        /* if called from menu, check to see if file modified */
        if (!lParam &&
        SendMessage (hWndEdit, EM_GETMODIFY, 0, 0))
        return FALSE;

    /* user defined msg is sent from Exit, Open and New menuitems */
    case UM_SAVEFILE:

        /* if untitled, get new name */
        if (GetWindowWord (hWnd, WW_UNTITLED) &&
        !(SaveAsFileName(hWnd, lpszFileTitle, lpszFilePath)))
        {
        /* make sure no name was saved */
        *lpszFilePath = 0;
        return FALSE;
        }

        /* save buffer and reset flag */
        if ((nResult = SaveFile (hWnd, lpszFilePath)) > 0)
        {
        /* if new file name, set window title */
        if (*lpszFileTitle)
            {
            SetWindowTitle (hWnd, lpszFileTitle);
            SetWindowWord (hWnd, WW_UNTITLED, FALSE);
            }
        SendMessage (hWndEdit, EM_SETMODIFY, FALSE, 0);
        }
        else
        {
        /* unable to save file, return error */
        ErrorNotify (hWnd, nResult);
        return FALSE;
        }
        }
        break;

    case IDM_FILEPRINT:
        {
        int    nRes;

        /* print the file */
        if ((nRes = PrintFile (hWnd)) < 0)
        ErrorNotify (hWnd, nRes);
        }
        break;

    case IDM_FILESETUP:
        {
        int    nRes;

        /* set up the printer environment */
        if ((nRes = PrinterSetup (hWnd)) < 0)
        ErrorNotify (hWnd, nRes);
        }
        break;

    case IDM_FILEEXIT:
        /* exit application */
        PostMessage (hWnd, WM_CLOSE, 0, 0L);
        break;

    case IDM_FILEABOUT:
        /* call about dialog box */
        DialogBox ((HANDLE)GetModuleHandle (NULL),
               (LPSTR)IDD_ABOUT,
               hWnd,
               AboutDlgProc);
        break;

    case IDM_EDITUNDO:
        SendMessage (hWndEdit, EM_UNDO, 0, 0L);
        break;

    case IDM_EDITCUT:
        SendMessage (hWndEdit, WM_CUT, 0, 0L);
        break;

    case IDM_EDITCOPY:
        SendMessage (hWndEdit, WM_COPY, 0, 0L);
        break;

    case IDM_EDITPASTE:
        SendMessage (hWndEdit, WM_PASTE, 0, 0L);
        break;

    case IDM_EDITCLEAR:
        SendMessage (hWndEdit, WM_CUT, 0, 0L);
        break;

    case IDM_EDITSELECT:
        /* 0, -1 selects the entire string */
        SendMessage (hWndEdit, EM_SETSEL, 0, (LONG)(int)-1);
        break;

    case IDM_EDITSCROLL:
        {
        WORD    wScroll = !GetWindowWord (hWnd, WW_SCROLL);

        /* toggle vertical scroll bar */
        SetScrollRange (hWndEdit, SB_VERT, 0, (int)(wScroll ? 100 : 0), TRUE);

        /* if not word wrap, toggle horizontal scroll */
        if (ES_AUTOHSCROLL & GetWindowLong (hWndEdit, GWL_STYLE))
        SetScrollRange (hWndEdit, SB_HORZ, 0, (int)(wScroll ? 100 : 0), TRUE);

        /* set scroll flag */
        SetWindowWord (hWnd, WW_SCROLL, wScroll);
        }
        break;

    case IDM_EDITWRAP:
        /* change edit control */
        if ((nResult = SetWrap (hWnd)) < 0)
        /* notify user of error */
        ErrorNotify (hWnd, nResult);
        break;

    case IDM_EDITFONT:
        {
        CHOOSEFONT    cf;
        LOGFONT       lfEditFont;
        HFONT         hEditFont;
        int           iSize=0;

        /* get logical font structure from current font */
        if (hEditFont = (HFONT)SendMessage (hWndEdit, WM_GETFONT, 0, 0))
        {
        GetObject (hEditFont, sizeof (lfEditFont), &lfEditFont);
        cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
        }
        else
        cf.Flags = CF_SCREENFONTS;

        /* call common dialog to select a font */
        cf.lStructSize    = sizeof (CHOOSEFONT);
        cf.hwndOwner      = hWnd;
        cf.hDC            = NULL;
        cf.lpLogFont      = &lfEditFont;
        cf.iPointSize     = iSize;
        cf.rgbColors      = 0;
        cf.lCustData      = 0;
        cf.lpfnHook       = NULL;
        cf.lpTemplateName = NULL;
        cf.hInstance      = NULL;
        cf.lpszStyle      = NULL;
        cf.nFontType      = SCREEN_FONTTYPE;
        cf.nSizeMin       = 0;
        cf.nSizeMax       = 0;

        if (ChooseFont (&cf))
        {
        /* create new font and put in edit control */
        SendMessage (hWndEdit,
                 WM_SETFONT,
                 (UINT)CreateFontIndirect
                 (&lfEditFont),
                 TRUE);

        if (hEditFont)
            DeleteObject (hEditFont);
        }
        }
        break;

    case IDM_SEARCHFIND:
        {
        UINT    uBegSel, uEndSel;
        WORD    wCase = GetWindowWord (hWnd, WW_SEARCHCASE);
        WORD    wDir = GetWindowWord (hWnd, WW_SEARCHDN);

        /* if selected text, replace global search string */
        SendMessage (hWndEdit, EM_GETSEL, (UINT)&uBegSel, (UINT)&uEndSel);
        if (uBegSel != uEndSel)
        GetEditSubString (hWndEdit, &uBegSel, &uEndSel, lpszSearch);

        /* Put up the find dialog box */
        if (!FindDialog (hWnd, wCase, wDir, lpszSearch))
        ErrorNotify (hWnd, IDS_SEARCHDLGFAILED);
        }
        break;

    case IDM_SEARCHNEXT:
        /* locate next search string in edit control */
        if (!LocateText (hWnd,
                 GetWindowWord (hWnd, WW_SEARCHCASE),
                 TRUE,
                 lpszSearch))
        ErrorNotify (hWnd, IDS_STRINGNOTFOUND);
        break;

    case IDM_SEARCHPREV:
        /* locate previous search string in edit control */
        if (!LocateText (hWnd,
                 GetWindowWord (hWnd, WW_SEARCHCASE),
                 FALSE,
                 lpszSearch))
        ErrorNotify (hWnd, IDS_STRINGNOTFOUND);
        break;

    case IDM_PORTCURFILE:
        /* if untitled, save first */
        if (GetWindowWord (hWnd, WW_UNTITLED) &&
        !SendMessage (hWnd, WM_COMMAND, IDM_FILEOPEN, 0))
        {
        ErrorNotify (hWnd, IDS_NOFILETOPORT);
        break;
        }

        /* start port dialog with flags */
        hDlgPort = CreateDialog (GetModuleHandle (NULL),
                     IDD_PORTDIALOG,
                     hWnd,
                     PortDlgProc);
        break;

    case IDM_PORTBKGND:
        if (IsWindow (hDlgPortStatus))
        ShowWindow (hDlgPortStatus, SW_SHOWNORMAL);
        else if (!(hDlgPortStatus = StartBackground (GetModuleHandle (NULL),
                             hWnd,
                             NULL)))
        ErrorNotify (hWnd, IDS_BKPORTSTARTFAILED);
        break;

    default:
        return FALSE;
    }
    return TRUE;
}



/* change the word wrapping in an edit control */
int WINAPI SetWrap (
    HWND    hWnd)

{
    DWORD   dwStyle;
    HANDLE  hOldData, hNewData;
    char    *lpOldData, *lpNewData;
    HWND    hWndOld = (HWND)GetWindowLong (hWnd, WL_HWNDEDIT);
    HWND    hWndNew;
    RECT    rc;
    UINT    uLen;
    UINT    uBegSel, uEndSel;
    WORD    wScroll = GetWindowWord (hWnd, WW_SCROLL);
    HFONT   hEditFont = (HFONT)SendMessage (hWndOld, WM_GETFONT, 0, 0);


    /* turn off scroll bars if currently present */
    if (wScroll)
    {
    SetScrollRange (hWndOld, SB_VERT, 0, 0, FALSE);
    SetScrollRange (hWndOld, SB_HORZ, 0, 0, FALSE);
    }

    /* new edit style = old style XOR ES_AUTOHSCROLL */
    dwStyle = ES_AUTOHSCROLL ^ (DWORD)GetWindowLong (hWndOld, GWL_STYLE);

    /* save text selection */
    SendMessage (hWndOld, EM_GETSEL, (UINT)&uBegSel, (UINT)&uEndSel);

    /* create a new edit control with the new style */
    GetClientRect (hWnd, &rc);
    hWndNew = CreateWindow ("edit",
                "",
                dwStyle,
                rc.left,
                rc.top,
                rc.right-rc.left,
                rc.bottom-rc.top,
                hWnd,
                (HMENU)IDC_EDIT,
                (HANDLE)GetModuleHandle (NULL),
                0);

    /* check for window created */
    if (!IsWindow (hWndNew))
    return IDS_EDITWNDFAILED;

    /* reset to no format lines */
    SendMessage (hWndOld, EM_FMTLINES, !(dwStyle & ES_AUTOHSCROLL), 0);

    /* get the data handle of the old control */
    if (!(hOldData = (HANDLE)SendMessage (hWndOld, EM_GETHANDLE, 0, 0)))
    {
    /* delete new edit window and return error */
    DestroyWindow (hWndNew);
    return IDS_GETHANDLEFAILED;
    }

    /* get data handle to new edit control and reallocate to size of old edit text */
    hNewData = (HANDLE)SendMessage (hWndNew, EM_GETHANDLE, 0, 0);
    uLen = GetWindowTextLength (hWndOld);
    if (LocalReAlloc(hNewData, uLen+1, LHND) == NULL)
    {
    /* abort, clean up and return error */
    DestroyWindow (hWndNew);
    return IDS_REALLOCFAILED;
    }

    lpOldData = LocalLock (hOldData);
    lpNewData = LocalLock (hNewData);
    lpNewData[uLen+1] = 0;

    /* copy from one buffer to the other */
    while (uLen-- > 0)
    lpNewData[uLen] = lpOldData[uLen];

    /* unlock and release data buffers */
    LocalUnlock (hOldData);
    LocalUnlock (hNewData);

    /* swap windows */
    SetWindowLong (hWnd, WL_HWNDEDIT, (LONG)hWndNew);
    DestroyWindow (hWndOld);
    SendMessage (hWndNew, EM_SETHANDLE, (UINT)hNewData, 0);

    /* set line formatting */
    SendMessage (hWndNew, EM_FMTLINES, !(dwStyle & ES_AUTOHSCROLL), 0);

    /* replace font in new edit control */
    if (hEditFont)
    SendMessage (hWndNew, WM_SETFONT, (UINT)hEditFont, 0);

    /* set scroll bars if appropriate */
    if (wScroll)
    {
    SetScrollRange (hWndNew, SB_VERT, 0, 100, TRUE);
    SetScrollRange (hWndNew, SB_HORZ, 0, (ES_AUTOHSCROLL & dwStyle ? 100 : 0), TRUE);
    }

    /* restore text selection, repaint and set focus */
    InvalidateRect (hWndNew, NULL, TRUE);
    UpdateWindow (hWndNew);
    SendMessage (hWndNew, EM_SETSEL, uBegSel, uEndSel);
    SetFocus (hWndNew);

    /* return success */
    return TRUE;
}



/* get win32 command line parameters */
BOOL WINAPI GetCmdLine(
    char    *lpStr,
    char    *lpszCmdLine,
    BOOL    *bBkgnd)
{
    if (*lpStr)
    {
    /* skip application name which precedes parameters */
    while (*lpStr != ' ' && *lpStr != 0)
        lpStr++;

    /* skip spaces */
    while (*lpStr == ' ' && *lpStr != 0)
        lpStr++;

    /* indeed command line parameter(s) present */
    if (*lpStr != 0)
        {
        /* if background switch, set flag and remove switch from command line */
        if ((*lpStr == '/' || *lpStr == '-') &&
        (*(lpStr+1) == 'b' || *(lpStr+1) == 'B'))
        {
        *bBkgnd = TRUE;
        lpStr += 2;

        if (*lpStr == 0)
            *lpszCmdLine = 0;
        else
            strcpy (lpszCmdLine, lpStr);
        }
        /* maybe switch is embedded in parameter(s) somewhere */
        else
        {
        char    *pStr = lpStr;
        char    *pCmdLine = lpszCmdLine;
        int     i, nCnt;

        while (*pStr != 0)
            {
            /* background switch is set, so prepare parameters and set flag */
            if ((*pStr == '/' || *pStr == '-') &&
            (*(pStr+1) == 'b' || *(pStr+1) == 'B'))
            {
            *bBkgnd = TRUE;

            /* copy from beg. of lpStr to *pStr to lpszCmdLine */
            nCnt = pStr - lpStr;
            for (i=0; i<nCnt; i++)
                lpszCmdLine[i] = lpStr[i];
            lpszCmdLine[i] = 0;
            strcat (lpszCmdLine, (pStr+2));

            /* break from loop */
            break;
            }

            pStr++;
            }

        /* no switch found, can only edit one file, remove extra parameters */
        if (*pStr == 0)
            {
            pStr = lpStr;

            while (*pStr != ' ' && *pStr != 0)
            pStr++;

            if (*pStr == ' ')
            *pStr = 0;

            strcpy (lpszCmdLine, lpStr);
            }
        }
        }
    else
        return FALSE;
    }
    else
    return FALSE;

    return TRUE;
}



/* display a Save, Yes|No|Cancel message box */
int WINAPI Save_YNC (
    HWND    hWnd)
{
    char    lpszMsg[MAX_PATH];
    char    lpszAppName[MAX_PATH];

    /* load string to prompt user */
    LoadString ((HANDLE)GetModuleHandle (NULL),
        IDS_DATACHANGED,
        lpszMsg,
        sizeof (lpszMsg));
    LoadString ((HANDLE)GetModuleHandle (NULL),
        IDS_APPNAME,
        lpszAppName,
        sizeof (lpszAppName));

    /* return user response */
    return (MessageBox (hWnd,
            lpszMsg,
            lpszAppName,
            MB_YESNOCANCEL | MB_ICONQUESTION));
}



/* error notification routine */
VOID WINAPI ErrorNotify (
    HWND    hWnd,
    int     nErrorString)
{
    char    lpszAppName[MAX_PATH];
    char    lpszErrStr[MAX_PATH];
    char    szNum[10];

    LoadString ((HANDLE)GetModuleHandle (NULL),
        IDS_APPNAME,
        lpszAppName,
        sizeof (lpszAppName));
    if (!LoadString ((HANDLE)GetModuleHandle (NULL),
             nErrorString,
             lpszErrStr,
             sizeof (lpszErrStr)))
    {
    strcpy (lpszErrStr, "Unknown error => ");
    strcat (lpszErrStr, itoa (nErrorString, szNum, 10));
    }

    MessageBox (hWnd, lpszErrStr, lpszAppName, MB_OK | MB_ICONSTOP);
}



VOID WINAPI SetWindowTitle (
    HWND    hWnd,
    char    *lpszFile)
{
    char    lpszAppName[MAX_PATH];

    /* load AppName and Window title string into window text */
    LoadString ((HANDLE)GetModuleHandle (NULL),
        IDS_PRINTJOB,
        lpszAppName,
        sizeof (lpszAppName));
    strcat (lpszAppName, lpszFile);
    SetWindowText (hWnd, lpszAppName);
}



/* extract a substring from the edit controls data buffer */
VOID WINAPI GetEditSubString (
    HWND    hWndEdit,
    PUINT   puStart,
    PUINT   puEnd,
    char    *lpszString)
{
    HANDLE    hEditData;
    char      *lpEditData;
    UINT      i;

    /* maximum search string length is MAXSEARCHSTRING characters */
    if ((*puEnd - *puStart) > MAXSEARCHSTRING)
    *puEnd = *puStart + MAXSEARCHSTRING;

    /* get edit data handle and lock */
    hEditData = (HANDLE)SendMessage (hWndEdit, EM_GETHANDLE, 0, 0);
    lpEditData = (char *)LocalLock (hEditData);

    /* copy characters to string and terminate */
    for (i=*puStart; i<*puEnd; i++)
    lpszString[i-*puStart] = lpEditData[i];
    lpszString[i-*puStart] = 0;

    /* unlock and return edit handle */
    LocalUnlock (hEditData);
}
