/*************************************************************************
**
**    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 "ansiapi.h"
#include "outline.h"
#if defined( USE_STATUSBAR )
#include "status.h"
#endif

#if !defined( WIN32 )
#if defined( USE_CTL3D )
//#include "..\include\ctl3d.h"
#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;
   char         szAnsiString[256];
#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.
         */

//???         W2A (APPNAME, szAnsiString, 256);

         int nResponse = MessageBox(
               hWnd,
               "Discard changes?",
               szAnsiString,
               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;
         OLECHAR lpszUniMessage[256];
#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);
            A2W (lpszMessage, lpszUniMessage, 256);
            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);
         }
         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);
            A2W (lpszMessage, lpszUniMessage, 256);
            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);
         }
         else if (fuFlags & MF_SYSMENU) {
            GetSysMenuMessage(uItem, &lpszMessage);
            A2W (lpszMessage, lpszUniMessage, 256);
            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);
         }
         else if (uItem != 0) {  // Command Item
            GetItemMessage(uItem, &lpszMessage);
            A2W (lpszMessage, lpszUniMessage, 256);
            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);
         }
         else {
            GetControlMessage(STATUS_BLANK, &lpszMessage);
            A2W (lpszMessage, lpszUniMessage, 256);
            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);
         }
         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;
         OLECHAR szUniMessage[256];

#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);
            A2W( lpszMessage, szUniMessage, 256);
            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);
         }
         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);
            A2W( lpszMessage, szUniMessage, 256);
            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);
         }
         else if (uItem != 0) {  // Command Item
            GetItemMessage(uItem, &lpszMessage);
            A2W( lpszMessage, szUniMessage, 256);
            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);
         }
         else {
            GetControlMessage(STATUS_BLANK, &lpszMessage);
            A2W( lpszMessage, szUniMessage, 256);
            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);
         }
         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)
{
#if defined( WIN32 )
    return CopyAcceleratorTable(hAccel, NULL, 0);
#else
   #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;
#endif
}
