windows-nt/Source/XPSP1/NT/com/ole32/ole232/inplace/inplace.cpp
2020-09-26 16:20:57 +08:00

2880 lines
75 KiB
C++

//+-------------------------------------------------------------------------
//
// 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)
#include "inplace.h"
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
#ifdef WIN32
// we'd be faster if we used an atom instead of a string!
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)
{
#ifdef _WIN64
//
// Sundown v-thief ( in accordance with Jerry Shea's feedback ):
//
// At this time - 07/98 - all the bits of the HMENUs have to be equal
//
return hmenu1 == hmenu2;
#else // !_WIN64
if (HIWORD(hmenu1) == 0 || HIWORD(hmenu2) == 0)
{
return LOWORD(hmenu1) == LOWORD(hmenu2);
}
else
{
return hmenu1 == hmenu2;
}
#endif // !_WIN64
}
//+-------------------------------------------------------------------------
//
// 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);
inline ~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)
{
OLETRACEIN((API_OleCreateMenuDescriptor, PARAMFMT("hmenuCombined= %h, lplMenuWidths= %tw"),
hmenuCombined, 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_LABEL( lplMenuWidths, OLEMENUGROUPWIDTHS,
(HOLEMENU)NULL, errRtn, hOleMenu );
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 = PtrToUlong(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 = PtrToUlong(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));
OLETRACEOUTEX((API_OleCreateMenuDescriptor, RETURNFMT("%h"), 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
)
{
OLETRACEIN((API_OleSetMenuDescriptor,
PARAMFMT("holemenu= %h, hwndFrame= %h, hwndObject= %h, lpFrame= %p, lpObject= %p"),
holemenu, hwndFrame, hwndObject, lpFrame, 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_LABEL(lpFrame, errRtn, error);
VDATEIFACE_LABEL(lpObject, errRtn, error);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IOleInPlaceFrame,
(IUnknown **)&lpFrame);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IOleInPlaceActiveObject,
(IUnknown **)&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 = (DWORD) 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))
{
// be sure to remove our window proc hook
pFrameFilter->RemoveWndProc();
pFrameFilter->SafeRelease();
}
// Add a new frame filter
if (holemenu)
{
error = CFrameFilter::Create (lpOleMenuCopy,
(HMENU)UlongToPtr(lpOleMenu->hmenuCombined),
hwndFrame,
hwndObject,
lpFrame,
lpObject);
if (FAILED(error))
{
PrivMemFree(lpOleMenuCopy);
}
wReleaseOleMenuPtr(holemenu);
}
errRtn:
LEDebugOut((DEB_TRACE, "%p OUT OleSetMenuDescriptor ( %lx )\n",
NULL, error ));
OLETRACEOUT((API_OleSetMenuDescriptor, 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)
{
OLETRACEIN((API_OleDestroyMenuDescriptor, PARAMFMT("holemenu= %h"), 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));
OLETRACEOUT((API_OleDestroyMenuDescriptor, 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)
{
OLETRACEIN((API_OleTranslateAccelerator,
PARAMFMT("lpFrame= %p, lpFrameInfo= %to, lpMsg= %tm"),
lpFrame, lpFrameInfo, lpMsg));
VDATEHEAP();
WORD cmd;
BOOL fFound;
HRESULT error;
LEDebugOut((DEB_TRACE, "%p _IN OleTranslateAccelerator ( %p , %p "
", %p )\n", NULL, lpFrame, lpFrameInfo, lpMsg));
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IOleInPlaceFrame,
(IUnknown **)&lpFrame);
// 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.
SSSendMessage(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.
// This is the original support as it appeared in
// the 16-bit version of OLE and the first 32-bit
// release. To fix the problem, remove the comment
// tags from the else case below and comment the
// code out in the _DEBUG #ifdef below. This new
// code will walk back up through the objects
// parent windows until a window is found that
// contains a system menu, at which point the
// message is sent.
if (lpMsg->wParam != OLESTR('-'))
{
SSSendMessage(lpFrameInfo->hwndFrame,
lpMsg->message,
lpMsg->wParam, lpMsg->lParam);
}
// else
// {
// HWND hWndCurrent = lpMsg->hwnd;
//
// while ( hWndCurrent &&
// !(GetWindowLong(hWndCurrent, GWL_STYLE) & WS_SYSMENU))
// {
// hWndCurrent = GetParent(hWndCurrent);
// }
//
// if (hWndCurrent)
// {
// SSSendMessage(hWndCurrent,
// 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));
OLETRACEOUT((API_OleTranslateAccelerator, 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)
{
OLETRACEIN((API_IsAccelerator,
PARAMFMT("hAccel= %h, cAccelEntries= %d, lpMsg= %tm, lpwCmd= %p"),
hAccel, cAccelEntries, lpMsg, 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.
// we get the command out of the table and record that we found
// something.
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));
OLETRACEOUTEX((API_IsAccelerator, RETURNFMT("%B"), 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, WPARAM uParam, LPARAM lParam)
{
VDATEHEAP();
PCFRAMEFILTER pFrameFilter;
LRESULT lresult;
LEDebugOut((DEB_TRACE, "%p _IN FrameWndFilterProc ( 0x%p , %u ,"
" %u , %ld )\n", NULL, hwnd, msg, PtrToUlong((void*)uParam), PtrToLong((void*)lParam)));
if (!(pFrameFilter = (PCFRAMEFILTER) wGetFrameFilterPtr(hwnd)))
{
lresult = SSDefWindowProc(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, PtrToUlong((void*)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) SetWindowLongPtr (hwndFrame,
GWLP_WNDPROC, (LONG_PTR) 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) :
CSafeRefCount(NULL)
{
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;
#ifdef _CHICAGO_
m_fInNCACTIVATE = FALSE;
#endif
}
//+-------------------------------------------------------------------------
//
// 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));
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 != NULL)
{
// OleUnInitialize could have been called.
// In such case we do not want to call releas
// on OLeObject.
COleTls tls;
if(tls->cOleInits > 0)
{
SafeReleaseAndNULL((IUnknown **)&m_lpFrame);
SafeReleaseAndNULL((IUnknown **)&m_lpObject);
}
else
{
m_lpObject = NULL;
m_lpFrame = NULL;
}
}
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 happens
// to be the case with Word 6 and inplace embeddings.
// and Word95 with SnapGraphics.
// 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.
if (GetWindowLongPtr(m_hwndFrame, GWLP_WNDPROC) ==
(LONG_PTR)FrameWndFilterProc)
{
SetWindowLongPtr (m_hwndFrame, GWLP_WNDPROC,
(LONG_PTR) m_lpfnPrevWndProc);
}
// We remove the window property at the
// same time as the sub-classing since
// the window property is the flag as to
// whether we are doing sub-classing. The
// problem this solves is that what if
// OleSetMenuDescriptor is called while we
// have the menu subclassed? We won't remove
// this property until the outer most sub
// classing is exited which if we are setting
// a new sub-class will remove the new
// sub-class' window property. Therefore, it
// will look like the window is not sub-classed
// at all.
#ifdef WIN32
HANDLE h = RemoveProp (m_hwndFrame, szPropFrameFilter);
// We must not free 'h'. It's not a real handle.
#else
RemoveProp (m_hwndFrame, szPropFrameFilterH);
RemoveProp (m_hwndFrame, szPropFrameFilterL);
#endif
}
}
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(WPARAM uParam, LPARAM lParam)
{
VDATEHEAP();
UINT uParamTmp = ((UINT)uParam & 0xFFF0);
LRESULT lresult;
LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnSysCommand ( %lu ,"
" %ld )\n", this, PtrToUlong((void*)uParam), PtrToLong((void*)lParam)));
// this lets the sending app continue processing
if (SSInSendMessage())
{
SSReplyMessage(NULL);
}
switch (uParamTmp)
{
case SC_KEYMENU:
case SC_MOUSEMENU:
OnEnterMenuMode();
SSCallWindowProc((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
SSSendMessage(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 = SSCallWindowProc((WNDPROC)m_lpfnPrevWndProc,
m_hwndFrame, WM_SYSCOMMAND, uParam, lParam);
OnExitAltTabMode();
goto errRtn;
default:
break;
}
lresult = SSCallWindowProc((WNDPROC)m_lpfnPrevWndProc, m_hwndFrame,
WM_SYSCOMMAND, uParam, lParam);
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CFrameFilter::OnSysCommand ( %lx )\n",
this, PtrToLong((void*)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????)
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, WPARAM uParam, LPARAM lParam)
{
VDATEHEAP();
LRESULT lresult;
LEDebugOut((DEB_ITRACE, "%p _IN CFrameFilter::OnMessage ( %u , %u ,"
" %ld )\n", this, msg, PtrToUlong((void*)uParam),
PtrToLong((void*)lParam)));
// We come to this routine only if the message is not WM_SYSCOMMAND
switch (msg)
{
case WM_SETFOCUS:
if (m_fInMenuMode)
{
lresult = SSDefWindowProc (m_hwndFrame, msg, uParam, lParam);
goto errRtn;
}
break;
case WM_MENUSELECT:
if (m_fInMenuMode)
{
#ifdef WIN32
HMENU hmenu = (HMENU) lParam;
UINT fwMenu = HIWORD(uParam);
UINT uItem = 0;
// 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.
if ( (fwMenu & MF_POPUP) &&
(hmenu != 0) )
{
uItem = (UINT) PtrToUlong(GetSubMenu(hmenu, (int) LOWORD(uParam)));
}
else {
uItem = LOWORD(uParam);
}
#ifdef _CHICAGO_
if (!uItem) {
uItem = LOWORD(uParam);
}
#endif // _CHICAGO_
#else // !WIN32
HMENU hmenu = (HMENU)HIWORD(lParam);
UINT fwMenu = LOWORD(lParam);
UINT uItem = uParam;
#endif // else !WIN32
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;
SSSendMessage(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 = SSSendMessage(m_hwndObject, msg, uParam, lParam);
goto errRtn;
}
} // else
} // if (m_fInMenuMode)
break; // WM_MENUSELECT
case WM_MEASUREITEM:
case WM_DRAWITEM:
if (m_fInMenuMode && m_fObjectMenu)
{
lresult = SSSendMessage(m_hwndObject, msg, uParam, lParam);
goto errRtn;
}
break;
case WM_ENTERIDLE:
{
WCHAR wstr[10];
// We need to post this message if the server is
// SnapGraphics. See bug #18576.
GetClassName(m_hwndObject, wstr, 10);
if (0 == lstrcmpW(OLESTR("MGX:SNAP2"), wstr))
{
PostMessage(m_hwndObject, msg, uParam, lParam);
}
else
{
SSSendMessage(m_hwndObject, msg, uParam, lParam);
}
}
break;
case WM_INITMENU:
m_fObjectMenu = FALSE;
if (m_fInMenuMode && IsHmenuEqual(m_hmenuCombined, (HMENU)uParam))
{
SSSendMessage(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 = SSSendMessage(m_hwndObject, msg, uParam, lParam);
goto errRtn;
}
break;
case WM_SYSCHAR:
if (SSInSendMessage())
{
SSReplyMessage(NULL);
}
break;
#ifdef _CHICAGO_
case WM_NCACTIVATE:
//Note: On chicago with new rpc WM_NCACTIVATE gets dispatched
// recursively until stack overflow.
// Needs to be reviewed. (OS problem)
// See bug 25313, 25490, 25549
if (m_fInNCACTIVATE)
{
goto errRtn;
}
m_fInNCACTIVATE = TRUE;
break;
#endif // _CHICAGO_
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;
} // switch
lresult = 0L;
goto errRtn;
} // if (msg == uOleMessage)
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;
}
HWND hwnd;
hwnd = m_hwndFrame;
if (m_fObjectMenu)
{
hwnd = m_hwndObject;
}
PostMessage (hwnd, WM_COMMAND, m_uCurItemID, 0L);
m_fObjectMenu = FALSE;
lresult = 0L;
goto errRtn;
} // else if
break; // default
} // switch
lresult = SSCallWindowProc ((WNDPROC) m_lpfnPrevWndProc, m_hwndFrame,
msg, uParam, lParam);
errRtn:
#ifdef _CHICAGO_
m_fInNCACTIVATE = FALSE;
#endif
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)
{
HMENU hmenuMenuListItem = (HMENU)UlongToPtr(lpMenuList[i].item);
// Are we dealing with a menu handle?
if (fwMenu & MF_POPUP)
{
// See if windows handles are equal
if (IsHmenuEqual((HMENU)IntToPtr(uMenuItem),
hmenuMenuListItem))
{
m_fObjectMenu = lpMenuList[i].fObjectMenu;
break;
}
}
// Are item handles equal?
else if (uMenuItem == lpMenuList[i].item)
{
m_fObjectMenu = lpMenuList[i].fObjectMenu;
// If the menu isn't hilited, another menu with a duplicate
// menu ID must have been selected. The duplicate menu was
// probably created by the other application.
if (!(GetMenuState(m_hmenuCombined, uMenuItem, MF_BYCOMMAND)
& MF_HILITE))
{
m_fObjectMenu = !m_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(WPARAM uParam, LPARAM 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)UlongToPtr(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)
{
HMENU hmenuListItem = (HMENU)UlongToPtr(lpMenuList[iCntrMenu].item);
if (GetMenuState(hmenuListItem, m_cmdId, MF_BYCOMMAND) != -1)
{
// We found match in the container's
// menu list Generate WM_INITMENUPOPUP
// for the corresponding popup
SSCallWindowProc ((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(hmenuListItem, m_cmdId, MF_BYCOMMAND) &
(MF_DISABLED | MF_GRAYED))
{
fGenerateWmCommand = FALSE;
}
break;
}
}
else
{
// top-level, non-popup container menu
HMENU hmenuCombined = (HMENU)UlongToPtr(m_lpOleMenu->hmenuCombined);
if (GetMenuItemID(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(hmenuCombined, m_cmdId, MF_BYCOMMAND) &
(MF_DISABLED | MF_GRAYED))
{
fGenerateWmCommand = FALSE;
}
break;
}
}
}
iCntrMenu++;
}
// Check the object's colliding menu's status
if (GetMenuState((HMENU)UlongToPtr(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)
{
SSCallWindowProc ((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;
}