/*************************************************************************
**
**    OLE 2 Sample Code
**
**    main.c
**
**    This file contains initialization functions which are WinMain,
**    WndProc, and OutlineApp_InitalizeMenu.
**
**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
**
*************************************************************************/

#include "outline.h"
#if defined( USE_STATUSBAR )
#include "status.h"
#endif

#if !defined( WIN32 )
#if defined( USE_CTL3D )
#include "..\include\ctl3d.h"
#endif  // USE_CTL3D
#endif  // !WIN32

#include "initguid.h"           // forces our GUIDs to be initialized
#include "defguid.h"

#if defined( OLE_CNTR )
//*************************************************************************

#if defined( INPLACE_CNTR )
OLEDBGDATA_MAIN("ICNTR")
#else
OLEDBGDATA_MAIN("CNTR")
#endif

CONTAINERAPP g_OutlineApp;  // Global App object maintains app instance state

/* Global interface Vtbl's
 * OLE2NOTE: we only need one copy of each Vtbl. When an object which
 *      exposes an interface is instantiated, its lpVtbl is intialized
 *      to point to one of these global Vtbl's.
 */
IUnknownVtbl            g_OleApp_UnknownVtbl;
IClassFactoryVtbl       g_OleApp_ClassFactoryVtbl;
IMessageFilterVtbl      g_OleApp_MessageFilterVtbl;

IUnknownVtbl            g_OleDoc_UnknownVtbl;
IPersistFileVtbl        g_OleDoc_PersistFileVtbl;
IOleItemContainerVtbl   g_OleDoc_OleItemContainerVtbl;
IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl;
IDataObjectVtbl         g_OleDoc_DataObjectVtbl;

#if defined( USE_DRAGDROP )
IDropSourceVtbl         g_OleDoc_DropSourceVtbl;
IDropTargetVtbl         g_OleDoc_DropTargetVtbl;
#endif  // USE_DRAGDROP

IOleUILinkContainerVtbl g_CntrDoc_OleUILinkContainerVtbl;

IOleClientSiteVtbl      g_CntrLine_UnknownVtbl;
IOleClientSiteVtbl      g_CntrLine_OleClientSiteVtbl;
IAdviseSinkVtbl         g_CntrLine_AdviseSinkVtbl;

#if defined( INPLACE_CNTR )
IOleInPlaceSiteVtbl     g_CntrLine_OleInPlaceSiteVtbl;
IOleInPlaceFrameVtbl    g_CntrApp_OleInPlaceFrameVtbl;
BOOL g_fInsideOutContainer = FALSE;     // default to outside-in activation
#endif  // INPLACE_CNTR

//*************************************************************************
#endif  // OLE_CNTR

#if defined( OLE_SERVER )
//*************************************************************************

#if defined( INPLACE_SVR )
OLEDBGDATA_MAIN("ISVR")
#else
OLEDBGDATA_MAIN("SVR")
#endif

SERVERAPP g_OutlineApp; // Global App object maintains app instance state

/* Global interface Vtbl's
 * OLE2NOTE: we only need one copy of each Vtbl. When an object which
 *      exposes an interface is instantiated, its lpVtbl is intialized
 *      to point to one of these global Vtbl's.
 */
IUnknownVtbl            g_OleApp_UnknownVtbl;
IClassFactoryVtbl       g_OleApp_ClassFactoryVtbl;
IMessageFilterVtbl      g_OleApp_MessageFilterVtbl;

IUnknownVtbl            g_OleDoc_UnknownVtbl;
IPersistFileVtbl        g_OleDoc_PersistFileVtbl;
IOleItemContainerVtbl   g_OleDoc_OleItemContainerVtbl;
IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl;
IDataObjectVtbl         g_OleDoc_DataObjectVtbl;

#if defined( USE_DRAGDROP )
IDropSourceVtbl         g_OleDoc_DropSourceVtbl;
IDropTargetVtbl         g_OleDoc_DropTargetVtbl;
#endif  // USE_DRAGDROP

IOleObjectVtbl          g_SvrDoc_OleObjectVtbl;
IPersistStorageVtbl     g_SvrDoc_PersistStorageVtbl;

#if defined( SVR_TREATAS )
IStdMarshalInfoVtbl     g_SvrDoc_StdMarshalInfoVtbl;
#endif  // SVR_TREATAS

#if defined( INPLACE_SVR )
IOleInPlaceObjectVtbl       g_SvrDoc_OleInPlaceObjectVtbl;
IOleInPlaceActiveObjectVtbl g_SvrDoc_OleInPlaceActiveObjectVtbl;
#endif // INPLACE_SVR

IUnknownVtbl            g_PseudoObj_UnknownVtbl;
IOleObjectVtbl          g_PseudoObj_OleObjectVtbl;
IDataObjectVtbl         g_PseudoObj_DataObjectVtbl;

//*************************************************************************
#endif  // OLE_SVR

#if !defined( OLE_VERSION )
OLEDBGDATA_MAIN("OUTL")
OUTLINEAPP g_OutlineApp;    // Global App object maintains app instance state
#endif

LPOUTLINEAPP g_lpApp=(LPOUTLINEAPP)&g_OutlineApp;   // ptr to global app obj
RECT        g_rectNull = {0, 0, 0, 0};
UINT        g_uMsgHelp = 0;  // help msg from ole2ui dialogs
BOOL        g_fAppActive = FALSE;

/* WinMain
** -------
**    Main routine for the Windows application.
*/
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
						LPSTR lpszCmdLine, int nCmdShow)
{
	LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
	MSG         msg;            /* MSG structure to store your messages */

#if defined( OLE_VERSION )
	/* OLE2NOTE: it is recommended that all OLE applications to set
	**    their message queue size to 96. this improves the capacity
	**    and performance of OLE's LRPC mechanism.
	*/
	int cMsg = 96;   // recommend msg queue size for OLE
	while (cMsg && ! SetMessageQueue(cMsg))  // take largest size we can get.
		cMsg -= 8;
	if (! cMsg)
		return -1;  // ERROR: we got no message queue
#endif

#if defined( USE_CTL3D )
   Ctl3dRegister(hInstance);
   Ctl3dAutoSubclass(hInstance);
#endif

	if(! hPrevInstance) {
		/* register window classes if first instance of application */
		if(! OutlineApp_InitApplication(lpOutlineApp, hInstance))
			return 0;
	}

	/* Create App Frame window */
	if (! OutlineApp_InitInstance(lpOutlineApp, hInstance, nCmdShow))
		return 0;

	if (! OutlineApp_ParseCmdLine(lpOutlineApp, lpszCmdLine, nCmdShow))
		return 0;

	lpOutlineApp->m_hAccelApp = LoadAccelerators(hInstance, APPACCEL);
	lpOutlineApp->m_hAccelFocusEdit = LoadAccelerators(hInstance,
			FB_EDIT_ACCEL);
	lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelApp;
	lpOutlineApp->m_hWndAccelTarget = lpOutlineApp->m_hWndApp;


	// Main message loop
	while(GetMessage(&msg, NULL, 0, 0)) {        /* Until WM_QUIT message */
		if(!MyTranslateAccelerator(&msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

#if defined( OLE_VERSION )
	OleApp_TerminateApplication((LPOLEAPP)lpOutlineApp);
#else
	/* OLE2NOTE: CoInitialize() is called in OutlineApp_InitInstance
	**    and therefore we need to uninitialize it when exit.
	*/
	CoUninitialize();
#endif

#if defined( USE_CTL3D )
   Ctl3dUnregister(hInstance);
#endif

	return msg.wParam;

} /*  End of WinMain */

BOOL MyTranslateAccelerator(LPMSG lpmsg)
{
	// if it's not a keystroke it can not be an accelerator
	if (lpmsg->message < WM_KEYFIRST || lpmsg->message > WM_KEYLAST)
		return FALSE;

	if (g_lpApp->m_hWndAccelTarget &&
		TranslateAccelerator(g_lpApp->m_hWndAccelTarget,
													g_lpApp->m_hAccel,lpmsg))
		return TRUE;

#if defined( INPLACE_SVR )
	/* OLE2NOTE: if we are in-place active and we did not translate the
	**    accelerator, we need to give the top-level (frame) in-place
	**    container a chance to translate the accelerator.
	**    we ONLY need to call OleTranslateAccelerator API if the
	**    message is a keyboard message. otherwise it is harmless but
	**    unnecessary.
	**
	**    NOTE: even a in-place server that does NOT have any
	**    Accelerators must still call OleTranslateAccelerator for all
	**    keyboard messages so that the server's OWN menu mneumonics
	**    (eg. &Edit -- Alt-e) function properly.
	**
	**    NOTE: an in-place server MUST check that the accelerator is
	**    NOT one of its own accelerators BEFORE calling
	**    OleTranslateAccelerator which tries to see if it is a
	**    container accelerator. if this is a server accelerator that
	**    was not translateed because the associated menu command was
	**    disabled, we MUST NOT call OleTranslateAccelerator. The
	**    IsAccelerator helper API has been added to assist with this
	**    check.
	*/
	if (g_OutlineApp.m_lpIPData &&
		!IsAccelerator(g_lpApp->m_hAccel,
			GetAccelItemCount(g_lpApp->m_hAccel), lpmsg,NULL) &&
		OleTranslateAccelerator(g_OutlineApp.m_lpIPData->lpFrame,
				(LPOLEINPLACEFRAMEINFO)&g_OutlineApp.m_lpIPData->frameInfo,
				lpmsg) == NOERROR) {
		return TRUE;
	}
#endif

	return FALSE;
}


/************************************************************************/
/*                                                                      */
/* Main Window Procedure                                                */
/*                                                                      */
/* This procedure provides service routines for the Windows events      */
/* (messages) that Windows sends to the window, as well as the user     */
/* initiated events (messages) that are generated when the user selects */
/* the action bar and pulldown menu controls or the corresponding       */
/* keyboard accelerators.                                               */
/*                                                                      */
/************************************************************************/

LRESULT FAR PASCAL AppWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)GetWindowLong(hWnd, 0);
	LPOUTLINEDOC lpOutlineDoc = NULL;
#if defined( OLE_VERSION )
	LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp;
#endif
#if defined( OLE_CNTR )
	LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOutlineApp;
#endif
	HWND         hWndDoc = NULL;

#if defined( USE_FRAMETOOLS )
	LPFRAMETOOLS lptb = OutlineApp_GetFrameTools(lpOutlineApp);
#endif

	if (lpOutlineApp) {
		lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp);

		if (lpOutlineDoc)
			hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc);
	}

	switch (Message) {
		case WM_COMMAND:
		{
#ifdef WIN32
			WORD wID    = LOWORD(wParam);
#else
			WORD wID    = wParam;
#endif

#if defined( INPLACE_CNTR )
			LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;
			LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

			/* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)
			**    m_fMenuHelpMode flag is set when F1 is pressed when a
			**    menu item is selected. this flag is set in
			**    IOleInPlaceFrame::ContextSensitveHelp method.
			**    m_fCSHelpMode flag is set when SHIFT-F1 context
			**    sensitive help is entered. this flag is set in
			**    IOleInPlaceSite::ContextSensitiveHelp method.
			**    if either of these flags are set then the WM_COMMAND
			**    message is received then, the corresponding command
			**    should NOT executed; help can be given (if desired).
			**    also the context sensitve help mode should be exited.
			**    the two different cases have their own way to exit
			**    the mode (please refer to the technote).
			*/
			if (lpOleDoc &&
				(lpContainerApp->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) &&
				(wID > IDM_FILE)   /* min wID for app command */ &&
				(wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) {

				if ((lpContainerApp->m_fMenuHelpMode)) {
					LPOLEINPLACEACTIVEOBJECT lpIPActiveObj =
							lpContainerApp->m_lpIPActiveObj;

					lpContainerApp->m_fMenuHelpMode = FALSE;

					// inform the in-place active object that we handled the
					//   menu help mode (F1) selection.
					if (lpIPActiveObj) {
						OLEDBG_BEGIN2("IOleInPlaceActiveObject::ContextSensitiveHelp(FALSE) called\r\n")
						lpIPActiveObj->lpVtbl->ContextSensitiveHelp(
								lpIPActiveObj, FALSE);
						OLEDBG_END2
					}
				}

				if ((lpOleDoc->m_fCSHelpMode)) {
					LPOLEINPLACEOBJECT lpIPObj;
					LPCONTAINERLINE lpLastIpActiveLine =
							lpContainerDoc->m_lpLastIpActiveLine;

					lpOleDoc->m_fCSHelpMode = FALSE;

					/* inform immediate in-place container parent and,
					**    if we were a container/server, immediate
					**    in-place object children that we handled the
					**    context sensitive help mode.
					*/
					if (lpLastIpActiveLine &&
							(lpIPObj=lpLastIpActiveLine->m_lpOleIPObj)!=NULL){
						OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp(FALSE) called\r\n")
						lpIPObj->lpVtbl->ContextSensitiveHelp(lpIPObj, FALSE);
						OLEDBG_END2
					}
				}

				// if we provided help, we would do it here...

				// remove context sensitive help cursor
				SetCursor(LoadCursor(NULL,IDC_ARROW));
				return 0L;
			}
#endif  // INPLACE_CNTR

			switch (wID) {

				case IDM_F_NEW:
					OleDbgIndent(-2);   // Reset debug output indent level
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_NewCommand\r\n")
					OutlineApp_NewCommand(lpOutlineApp);
					OLEDBG_END3

#if defined( OLE_CNTR )
					/* OLE2NOTE: this call will attempt to recover
					**    resources by unloading DLL's that were loaded
					**    by OLE and are no longer being used. it is a
					**    good idea to call this API now and then if
					**    your app tends to run for a long time.
					**    otherwise these DLL's will be unloaded when
					**    the app exits. some apps may want to call
					**    this as part of idle-time processing. this
					**    call is optional.
					*/
					OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")
					CoFreeUnusedLibraries();
					OLEDBG_END2
#endif

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(
							OutlineApp_GetActiveDoc(lpOutlineApp));
#endif
					break;

				case IDM_F_OPEN:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_OpenCommand\r\n")
					OutlineApp_OpenCommand(lpOutlineApp);
					OLEDBG_END3

#if defined( OLE_CNTR )
					/* OLE2NOTE: this call will attempt to recover
					**    resources by unloading DLL's that were loaded
					**    by OLE and are no longer being used. it is a
					**    good idea to call this API now and then if
					**    your app tends to run for a long time.
					**    otherwise these DLL's will be unloaded when
					**    the app exits. some apps may want to call
					**    this as part of idle-time processing. this
					**    call is optional.
					*/
					OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")
					CoFreeUnusedLibraries();
					OLEDBG_END2
#endif

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(
							OutlineApp_GetActiveDoc(lpOutlineApp));
#endif
					break;

				case IDM_F_SAVE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_SaveCommand\r\n")
					OutlineApp_SaveCommand(lpOutlineApp);
					OLEDBG_END3
					break;

				case IDM_F_SAVEAS:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_SaveAsCommand\r\n")
					OutlineApp_SaveAsCommand(lpOutlineApp);
					OLEDBG_END3
					break;

				case IDM_F_PRINT:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_PrintCommand\r\n")
					OutlineApp_PrintCommand(lpOutlineApp);
					OLEDBG_END3
					break;

				case IDM_F_PRINTERSETUP:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_PrinterSetupCommand\r\n")
					OutlineApp_PrinterSetupCommand(lpOutlineApp);
					OLEDBG_END3
					break;

				case IDM_F_EXIT:
					SendMessage(hWnd, WM_CLOSE, 0, 0L);
					break;

				case IDM_H_ABOUT:
					OutlineApp_AboutCommand(lpOutlineApp);
					break;

#if defined( INPLACE_CNTR )
				case IDM_ESCAPE:
				{
					/* ESCAPE key pressed */
					LPCONTAINERDOC lpContainerDoc =
								(LPCONTAINERDOC)lpOutlineDoc;

					/* OLE2NOTE: The standard OLE 2.0 UI convention
					**    is to have ESCAPE key exit in-place
					**    activation (ie. UIDeactivate). If
					**    possible it is recommended for both
					**    in-place servers AND in-place containers
					**    to take responsibility to handle the
					**    ESCAPE key accelerator. The server has
					**    the first crack at handling accelerator
					**    keys and normally the server should do
					**    the UIDeactivation. It is a good idea for
					**    in-place containers, in order to
					**    guarantee consistent behavior, to also
					**    handle the ESCAPE key and UIDeactivate
					**    the object in case the object does not do
					**    it itself. normally this should be
					**    unnecessary.
					*/
					if (lpContainerDoc->m_lpLastUIActiveLine &&
						lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive)
					{
						ContainerLine_UIDeactivate(
								lpContainerDoc->m_lpLastUIActiveLine);
					}
					break;
				}
#endif  // INPLACE_CNTR


				default:
					// forward message to document window
					if (hWndDoc) {
						return DocWndProc(hWndDoc, Message,wParam,lParam);
					}
			}

			break;  /* End of WM_COMMAND */
		}

		case WM_INITMENU:
			OutlineApp_InitMenu(lpOutlineApp, lpOutlineDoc, (HMENU)wParam);
			break;

#if defined( OLE_VERSION )

		/* OLE2NOTE: WM_INITMENUPOPUP is trapped primarily for the Edit
		**    menu. We didn't update the Edit menu until it is popped
		**    up to avoid the overheads of the OLE calls which are
		**    required to initialize some Edit menu items.
		*/
		case WM_INITMENUPOPUP:
		{
			HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1);
#if defined( INPLACE_CNTR )
			LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

			/* OLE2NOTE: we must check if there is an object currently
			**    in-place UIActive. if so, then our edit menu is not
			**    on the menu; we do not want to bother updating the
			**    edit menu when it is not even there.
			*/
			if (lpContainerDoc && lpContainerDoc->m_lpLastUIActiveLine &&
				lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive)
				break;  // an object is in-place UI active
#endif
			if ((HMENU)wParam == hMenuEdit &&
				(LOWORD(lParam) == POS_EDITMENU) &&
				OleDoc_GetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc)) {
				OleApp_UpdateEditMenu(lpOleApp, lpOutlineDoc, hMenuEdit);
			}
			break;
		}
#endif      // OLE_VERSION

		case WM_SIZE:
			if (wParam != SIZE_MINIMIZED)
				OutlineApp_ResizeWindows(lpOutlineApp);
			break;


		case WM_ACTIVATEAPP:
#if defined (OLE_CNTR)
			if (g_fAppActive = (BOOL) wParam)
				OleApp_QueryNewPalette(lpOleApp);
#endif

#if defined( INPLACE_CNTR )
			{
				BOOL fActivate = (BOOL)wParam;
				LPOLEINPLACEACTIVEOBJECT lpIPActiveObj =
						lpContainerApp->m_lpIPActiveObj;

				/* OLE2NOTE: the in-place container MUST inform the
				**    inner most in-place active object (this is NOT
				**    necessarily our immediate child if there are
				**    nested levels of embedding) of the WM_ACTIVATEAPP
				**    status.
				*/
				if (lpIPActiveObj) {
#if defined( _DEBUG )
					OLEDBG_BEGIN2((fActivate ?
						"IOleInPlaceActiveObject::OnFrameWindowActivate(TRUE) called\r\n" :
						"IOleInPlaceActiveObject::OnFrameWindowActivate(FALSE) called\r\n"))
#endif  // _DEUBG
					lpIPActiveObj->lpVtbl->OnFrameWindowActivate(
						lpIPActiveObj, fActivate);
					OLEDBG_END2
				}
			}

#endif  // INPLACE_CNTR

			// OLE2NOTE: We can't call OutlineDoc_UpdateFrameToolButtons
			//           right away which
			//           would generate some OLE calls and eventually
			//           WM_ACTIVATEAPP and a loop was formed. Therefore, we
			//           should delay the frame tool initialization until
			//           WM_ACTIVATEAPP is finished by posting a message
			//           to ourselves.
			//           we want to ignore the WM_ACTIVATEAPP that comes
			//           as we bring up a modal dialog.

			/* Update enable/disable state of buttons in toolbar */
			if (wParam
#if defined( OLE_VERSION )
					&& lpOleApp->m_cModalDlgActive == 0
#endif
			) {
				PostMessage(hWnd, WM_U_INITFRAMETOOLS, 0, 0L);
			}
			return 0L;

		case WM_SETFOCUS:
			SetFocus(hWndDoc);
			break;


#if defined( OLE_CNTR )
		case WM_QUERYNEWPALETTE:
			if (!g_fAppActive)
				return 0L;

			return OleApp_QueryNewPalette(lpOleApp);

		case WM_PALETTECHANGED:
		{
			HWND hWndPalChg = (HWND) wParam;
			static BOOL fInPaletteChanged = FALSE;

			if (fInPaletteChanged)  // Guard against recursion
				return 0L;

			fInPaletteChanged = TRUE;

			if (hWnd != hWndPalChg)
				wSelectPalette(hWnd, lpOleApp->m_hStdPal,TRUE/*fBackground*/);

#if defined( INPLACE_CNTR )
			/* OLE2NOTE: always forward the WM_PALETTECHANGED message (via
			**    SendMessage) to any in-place objects that currently have
			**    their window visible. this gives these objects the chance
			**    to select their palettes. this is
			**    REQUIRED by all in-place containers independent of
			**    whether they use color palettes themselves--their objects
			**    may use color palettes.
			**    (see ContainerDoc_ForwardPaletteChangedMsg for more info)
			*/
			if (lpOutlineDoc){
				ContainerDoc_ForwardPaletteChangedMsg(
						(LPCONTAINERDOC)lpOutlineDoc, hWndPalChg);
			}
#endif  // INPLACE_CNTR

			fInPaletteChanged = FALSE;
			return 0L;
		}
#endif  // OLE_CNTR

		case WM_DESTROY:
			PostQuitMessage(0);
			break;

		case WM_CLOSE:  /* close the window */

			/* Close all active documents. if successful, then exit */
			OleDbgOutNoPrefix2("\r\n");

			OutlineApp_CloseAllDocsAndExitCommand(lpOutlineApp, FALSE);
			break;

		case WM_QUERYENDSESSION:
		{
#if defined( OLE_CNTR )
			/* OLE2NOTE: we are not able to make OLE LRPC calls when
			**    WM_QUERYENDSESSION is recieved (this is a
			**    SendMessage). this means, for example, that we are
			**    NOT able to ask objects to save. thus the most we can
			**    do is ask the user if he wants to exit with
			**    discarding changes or else abort shutting down.
			*/

			int nResponse = MessageBox(
					hWnd,
					"Discard changes?",
					APPNAME,
					MB_ICONQUESTION | MB_OKCANCEL
			);
			if(nResponse == IDOK)
				return 1L;      /* can terminate */

#endif
#if defined( OLE_SERVER )
			/* OLE2NOTE: an embedded object should never prompt whether
			**    it should be saved (according the OLE 2.0 User
			**    Model). therefore, an embedded object will never
			**    complain that it needs to be saved. it will always
			**    allow the QueryEndSession to proceed.
			*/
			if (lpOutlineApp->m_lpDoc->m_docInitType == DOCTYPE_EMBEDDED)
				return 1L;      /* can terminate */
			else
#endif
			{
				/* this is not an embedded object; it is a user
				**    document. we will prompt if the user wants to
				**    save the document now in WM_QUERYENDSESSION. if
				**    the user cancels then that would abort the
				**    shutdown. if the user does not abort, then later
				**    in WM_ENDSESSION the document will be actually
				**    closed.
				**
				**    Because this is an SDI app, there is only one
				**    document. An MDI would need to loop through all
				**    open documents.
				*/
				DWORD dwSaveOption = OLECLOSE_PROMPTSAVE;
				if (OutlineDoc_CheckSaveChanges(
						lpOutlineApp->m_lpDoc, &dwSaveOption))
					return 1L;      /* can terminate */
			}

			/* else: can't terminate now */

			break;
		}

#if defined( OLE_VERSION)
		case WM_ENDSESSION:
		{
			BOOL fEndSession = (BOOL)wParam;

			if (fEndSession) {
				OutlineApp_CloseAllDocsAndExitCommand(lpOutlineApp, TRUE);
				return 0L;
			}
		}
		break;
#endif  // OLE_VERSION


#if defined( USE_STATUSBAR )
		case WM_MENUSELECT:
		{
			LPSTR lpszMessage;
#ifdef WIN32
			UINT fuFlags    = (UINT)HIWORD(wParam);
			UINT uItem      = (UINT)LOWORD(wParam);
#else
			UINT fuFlags    = (UINT)LOWORD(lParam);
			UINT uItem      = (UINT)wParam;
#endif

			if (uItem == 0 && fuFlags == (UINT)-1) {
				GetControlMessage(STATUS_READY, &lpszMessage);
				OutlineApp_SetStatusText(lpOutlineApp, lpszMessage);
			}
			else if (fuFlags & MF_POPUP) {
#ifdef WIN32
				HMENU hMainMenu = (HMENU)lParam;
				HMENU hPopupMenu = GetSubMenu(hMainMenu,uItem);
#else
				HMENU hPopupMenu = (HMENU)wParam;
#endif
				GetPopupMessage(hPopupMenu, &lpszMessage);
				OutlineApp_SetStatusText(lpOutlineApp, lpszMessage);
			}
			else if (fuFlags & MF_SYSMENU) {
				GetSysMenuMessage(uItem, &lpszMessage);
				OutlineApp_SetStatusText(lpOutlineApp, lpszMessage);
			}
			else if (uItem != 0) {  // Command Item
				GetItemMessage(uItem, &lpszMessage);
				OutlineApp_SetStatusText(lpOutlineApp, lpszMessage);
			}
			else {
				GetControlMessage(STATUS_BLANK, &lpszMessage);
				OutlineApp_SetStatusText(lpOutlineApp, lpszMessage);
			}
			break;
		}
#endif  // USE_STATUSBAR


#if defined( USE_FRAMETOOLS )
		case WM_U_INITFRAMETOOLS:
			OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
			break;
#endif

		default:
			/* For any message for which you don't specifically provide a  */
			/* service routine, you should return the message to Windows   */
			/* for default message processing.                             */

			return DefWindowProc(hWnd, Message, wParam, lParam);
	}

	return (LRESULT)0;
}     /* End of AppWndProc                                         */


/************************************************************************/
/*                                                                      */
/* Document Window Procedure                                            */
/*                                                                      */
/*   The Document Window is the parent of the OwnerDraw Listbox which   */
/* maintains the list of lines in the current document. This window     */
/* receives the ownerdraw callback messages from the list box.          */
/************************************************************************/

LRESULT FAR PASCAL DocWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
	LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)GetWindowLong(hWnd, 0);
	LPLINELIST      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);
	LPSCALEFACTOR   lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc);

#if defined( OLE_VERSION )
	LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp;
	LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;
#if defined( OLE_CNTR )
	LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;
#endif
#if defined( OLE_SERVER )
	LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;
#endif
#if defined( INPLACE_CNTR )
	LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOutlineApp;
#endif
#endif  // OLE_VERSION

	switch(Message) {

#if defined( INPLACE_SVR )

		/* OLE2NOTE: ISVROTL doesn't use color palettes. The inplace objects
		**    that use color palettes must implement the following
		**    lines of code.
		**
			case WM_QUERYNEWPALETTE:
				return wSelectPalette(hWnd, hPal, FALSE); // foreground

			case WM_PALETTECHANGED:
				if (hWnd != (HWND) wParam)
					wSelectPalette(hWnd, hPal, TRUE);     // background
			break;
		**
		**
		**
		*/
#endif

		case WM_MEASUREITEM:
		{
			LPMEASUREITEMSTRUCT lpmis = ((LPMEASUREITEMSTRUCT)lParam);

			switch (wParam) {
				case IDC_LINELIST:
				{
					HDC hDC = LineList_GetDC(lpLL);
					UINT uHeight;

					uHeight=Line_GetHeightInHimetric((LPLINE)lpmis->itemData);
					uHeight = XformHeightInHimetricToPixels(hDC, uHeight);
					uHeight = (UINT) (uHeight * lpscale->dwSyN /
							lpscale->dwSyD);

					if (uHeight >LISTBOX_HEIGHT_LIMIT)
						uHeight = LISTBOX_HEIGHT_LIMIT;

					lpmis->itemHeight = uHeight;
					LineList_ReleaseDC(lpLL, hDC);
					break;
				}

				case IDC_NAMETABLE:
				{
					// NOTE: NameTable is never made visible. do nothing.
					break;
				}

#if defined( USE_HEADING )
				case IDC_ROWHEADING:
				{
					UINT uHeight;

					uHeight = LOWORD(lpmis->itemData);
					uHeight = (UINT) (uHeight * lpscale->dwSyN /
							lpscale->dwSyD);
					if (uHeight >LISTBOX_HEIGHT_LIMIT)
						uHeight = LISTBOX_HEIGHT_LIMIT;
					lpmis->itemHeight = uHeight;
					break;
				}

				case IDC_COLHEADING:
				{
					UINT uHeight;

					uHeight = LOWORD(lpmis->itemData);
					uHeight = (UINT) (uHeight * lpscale->dwSyN /
							lpscale->dwSyD);
					if (uHeight > LISTBOX_HEIGHT_LIMIT)
						uHeight = LISTBOX_HEIGHT_LIMIT;
					lpmis->itemHeight = uHeight;
					break;
				}
#endif  // USE_HEADING

			}
			return (LRESULT)TRUE;
		}

		case WM_DRAWITEM:
		{
			LPDRAWITEMSTRUCT lpdis = ((LPDRAWITEMSTRUCT)lParam);

			switch (lpdis->CtlID) {

				case IDC_LINELIST:
				{
					RECT   rcClient;
					RECT   rcDevice;
					HWND   hWndLL = LineList_GetWindow(lpLL);
					LPLINE lpLine = (LPLINE)lpdis->itemData;

					// NOTE: When itemID == -1, the listbox is empty.
					//       We are supposed to draw focus rect only
					//       But it is not done in this app. If this line is
					//       removed, the app will crash in Line_DrawToScreen
					//       because of invalid lpLine.
					if (lpdis->itemID == -1)
						break;

					GetClientRect(hWndLL, &rcClient);

					rcDevice = lpdis->rcItem;

					// shift the item rect to account for horizontal scrolling

					rcDevice.left += rcClient.right - lpdis->rcItem.right;

#if defined( OLE_CNTR )
					/* we need to remember the horizontal scroll offset
					**    needed for the in-place object's window.
					**    (this is specific to ICNTROTL)
					*/
					if(lpdis->itemAction & ODA_DRAWENTIRE) {
						if (Line_GetLineType(lpLine) == CONTAINERLINETYPE)
							((LPCONTAINERLINE)lpLine)->m_nHorizScrollShift =
								rcDevice.left;
					}
#endif  // OLE_CNTR

					// shift rect for left margin
					rcDevice.left += (int)(XformWidthInHimetricToPixels(NULL,
							LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) *
							lpscale->dwSxN / lpscale->dwSxD);

					rcDevice.right = rcDevice.left +
							(int)(XformWidthInHimetricToPixels(lpdis->hDC,
									Line_GetWidthInHimetric(lpLine)) *
							lpscale->dwSxN / lpscale->dwSxD);

					Line_DrawToScreen(
							lpLine,
							lpdis->hDC,
							&lpdis->rcItem,
							lpdis->itemAction,
							lpdis->itemState,
							&rcDevice
					);

#if defined( USE_FRAMETOOLS )
					if (lpdis->itemState & ODS_FOCUS)
						OutlineDoc_SetFormulaBarEditText(lpOutlineDoc,lpLine);
#endif
					break;
				}
				case IDC_NAMETABLE:
				{
					// NOTE: NameTable is never made visible. do nothing
					break;
				}

#if defined( USE_HEADING )
				case IDC_ROWHEADING:
				{
					LPHEADING lphead;

					// Last dummy item shouldn't be drawn
					if (lpdis->itemID == (UINT)LineList_GetCount(lpLL))
						break;

					// only DrawEntire need be trapped as window is disabled
					if (lpdis->itemAction == ODA_DRAWENTIRE) {
						lphead = OutlineDoc_GetHeading(lpOutlineDoc);
						Heading_RH_Draw(lphead, lpdis);
					}
					break;
				}

				case IDC_COLHEADING:
				{
					RECT   rect;
					RECT   rcDevice;
					RECT   rcLogical;
					LPHEADING lphead;

					// only DrawEntire need be trapped as window is disabled
					if (lpdis->itemAction == ODA_DRAWENTIRE) {
						lphead = OutlineDoc_GetHeading(lpOutlineDoc);
						GetClientRect(lpdis->hwndItem, &rect);

						rcDevice = lpdis->rcItem;

						// shift the item rect to account for
						// horizontal scrolling
						rcDevice.left = -(rcDevice.right - rect.right);

						// shift rect for left margin
						rcDevice.left += (int)(XformWidthInHimetricToPixels(
								NULL,
								LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) *
							lpscale->dwSxN / lpscale->dwSxD);

						rcDevice.right = rcDevice.left + (int)lpscale->dwSxN;
						rcLogical.left = 0;
						rcLogical.bottom = 0;
						rcLogical.right = (int)lpscale->dwSxD;
						rcLogical.top = LOWORD(lpdis->itemData);

						Heading_CH_Draw(lphead, lpdis, &rcDevice, &rcLogical);
					}
					break;
				}
#endif  // USE_HEADING

			}
			return (LRESULT)TRUE;
		}

		case WM_SETFOCUS:
			if (lpLL)
				SetFocus(LineList_GetWindow(lpLL));
			break;

#if !defined( OLE_VERSION )
		case WM_RENDERFORMAT:
		{
			LPOUTLINEDOC lpClipboardDoc = lpOutlineApp->m_lpClipboardDoc;
			if (lpClipboardDoc)
				OutlineDoc_RenderFormat(lpClipboardDoc, wParam);

			break;
		}
		case WM_RENDERALLFORMATS:
		{
			LPOUTLINEDOC lpClipboardDoc = lpOutlineApp->m_lpClipboardDoc;
			if (lpClipboardDoc)
				OutlineDoc_RenderAllFormats(lpClipboardDoc);

			break;
		}
		case WM_DESTROYCLIPBOARD:
			if (g_lpApp->m_lpClipboardDoc) {
				OutlineDoc_Destroy(g_lpApp->m_lpClipboardDoc);
				g_lpApp->m_lpClipboardDoc = NULL;
			}
			break;

#endif   // OLE_VERSION

#if defined( OLE_CNTR )
		case WM_U_UPDATEOBJECTEXTENT:
		{
			/* Update the extents of any OLE object that is marked that
			**    its size may  have changed. when an
			**    IAdviseSink::OnViewChange notification is received,
			**    the corresponding ContainerLine is marked
			**    (m_fDoGetExtent==TRUE) and a message
			**    (WM_U_UPDATEOBJECTEXTENT) is posted to the document
			**    indicating that there are dirty objects.
			*/
			ContainerDoc_UpdateExtentOfAllOleObjects(lpContainerDoc);
			break;
		}
#endif  // OLE_CNTR

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )
		/* OLE2NOTE: Any window that is used during in-place activation
		**    must handle the WM_SETCURSOR message or else the cursor
		**    of the in-place parent will be used. if WM_SETCURSOR is
		**    not handled, then DefWindowProc sends the message to the
		**    window's parent.
		**
		**    see context sensitive help technote (CSHELP.DOC).
		**    m_fCSHelpMode flag is set when SHIFT-F1 context
		**    sensitive help is entered.
		**    if this flag is set then the context sensitive help
		**    cursor should be shown.
		*/
		case WM_SETCURSOR:
			if (lpOleDoc->m_fCSHelpMode)
				SetCursor(UICursorLoad(IDC_CONTEXTHELP));
			else
				SetCursor(LoadCursor(NULL, IDC_ARROW) );
			return (LRESULT)TRUE;
#endif  // INPLACE_SVR || INPLACE_CNTR

#if defined( INPLACE_SVR )
		/* OLE2NOTE: when the in-place active, our in-place server
		**    document window (passed to IOleInPlaceFrame::SetMenu)
		**    will receive the WM_INITMENU and WM_INITMENUPOPUP messages.
		*/
		case WM_INITMENU:
			OutlineApp_InitMenu(lpOutlineApp, lpOutlineDoc, (HMENU)wParam);
			break;

		/* OLE2NOTE: WM_INITMENUPOPUP is trapped primarily for the Edit
		**    menu. We didn't update the Edit menu until it is popped
		**    up to avoid the overheads of the OLE calls which are
		**    required to initialize some Edit menu items.
		*/
		case WM_INITMENUPOPUP:
		{
			HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1);
			if ((HMENU)wParam == hMenuEdit &&
				(LOWORD(lParam) == POS_EDITMENU) &&
				OleDoc_GetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc)) {
				OleApp_UpdateEditMenu(
						(LPOLEAPP)lpOutlineApp, lpOutlineDoc, hMenuEdit);
			}
			break;
		}
#endif      // INPLACE_SVR

#if defined( INPLACE_SVR ) && defined( USE_STATUSBAR )
		/* OLE2NOTE: when the server is in-place active the
		**    WM_MENUSELECT message is sent to the object's window and
		**    not the server app's frame window. processing this
		**    message allows there in-place server to give status bar
		**    help text for menu commands.
		*/
		case WM_MENUSELECT:
		{
			LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;
			LPSTR lpszMessage;
#ifdef WIN32
			UINT fuFlags    = (UINT)HIWORD(wParam);
			UINT uItem      = (UINT)LOWORD(wParam);
#else
			UINT fuFlags    = (UINT)LOWORD(lParam);
			UINT uItem      = (UINT)wParam;
#endif

			if (uItem == 0 && fuFlags == (UINT)-1) {
				GetControlMessage(STATUS_READY, &lpszMessage);
				ServerDoc_SetStatusText(lpServerDoc, lpszMessage);
			}
			else if (fuFlags & MF_POPUP) {
#ifdef WIN32
				HMENU hMainMenu = (HMENU)lParam;
				HMENU hPopupMenu = GetSubMenu(hMainMenu,uItem);
#else
				HMENU hPopupMenu = (HMENU)wParam;
#endif
				GetPopupMessage(hPopupMenu, &lpszMessage);
				ServerDoc_SetStatusText(lpServerDoc, lpszMessage);
			}
			else if (uItem != 0) {  // Command Item
				GetItemMessage(uItem, &lpszMessage);
				ServerDoc_SetStatusText(lpServerDoc, lpszMessage);
			}
			else {
				GetControlMessage(STATUS_BLANK, &lpszMessage);
				ServerDoc_SetStatusText(lpServerDoc, lpszMessage);
			}
			break;
		}
#endif  // INPLACE_SVR && USE_STATUSBAR
#if defined( INPLACE_SVR ) && defined( USE_FRAMETOOLS )

		case WM_U_INITFRAMETOOLS:
			OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
			break;
#endif      // INPLACE_SVR && USE_FRAMETOOLS


		case WM_COMMAND:
		{
#ifdef WIN32
			WORD wNotifyCode = HIWORD(wParam);
			WORD wID          = LOWORD(wParam);
			HWND hwndCtl     = (HWND) lParam;
#else
			WORD wNotifyCode = HIWORD(lParam);
			WORD wID             = wParam;
			HWND hwndCtl     = (HWND) LOWORD(lParam);
#endif

#if defined( INPLACE_SVR )
			/* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)
			**    m_fMenuHelpMode flag is set when F1 is pressed when a
			**    menu item is selected. this flag is set in
			**    IOleInPlaceActiveObject::ContextSensitveHelp method.
			**    m_fCSHelpMode flag is set when SHIFT-F1 context
			**    sensitive help is entered. this flag is set in
			**    IOleInPlaceObject::ContextSensitiveHelp method.
			**    if either of these flags are set then the WM_COMMAND
			**    message is received then, the corresponding command
			**    should NOT executed; help can be given (if desired).
			**    also the context sensitve help mode should be exited.
			**    the two different cases have their own way to exit
			**    the mode (please refer to the technote).
			*/
			if (lpOleDoc &&
				(lpServerDoc->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) &&
				(wID > IDM_FILE)   /* min wID for app command */ &&
				(wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) {

				if ((lpServerDoc->m_fMenuHelpMode)) {
					LPOLEINPLACEFRAME lpFrame;

					lpServerDoc->m_fMenuHelpMode = FALSE;

					// inform top-level frame that we handled the
					//   menu help mode (F1) selection.
					if (lpServerDoc->m_lpIPData &&
							(lpFrame=lpServerDoc->m_lpIPData->lpFrame)!=NULL){
						OLEDBG_BEGIN2("IOleInPlaceFrame::ContextSensitiveHelp(FALSE) called\r\n")
						lpFrame->lpVtbl->ContextSensitiveHelp(lpFrame, FALSE);
						OLEDBG_END2
					}
				}

				if ((lpOleDoc->m_fCSHelpMode)) {
					LPOLEINPLACESITE lpSite;

					lpOleDoc->m_fCSHelpMode = FALSE;

					/* inform immediate in-place container parent and,
					**    if we were a container/server, immediate
					**    in-place object children that we handled the
					**    context sensitive help mode.
					*/
					if (lpServerDoc->m_lpIPData &&
							(lpSite=lpServerDoc->m_lpIPData->lpSite) !=NULL) {
						OLEDBG_BEGIN2("IOleInPlaceSite::ContextSensitiveHelp(FALSE) called\r\n")
						lpSite->lpVtbl->ContextSensitiveHelp(lpSite, FALSE);
						OLEDBG_END2
					}
				}

				// if we provided help, we would do it here...

				// remove context sensitive help cursor
				SetCursor(LoadCursor(NULL,IDC_ARROW));
				return 0L;
			}
#endif  // INPLACE_SVR
#if defined( INPLACE_CNTR )

			/* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)
			**    m_fMenuHelpMode flag is set when F1 is pressed when a
			**    menu item is selected. this flag is set in
			**    IOleInPlaceFrame::ContextSensitveHelp method.
			**    m_fCSHelpMode flag is set when SHIFT-F1 context
			**    sensitive help is entered. this flag is set in
			**    IOleInPlaceSite::ContextSensitiveHelp method.
			**    if either of these flags are set then the WM_COMMAND
			**    message is received then, the corresponding command
			**    should NOT executed; help can be given (if desired).
			**    also the context sensitve help mode should be exited.
			**    the two different cases have their own way to exit
			**    the mode (please refer to the technote).
			*/
			if (lpOleDoc &&
				(lpContainerApp->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) &&
				(wID > IDM_FILE)   /* min wID for app command */ &&
				(wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) {

				if ((lpContainerApp->m_fMenuHelpMode)) {
					LPOLEINPLACEACTIVEOBJECT lpIPActiveObj =
							lpContainerApp->m_lpIPActiveObj;

					lpContainerApp->m_fMenuHelpMode = FALSE;

					// inform the in-place active object that we handled the
					//   menu help mode (F1) selection.
					if (lpIPActiveObj) {
						OLEDBG_BEGIN2("IOleInPlaceActiveObject::ContextSensitiveHelp(FALSE) called\r\n")
						lpIPActiveObj->lpVtbl->ContextSensitiveHelp(
								lpIPActiveObj, FALSE);
						OLEDBG_END2
					}
				}

				if ((lpOleDoc->m_fCSHelpMode)) {
					LPOLEINPLACEOBJECT lpIPObj;
					LPCONTAINERLINE lpLastIpActiveLine =
							lpContainerDoc->m_lpLastIpActiveLine;

					lpOleDoc->m_fCSHelpMode = FALSE;

					/* inform immediate in-place container parent and,
					**    if we were a container/server, immediate
					**    in-place object children that we handled the
					**    context sensitive help mode.
					*/
					if (lpLastIpActiveLine &&
							(lpIPObj=lpLastIpActiveLine->m_lpOleIPObj)!=NULL){
						OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp(FALSE) called\r\n")
						lpIPObj->lpVtbl->ContextSensitiveHelp(lpIPObj, FALSE);
						OLEDBG_END2
					}
				}

				// if we provided help, we would do it here...

				// remove context sensitive help cursor
				SetCursor(LoadCursor(NULL,IDC_ARROW));
				return 0L;
			}
#endif  // INPLACE_CNTR

			switch (wID) {

				/*********************************************************
				** File new, open, save and print as well as Help about
				**    are duplicated in this switch statement and they are
				**    used to trap the message from the toolbar
				**
				*********************************************************/

				case IDM_F_NEW:
					OleDbgIndent(-2);   // Reset debug output indent level
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_NewCommand\r\n")
					OutlineApp_NewCommand(lpOutlineApp);
					OLEDBG_END3

#if defined( OLE_CNTR )
					/* OLE2NOTE: this call will attempt to recover
					**    resources by unloading DLL's that were loaded
					**    by OLE and are no longer being used. it is a
					**    good idea to call this API now and then if
					**    your app tends to run for a long time.
					**    otherwise these DLL's will be unloaded when
					**    the app exits. some apps may want to call
					**    this as part of idle-time processing. this
					**    call is optional.
					*/
					OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")
					CoFreeUnusedLibraries();
					OLEDBG_END2
#endif

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(
							OutlineApp_GetActiveDoc(lpOutlineApp));
#endif
					break;

				case IDM_F_OPEN:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_OpenCommand\r\n")
					OutlineApp_OpenCommand(lpOutlineApp);
					OLEDBG_END3

#if defined( OLE_CNTR )
					/* OLE2NOTE: this call will attempt to recover
					**    resources by unloading DLL's that were loaded
					**    by OLE and are no longer being used. it is a
					**    good idea to call this API now and then if
					**    your app tends to run for a long time.
					**    otherwise these DLL's will be unloaded when
					**    the app exits. some apps may want to call
					**    this as part of idle-time processing. this
					**    call is optional.
					*/
					OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")
					CoFreeUnusedLibraries();
					OLEDBG_END2
#endif

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(
							OutlineApp_GetActiveDoc(lpOutlineApp));
#endif
					break;

				case IDM_F_SAVE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_SaveCommand\r\n")
					OutlineApp_SaveCommand(lpOutlineApp);
					OLEDBG_END3
					break;

				case IDM_F_PRINT:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineApp_PrintCommand\r\n")
					OutlineApp_PrintCommand(lpOutlineApp);
					OLEDBG_END3
					break;


				case IDM_E_UNDO:
					// SORRY. NOT IMPLEMENTED
					break;

				case IDM_E_CUT:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_CutCommand\r\n")
					OutlineDoc_CutCommand(lpOutlineDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

				case IDM_E_COPY:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_CopyCommand\r\n")
					OutlineDoc_CopyCommand(lpOutlineDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

				case IDM_E_PASTE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_PasteCommand\r\n")
					OutlineDoc_PasteCommand(lpOutlineDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

#if defined( OLE_VERSION )
				case IDM_E_PASTESPECIAL:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OleDoc_PasteSpecialCommand\r\n")
					OleDoc_PasteSpecialCommand((LPOLEDOC)lpOutlineDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

#endif  // OLE_VERSION

				case IDM_E_CLEAR:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_ClearCommand\r\n")
					OutlineDoc_ClearCommand(lpOutlineDoc);
					OLEDBG_END3

#if defined( OLE_CNTR )
					/* OLE2NOTE: this call will attempt to recover
					**    resources by unloading DLL's that were loaded
					**    by OLE and are no longer being used. it is a
					**    good idea to call this API now and then if
					**    your app tends to run for a long time.
					**    otherwise these DLL's will be unloaded when
					**    the app exits. some apps may want to call
					**    this as part of idle-time processing. this
					**    call is optional.
					*/
					OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")
					CoFreeUnusedLibraries();
					OLEDBG_END2
#endif

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

				case IDM_L_ADDLINE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_AddTextLineCommand\r\n")
					OutlineDoc_AddTextLineCommand(lpOutlineDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
					SetFocus(LineList_GetWindow(lpLL));
#endif
					break;

				case IDM_L_EDITLINE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_EditLineCommand\r\n")
					OutlineDoc_EditLineCommand(lpOutlineDoc);
					OLEDBG_END3
					SetFocus(LineList_GetWindow(lpLL));
					break;

				case IDM_L_INDENTLINE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_IndentCommand\r\n")
					OutlineDoc_IndentCommand(lpOutlineDoc);
					OLEDBG_END3
					break;

				case IDM_L_UNINDENTLINE:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_UnindentCommand\r\n")
					OutlineDoc_UnindentCommand(lpOutlineDoc);
					OLEDBG_END3
					break;

				case IDM_L_SETLINEHEIGHT:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_SetLineHeight\r\n")
					OutlineDoc_SetLineHeightCommand(lpOutlineDoc);
					OLEDBG_END3
					break;

				case IDM_E_SELECTALL:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_SelectAllCommand\r\n")
					OutlineDoc_SelectAllCommand(lpOutlineDoc);
					OLEDBG_END3
					break;

#if defined( OLE_CNTR )
				case IDM_E_INSERTOBJECT:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("ContainerDoc_InsertOleObjectCommand\r\n")
					ContainerDoc_InsertOleObjectCommand(lpContainerDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

				case IDM_E_EDITLINKS:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("ContainerDoc_EditLinksCommand\r\n")
					ContainerDoc_EditLinksCommand(lpContainerDoc);
					OLEDBG_END3
					break;

				case IDM_E_CONVERTVERB:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("ContainerDoc_ConvertCommand\r\n")
					ContainerDoc_ConvertCommand(
							lpContainerDoc, FALSE /*fMustActivate*/);
					OLEDBG_END3
					break;


				case IDM_E_PASTELINK:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("ContainerDoc_PasteLinkCommand\r\n")
					ContainerDoc_PasteLinkCommand(lpContainerDoc);
					OLEDBG_END3

#if defined( USE_FRAMETOOLS )
					OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
#endif
					break;

#endif  // OLE_CNTR

				case IDM_N_DEFINENAME:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_DefineNameCommand\r\n")
					OutlineDoc_DefineNameCommand(lpOutlineDoc);
					OLEDBG_END3
					break;

				case IDM_N_GOTONAME:
					OleDbgOutNoPrefix2("\r\n");

					OLEDBG_BEGIN3("OutlineDoc_GotoNameCommand\r\n")
					OutlineDoc_GotoNameCommand(lpOutlineDoc);
					OLEDBG_END3
					break;

#if defined( USE_FRAMETOOLS )
				case IDM_O_BB_TOP:
					FrameTools_BB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_TOP);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_O_BB_BOTTOM:
					FrameTools_BB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_BOTTOM);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_O_BB_POPUP:
					FrameTools_BB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_POPUP);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_O_BB_HIDE:
					FrameTools_BB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_HIDE);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_O_FB_TOP:
					FrameTools_FB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_TOP);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_O_FB_BOTTOM:
					FrameTools_FB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_BOTTOM);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_O_FB_POPUP:
					FrameTools_FB_SetState(
							lpOutlineDoc->m_lpFrameTools, BARSTATE_POPUP);
					OutlineDoc_AddFrameLevelTools(lpOutlineDoc);
					break;

				case IDM_FB_EDIT:

					switch (wNotifyCode) {
						case EN_SETFOCUS:
							OutlineDoc_SetFormulaBarEditFocus(
									lpOutlineDoc, TRUE);
							OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
							break;

						case EN_KILLFOCUS:
							OutlineDoc_SetFormulaBarEditFocus(
									lpOutlineDoc, FALSE);
							OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);
							break;
					}
					break;

				case IDM_FB_CANCEL:

					SetFocus(hWnd);
					break;


				case IDM_F2:
					SendMessage(hWnd, WM_COMMAND, (WPARAM)IDM_FB_EDIT,
							MAKELONG(0, EN_SETFOCUS));
					break;
#endif  // USE_FRAMETOOLS

				case IDM_ESCAPE:
					/* ESCAPE key pressed */

#if defined( USE_FRAMETOOLS )
					if (OutlineDoc_IsEditFocusInFormulaBar(lpOutlineDoc))
						SendMessage(
							hWnd, WM_COMMAND,(WPARAM)IDM_FB_CANCEL,(LPARAM)0);
#endif  // USE_FRAMETOOLS

#if defined( INPLACE_SVR )
					else {
						LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

						/* OLE2NOTE: The standard OLE 2.0 UI convention
						**    is to have ESCAPE key exit in-place
						**    activation (ie. UIDeactivate). If
						**    possible it is recommended for both
						**    in-place servers AND in-place containers
						**    to take responsibility to handle the
						**    ESCAPE key accelerator. The server has
						**    the first crack at handling accelerator
						**    keys and normally the server should do
						**    the UIDeactivation.
						*/
						if (lpServerDoc->m_fUIActive) {
							SvrDoc_IPObj_UIDeactivate( (LPOLEINPLACEOBJECT)&
									lpServerDoc->m_OleInPlaceObject);
						}
					}
#endif  // INPLACE_SVR

					break;


#if defined( USE_HEADING )
				case IDC_BUTTON:
					if (wNotifyCode == BN_CLICKED) {
						SendMessage(hWnd, WM_COMMAND, IDM_E_SELECTALL, 0L);
						SetFocus(hWnd);
					}
					break;

				case IDM_O_HEAD_SHOW:
					OutlineDoc_ShowHeading(lpOutlineDoc, TRUE);
					break;

				case IDM_O_HEAD_HIDE:
					OutlineDoc_ShowHeading(lpOutlineDoc, FALSE);
					break;
#endif  // USE_HEADING


#if defined( OLE_CNTR )
				case IDM_O_SHOWOBJECT:
				{
					LPCONTAINERDOC lpContainerDoc =
								(LPCONTAINERDOC)lpOutlineDoc;
					BOOL        fShowObject;

					fShowObject = !ContainerDoc_GetShowObjectFlag(
							lpContainerDoc);
					ContainerDoc_SetShowObjectFlag(
							lpContainerDoc, fShowObject);
					LineList_ForceRedraw(lpLL, TRUE);

					break;
				}
#endif  // OLE_CNTR

#if !defined( OLE_CNTR )
				// Container does not allow zoom factors > 100%
				case IDM_V_ZOOM_400:
				case IDM_V_ZOOM_300:
				case IDM_V_ZOOM_200:
#endif      // !OLE_CNTR

				case IDM_V_ZOOM_100:
				case IDM_V_ZOOM_75:
				case IDM_V_ZOOM_50:
				case IDM_V_ZOOM_25:
					OutlineDoc_SetCurrentZoomCommand(lpOutlineDoc, wID);
					break;

				case IDM_V_SETMARGIN_0:
				case IDM_V_SETMARGIN_1:
				case IDM_V_SETMARGIN_2:
				case IDM_V_SETMARGIN_3:
				case IDM_V_SETMARGIN_4:
					OutlineDoc_SetCurrentMarginCommand(lpOutlineDoc, wID);
					break;

				case IDM_V_ADDTOP_1:
				case IDM_V_ADDTOP_2:
				case IDM_V_ADDTOP_3:
				case IDM_V_ADDTOP_4:
				{
					UINT nHeightInHimetric;

					switch (wID) {
						case IDM_V_ADDTOP_1:
							nHeightInHimetric = 1000;
							break;

						case IDM_V_ADDTOP_2:
							nHeightInHimetric = 2000;
							break;

						case IDM_V_ADDTOP_3:
							nHeightInHimetric = 3000;
							break;

						case IDM_V_ADDTOP_4:
							nHeightInHimetric = 4000;
							break;
					}

					OutlineDoc_AddTopLineCommand(
							lpOutlineDoc, nHeightInHimetric);
					break;
				}


				case IDM_H_ABOUT:
					OutlineApp_AboutCommand(lpOutlineApp);
					break;

				case IDM_D_DEBUGLEVEL:
					SetDebugLevelCommand();
					break;

#if defined( OLE_VERSION )
				case IDM_D_INSTALLMSGFILTER:
					InstallMessageFilterCommand();
					break;

				case IDM_D_REJECTINCOMING:
					RejectIncomingCommand();
					break;
#endif  // OLE_VERSION

#if defined( INPLACE_CNTR )
				case IDM_D_INSIDEOUT:
					g_fInsideOutContainer = !g_fInsideOutContainer;

					// force all object to unload so they can start new
					// activation behavior.
					ContainerDoc_UnloadAllOleObjectsOfClass(
							(LPCONTAINERDOC)lpOutlineDoc,
							&CLSID_NULL,
							OLECLOSE_SAVEIFDIRTY
					);
					OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE);
					break;
#endif  // INPLACE_CNTR


#if defined( OLE_CNTR )
				case IDC_LINELIST: {

					if (wNotifyCode == LBN_DBLCLK) {

						/* OLE2NOTE: a container should execute the
						**    OLEIVERB_PRIMARY verb on an OLE object
						**    when the user DBLCLK's the object.
						*/
						int nIndex = LineList_GetFocusLineIndex(lpLL);
						LPLINE lpLine = LineList_GetLine(lpLL, nIndex);

						if (lpLine &&
								Line_GetLineType(lpLine)==CONTAINERLINETYPE) {
							MSG msg;

							_fmemset((LPMSG)&msg,0,sizeof(msg));
							msg.hwnd = hWnd;
							msg.message = Message;
							msg.wParam = wParam;
							msg.lParam = lParam;

							ContainerLine_DoVerb(
									(LPCONTAINERLINE)lpLine,
									OLEIVERB_PRIMARY,
									(LPMSG)&msg,
									TRUE,
									TRUE
							);
						}

#if defined( INPLACE_CNTR )
						{ // BEGIN BLOCK
							LPCONTAINERDOC lpContainerDoc =
									(LPCONTAINERDOC) lpOutlineDoc;
							if (lpContainerDoc->m_fAddMyUI) {
								/* OLE2NOTE: fAddMyUI is TRUE when
								**    there was previously an in-place
								**    active object which got
								**    UIDeactivated as a result of this
								**    DBLCLK AND the DBLCLK did NOT
								**    result in in-place activating
								**    another object.
								**    (see IOleInPlaceSite::OnUIActivate and
								**    IOleInPlaceSite::OnUIDeactivate
								**    methods).
								*/

								/* OLE2NOTE: You need to generate
								**    QueryNewPalette only if you own
								**    the top level frame (ie. you are
								**    a top-level inplace container).
								*/


								OleApp_QueryNewPalette((LPOLEAPP)g_lpApp);

#if defined( USE_DOCTOOLS )
								ContainerDoc_AddDocLevelTools(lpContainerDoc);
#endif

#if defined( USE_FRAMETOOLS )
								ContainerDoc_AddFrameLevelUI(lpContainerDoc);
#endif
								lpContainerDoc->m_fAddMyUI = FALSE;
							}
						} // END BLOCK
#endif // INPLACE_CNTR
					}
					break;
				}
#endif  // OLE_CNTR


				default:

#if defined( OLE_CNTR )
					if (wID >= IDM_E_OBJECTVERBMIN) {

						OleDbgOutNoPrefix2("\r\n");
						OLEDBG_BEGIN3("ContainerDoc_ContainerLineDoVerbCommand\r\n")
						ContainerDoc_ContainerLineDoVerbCommand(
								(LPCONTAINERDOC)lpOutlineDoc,
								(LONG)(wID-IDM_E_OBJECTVERBMIN)
						);
						OLEDBG_END3
						break;
					}
#endif  // OLE_CNTR
					return DefWindowProc(hWnd, Message, wParam, lParam);
			}

			break;  /* End of WM_COMMAND */
		}
		default:

			if (Message == g_uMsgHelp) {
				/* Handle OLE2UI dialog's help messages.
				** We get the hDlg of the dialog that called us in the wParam
				** and the dialog type in the LOWORD of the lParam,
				** so we pass this along to our help function.
				*/
				OutlineDoc_DialogHelp((HWND)wParam, LOWORD(lParam));
				break;
			}

			/* For any message for which you don't specifically provide a  */
			/* service routine, you should return the message to Windows   */
			/* for default message processing.                             */
			return DefWindowProc(hWnd, Message, wParam, lParam);
	}

	return (LRESULT)0;

} /* End of DocWndProc */



//***********************************************************************
//*
//* LineListWndProc()  Drag and Drop Listbox Window Proc Sub-Class
//*
//* Sub Class the Ownerdraw list box in order to activate the drag drop.
//***********************************************************************

LRESULT FAR PASCAL LineListWndProc(
	HWND   hWnd,
	UINT   Message,
	WPARAM wParam,
	LPARAM lParam
)
{
	HWND         hwndParent = GetParent ( hWnd );
	LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
	LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC) GetWindowLong( hwndParent, 0 );
	LPLINELIST   lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

#if defined( OLE_VERSION )
	LPOLEAPP     lpOleApp = (LPOLEAPP)lpOutlineApp;
	LPOLEDOC     lpOleDoc = (LPOLEDOC)lpOutlineDoc;
#endif  // OLE_VERSION

#if defined( INPLACE_SVR )
	LPSERVERDOC  lpServerDoc = (LPSERVERDOC)lpOutlineDoc;
	static BOOL  fUIActivateClick = FALSE;
	static BOOL  fInWinPosChged = FALSE;
#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )
	LPCONTAINERAPP lpContainerApp=(LPCONTAINERAPP)lpOutlineApp;
	LPCONTAINERDOC lpContainerDoc=(LPCONTAINERDOC)lpOutlineDoc;
#endif  // INPLACE_CNTR

	switch (Message) {

		case WM_KILLFOCUS:
			/* OLE2NOTE: when our window looses focus we
			**    should not display any active selection
			*/
#if defined( INPLACE_CNTR )
			if (! lpContainerApp->m_fPendingUIDeactivate)
#endif  // INPLACE_CNTR
				LineList_RemoveSel(lpLL);
			break;

		case WM_SETFOCUS:

#if defined( INPLACE_CNTR )
			{
				HWND hWndObj=ContainerDoc_GetUIActiveWindow(lpContainerDoc);

				/* OLE2NOTE: if there is a UIActive in-place object, we must
				**    forward focus to its window as long as there is
				**    not a pending UIDeactivate. if the mouse is
				**    clicked outside of the object and the object is
				**    about to be deactivated then we do NOT want to
				**    forward focus to the object. we do NOT want it to
				**    restore its selection feedback.
				*/
				if (lpContainerApp->m_fPendingUIDeactivate)
					break;
				else if (hWndObj) {
					SetFocus(hWndObj);
					break;      // do not restore containers selection state
				}
			}
#endif  // INPLACE_CNTR

			/* OLE2NOTE: when our window gains focus we
			**    should restore the previous selection
			*/
			LineList_RestoreSel(lpLL);

			break;

#if defined( INPLACE_SVR )
		case WM_MOUSEACTIVATE:
		{
			if (lpServerDoc->m_fInPlaceActive && !lpServerDoc->m_fUIActive) {
				fUIActivateClick = TRUE;
			};
			break;
		}

#endif  // INPLACE_SVR


#if defined( USE_FRAMETOOLS )
		case WM_CHAR:
		{
			OutlineDoc_SetFormulaBarEditFocus(lpOutlineDoc, TRUE);
			FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, NULL);
			FrameTools_FB_SendMessage(
					lpOutlineDoc->m_lpFrameTools,
					IDM_FB_EDIT,
					Message,
					wParam,
					lParam
			);

			return (LRESULT)0;   // don't do default listbox processing
		}
#endif  // USE_FRAMETOOLS

#if defined( INPLACE_CNTR )
		case WM_VSCROLL:
		{
			if (wParam == SB_ENDSCROLL) {
				/* OLE2NOTE: after scrolling finishes, update position of
				**    in-place visible windows.
				**    (ICNTROTL specific) we first let the ListBox
				**    perform it normal processing with the EndScroll
				**    message. also we let the ListBox handle all other
				**    scroll messages.
				*/
				LRESULT lResult =  CallWindowProc(
						(WNDPROC)lpOutlineApp->m_ListBoxWndProc,
						hWnd,
						Message,
						wParam,
						lParam
				);
				ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, 0);
				return lResult;
			}

			break;
		}
#endif  // INPLACR_CNTR

#if defined( USE_HEADING )
		case WM_HSCROLL:
		{
			LPHEADING lphead = OutlineDoc_GetHeading(lpOutlineDoc);

			Heading_CH_SendMessage(lphead, Message, wParam, lParam);

			break;
		}

		/* NOTE: WM_PAINT trapped in order to track vertical scrolling
		**    that has taken place so the row headings can be
		**    coordinated with the LineList. we wanted to trap instead
		**    but it is not generated from scrolling without using
		**    scroll bar (e.g. use keyboard).
		*/
		case WM_PAINT:
		{
			Heading_RH_Scroll(OutlineDoc_GetHeading(lpOutlineDoc), hWnd);
			break;
		}

#endif  // USE_HEADING

		case WM_LBUTTONUP:
		{

#if defined( USE_DRAGDROP )
			if (lpOleDoc->m_fPendingDrag) {
				/* ButtonUP came BEFORE distance/time threshholds were
				**    exceeded. clear fPendingDrag state.
				*/
				ReleaseCapture();
				KillTimer(hWnd, 1);
				lpOleDoc->m_fPendingDrag = FALSE;
			}
#endif  // USE_DRAGDROP

#if defined( INPLACE_SVR )
			if (fUIActivateClick) {
				fUIActivateClick = FALSE;
				ServerDoc_UIActivate((LPSERVERDOC) lpOleDoc);
			}
#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )
			{
				/* check if a UIDeactivate is pending.
				**      (see comment in WM_LBUTTONDOWN)
				*/
				if ( lpContainerApp->m_fPendingUIDeactivate ) {
					ContainerLine_UIDeactivate(
							lpContainerDoc->m_lpLastUIActiveLine);

					lpContainerApp->m_fPendingUIDeactivate = FALSE;
				}
			}
#endif  // INPLACE_CNTR

			break;
		}

		case WM_LBUTTONDOWN:
		{
			POINT pt;

			pt.x = (int)(short)LOWORD (lParam );
			pt.y = (int)(short)HIWORD (lParam );

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )
			/* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)
			**    m_fCSHelpMode flag is set when SHIFT-F1 context
			**    sensitive help is entered.
			**    if this flag is set then the button click should not
			**    cause any action. if the application implements a
			**    help system, then context sensitive help should be
			**    given for the location clicked by the user.
			*/
			if (lpOleDoc->m_fCSHelpMode) {
				return (LRESULT)0;   // eat the button click because we do
									 // not give any help.
			}
#endif  // INPLACE_SVR || INPLACE_CNTR

#if defined( INPLACE_CNTR )
			{
				/* OLE2NOTE: both inside-out and outside-in style
				**    containers must check if the mouse click is
				**    outside of the current UIActive object (if
				**    any). If so, then set the flag indicating that
				**    there is a pending UIDeactivate needed. We do NOT
				**    want to do it now,
				**    because that would result in un-wanted movement of
				**    the data on the screen as frame adornments (eg.
				**    toolbar) and/or object adornments (eg. ruler) would
				**    be removed from the screen. we want to defer the
				**    UIDeactivate till the mouse up event. The listbox's
				**    default processing captures the mouse on button down
				**    so that it is sure to get the button up message.
				**
				**    SPECIAL NOTE: there is potential interaction here
				**    with Drag/Drop. if this button down event actually
				**    starts a Drag/Drop operation, then OLE does the mouse
				**    capture. in this situation we will NOT get our button
				**    up event. we must instead perform the UIDeactivate
				**    when the drop operation finishes
				*/
				lpContainerApp->m_fPendingUIDeactivate =
						ContainerDoc_IsUIDeactivateNeeded(lpContainerDoc, pt);
			}
#endif  // INPLACE_CNTR

#if defined( USE_DRAGDROP )

			/* OLE2NOTE: check if this is a button down on the region
			**    that is a handle to start a drag operation. for us,
			**    this this the top/bottom border of the selection.
			**    do NOT want to start a drag immediately; we want to
			**    wait until the mouse moves a certain threshold. if
			**    LButtonUp comes before mouse move to start drag, then
			**    the fPendingDrag state is cleared. we must capture
			**    the mouse to ensure the modal state is handled
			**    properly.
			*/
			if ( OleDoc_QueryDrag(lpOleDoc, pt.y) ) {
				lpOleDoc->m_fPendingDrag = TRUE;
				lpOleDoc->m_ptButDown = pt;
				SetTimer(hWnd, 1, lpOleApp->m_nDragDelay, NULL);
				SetCapture(hWnd);

				/* We do NOT want to do the listbox's default
				**    processing which would be to capture the mouse
				**    and enter a modal multiple selection state until
				**    a mouse up occurs. we have just finished a modal
				**    drag/drop operation where OLE has captured the
				**    mouse. thus by now the mouse up has already occured.
				*/

				return (LRESULT)0;   // don't do default listbox processing
			}
#endif  // USE_DRAGDROP

			break;
		}


		case WM_MOUSEMOVE: {

#if defined( USE_DRAGDROP )

			int  x = (int)(short)LOWORD (lParam );
			int  y = (int)(short)HIWORD (lParam );
			POINT pt = lpOleDoc->m_ptButDown;
			int nDragMinDist = lpOleApp->m_nDragMinDist;

			if (lpOleDoc->m_fPendingDrag) {

				if (! ( ((pt.x - nDragMinDist) <= x)
						&& (x <= (pt.x + nDragMinDist))
						&& ((pt.y - nDragMinDist) <= y)
						&& (y <= (pt.y + nDragMinDist)) ) ) {

					DWORD dwEffect;

					// mouse moved beyond threshhold to start drag
					ReleaseCapture();
					KillTimer(hWnd, 1);
					lpOleDoc->m_fPendingDrag = FALSE;

					// perform the modal drag/drop operation.
					dwEffect = OleDoc_DoDragDrop( lpOleDoc );

#if defined( INPLACE_CNTR )
					{
						/* if necessary UIDeactive the in-place object.
						**    this applies to outside-in style
						**    container only.
						**    (see comment above)
						*/
						if (lpContainerApp->m_fPendingUIDeactivate) {
							lpContainerApp->m_fPendingUIDeactivate = FALSE;

							// do not UIDeactivate if drag/drop was canceled
							if (dwEffect != DROPEFFECT_NONE)
								ContainerLine_UIDeactivate(
										lpContainerDoc->m_lpLastUIActiveLine
								);
						}
					}
#endif  // INPLACE_CNTR

					return (LRESULT)0; // don't do default listbox process
				}
				else {
					/* cursor did not move from initial mouse down
					**    (pending drag) point.
					*/
					return (LRESULT)0; // don't do default listbox process
				}
			}

#endif  // USE_DRAGDROP

#if defined( INPLACE_CNTR )
			{ // BEGIN BLOCK
				if (lpContainerDoc->m_fAddMyUI) {
					/* OLE2NOTE: fAddMyUI is TRUE when
					**    there was previously an in-place
					**    active object which got
					**    UIDeactivated as a result of a
					**    DBLCLK AND the DBLCLK did NOT
					**    result in in-place activating
					**    another object.
					**    (see IOleInPlaceSite::OnUIActivate and
					**    IOleInPlaceSite::OnUIDeactivate
					**    methods).
					*/
#if defined( USE_DOCTOOLS )
					ContainerDoc_AddDocLevelTools(lpContainerDoc);
#endif

#if defined( USE_FRAMETOOLS )
					ContainerDoc_AddFrameLevelUI(lpContainerDoc);
#endif
					lpContainerDoc->m_fAddMyUI = FALSE;
				}
			} // END BLOCK
#endif // INPLACE_CNTR

			break;
		}


#if defined( USE_DRAGDROP )
		case WM_TIMER:
		{
			DWORD dwEffect;

			// drag time delay threshhold exceeded -- start drag
			ReleaseCapture();
			KillTimer(hWnd, 1);
			lpOleDoc->m_fPendingDrag = FALSE;

			// perform the modal drag/drop operation.
			dwEffect = OleDoc_DoDragDrop( lpOleDoc );

#if defined( INPLACE_CNTR )
			/* if necessary UIDeactive the in-place object.
			**    this applies to outside-in style
			**    container only.
			**    (see comment above)
			*/
			if (lpContainerApp->m_fPendingUIDeactivate) {
				lpContainerApp->m_fPendingUIDeactivate = FALSE;

				// do not UIDeactivate if drag/drop was canceled
				if (dwEffect != DROPEFFECT_NONE)
					ContainerLine_UIDeactivate(
							lpContainerDoc->m_lpLastUIActiveLine);
			}
#endif  // INPLACE_CNTR
			break;
		}
#endif  // USE_DRAGDROP

		case WM_SETCURSOR:
		{
			RECT rc;
			POINT ptCursor;
#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )
			/* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)
			**    m_fCSHelpMode flag is set when SHIFT-F1 context
			**    sensitive help is entered.
			**    if this flag is set then the context sensitive help
			**    cursor should be shown.
			*/
			if (lpOleDoc->m_fCSHelpMode) {
				SetCursor(UICursorLoad(IDC_CONTEXTHELP));
				return (LRESULT)TRUE;
			}
#endif  // INPLACE_SVR || INPLACE_CNTR

			GetCursorPos((POINT FAR*)&ptCursor);
			ScreenToClient(hWnd, (POINT FAR*)&ptCursor);
			GetClientRect(hWnd, (LPRECT)&rc);

			// use arrow cursor if in scroll bar
			if (! PtInRect((LPRECT)&rc, ptCursor) )
				SetCursor(LoadCursor(NULL, IDC_ARROW) );

#if defined( USE_DRAGDROP )
			// use arrow cursor if on drag handle (top/bottom of selection)
			else if ( OleDoc_QueryDrag ( lpOleDoc, ptCursor.y) )
				SetCursor(LoadCursor(NULL, IDC_ARROW) );
#endif  // USE_DRAGDROP

			else
				SetCursor(lpOutlineApp->m_hcursorSelCur);

			return (LRESULT)TRUE;
		}

#if defined( INPLACE_SVR )

		/* The handling of WM_WINDOWPOSCHANGED message is ISVROTL
		**    application specific. The nature of the owner-draw list
		**    box used by the ISVROTL application causes a recursive
		**    call to this message in some situations when in-place
		**    active. in order not to crash this recursive call must be
		**    guarded.
		*/
		case WM_WINDOWPOSCHANGED:
		{
			WINDOWPOS FAR* lpWinPos = (WINDOWPOS FAR*) lParam;
			LRESULT lResult;

			// guard against recursive call
			if (fInWinPosChged)
				return (LRESULT)0;

			fInWinPosChged = TRUE;
			lResult = CallWindowProc(
					(WNDPROC)lpOutlineApp->m_ListBoxWndProc,
					hWnd,
					Message,
					wParam,
					lParam
			);
			fInWinPosChged = FALSE;

			return lResult;
		}
#endif  // INPLACE_SVR

	}

	return CallWindowProc(
			(WNDPROC)lpOutlineApp->m_ListBoxWndProc,
			hWnd,
			Message,
			wParam,
			lParam
	);

}

// Utility function to count the number of accelerator items in an
//  accelerator table.  A number of OLE APIs need this count, so
//  this can be quite handy.
// (code shamelessly stolen from the Microsoft Foundation Classes)

int GetAccelItemCount(HACCEL hAccel)
{
	#pragma pack(1)
	typedef struct tagACCELERATOR
	{
		BYTE    fFlags;
		WORD    wEvent;
		WORD    wID;
	} ACCELERATOR;
	#pragma pack()

	// attempt to lock down the accelerator resource
	ACCELERATOR FAR* pAccel;
	int cAccelItems = 1;
	if (hAccel == NULL ||
		(pAccel = (ACCELERATOR FAR*)LockResource((HGLOBAL)hAccel)) == NULL)
	{
		// NULL accerator table or LockResource failed on the HACCEL,
		//  no accelerators
		return 0;
	}
	// otherwise, count them -- last entry in accel table has 0x80 bit set
	while ((pAccel->fFlags & 0x80) == 0)
	{
		++cAccelItems;
		++pAccel;
	}
	UnlockResource((HGLOBAL)hAccel);
	return cAccelItems;
}
