
//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
//  File:	inplace.cpp
//
//  Contents:	Implementation of OLE inplace editing API's
//
//  Classes:	CFrame implementation, used to store per-window info
//
//  Functions:	OleCreateMenuDescriptor
//		OleSetMenuDescriptor
//		OleDestroyMenuDescriptor
//		OleTranslateAccelerator
//		IsAccelerator
//		FrameWndFilterProc
//		MessageFilterProc
//				
//
//  History:	dd-mmm-yy Author    Comment
//		31-Mar-94 ricksa    Fixed menu merge bug & added some comments
//		23-Feb-94 alexgo    added call tracing
//		11-Jan-94 alexgo    added VDATEHEAP macros to every function
//		31-Dec-93 ChrisWe   fixed casts in OutputDebugStrings
//		07-Dec-93 alexgo    merged changes with shipped 16bit 2.01a
//				    (RC9).  Also removed lots of bad inlining.
//		01-Dec-93 alexgo    32bit port, made globals static
//		07-Dec-92 srinik    Converted frame filter implementatio
//				    into a C++ class implementation.
//				    So, most of the code is rewritten.
//		09-Jul-92 srinik    author
//
//  Notes:	REVIEW32:  we need to do something about the new
//		focus management policy for NT (re TonyWi's mail)
//
//--------------------------------------------------------------------------

#include <le2int.h>
#pragma SEG(inplace)

#ifndef _MAC
#include "inplace.h"
#endif

NAME_SEG(InPlace)
ASSERTDATA

// to keep the code bases common
// REVIEW32:  we may want to clean this up a bit
#ifdef WIN32
#define FARPROC  WNDPROC
#endif

#ifndef _MAC

#ifdef WIN32
static const OLECHAR 	szPropFrameFilter[] = OLESTR("pFrameFilter");
#else
static const OLECHAR	szPropFrameFilterH[] = OLESTR("pFrameFilterH");
static const OLECHAR	szPropFrameFilterL[] = OLESTR("pFrameFilterL");
#endif //WIN32

static WORD		wSignature; //    =  (WORD) { 'S', 'K' }

static HHOOK		hMsgHook = NULL;
static PCFRAMEFILTER	pFrameFilter = NULL;

// the values for these globals are set in ole2.cpp
UINT			uOmPostWmCommand;
UINT			uOleMessage;

#define OM_CLEAR_MENU_STATE		0	// lParam is NULL
#define OM_COMMAND_ID			1	// LOWORD(lParam) contains
						// the command ID



//+-------------------------------------------------------------------------
//
//  Function:   IsHmenuEqual
//
//  Synopsis:   Test whether two menu handles are equal taking into
//              account whether one might be a Win16 handle.
//
//  History:	dd-mmm-yy Author    Comment
//		31-May-94 Ricksa    Created
//
//--------------------------------------------------------------------------
inline BOOL IsHmenuEqual(HMENU hmenu1, HMENU hmenu2)
{
    if (HIWORD(hmenu1) == 0 || HIWORD(hmenu2) == 0)
    {
        return LOWORD(hmenu1) == LOWORD(hmenu2);
    }
    else
    {
        return hmenu1 == hmenu2;
    }
}




//+-------------------------------------------------------------------------
//
//  Class:	CPaccel
//
//  Purpose:	Handles enumeration of ACCEL table for IsAccelerator
//
//  Interface:	InitLPACCEL - Initialize object
//		operator-> Get pointer to current ACCEL in enumeration
//		Next - bump current pointer
//
//  History:	dd-mmm-yy Author    Comment
//		14-Apr-94 Ricksa    Created
//
//  Notes:	This class also guarantees clean up of the
//		allocated accelerator table & to localize the differences
//		between Win16 & Win32 within this class.
//
//--------------------------------------------------------------------------
class CPaccelEnum : public CPrivAlloc
{
public:
			CPaccelEnum(void);

			~CPaccelEnum(void);

    BOOL		InitLPACCEL(HACCEL haccel, int cAccel);

    LPACCEL		operator->(void);

    void		Next(void);

private:

    LPACCEL		_lpaccel;

#ifdef WIN32

    LPACCEL		_lpaccelBase;

#else // !WIN32

    HACCEL		_haccel;

#endif // WIN32
};





//+-------------------------------------------------------------------------
//
//  Function:	CPaccelEnum::CPaccelEnum
//
//  Synopsis:	Initialize object to zero
//
//  History:	dd-mmm-yy Author    Comment
//		14-Apr-94 Ricksa    Created
//
//--------------------------------------------------------------------------
inline CPaccelEnum::CPaccelEnum(void) : _lpaccel(NULL)
{
#ifdef WIN32

    // In Win32, we allocate the memory so we need to keep track of the
    // base of the memory that we allocated.
    _lpaccelBase = NULL;

#else // !WIN32

    // In Win16, we release by unlock resource so we need to keep track of
    // the accelerator handle.
    _haccel = NULL;

#endif // WIN32
}




//+-------------------------------------------------------------------------
//
//  Function:	CPaccelEnum::~CPaccelEnum
//
//  Synopsis:	Free resources connected with resource table
//
//  History:	dd-mmm-yy Author    Comment
//		14-Apr-94 Ricksa    Created
//
//--------------------------------------------------------------------------
inline CPaccelEnum::~CPaccelEnum(void)
{
#ifdef WIN32

    PrivMemFree(_lpaccelBase);

#else // !WIN32

    UnlockResource(hAccel);

#endif // WIN32
}




//+-------------------------------------------------------------------------
//
//  Function:	CPaccelEnum::InitLPACCEL
//
//  Synopsis:	Initialize Accelerator table pointer
//
//  Arguments:	[haccel] - handle to accelerator table
//		[cAccel] - count of entries in the table
//
//  Returns:	TRUE - table was allocated successfully
//		FALSE - table could not be allocated
//
//  History:	dd-mmm-yy Author    Comment
//		14-Apr-94 Ricksa    Created
//
//--------------------------------------------------------------------------
inline BOOL CPaccelEnum::InitLPACCEL(HACCEL haccel, int cAccel)
{
#ifdef WIN32

    // Allocate the memory for the table. If that succeeds, then copy
    // the accelerator table. Note that if _lpaccelBase gets allocated,
    // but CopyAcceleratorTable fails, the memory will be cleaned up
    // in the destructor.
    if (((_lpaccelBase
	    = (LPACCEL) PrivMemAlloc(cAccel * sizeof(ACCEL))) != NULL)
	&& (CopyAcceleratorTable(haccel, _lpaccelBase, cAccel) == cAccel))
    {
	_lpaccel = _lpaccelBase;
	return TRUE;
    }

    return FALSE;

#else // !WIN32

    // Just lock the resource
    return ((_lpaccel = LockResource(haccel)) != NULL);

#endif // WIN32
}



//+-------------------------------------------------------------------------
//
//  Function:	CPaccelEnum::operator->
//
//  Synopsis:	Return pointer to accelerator table
//
//  History:	dd-mmm-yy Author    Comment
//		14-Apr-94 Ricksa    Created
//
//--------------------------------------------------------------------------
inline LPACCEL CPaccelEnum::operator->(void)
{
    AssertSz((_lpaccel != NULL), "CPaccelEnum::operator-> _lpaccel NULL!");
    return _lpaccel;
}




//+-------------------------------------------------------------------------
//
//  Function:	CPaccelEnum::Next
//
//  Synopsis:	Bump enumeration pointer
//
//  History:	dd-mmm-yy Author    Comment
//		14-Apr-94 Ricksa    Created
//
//--------------------------------------------------------------------------
inline void CPaccelEnum::Next(void)
{
    AssertSz((_lpaccel != NULL), "CPaccelEnum::Next _lpaccel NULL!");
    _lpaccel++;
}




//+-------------------------------------------------------------------------
//
//  Function: 	OleCreateMenuDescriptor
//
//  Synopsis:   creates a descriptor from a combined menu (for use in
//		dispatching menu messages)
//
//  Effects:
//
//  Arguments:  [hmenuCombined]		-- handle the combined menu
//		[lpMenuWidths]		-- an array of 6 longs with the
//					   the number of menus in each
//					   group
//
//  Requires:
//
//  Returns:  	handle to an OLEMENU
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  Allocates space for enough ole menu items (total of all the
//		combined menues) and then fills in each ole menu item from
//		the combined menu
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes: 	if hmenuCombined is NULL, we still allocate the ole menu
//		descriptor handle
//
//--------------------------------------------------------------------------

#pragma SEG(OleCreateMenuDescriptor)
STDAPI_(HOLEMENU) OleCreateMenuDescriptor (HMENU hmenuCombined,
	LPOLEMENUGROUPWIDTHS lplMenuWidths)
{
	VDATEHEAP();

	int			iGroupCnt, n;
	int			iMenuCnt;
	HGLOBAL			hOleMenu;
	LPOLEMENU		lpOleMenu;
	LPOLEMENUITEM		lpMenuList;
	DWORD			dwOleMenuItemsSize = 0;

	LEDebugOut((DEB_TRACE, "%p _IN OleCreateMenuDescriptor ( %lx , "
		"%p )\n", NULL, hmenuCombined, lplMenuWidths));
			
	if (hmenuCombined)
	{
		GEN_VDATEPTRIN( lplMenuWidths, OLEMENUGROUPWIDTHS,
			(HOLEMENU)NULL );

		iMenuCnt = 0;
		for (iGroupCnt = 0; iGroupCnt < 6; iGroupCnt++)
		{
			iMenuCnt += (int) lplMenuWidths->width[iGroupCnt];
		}

		if (iMenuCnt == 0)
		{
			hOleMenu = NULL;
			goto errRtn;
		}
		
		dwOleMenuItemsSize = (iMenuCnt-1) * sizeof(OLEMENUITEM);
	}
	
	hOleMenu = GlobalAlloc(GMEM_SHARE | GMEM_ZEROINIT,	
				sizeof(OLEMENU) + dwOleMenuItemsSize);
	
	if (!hOleMenu)
	{
		goto errRtn;
	}
	
	if (! (lpOleMenu = (LPOLEMENU) GlobalLock(hOleMenu)))
	{
		GlobalFree(hOleMenu);
		hOleMenu = NULL;
		goto errRtn;
	}
	
	lpOleMenu->wSignature 		= wSignature;
	lpOleMenu->hmenuCombined 	= hmenuCombined;
	lpOleMenu->lMenuCnt		= (LONG) iMenuCnt;

	if (! hmenuCombined)
	{
		goto Exit;
	}
	
    	lpMenuList = lpOleMenu->menuitem;

	for (iMenuCnt = 0, iGroupCnt = 0; iGroupCnt < 6; iGroupCnt++)
	{
		lpOleMenu->MenuWidths.width[iGroupCnt] =
			lplMenuWidths->width[iGroupCnt];
		for (n = 0; n < lplMenuWidths->width[iGroupCnt]; n++)
		{
			lpMenuList->fObjectMenu = (iGroupCnt % 2);
			if (GetSubMenu(hmenuCombined, iMenuCnt) != NULL)
			{
				lpMenuList->fwPopup = MF_POPUP;
				lpMenuList->item = (UINT) GetSubMenu(
						hmenuCombined, iMenuCnt);
			}
			else
			{
				lpMenuList->fwPopup = NULL;
				lpMenuList->item = GetMenuItemID (
						hmenuCombined, iMenuCnt);
			}
			
			lpMenuList++;
			iMenuCnt++;
		}
	}
	
	
Exit:	
	GlobalUnlock(hOleMenu);

errRtn:

 	LEDebugOut((DEB_TRACE, "%p OUT OleCreateMenuDescriptor ( %lx )\n",
		NULL, hOleMenu));

	return (HOLEMENU) hOleMenu;
}

//+-------------------------------------------------------------------------
//
//  Function: 	OleSetMenuDescriptor
//
//  Synopsis: 	Called by the SetMenu method on the IOleInPlace frame
//		interface.  This API adds(removes) the FrameWndFilterProc
//		to the Frame window of the container. And then sets and
//		removes the main(frame) menu bar
//
//  Effects:
//
//  Arguments:	[holemenu]	-- a handle to the composite menu descriptor
//		[hwndFrame]	-- a handle to the container's frame window
//		[hwndActiveObject]	-- a handle to the object's in-place
//					   window
//		[lpFrame]	-- pointer to the container's
//				   IOleInPlaceFrame implementation
//		[lpActiveObj]	-- pointer to in-place object
//
//  Requires:
//
//  Returns:  	HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  check arguments, then create a new frame filter object
//		and attach it to the frame (replacing any that might
//		already be there).
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleSetMenuDescriptor)
STDAPI OleSetMenuDescriptor
(
	HOLEMENU			holemenu,
	HWND				hwndFrame,
	HWND				hwndObject,
	LPOLEINPLACEFRAME		lpFrame,
	LPOLEINPLACEACTIVEOBJECT	lpObject
)
{
	VDATEHEAP();

	PCFRAMEFILTER			pFrameFilter;
	LPOLEMENU			lpOleMenu = NULL;
	LPOLEMENU			lpOleMenuCopy = NULL;
	HRESULT				error = NOERROR;

	LEDebugOut((DEB_TRACE, "%p _IN OleSetMenuDescriptor ( %lx , %lx ,"
		"%lx , %p , %p )\n", NULL, holemenu, hwndFrame, hwndObject,
		lpFrame, lpObject));

        // The Frame window parameter always needs to be valid since
        // we use it for both hook and unhook of menus
        if (hwndFrame == NULL || !IsWindow(hwndFrame))
        {
	        LEDebugOut((DEB_ERROR,
		    "ERROR in OleSetMenuDesciptor: bad hwndFrame\n"));
		error =  ResultFromScode(OLE_E_INVALIDHWND);
                goto errRtn;
        }
			
	if (holemenu != NULL)
	{
	    	if (hwndObject == NULL || !IsWindow(hwndObject))
	    	{
			LEDebugOut((DEB_ERROR,
			"ERROR in OleSetMenuDesciptor: bad hwndFrame\n"));
			error =  ResultFromScode(OLE_E_INVALIDHWND);
			goto errRtn;
		}
		
		if (lpFrame && lpObject)
		{
			// the caller wants us to provide the support for
			// context sensitive help, let's validat the pointers
			VDATEIFACE(lpFrame);
			VDATEIFACE(lpObject);
		}
		
		if (!(lpOleMenu = wGetOleMenuPtr(holemenu)))
		{
			error = ResultFromScode(E_HANDLE);
			goto errRtn;
		}
		
		// OleMenuPtr gets released down below by wReleaseOleMenuPtr

		// Allocate memory for the copy
		DWORD dwSize = GlobalSize(holemenu);

		lpOleMenuCopy = (LPOLEMENU) PrivMemAlloc(dwSize);

		if (lpOleMenuCopy == NULL)
		{
		    wReleaseOleMenuPtr(holemenu);
		    error = E_OUTOFMEMORY;
		    goto errRtn;
		}

		memcpy(lpOleMenuCopy, lpOleMenu, dwSize);
	}
	
	// if there is a frame filter get rid off it.
	if (pFrameFilter =  (PCFRAMEFILTER) wGetFrameFilterPtr(hwndFrame))
	{
		SetProp(hwndFrame, szPropFrameFilter, NULL);
		// be sure to remove our window proc hook

		pFrameFilter->RemoveWndProc();

		pFrameFilter->SafeRelease();
	}

	// Add a new frame filter
	if (holemenu)
	{
		error = CFrameFilter::Create (lpOleMenuCopy,
					lpOleMenu->hmenuCombined,
					hwndFrame, hwndObject,	lpFrame,
					lpObject);

		if (FAILED(error))
		{
		    PrivMemFree(lpOleMenuCopy);
		}

		wReleaseOleMenuPtr(holemenu);
	}	

errRtn:

	LEDebugOut((DEB_TRACE, "%p OUT OleSetMenuDescriptor ( %lx )\n",
		NULL, error ));

	return error;
}


//+-------------------------------------------------------------------------
//
//  Function:	OleDestroyMenuDescriptor
//
//  Synopsis:  	Releases the menu descriptor allocated by
//		OleCreateMenuDescriptor
//
//  Effects:
//
//  Arguments: 	[holemenu]	-- the menu descriptor
//
//  Requires:
//
//  Returns:    NOERROR, E_HANDLE
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  does a global lock and verifies that holemenu is
//		really a menu descriptor handle (via wGetOleMenuPtr),
//		then unlock's and free's.
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleDestroyMenuDescriptor)
STDAPI OleDestroyMenuDescriptor (HOLEMENU holemenu)
{
	VDATEHEAP();

	LPOLEMENU 	lpOleMenu;
	HRESULT		error;

	LEDebugOut((DEB_TRACE, "%p _IN OleDestroyMenuDescriptor ( %lx )\n",
		NULL, holemenu));
	
	// make sure that it is a valid handle
	if (! (lpOleMenu = wGetOleMenuPtr(holemenu)))
	{
		error = ResultFromScode(E_HANDLE);
	}
	else
	{	
		wReleaseOleMenuPtr(holemenu);
		GlobalFree((HGLOBAL) holemenu);
		error = NOERROR;
	}

	LEDebugOut((DEB_TRACE, "%p OUT OleDestroyMenuDescriptor ( %lx )\n",
		NULL, error));

	return error;
}

//+-------------------------------------------------------------------------
//
//  Function: 	wSysKeyToKey (internal)
//
//  Synopsis:  	Converts a message from a WM_SYSKEY to a WM_KEY message
//		if the alt key was not held down
//
//  Effects:
//
//  Arguments:  [lpMsg]		-- the message to convert
//
//  Requires:
//
//  Returns:    UINT -- the new message
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes: 	original notes:
//
// if the ALT key is down when a key is pressed, then the 29th bit of the
// LPARAM will be set
//	
// If the message was not made with the ALT key down, convert the message
// from a WM_SYSKEY* to a WM_KEY* message.
//
//--------------------------------------------------------------------------

static UINT wSysKeyToKey(LPMSG lpMsg)
{
	VDATEHEAP();

	UINT 	message = lpMsg->message;

	if (!(HIWORD(lpMsg->lParam) & 0x2000)
		&& (message >= WM_SYSKEYDOWN && message <= WM_SYSDEADCHAR))
	{
		message -= (WM_SYSKEYDOWN - WM_KEYDOWN);
	}	
	
	return message;
}


//+-------------------------------------------------------------------------
//
//  Function: 	OleTranslateAccelerator
//
//  Synopsis:  	Called by an inplace object to allow a container to attempt
//		to handle an accelerator
//
//  Effects:
//
//  Arguments: 	[lpFrame]	-- pointer to IOleInPlaceFrame where the
//				   keystroke might be sent
//		[lpFrameInfo]	-- pointer to and OLEINPLACEFRAMEINFO
//				   from the container with it's accelerator
//				   table
//		[lpmsg]		-- the keystroke
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm: 	We call SendMessage to store the accelerator cmd
//		(to handle degenerate lookups on the container) and
//		then ask the container to handle
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleTranslateAccelerator)
STDAPI OleTranslateAccelerator(LPOLEINPLACEFRAME lpFrame,
	LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpMsg)
{
	VDATEHEAP();

	WORD 		cmd;
	BOOL 		fFound;
	HRESULT		error;

	LEDebugOut((DEB_TRACE, "%p _IN OleTranslateAccelerator ( %p , %p "
		", %p )\n", NULL, lpFrame, lpFrameInfo, lpMsg));

	// Validate parameters -- the best that we can!
	// Note: the macro's VDATEPTR* were not used because they return
	// immediately & break the tracing semantics
	if (!IsValidInterface(lpFrame)
	    || !IsValidPtrIn(lpFrameInfo, sizeof(OLEINPLACEFRAMEINFO))
	    || !IsValidPtrIn(lpMsg, sizeof(MSG)))
	{
	    error = ResultFromScode(E_INVALIDARG);
	    goto exitRtn;
	}


	// Search the (container) frame's table of accelerators. Remember that
	// the container may be (actually most likely) is in a separate
	// process.
	fFound = IsAccelerator(lpFrameInfo->haccel,
			lpFrameInfo->cAccelEntries, lpMsg, &cmd);
					
	if (!fFound && lpFrameInfo->fMDIApp)
	{
		// If no accelerator was found and the app is a MDI app,
		// then we see if there is a mdi accelerator found.
		fFound = IsMDIAccelerator(lpMsg, &cmd);
	}

	if (fFound)
	{
		// Found some kind of for the container accelerator.

		// uOleMessage is set in ole2.cpp -- it is a private message
		// between OLE applications.

		// This SendMessage tells the message filter that is on the
		// frame window what the command translated to. This will
		// be used in menu collision processing.

		SendMessage(lpFrameInfo->hwndFrame, uOleMessage,
			OM_COMMAND_ID, MAKELONG(cmd, 0));

		// Send the command and the message to the container. The
		// result tells the caller whether the container really
		// used the command.

		error = lpFrame->TranslateAccelerator(lpMsg, cmd);
		
	}
	else if (wSysKeyToKey(lpMsg) == WM_SYSCHAR)
	{
		// Eat the message if it is "Alt -". This is supposed
		// to bring the MDI system menu down. But we can not
		// support it. And we also don't want the message to
		// be Translated by the object application either.
		// So, we return as if it has been accepted by the
		// container as an accelerator.
			
		// If the container wants to support this it can
		// have an accelerator for this. This is not an
		// issue for SDI apps, because it will be thrown
		// away by USER anyway.
			
		if (lpMsg->wParam != OLESTR('-'))
		{
			SendMessage(lpFrameInfo->hwndFrame,
				lpMsg->message,
				lpMsg->wParam, lpMsg->lParam);
		}
#ifdef _DEBUG
		else
		{
			OutputDebugString(
		TEXT("OleTranslateAccelerator: Alt+ - key is discarded\r\n"));
		}
#endif								
		error = NOERROR;
	}
	else
	{
		error = ResultFromScode(S_FALSE);
	}

exitRtn:

	LEDebugOut((DEB_TRACE, "%p OUT OleTranslateAccelerator ( %lx )\n",
		NULL, error));

	return error;
}

//+-------------------------------------------------------------------------
//
//  Function:  	IsAccelerator
//
//  Synopsis:   determines whether [lpMsg] is an accelerator in the [hAccel]
//
//  Effects:
//
//  Arguments:  [hAccel]	-- the accelerator table
//		[cAccelEntries]	-- the number of entries in the accelerator
//				   table
//		[lpMsg]		-- the keystroke message that we should
//				   see if it's an accelerator
//		[lpCmd]		-- where to return the corresponding command
//				   ID if an accelerator is found (may be NULL)
//
//  Requires:
//
//  Returns:    TRUE if accelerator is found, FALSE otherwise or on error
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

STDAPI_(BOOL) IsAccelerator
	(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD FAR* lpwCmd)
{
	VDATEHEAP();

	WORD		cmd = NULL;
	WORD		flags;	
	BOOL		fFound = FALSE;
	BOOL		fVirt;
	UINT		message;

	// Safe place for pointer to accelerator table
	CPaccelEnum	cpaccelenum;

	LEDebugOut((DEB_TRACE, "%p _IN IsAccelerator ( %lx , %d , %p , %p )\n",
		NULL, hAccel, cAccelEntries, lpMsg, lpwCmd));

	if (! cAccelEntries)
	{
		// no accelerators so we can stop here.
		goto errRtn;
	}
			
	// Change message type from WM_SYS type to WM_KEY type if the ALT
	// key is not pressed.
	message = wSysKeyToKey(lpMsg);

	// Figure out whether this message is one that can possibly contain
	// an accelerator.
	switch (message)
	{
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
		// wParam in this message is virtual key code
		fVirt = TRUE;
		break;

	case WM_CHAR:
	case WM_SYSCHAR:
		// wParam is the character
		fVirt = FALSE;
		break;

	default:
		goto errRtn;
	}

	// Get a pointer to the accerator table
	if ((hAccel == NULL)
	    || !cpaccelenum.InitLPACCEL(hAccel, cAccelEntries))
	{
		// Handle is NULL or we could not lock the resource so exit.
		goto errRtn;
	}

	do
	{
		// Get the flags from the accelerator table entry to save
		// a pointer dereference.
		flags = cpaccelenum->fVirt;

		// if the key in the message and the table aren't the same,
		// or if the key is virtual and the accel table entry is not or
		// vice versa (if key is not virtual & accel table entry is
		// not), we can skip checking the accel entry immediately.
		if ((cpaccelenum->key != (WORD) lpMsg->wParam) ||
			((fVirt != 0) != ((flags & FVIRTKEY) != 0)))
		{
			goto Next;
		}

		if (fVirt)
		{
			// If shift down & shift not requested in accelerator
			// table or if shift not down and shift not set,
			// we skip this table entry.
			if ((GetKeyState(VK_SHIFT) < 0) != ((flags & FSHIFT)
				!= 0))
			{
				goto Next;
			}

			// Likewise if control key down & control key not
			// set in accelerator table or if control not down
			// and it was set in the accelerator table, we skip
			// skip this entry in the table.
			if ((GetKeyState(VK_CONTROL) < 0) !=
				((flags & FCONTROL) != 0))
			{
				goto Next;
			}
	    	}

		// If the ALT key is down and the accel table flags do not
		// request the ALT flags or if the alt key is not down and
		// the ALT is requested, this item does not match.
		if ((GetKeyState(VK_MENU) < 0) != ((flags & FALT) != 0))
		{
			goto Next;
		}

		// We have gotten a match in the table. If there is a command,
		// we get it out of the table and record that we found
		// something.
		if (cmd = cpaccelenum->cmd)
		{
			fFound = TRUE;
		}

		goto errRtn;
		
Next:
		cpaccelenum.Next();

	} while (--cAccelEntries);
	
	
errRtn:
	// Common exit

	if (lpwCmd)
	{
		// If caller wants to get back the command that they
		// requested, we assign it at this point.
		*lpwCmd = cmd;
	}


	LEDebugOut((DEB_TRACE, "%p OUT IsAccelerator ( %lu )\n", NULL,
		fFound));

	// Return the result of the search.
	return fFound;
}


//+-------------------------------------------------------------------------
//
//  Function: 	IsMDIAccelerator
//
//  Synopsis: 	determines wither [lpMsg] is an accelerator for MDI window
//		commands
//
//  Effects:
//
//  Arguments:  [lpMsg]		-- the keystroke to look at
//		[lpCmd]		-- where to put the command ID
//
//  Requires:
//
//  Returns:    BOOL
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:	Make sure message is a key down message. Then make sure
//		that the control key is up or toggled and the ALT key is
//		down. Then if F4 is pressed set the system command to
//		close or if the F6 or tab keys are pressed send the
//		appropriate window switch message.
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port, fixed fall-through bug
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(IsMDIAccelerator)
BOOL IsMDIAccelerator(LPMSG lpMsg, WORD FAR* lpCmd)
{
	VDATEHEAP();

	BOOL fResult = FALSE;

	LEDebugOut((DEB_TRACE, "%p _IN IsMDIAccelerator ( %p , %p )\n",
		NULL, lpMsg, lpCmd));

	// This can be an accelerator only if this is some kind of key down.
	if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
	{
		goto IsMDIAccelerator_exit;
	}

	if (GetKeyState(VK_CONTROL) >= 0)
	{
		// All MIDI accelerators have the control key up (or toggled),
		// so we can exit here if it isn't down.
		goto IsMDIAccelerator_exit;
	}

	switch ((WORD)lpMsg->wParam)
	{
	case VK_F4:
		*lpCmd = SC_CLOSE;
                fResult = TRUE;
		break;		// this break was not in the 16bit code, but
				// it looks like it must be there (otherwise
				// this info is lost)
	case VK_F6:
	case VK_TAB:
                fResult = TRUE;

                *lpCmd = (GetKeyState(VK_SHIFT) < 0)
                    ? SC_PREVWINDOW : SC_NEXTWINDOW;

		break;
	}

IsMDIAccelerator_exit:

	LEDebugOut((DEB_TRACE, "%p OUT IsMDIAccelerator ( %lu ) [ %lu ] \n",
		NULL, fResult, *lpCmd));

	return fResult;
}

//+-------------------------------------------------------------------------
//
//  Function: 	FrameWndFilterProc
//
//  Synopsis: 	The callback proc for the container's frame window
//
//  Effects:
//
//  Arguments:  [hwnd]		-- the window handle
//		[msg]		-- the msg causing the notification
//		[uParam]	-- first param
//		[lParam]	-- second param
//
//  Requires:
//
//  Returns:    LRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  Gets the CFrame object (if available) and asks it
//		to deal with the window message
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(FrameWndFilterProc)
STDAPI_(LRESULT) FrameWndFilterProc (HWND hwnd, UINT msg, UINT uParam,
	LONG lParam)
{
	VDATEHEAP();

	PCFRAMEFILTER 	pFrameFilter;
	LRESULT		lresult;


	LEDebugOut((DEB_TRACE, "%p _IN FrameWndFilterProc ( %lx , %u ,"
		" %u , %ld )\n", NULL, hwnd, msg, uParam, lParam));

	if (!(pFrameFilter = (PCFRAMEFILTER) wGetFrameFilterPtr(hwnd)))
	{
		lresult = DefWindowProc(hwnd, msg, uParam, lParam);
	}
	else
	{
		// stabilize the frame filter
		CStabilize FFstabilize((CSafeRefCount *)pFrameFilter);
	
		if (msg == WM_SYSCOMMAND)
		{
			lresult = pFrameFilter->OnSysCommand(uParam,
					lParam);
		}
		else
		{
			lresult = pFrameFilter->OnMessage(msg, uParam,
					lParam);
		}
	}

	LEDebugOut((DEB_TRACE, "%p OUT FrameWndFilterProc ( %lu )\n",
		NULL, lresult));
		
	return lresult;	
}

//+-------------------------------------------------------------------------
//
//  Function: 	CFrameFilter::Create
//
//  Synopsis:   Allocates and initializes a CFrame object (which handles
//		all of the real processing work for event callbacks)
//
//  Effects:
//
//  Arguments:	[lpOleMenu]	-- pointer to the ole menu descriptor
//		[hmenuCombined]	-- the combined menu handle
//		[hwndFrame]	-- handle to the container's frame
//				   (where the CFrame should be installed)
//		[hwndActiveObj]	-- handle to the in-place object's window
//		[lpFrame]	-- pointer to the container's
//				   IOleInPlaceFrame implementation
//
//  Requires:
//
//  Returns:   	HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  Allocates the object and installs a pointer to it as
//		a property on the window
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_Create)
HRESULT CFrameFilter::Create(LPOLEMENU lpOleMenu, HMENU hmenuCombined,
	HWND hwndFrame,	HWND hwndActiveObj,
	LPOLEINPLACEFRAME lpFrame, LPOLEINPLACEACTIVEOBJECT lpActiveObj)
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::Create ( %lx , %p ,"
		" %lx , %lx , %p , %p )\n", NULL, lpOleMenu,
		hmenuCombined, hwndFrame, hwndActiveObj,
		lpFrame, lpActiveObj));

	CFrameFilter * pFF = new CFrameFilter(hwndFrame, hwndActiveObj);
	
	if (!pFF)
	{
		goto errRtn;
	}

	pFF->SafeAddRef();

	pFF->m_lpOleMenu = lpOleMenu;
	pFF->m_hmenuCombined = hmenuCombined;
	
	// If the following pointers are NON-NULL, it means that the container
	// wants us to use our message filter to deal with the F1 key. So,
	// remember the pointers.
								
	if (lpFrame && lpActiveObj)
	{
		// these addref's should not be outgoing calls, so
		// no need to stabilize around them.  (unless, of
		// course, the container made an outgoing call for
		// frame->AddRef, but that would be really weird).

		(pFF->m_lpFrame  = lpFrame)->AddRef();
		(pFF->m_lpObject = lpActiveObj)->AddRef();
	}	

	// Hook the frame wnd proc
	if (!(pFF->m_lpfnPrevWndProc = (WNDPROC) SetWindowLong (hwndFrame,
		GWL_WNDPROC, (LONG) FrameWndFilterProc)))
	{
		goto errRtn;
	}

#ifdef WIN32	
	if (!SetProp (hwndFrame, szPropFrameFilter, (HANDLE) pFF))
	{
		goto errRtn;
	}
#else
	if (!SetProp (hwndFrame, szPropFrameFilterH, HIWORD(pFF)))
	{
		goto errRtn;
	}

	if (!SetProp (hwndFrame, szPropFrameFilterL, LOWORD(pFF)))
	{
		goto errRtn;
	}
#endif

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::Create ( %lx )\n",
		NULL, NOERROR ));	
	return NOERROR;
	
errRtn:	
	if (pFF)
	{
		pFF->SafeRelease();
	}
	
	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::Create ( %lx )\n",
		NULL, ResultFromScode(E_OUTOFMEMORY)));

	return ResultFromScode(E_OUTOFMEMORY);
}


//+-------------------------------------------------------------------------
//
//  Member: 	CFrameFilter::CFrameFilter
//
//  Synopsis:   Constructor for the frame filter object
//
//  Effects:
//
//  Arguments:  [hwndFrame]	-- the container's frame
//		[hwndActiveObj]	-- the inplace object's window
//
//  Requires:
//
//  Returns:
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_ctor)
CFrameFilter::CFrameFilter (HWND hwndFrame, HWND hwndActiveObj)
{
	VDATEHEAP();

	m_hwndFrame		= hwndFrame;
	m_hwndObject		= hwndActiveObj;
	m_lpFrame		= NULL;
	m_lpObject		= NULL;
	m_lpfnPrevWndProc	= NULL;
	m_fObjectMenu		= FALSE;
	m_fCurItemPopup		= FALSE;
	m_fInMenuMode		= FALSE;
	m_fGotMenuCloseEvent	= FALSE;	
	m_uCurItemID		= NULL;
	m_cAltTab		= NULL;
	m_hwndFocusOnEnter  	= NULL;
	m_fDiscardWmCommand 	= FALSE;
	m_cmdId			= NULL;
	m_fRemovedWndProc	= FALSE;
}
		
//+-------------------------------------------------------------------------
//
//  Member:  	CFrameFileter::~CFrameFilter
//
//  Synopsis:   destroys the object
//
//  Effects:
//
//  Arguments: 	void
//
//  Requires:
//
//  Returns:
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_dtor)
CFrameFilter::~CFrameFilter(void)
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::~CFrameFilter ( )\n",
		this));
#ifdef WIN32
	RemoveProp (m_hwndFrame, szPropFrameFilter);
#else
	RemoveProp (m_hwndFrame, szPropFrameFilterH);
	RemoveProp (m_hwndFrame, szPropFrameFilterL);
#endif

	PrivMemFree(m_lpOleMenu);

	// remove the FrameWndFilterProc hook.  We do this *before*
	// the Releases since those releases may make outgoing calls
	// (we'd like to be in a 'safe' state).

 	// REVIEW32:  We may want to check to see if we're the current
	// window proc before blowing it away.  Some apps (like Word)
	// go ahead and blow away the wndproc by theselves without calling
	// OleSetMenuDescriptor(NULL);

	RemoveWndProc();

	if (m_lpFrame)
	{
		SafeReleaseAndNULL((IUnknown **)&m_lpFrame);
		SafeReleaseAndNULL((IUnknown **)&m_lpObject);
	}			



	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::~CFrameFilter ( )\n",
		this));
}

//+-------------------------------------------------------------------------
//
//  Member:	CFrameFilter::RemoveWndProc
//
//  Synopsis: 	un-installs our window proc for inplace-processing
//
//  Effects:
//
//  Arguments:
//
//  Requires:  	none
//
//  Returns: 	void
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//  		04-Aug-94 alexgo    author
//
//  Notes:
//
//--------------------------------------------------------------------------

void CFrameFilter::RemoveWndProc()
{
	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::RemoveWndProc ( )\n",
		this));

	if( m_fRemovedWndProc == FALSE)
	{
		m_fRemovedWndProc = TRUE;

		if (m_lpfnPrevWndProc)
		{
                    // If the sub-classing has already been removed, then don't
                    // bother to remove it again.  This only happens to be the case
                    // with Word 6 and inplace embeddings.  At some future date, we
                    // might want to make this for non-wow things to (just to be safe).
                    // Also note, that if somebody comes along later (after us) and sub-classes
                    // the window, we won't be able to remove ourselves so we just avoid it.
                    // Maybe this function should return a BOOL indicating this failure condition?
 
                    if (!InWow() ||
                        GetWindowLong(m_hwndFrame, GWL_WNDPROC) ==
                        (DWORD)FrameWndFilterProc)
                    {
			SetWindowLong (m_hwndFrame, GWL_WNDPROC,
				(LONG) m_lpfnPrevWndProc);
                    }
		}
	}

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::RemoveWndProc ( )\n",
		this));

}


//+-------------------------------------------------------------------------
//
//  Member:  	CFrameFilter::OnSysCommand
//
//  Synopsis:   Process system messages
//
//  Effects:
//
//  Arguments:  [uParam]	-- the first message argument
//		[lParam]	-- the second message argument
//
//  Requires: 	the 'this' pointer must have been stabilized before
//		calling this function.
//
//  Returns:    LRESULT
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:  big switch to deal with the different types of messages
//		see comments below
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes: 	FrameWndFilterProc currently does the work of stabilizing
//		the framefilter's 'this' pointer.
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_OnSysCommand)
LRESULT CFrameFilter::OnSysCommand(UINT uParam, LONG lParam)
{
	VDATEHEAP();

	UINT 	uParamTmp = (uParam & 0xFFF0);
	LRESULT	lresult;

	
	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnSysCommand ( %lu ,"
		" %ld )\n", this, uParam, lParam));

	// this lets the sending app continue processing
	if (InSendMessage())
	{
		ReplyMessage(NULL);
	}

	switch (uParamTmp)
	{
	case SC_KEYMENU:
	case SC_MOUSEMENU:
		OnEnterMenuMode();
		CallWindowProc((WNDPROC) m_lpfnPrevWndProc, m_hwndFrame,
				WM_SYSCOMMAND, uParam, lParam);

		// By this time menu processing would've been completed.
 				
		if (! m_fGotMenuCloseEvent)
		{		
			// Can happen if user cancelled menu mode when MDI
			// window's system menu is down. Hence generate
			// the message here
			
			SendMessage(m_hwndFrame, WM_MENUSELECT, 0,
				MAKELONG(-1,0));
		}
		
		// We can not set m_fObjectMenu to FALSE yet, 'cause we
		// could be recieving the WM_COMMAND (if a menu item is
		// selected), which gets posted by the windows' menu
		// processing code.
		// We will clear the flag when we get OM_CLEAR_MENU_STATE
		// message. Even if WM_COMMAND got generated, this message
		// will come after that
		PostMessage (m_hwndFrame, uOleMessage, OM_CLEAR_MENU_STATE,
			0L);
		OnExitMenuMode();
		lresult = 0L;
		goto errRtn;
		
	case SC_NEXTWINDOW:
	case SC_PREVWINDOW:
		
		OnEnterAltTabMode();
		lresult = CallWindowProc((WNDPROC)m_lpfnPrevWndProc,
				m_hwndFrame, WM_SYSCOMMAND, uParam, lParam);
		OnExitAltTabMode();
		
		goto errRtn;
		
	default:
		break;
	}	
		
	lresult = CallWindowProc((WNDPROC)m_lpfnPrevWndProc, m_hwndFrame,
					WM_SYSCOMMAND, uParam, lParam);

errRtn:
			
	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnSysCommand ( %lx )\n",
		this, lresult));
		
	return lresult;	
}

//+-------------------------------------------------------------------------
//
//  Member: 	CFrameFilter::OnEnterMenuMode
//
//  Synopsis:   called by the SysCommand processing, puts us into in
//		InMenuMode, sets the focus and installs our message filter
//		hook.
//
//  Effects:
//
//  Arguments:  void
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		23-Feb-94 alexgo    restored OLE32 in GetModuleHandle
//      31-Dec-93 erikgav   removed hardcoded "OLE2" in GetModuleHandle
//		07-Dec-93 alexgo    removed inlining
//		01-Dec-93 alexgo    32bit port
//
//  Notes: 	REVIEW32:  We may need to update this to reflect new
//		focus management policies.
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_OnEnterMenuMode)
void CFrameFilter::OnEnterMenuMode()
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnEnterMenuMode ( )\n",
		this ));

	if (m_fInMenuMode)
	{
		goto errRtn;
	}
	
	m_fInMenuMode = TRUE;
	m_fGotMenuCloseEvent = FALSE;
	m_hwndFocusOnEnter = SetFocus(m_hwndFrame);
	
	if (!m_lpFrame)
	{
		goto errRtn;
	}

	// REVIEW32:  hMsgHook is a static (formerly global) variable for
	// the whole dll.  This may cause problems on NT (with threads, etc)
	// (what happens if we haven't yet unhooked a previous call and
	// we get here again????)

    // BUGBUG: GetModuleHandle("OLE2") below -- DLL's are
    // named differently across platforms

	if (hMsgHook = (HHOOK) SetWindowsHookEx (WH_MSGFILTER,
		(HOOKPROC) MessageFilterProc,
		//GetModuleHandle(NULL),
		GetModuleHandle(TEXT("OLE32")),
		GetCurrentThreadId()))
	{
		pFrameFilter = this;
	}
	
errRtn:

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnEnterMenuMode ( )\n",
		this ));
							
}

//+-------------------------------------------------------------------------
//
//  Member: 	CFrameFilter::OnExitMenuMode
//
//  Synopsis:   takes us out of InMenuMode
//
//  Effects:
//
//  Arguments:  void
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:  Resets the focus and unhooks our callback function
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes:	REVIEW32:: see OnEnterMenuMode
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_OnExitMenuMode)
void CFrameFilter::OnExitMenuMode()				
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnExitMenuMode ( )\n",
		this));

	if (m_fInMenuMode)
	{
	
		m_fInMenuMode = FALSE;
		m_fGotMenuCloseEvent = TRUE;	
		m_uCurItemID = NULL;

		if (hMsgHook)
		{
			UnhookWindowsHookEx(hMsgHook);
			hMsgHook = NULL;
			pFrameFilter = NULL;
		}
	
		SetFocus(m_hwndFocusOnEnter);
		m_hwndFocusOnEnter = NULL;
	}

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnExitMenuMode ( )\n",
		this));
}

//+-------------------------------------------------------------------------
//
//  Member: 	CFrameFileter::OnEnterAltTabMode
//
//  Synopsis:   enters AltTab mode and sets the focus
//
//  Effects:
//
//  Arguments:  void
//
//  Requires:
//
//  Returns:
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm: 	
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes: 	REVIEW32:  we may need to modify to implement new
//		focus management policy
//
//--------------------------------------------------------------------------

void CFrameFilter::OnEnterAltTabMode(void)
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnEnterAltTabMode ( )\n",
		this ));

	if (m_cAltTab == NULL)
	{
		
		m_fInMenuMode = TRUE;
		// this will prevent SetFocus from getting
		// delegated to the object
		m_hwndFocusOnEnter = SetFocus(m_hwndFrame);
		m_fInMenuMode = FALSE;
	}
	
	m_cAltTab++;

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnEnterAltTabMode ( )\n",
		this ));
}

//+-------------------------------------------------------------------------
//
//  Member:  	CFrameFilter::OnExitAltTabMode
//
//  Synopsis: 	exits alt-tab mode and sets the focus
//
//  Effects:
//
//  Arguments:  void
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes:
//
//--------------------------------------------------------------------------

void CFrameFilter::OnExitAltTabMode()
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnExitAltTabMode ( )\n",
		this ));

	Assert(m_cAltTab != NULL);
	
	if (--m_cAltTab == 0)
	{
		// The m_hwndFocusOnEnter would've been set to NULL if we are
		// going to ALT-TAB out into some other process. In that case
		// we would have got WM_ACTIVATEAPP and/or WM_KILLFOCUS.
		if (m_hwndFocusOnEnter)
		{
			SetFocus(m_hwndFocusOnEnter);
			m_hwndFocusOnEnter = NULL;
		}
	}

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnExitAltTabMode ( )\n",
		this ));
}

//+-------------------------------------------------------------------------
//
//  Member:  	CFrameFilter::OnMessage
//
//  Synopsis:   Handles window message processing
//
//  Effects:
//
//  Arguments:  [msg]		-- the window message
//		[uParam]	-- the first argument
//		[lParam]	-- the second argument
//
//  Requires:
//
//  Returns:    LRESULT
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:  a big switch to deal with the different commands
//		see comments below
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_OnMessage)
LRESULT CFrameFilter::OnMessage(UINT msg, UINT uParam, LONG lParam)
{
	LRESULT		lresult;

	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnMessage ( %u , %u ,"
		" %ld )\n", this, msg, uParam, lParam));

	// We come to this routine only if the message is not WM_SYSCOMMAND
	
	switch (msg)
	{
	case WM_SETFOCUS:
		if (m_fInMenuMode)
		{
			lresult = DefWindowProc (m_hwndFrame, msg,
					uParam, lParam);
			goto errRtn;
		}
		break;
		
	case WM_MENUSELECT:
		if (m_fInMenuMode)
		{
#ifdef WIN32
            		HMENU   hmenu = (HMENU) lParam;
			UINT	fwMenu = HIWORD(uParam);

			// There is a subtle difference in the message between
			// Win16 & Win32 here. In Win16, the item is either
			// an item id or a menu handle for a pop up menu.
			// In Win32, the item is an item id or an offset
			// in a menu if it is a popup menu handle. To minimize
			// changes, we map this field as was appropriate for
			// Win16.
			UINT	uItem = (fwMenu & MF_POPUP)
			    ? (UINT) GetSubMenu(hmenu, (int) LOWORD(uParam))
			    : LOWORD(uParam);
#else
			HMENU	hmenu = (HMENU)HIWORD(lParam);
            		UINT    fwMenu = LOWORD(lParam);
            		UINT    uItem = uParam;
#endif

            		m_uCurItemID = uItem;
			m_fCurItemPopup = fwMenu & MF_POPUP;
				
			if (hmenu == 0 && fwMenu == 0xFFFF)
			{
				// end of menu processing

				// We can not set m_fObjectMenu to FALSE yet,
				// because we could be recieving the
				// WM_COMMAND (if a menu item is selected),
				// which is posted by the windows' menu
				// processing code, and will be recieved at
				// a later time.

				// There is no way to figure whether the user
				// has selected a menu (which implies that
				// WM_COMMAND is posted), or ESCaped out of
				// menu selection.
				
				// This problem is handled by posting a
				// message to ourselves to clear the flag.
				// See CFrameFilter::OnSysCommand() for
				// more details...
			
				m_fGotMenuCloseEvent = TRUE;
				SendMessage(m_hwndObject, msg, uParam, lParam);

			}
			else
			{
				if (fwMenu & MF_SYSMENU)
				{
					m_fObjectMenu = FALSE;
				// if it is top level menu, see whose
				// menu it is 	
				}
                                else if (IsHmenuEqual(hmenu, m_hmenuCombined))
				{
					// set m_fObjectMenu
					IsObjectMenu (uItem, fwMenu);
					
					// this flag must not be modified
				// when nested menus are selected.
				}	

				if (m_fObjectMenu)
				{
					lresult = SendMessage(m_hwndObject,
						msg, uParam, lParam);
					goto errRtn;
				}
			}
		}
		break;
	
	case WM_MEASUREITEM:
	case WM_DRAWITEM:
		if (m_fInMenuMode && m_fObjectMenu)
		{
			lresult = SendMessage(m_hwndObject, msg, uParam,
				lParam);
			goto errRtn;
		}
		break;

	case WM_ENTERIDLE:
		PostMessage(m_hwndObject, msg, uParam, lParam);
		break;

	case WM_INITMENU:

		m_fObjectMenu = FALSE;
		if (m_fInMenuMode
                    && IsHmenuEqual(m_hmenuCombined, (HMENU)uParam))
		{
			SendMessage(m_hwndObject, msg, uParam, lParam);
		}			
		break;
		
	case WM_INITMENUPOPUP:
		if (!m_fInMenuMode)
		{
			// Accelarator translation....
			
			if (! ((BOOL) HIWORD(lParam)))
			{
				// if not a system menu, see whether windows
				// generated WM_INITMENUPOPUP for object's
				// menu because of menu collision. If so
				// fix it and route it to container

				// menu collisions can occur with combined
				// menus (from object and container)
				if (IsMenuCollision(uParam, lParam))
				{
					lresult = 0L;
					goto errRtn;
				}
			}
		}
		
		if (m_fObjectMenu)
		{
			lresult = SendMessage(m_hwndObject, msg, uParam,
				lParam);
			goto errRtn;
		}
		
		break;
		
	case WM_SYSCHAR:
		if (InSendMessage())
		{
			ReplyMessage(NULL);
		}
		break;
		
	case WM_COMMAND:
		// End of menu processing or accelartor translation.
		// Check whether we should give the message to the object
		// or not.
		
		// If the LOWORD of lParam is NON-NULL, then the message
		// must be from a control, and the control must belong to
		// the container app.

		// REVIEW32:  what about app-specific commands with NULL
		// lParams???
		
		if (LOWORD(lParam) == 0)
		{
			m_cmdId = 0;
			
			if (m_fDiscardWmCommand)
			{
				m_fDiscardWmCommand = FALSE;
				lresult = 0L;
				goto errRtn;
			}	

			if (m_fObjectMenu)
			{
				m_fObjectMenu = FALSE;
				lresult = PostMessage(m_hwndObject, msg,
					uParam,lParam);
				goto errRtn;
			}
		}
		
		break;
	
	case WM_ACTIVATEAPP:
	case WM_KILLFOCUS:
		// If in ALT-TAB mode, we get these messages only if we are
		// going to ALT-TAB out in to some other task. In this case,
		// on exit from ALT-TAB mode we wouldn't want to set
		// focus back to the window that had the focus on
		// entering the ALT-TAB mode.
		
		if (m_cAltTab)
		{
			m_hwndFocusOnEnter = NULL;
		}
		break;
		
	default:
		if (msg == uOleMessage)
		{
			switch(uParam)
			{
			case OM_CLEAR_MENU_STATE:
				m_fObjectMenu = FALSE;
				break;
				
			case OM_COMMAND_ID:
				// this message is sent by
				// OleTranslateAccelerator, before it actually
				// calls the lpFrame->TranslateAccelerator
				// method.
				// We remember the command id here, later it
				// gets used if the container's calling of
				// TranslateAccelerator results in a
				// WM_INITMENUPOPUP for the object because
				// of command id collision. In that case we
				// scan the menu list to see whether there is
				// any container menu which has the same
				// command id, if so we generate
				// WM_INITMENUPOPUP for that menu.
				m_cmdId = LOWORD(lParam);
				break;
				
			default:	
				AssertSz(FALSE,
					"Unexpected OLE private message");
				break;
			}

			lresult = 0L;
			goto errRtn;
			
		}
		else if (m_fInMenuMode && (msg == uOmPostWmCommand))
		{
			// if the current selection is a popup menu then
			// return its menu handle else post the command
			// and return NULL.

			if (m_fCurItemPopup)
			{
				lresult = m_uCurItemID;
				goto errRtn;
			}

			if (m_fObjectMenu)
			{
				PostMessage (m_hwndObject, WM_COMMAND,
					m_uCurItemID, 0L);
			}
			else
			{
				PostMessage (m_hwndFrame, WM_COMMAND,
					m_uCurItemID, 0L);
			}

			m_fObjectMenu = FALSE;
			lresult = 0L;
			goto errRtn;
		}

		break;
	}
	
	lresult = CallWindowProc ((WNDPROC) m_lpfnPrevWndProc, m_hwndFrame,
			msg, uParam, lParam);

errRtn:

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnMessage ( %lu )\n",
		this, lresult));

	return lresult;
}

//+-------------------------------------------------------------------------
//
//  Member:  	CFrameFilter::IsObjectMenu
//
//  Synopsis: 	This gets called when WM_MENUSELECT is sent for a
// 		top level (either POPUP or normal) menu item.  Figures
//		out whether [uMenuItem]	really belongs to the in-place object
//
//  Effects:
//
//  Arguments:  [uMenuItem]	-- the menu in question
//		[fwMenu]	-- the menu type
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm: 	Searchs through our ole menu descriptor to find a match
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(CFrameFilter_IsObjectMenu)
void CFrameFilter::IsObjectMenu(UINT uMenuItem, UINT fwMenu)
{
	VDATEHEAP();
	int 		i,
			iMenuCnt;
	LPOLEMENUITEM 	lpMenuList;
	

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::IsObjectMenu ( %u , "
		"%u )\n", this, uMenuItem, fwMenu));

	if (m_hmenuCombined == NULL)
	{
		goto errRtn;
	}
	
	m_fObjectMenu = FALSE;

	lpMenuList = m_lpOleMenu->menuitem;
	iMenuCnt = (int) m_lpOleMenu->lMenuCnt;
	
	for (i = 0; i < iMenuCnt; i++)
	{
                // Are the types of the menus the same?
                if ((fwMenu & MF_POPUP) == lpMenuList[i].fwPopup)
                {
                    // Are we dealing with a menu handle?
                    if (fwMenu & MF_POPUP)
                    {
                        // See if windows handles are equal
                        if (IsHmenuEqual((HMENU) uMenuItem,
                            (HMENU)lpMenuList[i].item))
                        {
			    m_fObjectMenu = lpMenuList[i].fObjectMenu;
                            break;
                        }
                    }
                    // Are item handles equal?
                    else if (uMenuItem == lpMenuList[i].item)
                    {
			m_fObjectMenu = lpMenuList[i].fObjectMenu;
                        break;
                    }
		}
	}
	
errRtn:
	
	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::IsObjectMenu ( )\n",
		this ));
}

//+-------------------------------------------------------------------------
//
//  Member:  	CFrameFilter::IsMenuCollision
//
//  Synopsis:	Determines if we've had a menu collission. This gets called
// 		as a result of WM_INITMENUPOPUP during accelerator translation
//
//  Effects:
//
//  Arguments:	[uParam]	-- the first window message argument
//		[lParam]	-- the second argument
//
//  Requires:
//
//  Returns:    BOOL
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    changed Assert(hmenuPopup) to an if
//				    in merging with 16bit RC9 sources
//		07-Dec-93 alexgo    removed inlining
//
//  Notes:
//
//--------------------------------------------------------------------------

BOOL CFrameFilter::IsMenuCollision(UINT uParam, LONG lParam)
{
	BOOL fRet;
	int	 	iCntrMenu,
			iObjMenu,
			iMenuCnt;
	BOOL 		fGenerateWmCommand;
	HMENU		hmenuPopup;
	LPOLEMENUITEM	lpMenuList;

	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::IsMenuCollision ( %u ,"
		" %ld )\n", this, uParam, lParam ));

	if (m_hmenuCombined == NULL)
	{
		fRet = FALSE;
		goto errRtn;
	}

	if (m_lpOleMenu == NULL)
	{
		fRet = FALSE;
		goto errRtn;
	}

	hmenuPopup = (HMENU) uParam;
	iObjMenu = (int) LOWORD(lParam);

	lpMenuList = m_lpOleMenu->menuitem;
	iMenuCnt = (int) m_lpOleMenu->lMenuCnt;
	
	if (iObjMenu >= iMenuCnt)
	{
		fRet = FALSE;
		goto errRtn;
	}

	if( hmenuPopup != (HMENU)lpMenuList[iObjMenu].item )
	{
		// this could be the container's popmenu, not associated
		// with the frame
		fRet = FALSE;
		goto errRtn;
	}

	Assert(lpMenuList[iObjMenu].fwPopup);

	if (! lpMenuList[iObjMenu].fObjectMenu)
	{
		fRet = FALSE; // container's pop-up menu
		goto errRtn;
	}
	
	// Otherwise the popup menu belongs to the object. This can only
	// happen because of id collision. Start scanning the menus starting
	// from the next top level menu item to look for a match in
	// container's menus (while scanning skip object's menus)
		
	
	// It is possible that the colliding command id may not be associated
	// with any of the container's menus. In that case we must send
	// WM_COMMAND to  the container.
	
	fGenerateWmCommand = TRUE;
	m_fDiscardWmCommand = FALSE;	
	iCntrMenu = iObjMenu + 1;
	
	
	while (iCntrMenu < iMenuCnt)
	{
		if (! lpMenuList[iCntrMenu].fObjectMenu)
		{

			if (lpMenuList[iCntrMenu].fwPopup & MF_POPUP)
			{
				if (GetMenuState(
					(HMENU)lpMenuList[iCntrMenu].item,
					m_cmdId, MF_BYCOMMAND) != -1)
				{
					// We found match in the container's
					// menu list Generate WM_INITMENUPOPUP
					// for the corresponding popup
					CallWindowProc ((WNDPROC)
						m_lpfnPrevWndProc,
						m_hwndFrame, WM_INITMENUPOPUP,
						lpMenuList[iCntrMenu].item
						/*uParam*/,
						MAKELONG(iCntrMenu,
						HIWORD(lParam)));
								
					// We have sent WM_INITMENUPOPUP to
					// the container.
					// Now rechek the menu state. If
					// disabled or grayed then
					// don't generate WM_COMMAND
							
					if (GetMenuState((HMENU)
						lpMenuList[iCntrMenu].item,
						m_cmdId, MF_BYCOMMAND) &
						(MF_DISABLED | MF_GRAYED))
					{
						fGenerateWmCommand = FALSE;
					}		

					break;
				}
				
			}
			else
			{
				// top-level, non-popup container menu
				if (GetMenuItemID(m_lpOleMenu->hmenuCombined,
					iCntrMenu) == m_cmdId)
				{
					// No need to generate
					// WM_INITMENUPOPUP

					// Chek the menu state. If disabled or
					// grayed then don't generate
					// WM_COMMAND
					if (GetMenuState(
						m_lpOleMenu->hmenuCombined,
						m_cmdId, MF_BYCOMMAND) &
						(MF_DISABLED | MF_GRAYED))
					{
						fGenerateWmCommand = FALSE;
					}		
				
					break;
				}	
			}
		}
		
		iCntrMenu++;
	}

	// Check the object's colliding menu's status
	if (GetMenuState((HMENU)lpMenuList[iObjMenu].item, m_cmdId,
		MF_BYCOMMAND) & (MF_DISABLED | MF_GRAYED))
	{
		// Then windows is not going to genearte WM_COMMAND for the
		// object's  menu, so we will generate
		// the command and send it to the container
		
		if (fGenerateWmCommand)
		{
			CallWindowProc ((WNDPROC) m_lpfnPrevWndProc,
				m_hwndFrame, WM_COMMAND, m_cmdId,
				MAKELONG(0, 1)); /* not from control */
						 // & and as result of
						 // accelerator
			m_cmdId = NULL;
		}		
	}
	else
	{
	
		// Wait for WM_COMMAND generated by windows to come to our
		// frame filter wndproc which would have been sent to the
		// container anyway because we have not set the m_fObjectMenu
		// flag.
		//
		// But we need to throw it away if the container's menu
		// associated with the command is disabled or grayed
		
		if (! fGenerateWmCommand)
		{
			m_fDiscardWmCommand = TRUE;
		}
	}
	
	fRet = TRUE;

errRtn:

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::IsMenuCollision "
		"( %lu )\n", this, fRet));

	return fRet;
}

//+-------------------------------------------------------------------------
//
//  Member: 	CFrameFilter::DoContextSensitiveHelp
//
//  Synopsis:   Calls IOIPF->ContextSensitive help on both the container
//		and the object.
//
//  Effects:
//
//  Arguments:  void
//
//  Requires:
//
//  Returns: 	FALSE if we're in popup menu mode, TRUE otherwise
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//		07-Dec-93 alexgo    removed inlining
//
//  Notes:
//
//--------------------------------------------------------------------------
	
#pragma SEG(CFrameFilter_DoContextSensitiveHelp)
BOOL CFrameFilter::DoContextSensitiveHelp(void)
{
	VDATEHEAP();
	BOOL 		fRet;

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::DoContextSensitiveHelp"
		" ( )\n", this ));

	if (m_fCurItemPopup)
	{
		fRet = FALSE;
	}
	else
	{
		m_lpFrame->ContextSensitiveHelp(TRUE);	
		m_lpObject->ContextSensitiveHelp (TRUE);
		PostMessage (m_hwndFrame, WM_COMMAND, m_uCurItemID, 0L);
		fRet = TRUE;
	}

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::DoContextSensitiveHelp"
		" ( %lu )\n", this, fRet));

	return fRet;
}

//+-------------------------------------------------------------------------
//
//  Member: 	CFrameFilter::GetActiveObject
//
//  Synopsis:   Returns the IOleInplaceActiveObject interface pointer
//
//  Effects:
//
//  Arguments:  lplpOIAO
//
//  Requires:
//
//  Returns: 	NOERROR or E_INVALIDARG
//
//  Signals:
//
//  Modifies:
//
//  Derivation:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		28-Jul-94 bobday    created for WinWord hack
//
//  Notes:
//
//--------------------------------------------------------------------------
	
#pragma SEG(CFrameFilter_GetActiveObject)
STDMETHODIMP CFrameFilter::GetActiveObject( LPOLEINPLACEACTIVEOBJECT *lplpOIAO)
{
	VDATEHEAP();

	LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::GetActiveObject"
		" ( %p )\n", this, lplpOIAO ));

	VDATEPTROUT( lplpOIAO, LPOLEINPLACEACTIVEOBJECT);

        *lplpOIAO = m_lpObject;

        if ( m_lpObject )
        {
            m_lpObject->AddRef();
        }

	LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::GetActiveObject"
		" ( %lx ) [ %p ]\n", this, NOERROR , *lplpOIAO ));

	return NOERROR;
}

//+-------------------------------------------------------------------------
//
//  Function: 	wGetFrameFilterPtr
//
//  Synopsis:   Gets the CFrame object from the window
//
//  Effects:
//
//  Arguments:  [hwndFrame]	-- the window to get the CFrame object from
//
//  Requires:
//
//  Returns:    pointer to the frame filter
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


inline PCFRAMEFILTER wGetFrameFilterPtr(HWND hwndFrame)
{
	VDATEHEAP();

#ifdef WIN32

	return (PCFRAMEFILTER) GetProp (hwndFrame, szPropFrameFilter);
#else	
	WORD 	hiword;
	WORD 	loword;

	if (!(hiword = GetProp (hwndFrame, szPropFrameFilterH)))
	{
		return NULL;
	}
		
	loword = GetProp (hwndFrame, szPropFrameFilterL);

	return (PCFRAMEFILTER) (MAKELONG(loword, hiword));
#endif			
}

//+-------------------------------------------------------------------------
//
//  Function: 	wGetOleMenuPtr
//
//  Synopsis:   Locks a handle to an ole menu and returns the pointer
//		(after some error checking)
//
//  Effects:
//
//  Arguments:  [holemenu]
//
//  Requires:
//
//  Returns:    pointer to the ole menu
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

LPOLEMENU wGetOleMenuPtr(HOLEMENU holemenu)
{
	VDATEHEAP();

	LPOLEMENU 	lpOleMenu;
	
	if (! (holemenu &&
		(lpOleMenu = (LPOLEMENU) GlobalLock((HGLOBAL) holemenu))))
	{
		return NULL;
	}
		
	if (lpOleMenu->wSignature != wSignature)
	{
		AssertSz(FALSE, "Error - handle is not a HOLEMENU");
		GlobalUnlock((HGLOBAL) holemenu);
		return NULL;
	}
	
	return lpOleMenu;
}	

//+-------------------------------------------------------------------------
//
//  Function: 	wReleaseOleMenuPtr
//
//  Synopsis:   calls GlobalUnlock
//
//  Effects:
//
//  Arguments:  [holemenu]	-- handle to the ole menu
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

inline void	wReleaseOleMenuPtr(HOLEMENU holemenu)
{
	VDATEHEAP();

	GlobalUnlock((HGLOBAL) holemenu);
}

//+-------------------------------------------------------------------------
//
//  Function: 	MessageFilterProc
//
//  Synopsis: 	The message filter installed when entering menu mode;
//		handles context sensitive help
//
//  Effects:
//
//  Arguments:  [nCode]		-- hook code
//		[wParam]	-- first arg
//		[lParam]	-- second arg
//
//  Requires:
//
//  Returns:    LRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		01-Dec-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(MessageFilterProc)
STDAPI_(LRESULT) MessageFilterProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	VDATEHEAP();
	LRESULT		lresult;
	LPMSG		lpMsg = (LPMSG) lParam;


	LEDebugOut((DEB_TRACE, "%p _IN MessageFilterProc ( %d , %ld , %lu )\n",
		NULL, nCode, (LONG)wParam, lParam));
			
	// If it is not the F1 key then let the message (wihtout modification)
	// go to the next proc in the hook/filter chain.
	
	if (lpMsg && lpMsg->message == WM_KEYDOWN
		&& lpMsg->wParam == VK_F1 && pFrameFilter)
	{
		if (pFrameFilter->DoContextSensitiveHelp())
		{
			// Change message value to be WM_CANCELMODE and then
			// call the next hook. When the windows USER.EXE's
			// menu processing code sees this message it will
			// bring down menu state and come out of its
			// menu processing loop.
		
			lpMsg->message = WM_CANCELMODE;
			lpMsg->wParam  = NULL;
			lpMsg->lParam  = NULL;
		}
		else
		{
			lresult = TRUE;  // otherwise throw away this message.
			goto errRtn;
		}
	}	

	lresult = CallNextHookEx (hMsgHook, nCode, wParam, lParam);

errRtn:
	LEDebugOut((DEB_TRACE, "%p OUT MessageFilterProc ( %ld )\n", NULL,
		lresult));

	return lresult;
}

// MAC stuff below here
#else

#pragma SEG(OleCreateMenuDescriptor)
STDAPI_(HOLEMENU) OleCreateMenuDescriptor
	(HMENU hmenuCombined,	LPOLEMENUGROUPWIDTHS lplMenuWidths)
{
	VDATEHEAP();

	return NULL;
}

#pragma SEG(OleSetMenuDescriptor)
STDAPI OleSetMenuDescriptor
	HOLEMENU					holemenu,
	HWND						hwndFrame,
	HWND						hwndObject,
	LPOLEINPLACEFRAME			lpFrame,
	LPOLEINPLACEACTIVEOBJECT	lpObject
{
	VDATEHEAP();

	return ReportResult(0, E_NOTIMPL, 0, 0);
}

#pragma SEG(OleDestroyMenuDescriptor)
		
STDAPI_(void) OleDestroyMenuDescriptor (HOLEMENU holemenu)
{
	VDATEHEAP();


}

#pragma SEG(OleTranslateAccelerator)
STDAPI OleTranslateAccelerator
   (LPOLEINPLACEFRAME lpFrame, LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpMsg)
{
	VDATEHEAP();

	return ReportResult(0, S_FALSE, 0, 0);
}

#endif // !_MAC
