//+------------------------------------------------------------------------- // // 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 #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; }