/***************************************************************************
 *									   *
 *  PROGRAM	: MultiPad.c						   *
 *									   *
 *  PURPOSE	: To give a multi-Notepad demonstration of the new MDI	   *
 *		  API in Windows 3.0					   *
 *									   *
 *  FUNCTIONS	: WinMain()	      - Calls the initialization function  *
 *					and processes message loop	   *
 *									   *
 *		  MPFrameWndProc()    - Window function for the "frame"    *
 *					window, which controls the menu    *
 *					and contains the MDI document	   *
 *					windows as child windows.	   *
 *									   *
 *		  MPMDIChildWndProc() - Window function for the individual *
 *					document windows		   *
 *									   *
 *		  InitializeMenu()    - Handles enabling/greying of menu   *
 *					items according to the app's state.*
 *									   *
 *		  CloseAllChildren    - Destroys all MDI child windows.    *
 *									   *
 *		  CommandHandler()    - Processes the "frame" window's     *
 *					WM_COMMAND messages.		   *
 *									   *
 *		  AboutDlgProc()      - Dialog function for the ubiquitous *
 *					About.. dialog. 		   *
 *									   *
 *		  SetWrap()	      - Alters word wrapping in the edit   *
 *					control.			   *
 *									   *
 *		  MPError()	      - Flashes an error messagebox.	   *
 *									   *
 *		  QueryCloseChild     - Prompts for saving current MDI	   *
 *					child window.			   *
 *									   *
 *		  QueryCloseAllChildren() - Asks whether it is OK to close *
 *					    down app.			   *
 *									   *
 ***************************************************************************/
// COPYRIGHT:
//
//   (C) Copyright Microsoft Corp. 1992.  All rights reserved.
//
//   You have a royalty-free right to use, modify, reproduce and
//   distribute the Sample Files (and/or any modified version) in
//   any way you find useful, provided that you agree that
//   Microsoft has no warranty obligations or liability for any
//   Sample Application Files which are modified.


#include "multipad.h"
#include "commdlg.h"

/* global variables used in this module or among more than one module */
PRINTDLG pd;      /* Common print dialog structure */
HANDLE hInst;			    /* Program instance handle		     */
HANDLE hAccel;			    /* Main accelerator resource	     */
HWND hwndFrame		 = NULL;    /* Handle to main window		     */
HWND hwndMDIClient	 = NULL;    /* Handle to MDI client		     */
HWND hwndActive 	 = NULL;    /* Handle to currently activated child   */
HWND hwndActiveEdit	 = NULL;    /* Handle to edit control		     */
LONG styleDefault    = WS_MAXIMIZE; /* Default style bits for child windows  */
				    /* The first window is created maximized */
				    /* to resemble Notepad.  Later children  */
				    /* are normal windows.		     */
LPSTR lpMenu	     = (LPSTR)IDMULTIPAD;  /* Contains the resource id of the	    */
				    /* current frame menu		     */


/* Forward declarations of helper functions in this module */
VOID NEAR PASCAL InitializeMenu (HANDLE);
VOID NEAR PASCAL CommandHandler (HWND,WORD);
VOID NEAR PASCAL SetWrap (HWND,BOOL);
BOOL NEAR PASCAL QueryCloseAllChildren ( VOID );
int  NEAR PASCAL QueryCloseChild (HWND);

/****************************************************************************
 *									    *
 *  FUNCTION   : WinMain(HANDLE, HANDLE, LPSTR, int)			    *
 *									    *
 *  PURPOSE    : Creates the "frame" window, does some initialization and   *
 *		 enters the message loop.				    *
 *									    *
 ****************************************************************************/
int NEAR PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)

HANDLE hInstance;
HANDLE hPrevInstance;
LPSTR  lpszCmdLine;
int    nCmdShow;
{
    MSG msg;

    hInst = hInstance;

    /* If this is the first instance of the app. register window classes */
    if (!hPrevInstance){
	if (!InitializeApplication ())
	    return 0;
    }

    /* Create the frame and do other initialization */
    if (!InitializeInstance (lpszCmdLine, nCmdShow))
	return 0;

    /* Enter main message loop */
    while (GetMessage (&msg, NULL, 0, 0)){
	/* If a keyboard message is for the MDI , let the MDI client
	 * take care of it.  Otherwise, check to see if it's a normal
	 * accelerator key (like F3 = find next).  Otherwise, just handle
	 * the message as usual.
	 */
	if ( !TranslateMDISysAccel (hwndMDIClient, &msg) &&
	     !TranslateAccelerator (hwndFrame, hAccel, &msg)){
	    TranslateMessage (&msg);
	    DispatchMessage (&msg);
	}
    }
    return 0;
}

/****************************************************************************
 *									    *
 *  FUNCTION   : MPFrameWndProc (hwnd, msg, wParam, lParam )		    *
 *									    *
 *  PURPOSE    : The window function for the "frame" window, which controls *
 *		 the menu and encompasses all the MDI child windows. Does   *
 *		 the major part of the message processing. Specifically, in *
 *		 response to:						    *
 *									    *
 *		     WM_CREATE		: Creates and displays the "frame". *
 *									    *
 *		     WM_INITMENU	: Sets up the state of the menu.    *
 *									    *
 *		     WM_WININICHANGE &  : If default printer characteristics*
 *		     WM_DEVMODECHANGE	  have been changed, reinitialises  *
 *					  printer DC.			    *
 *									    *
 *		     WM_COMMAND 	: Passes control to a command-	    *
 *					  handling function.		    *
 *									    *
 *		     WM_CLOSE		: Quits the app. if all the child   *
 *					  windows agree.		    *
 *									    *
 *		     WM_QUERYENDSESSION : Checks that all child windows     *
 *					  agree to quit.		    *
 *									    *
 *		     WM_DESTROY 	: Destroys frame window and quits   *
 *					  app.				    *
 *									    *
 ****************************************************************************/
LONG FAR PASCAL MPFrameWndProc ( hwnd, msg, wParam, lParam )

register HWND	 hwnd;
UINT		 msg;
register WPARAM    wParam;
LPARAM		   lParam;

{
    switch (msg){
      case WM_CREATE:{

	    CLIENTCREATESTRUCT ccs;

	    /* Find window menu where children will be listed */
	    ccs.hWindowMenu = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
	    ccs.idFirstChild = IDM_WINDOWCHILD;

	    /* Create the MDI client filling the client area */
	    hwndMDIClient = CreateWindow ("mdiclient",
					  NULL,
					  WS_CHILD | WS_CLIPCHILDREN |
					  WS_VSCROLL | WS_HSCROLL,
					  0,
					  0,
					  0,
					  0,
					  hwnd,
					  0xCAC,
					  hInst,
					  (LPSTR)&ccs);


	    ShowWindow (hwndMDIClient,SW_SHOW);
	    break;
    }

	case WM_INITMENU:
	    /* Set up the menu state */
	    InitializeMenu ((HMENU)wParam);
	    break;

	case WM_COMMAND:
	    /* Direct all menu selection or accelerator commands to another
	     * function
	     */
	    CommandHandler (hwnd,wParam);
	    break;

	case WM_CLOSE:
	    /* don't close if any children cancel the operation */
	    if (!QueryCloseAllChildren ())
		break;
	    DestroyWindow (hwnd);
	    break;

	case WM_QUERYENDSESSION:
	    /*	Before session ends, check that all files are saved */
	    return QueryCloseAllChildren ();

	case WM_DESTROY:
	    PostQuitMessage (0);
	    break;

	default:
	    /*	use DefFrameProc() instead of DefWindowProc() since there
	     *	are things that have to be handled differently because of MDI
	     */
	    return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
    }
    return 0;
}

/****************************************************************************
 *									    *
 *  FUNCTION   : MPMDIWndProc ( hwnd, msg, wParam, lParam )		    *
 *									    *
 *  PURPOSE    : The window function for the individual document windows,   *
 *		 each of which has a "note". Each of these windows contain  *
 *		 one multi-line edit control filling their client area.     *
 *		 In response to the following:				    *
 *									    *
 *		     WM_CREATE		: Creates & diplays an edit control *
 *					  and does some initialization.     *
 *									    *
 *		     WM_MDIACTIVATE	: Activates/deactivates the child.  *
 *									    *
 *		     WM_SETFOCUS	: Sets focus on the edit control.   *
 *									    *
 *		     WM_SIZE		: Resizes the edit control.	    *
 *									    *
 *		     WM_COMMAND 	: Processes some of the edit	    *
 *					  commands, saves files and alters  *
 *					  the edit wrap state.		    *
 *									    *
 *		     WM_CLOSE		: Closes child if it is ok to do so.*
 *									    *
 *		     WM_QUERYENDSESSION : Same as above.		    *
 *									    *
 ****************************************************************************/

LONG FAR PASCAL MPMDIChildWndProc ( hwnd, msg, wParam, lParam )

register HWND	hwnd;
UINT		msg;
register WPARAM   wParam;
LPARAM		  lParam;

{
    HWND hwndEdit;

    switch (msg){
	case WM_CREATE:
	    /* Create an edit control */
	    hwndEdit = CreateWindow ("edit",
				     NULL,
				     WS_CHILD|WS_HSCROLL|WS_MAXIMIZE|WS_VISIBLE|WS_VSCROLL|ES_AUTOHSCROLL|ES_AUTOVSCROLL|ES_MULTILINE,
				     0,
				     0,
				     0,
				     0,
				     hwnd,
				     ID_EDIT,
				     hInst,
				     NULL);

	    /* Remember the window handle and initialize some window attributes */
	    SetWindowWord (hwnd, GWW_HWNDEDIT, (WORD)hwndEdit);
	    SetWindowWord (hwnd, GWW_CHANGED, FALSE);
	    SetWindowWord (hwnd, GWW_WORDWRAP, FALSE);
	    SetWindowWord (hwnd, GWW_UNTITLED, TRUE);
	    SetFocus (hwndEdit);
	    break;

	case WM_MDIACTIVATE:
	    /* If we're activating this child, remember it */
	    if (wParam){
		hwndActive     = hwnd;
		hwndActiveEdit = (HWND)GetWindowWord (hwnd, GWW_HWNDEDIT);
	    }
	    else{
		hwndActive     = NULL;
		hwndActiveEdit = NULL;
	    }
	    break;

	case WM_QUERYENDSESSION:
	    /* Prompt to save the child */
	    return !QueryCloseChild (hwnd);

	case WM_CLOSE:
	    /* If its OK to close the child, do so, else ignore */
	    if (QueryCloseChild (hwnd))
		goto CallDCP;
	    else
		break;

	case WM_SIZE:{
	    RECT rc;

	    /* On creation or resize, size the edit control. */
	    hwndEdit = GetWindowWord (hwnd, GWW_HWNDEDIT);
	    GetClientRect (hwnd, &rc);
	    MoveWindow (hwndEdit,
			rc.left,
			rc.top,
			rc.right-rc.left,
			rc.bottom-rc.top,
			TRUE);
	    goto CallDCP;
	}

	case WM_SETFOCUS:
	    SetFocus (GetWindowWord (hwnd, GWW_HWNDEDIT));
	    break;

	case WM_COMMAND:
	    switch (wParam){
		case ID_EDIT:
		    switch (HIWORD(lParam)){
			case EN_CHANGE:

			    /* If the contents of the edit control have changed,
			       set the changed flag
			     */
			    SetWindowWord (hwnd, GWW_CHANGED, TRUE);
			    break;

			case EN_ERRSPACE:
			    /* If the control is out of space, honk */
			    MessageBeep (0);
			    break;

			default:
			    goto CallDCP;
		    }
		    break;

		case IDM_FILESAVE:
		    /* If empty file, ignore save */
		    if ((GetWindowWord(hwnd, GWW_UNTITLED)) && (!ChangeFile(hwnd)))
			break;

		    /* Save the contents of the edit control and reset the
		     * changed flag
		     */
		    SaveFile (hwnd);
		    SetWindowWord (hwnd, GWW_CHANGED, FALSE);
		    break;

		case IDM_EDITWRAP: {
		    int fWrap = GetWindowWord (hwnd, GWW_WORDWRAP);

		    /* Set the wrap state, or report it */
		    if (LOWORD (lParam)){
			fWrap = !fWrap;
			SetWrap (hwnd, fWrap);
		    }

		    /* return wrap state */
		    return fWrap;
		}

		default:
		    goto CallDCP;
	    }
	    break;

	default:
CallDCP:
	    /* Again, since the MDI default behaviour is a little different,
	     * call DefMDIChildProc instead of DefWindowProc()
	     */
	    return DefMDIChildProc (hwnd, msg, wParam, lParam);
    }
    return FALSE;
}


/****************************************************************************
 *									    *
 *  FUNCTION   : AboutDlgProc ( hwnd, msg, wParam, lParam )		    *
 *									    *
 *  PURPOSE    : Dialog function for the About MultiPad... dialog.	    *
 *									    *
 ****************************************************************************/
BOOL FAR PASCAL AboutDlgProc ( hwnd, msg, wParam, lParam )
HWND	      hwnd;
register WORD msg;
register WORD wParam;
LONG	      lParam;
{
    switch (msg){
	case WM_INITDIALOG:
	    /* nothing to initialize */
	    break;

	case WM_COMMAND:
	    switch (wParam){
		case IDOK:
		case IDCANCEL:
		    EndDialog(hwnd, 0);
		    break;

		default:
		    return FALSE;
	    }
	    break;

	default:
	    return FALSE;
    }

    return TRUE;
}

/****************************************************************************
 *									    *
 *  FUNCTION   : Initializemenu ( hMenu )				    *
 *									    *
 *  PURPOSE    : Sets up greying, enabling and checking of main menu items  *
 *		 based on the app's state.                                  *
 *									    *
 ****************************************************************************/
VOID NEAR PASCAL InitializeMenu ( hmenu )
register HANDLE hmenu;
{
    register WORD status;
    int 	  i;
    long	  l;

    /* Is there any active child to talk to? */
    if (hwndActiveEdit){
	/* If edit control can respond to an undo request, enable the
	 * undo selection.
	 */
	if (SendMessage (hwndActiveEdit, EM_CANUNDO, 0, 0L))
	    status = MF_ENABLED;
	else
	    status = MF_GRAYED;
	EnableMenuItem (hmenu, IDM_EDITUNDO, status);

	/* If edit control is non-empty, allow cut/copy/clear */
	l      = SendMessage (hwndActiveEdit, EM_GETSEL, 0, 0L);
	status = (HIWORD(l) == LOWORD(l)) ? MF_GRAYED : MF_ENABLED;
	EnableMenuItem (hmenu, IDM_EDITCUT, status);
	EnableMenuItem (hmenu, IDM_EDITCOPY, status);
	EnableMenuItem (hmenu, IDM_EDITCLEAR, status);

	status=MF_GRAYED;
	/* If the clipboard contains some CF_TEXT data, allow paste */
	if (OpenClipboard (hwndFrame)){
	    int wFmt = 0;

	    while (wFmt = EnumClipboardFormats (wFmt))
		if (wFmt == CF_TEXT){
		    status = MF_ENABLED;
		    break;
		}

	    CloseClipboard ();
	}
	EnableMenuItem (hmenu, IDM_EDITPASTE, status);

	/* Set the word wrap state for the window */
	if ((WORD) SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 0L))
	    status = MF_CHECKED;
	else
	    status = MF_UNCHECKED;
	CheckMenuItem (hmenu, IDM_EDITWRAP, status);

	/* Enable search menu items only if there is a search string */
	if (*szSearch)
	    status = MF_ENABLED;
	else
	    status = MF_GRAYED;
	EnableMenuItem (hmenu, IDM_SEARCHNEXT, status);
	EnableMenuItem (hmenu, IDM_SEARCHPREV, status);

	/* select all and wrap toggle always enabled */
	status = MF_ENABLED;
	EnableMenuItem(hmenu, IDM_EDITSELECT, status);
	EnableMenuItem(hmenu, IDM_EDITWRAP, status);
	EnableMenuItem(hmenu, IDM_SEARCHFIND, status);
    }
    else {
	/* There are no active child windows */
	status = MF_GRAYED;

	/* No active window, so disable everything */
	for (i = IDM_EDITFIRST; i <= IDM_EDITLAST; i++)
	    EnableMenuItem (hmenu, i, status);

	CheckMenuItem (hmenu, IDM_EDITWRAP, MF_UNCHECKED);

	for (i = IDM_SEARCHFIRST; i <= IDM_SEARCHLAST; i++)
	    EnableMenuItem (hmenu, i, status);

	EnableMenuItem (hmenu, IDM_FILEPRINT, status);

    }

    /* The following menu items are enabled if there is an active window */
    EnableMenuItem (hmenu, IDM_FILESAVE, status);
    EnableMenuItem (hmenu, IDM_FILESAVEAS, status);
    EnableMenuItem (hmenu, IDM_WINDOWTILE, status);
    EnableMenuItem (hmenu, IDM_WINDOWCASCADE, status);
    EnableMenuItem (hmenu, IDM_WINDOWICONS, status);
    EnableMenuItem (hmenu, IDM_WINDOWCLOSEALL, status);

}

/****************************************************************************
 *									    *
 *  FUNCTION   : CloseAllChildren ()					    *
 *									    *
 *  PURPOSE    : Destroys all MDI child windows.			    *
 *									    *
 ****************************************************************************/
VOID NEAR PASCAL CloseAllChildren ()
{
    register HWND hwndT;

    /* hide the MDI client window to avoid multiple repaints */
    ShowWindow(hwndMDIClient,SW_HIDE);

    /* As long as the MDI client has a child, destroy it */
    while ( hwndT = GetWindow (hwndMDIClient, GW_CHILD)){

	/* Skip the icon title windows */
	while (hwndT && GetWindow (hwndT, GW_OWNER))
	    hwndT = GetWindow (hwndT, GW_HWNDNEXT);

	if (!hwndT)
	    break;

	SendMessage (hwndMDIClient, WM_MDIDESTROY, (WORD)hwndT, 0L);
    }
}

/****************************************************************************
 *									    *
 *  FUNCTION   : CommandHandler ()					    *
 *									    *
 *  PURPOSE    : Processes all "frame" WM_COMMAND messages.		    *
 *									    *
 ****************************************************************************/
VOID NEAR PASCAL CommandHandler ( hwnd, wParam )
register HWND hwnd;
register WORD wParam;

{
   DWORD FlagSave;
   
   switch (wParam){
	case IDM_FILENEW:
	    /* Add a new, empty MDI child */
	    AddFile (NULL);
	    break;

	case IDM_FILEOPEN:
	    ReadFile (hwnd);
	    break;

	case IDM_FILESAVE:
	    /* Save the active child MDI */
	    SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
	    break;

	case IDM_FILESAVEAS:
	    /* Save active child MDI under another name */
	    if (ChangeFile (hwndActive))
		SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
	    break;

	case IDM_FILEPRINT:
	    /* Print the active child MDI */
	    PrintFile (hwndActive);
	    break;

	case IDM_FILESETUP:
       FlagSave = pd.Flags;
       pd.Flags |= PD_PRINTSETUP;    /* Set option */
       PrintDlg((LPPRINTDLG)&pd);
       pd.Flags = FlagSave;          /* Remove option */
       break;
	    
#if 0      
      /* Set up the printer environment for this app */
	    GetInitializationData (hwnd);
	    break;
#endif

	case IDM_FILEMENU:{

	      /* lengthen / shorten the size of the MDI menu */
	      HMENU hMenu;
	      HMENU hWindowMenu;
	      int i;

	      if (lpMenu == (LPSTR)IDMULTIPAD){
		  lpMenu = (LPSTR)IDMULTIPAD2;
		  i	 = SHORTMENU;
	      }
	      else{
		  lpMenu = (LPSTR)IDMULTIPAD;
		  i	 = WINDOWMENU;
	      }

	      hMenu = LoadMenu (hInst, lpMenu);
	      hWindowMenu = GetSubMenu (hMenu, i);

	      /* Set the new menu */
	      hMenu = (HMENU)SendMessage (hwndMDIClient,
					  WM_MDISETMENU,
					  0,
					  MAKELONG(hMenu,hWindowMenu));

	      DestroyMenu (hMenu);
	      DrawMenuBar (hwndFrame);
	      break;
	}

	case IDM_FILEEXIT:
	    /* Close Multipad */
	    SendMessage (hwnd, WM_CLOSE, 0, 0L);
	    break;

	case IDM_HELPABOUT:{
	    /* Bring up the ubiquitous Ego box */
	    FARPROC lpfn;

	    lpfn = MakeProcInstance(AboutDlgProc, hInst);
	    DialogBox (hInst, IDD_ABOUT, hwnd, lpfn);
	    FreeProcInstance (lpfn);
	    break;
	}

	/* The following are edit commands. Pass these off to the active
	 * child's edit control window.
	 */
	case IDM_EDITCOPY:
	    SendMessage (hwndActiveEdit, WM_COPY, 0, 0L);
	    break;

	case IDM_EDITPASTE:
	    SendMessage (hwndActiveEdit, WM_PASTE, 0, 0L);
	    break;

	case IDM_EDITCUT:
	    SendMessage (hwndActiveEdit, WM_CUT, 0, 0L);
	    break;

	case IDM_EDITCLEAR:
	    SendMessage (hwndActiveEdit, EM_REPLACESEL, 0,( LONG)(LPSTR)"");
	    break;

	case IDM_EDITSELECT:
	    SendMessage (hwndActiveEdit, EM_SETSEL, 0, MAKELONG(0, 0xe000));
	    break;

	case IDM_EDITUNDO:
	    SendMessage (hwndActiveEdit, EM_UNDO, 0, 0L);
	    break;

	case IDM_EDITWRAP:
	    SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 1L);
	    break;

	case IDM_SEARCHFIND:
	    /* Put up the find dialog box */
	    Find ();
	    break;

	case IDM_SEARCHNEXT:
	    /* Find next occurence */
	    FindNext ();
	    break;

	case IDM_SEARCHPREV:
	    /* Find previous occurence */
	    FindPrev ();
	    break;

	/* The following are window commands - these are handled by the
	 * MDI Client.
	 */
	case IDM_WINDOWTILE:
	    /* Tile MDI windows */
	    SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
	    break;

	case IDM_WINDOWCASCADE:
	    /* Cascade MDI windows */
	    SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
	    break;

	case IDM_WINDOWICONS:
	    /* Auto - arrange MDI icons */
	    SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
	    break;

	case IDM_WINDOWCLOSEALL:
	    /* Abort operation if something is not saved */
	    if (!QueryCloseAllChildren())
		break;

	    CloseAllChildren();

	    /* Show the window since CloseAllChilren() hides the window
	     * for fewer repaints.
	     */
	    ShowWindow( hwndMDIClient, SW_SHOW);

	    break;

	default:
	   /*
	    * This is essential, since there are frame WM_COMMANDS generated
	    * by the MDI system for activating child windows via the
	    * window menu.
	    */
	    DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND, wParam, 0L);
    }
}
/****************************************************************************
 *									    *
 *  FUNCTION   : SetWrap ()						    *
 *									    *
 *  PURPOSE    : Changes the word wrapping in an edit control. Since this   *
 *		 cannot be done by direct means, the function creates a new *
 *		 edit control, moves data from the old control to the new   *
 *		 control and destroys the original control. Note that the   *
 *		 function assumes that the child being modified is currently*
 *		 active.						    *	    *
 *									    *
 ****************************************************************************/

VOID NEAR PASCAL SetWrap(hwnd, fWrap)
HWND hwnd;
BOOL fWrap;

{
    LONG    dws;
    HANDLE  hT;
    HANDLE  hTT;
    HWND    hwndOld;
    HWND    hwndNew;

    /* Change word wrap mode */
    SetWindowWord (hwnd, GWW_WORDWRAP, fWrap);

    /* Create the appropriate window style, adding a horizontal scroll
     * facility if wrapping is not present.
     */
    dws = WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE;
    if (!fWrap)
	dws |= WS_HSCROLL | ES_AUTOHSCROLL;

    /* Create a new child window */
    hwndNew = CreateWindow ( "edit",
			     NULL,
			     dws,
			     0,
			     SW_SHOW,
			     0,
			     0,
			     hwnd,
			     ID_EDIT,
			     hInst,
			     NULL);

    /* Get handle to current edit control */
    hwndOld = GetWindowWord (hwnd, GWW_HWNDEDIT);

    /* Get the data handle of the old control */
    hT = (HANDLE)SendMessage (hwndOld, EM_GETHANDLE, 0, 0L);

    /* Create a dummy data handle and make it the handle to
     * the old edit control( hT still references the text of
     * old control).
     */
    hTT = LocalAlloc (LHND, 0);
    SendMessage (hwndOld, EM_SETHANDLE, hTT, 0L);

    /* Make the new window the window of interest and destroy the
     * old control.
     */
    SetWindowWord (hwnd, GWW_HWNDEDIT, hwndNew);
    hwndActiveEdit = hwndNew;
    DestroyWindow (hwndOld);

    /* Cause the window to be properly sized */
    SendMessage (hwnd, WM_SIZE, 0, 0L);

    /* Free the new window's old data handle and set it to
     * hT (text of old edit control)
     */
    LocalFree ((HANDLE)SendMessage (hwndNew, EM_GETHANDLE, 0, 0L));
    SendMessage (hwndNew, EM_SETHANDLE, hT, 0L);

    ShowWindow (hwndNew, SW_SHOW);

    /* Set focus to the new edit control */
    SetFocus (hwndNew);

}


/****************************************************************************
 *									    *
 *  FUNCTION   : MPError ( hwnd, flags, id, ...)			    *
 *									    *
 *  PURPOSE    : Flashes a Message Box to the user. The format string is    *
 *		 taken from the STRINGTABLE.				    *
 *									    *
 *  RETURNS    : Returns value returned by MessageBox() to the caller.	    *
 *									    *
 ****************************************************************************/
short FAR CDECL MPError(hwnd, bFlags, id, ...)
HWND hwnd;
WORD bFlags;
WORD id;
{
    char sz[160];
    char szFmt[128];

    LoadString (hInst, id, szFmt, sizeof (szFmt));
    wvsprintf (sz, szFmt, (LPSTR)(&id + 1));
    LoadString (hInst, IDS_APPNAME, szFmt, sizeof (szFmt));
    return MessageBox (hwndFrame, sz, szFmt, bFlags);
}


/****************************************************************************
 *									    *
 *  FUNCTION   : QueryCloseAllChildren()				    *
 *									    *
 *  PURPOSE    : Asks the child windows if it is ok to close up app. Nothing*
 *		 is destroyed at this point. The z-order is not changed.    *
 *									    *
 *  RETURNS    : TRUE - If all children agree to the query.		    *
 *		 FALSE- If any one of them disagrees.			    *
 *									    *
 ****************************************************************************/

BOOL NEAR PASCAL QueryCloseAllChildren()
{
    register HWND hwndT;

    for ( hwndT = GetWindow (hwndMDIClient, GW_CHILD);
	  hwndT;
	  hwndT = GetWindow (hwndT, GW_HWNDNEXT)       ){

	/* Skip if an icon title window */
	if (GetWindow (hwndT, GW_OWNER))
	    continue;

	if (SendMessage (hwndT, WM_QUERYENDSESSION, 0, 0L))
	    return FALSE;
    }
    return TRUE;
}

/****************************************************************************
 *									    *
 *  FUNCTION   : QueryCloseChild (hwnd) 				    *
 *									    *
 *  PURPOSE    : If the child MDI is unsaved, allow the user to save, not   *
 *               save, or cancel the close operation.                       *
 *									    *
 *  RETURNS    : TRUE  - if user chooses save or not save, or if the file   *
 *                       has not changed.                                   *
 *		 FALSE - otherwise.					    *
 *									    *
 ****************************************************************************/

BOOL NEAR PASCAL QueryCloseChild(hwnd)
register HWND hwnd;
{
    char	 sz [64];
    register int i;

    /* Return OK if edit control has not changed. */
    if (!GetWindowWord (hwnd, GWW_CHANGED))
	return TRUE;

    GetWindowText (hwnd, sz, sizeof(sz));

    /* Ask user whether to save / not save / cancel */
    i = MPError (hwnd,
		 MB_YESNOCANCEL|MB_ICONQUESTION,IDS_CLOSESAVE,
		 (LPSTR)sz);

    switch (i){
	case IDYES:
	    /* User wants file saved */
	    SaveFile(hwnd);
	    break;

	case IDNO:
	    /* User doesn't want file saved */
	    break;

	default:
	    /* We couldn't do the messagebox, or not ok to close */
	    return FALSE;
    }
    return TRUE;
}

