// Copyright (c) 1996-1999 Microsoft Corporation // -------------------------------------------------------------------------- // // WINDOW.CPP // // Window class. // // -------------------------------------------------------------------------- #include "oleacc_p.h" #include "default.h" #include "classmap.h" #include "ctors.h" #include "client.h" #include "window.h" #pragma warning( disable : 4005 ) // macro redefinition #define COMPILE_MULTIMON_STUBS #include "multimon.h" #pragma warning( default : 4005 ) #define MaskBit(n) (1 << (n)) #define IndexFromNavDir(navdir) (navdir - NAVDIR_UP) // Remember, these are negative! #define OBJID_WINDOW_FIRST OBJID_SIZEGRIP #define OBJID_WINDOW_LAST OBJID_SYSMENU typedef struct tagNAVIGATE { long NavPeer[4]; } NAVIGATE; #ifndef CCHILDREN_FRAME #define CCHILDREN_FRAME 7 #endif // Order is Up, Down, Left, Right NAVIGATE rgFrameNavigate[CCHILDREN_FRAME] = { // System menu { 0, IndexFromObjid(OBJID_MENU), 0, IndexFromObjid(OBJID_TITLEBAR) }, // Title bar { 0, IndexFromObjid(OBJID_MENU), IndexFromObjid(OBJID_SYSMENU), 0 }, // Menu bar { IndexFromObjid(OBJID_TITLEBAR), IndexFromObjid(OBJID_CLIENT), 0, 0 }, // Client { IndexFromObjid(OBJID_MENU), IndexFromObjid(OBJID_HSCROLL), 0, IndexFromObjid(OBJID_VSCROLL) }, // Vertical scrollbar { IndexFromObjid(OBJID_MENU), IndexFromObjid(OBJID_SIZEGRIP), IndexFromObjid(OBJID_CLIENT), 0 }, // Horizontal scrollbar { IndexFromObjid(OBJID_CLIENT), 0, 0, IndexFromObjid(OBJID_SIZEGRIP) }, // Size grip { IndexFromObjid(OBJID_VSCROLL), 0, IndexFromObjid(OBJID_HSCROLL), 0 } }; // -------------------------------------------------------------------------- // // CreateWindowObject() // // External function for CreateDefault... // // -------------------------------------------------------------------------- HRESULT CreateWindowObject(HWND hwnd, long idObject, REFIID riid, void** ppvWindow) { UNUSED(idObject); InitPv(ppvWindow); if (!IsWindow(hwnd)) return(E_FAIL); // Look for (and create) a suitable proxy/handler if one // exists. Use CreateWindowThing as default if none found. // (TRUE => use window, as opposed to client, classes) return FindAndCreateWindowClass( hwnd, TRUE, CLASS_WindowObject, OBJID_WINDOW, 0, riid, ppvWindow ); } // -------------------------------------------------------------------------- // // CreateWindowThing() // // Private function that uses atom type to decide what class of window // this is. If there is a private create function, uses that one. Else // uses generic window frame handler. // // -------------------------------------------------------------------------- HRESULT CreateWindowThing(HWND hwnd, long idChildCur, REFIID riid, void** ppvWindow) { CWindow * pwindow; HRESULT hr; InitPv(ppvWindow); pwindow = new CWindow(); if (!pwindow) return(E_OUTOFMEMORY); // Can't be in the constructor--derived classes can't call the init // code if so. pwindow->Initialize(hwnd, idChildCur); hr = pwindow->QueryInterface(riid, ppvWindow); if (!SUCCEEDED(hr)) delete pwindow; return(hr); } // -------------------------------------------------------------------------- // // CWindow::Initialize() // // -------------------------------------------------------------------------- void CWindow::Initialize(HWND hwnd, LONG iChild) { m_hwnd = hwnd; m_cChildren = CCHILDREN_FRAME; m_idChildCur = iChild; } // -------------------------------------------------------------------------- // // CWindow::ValidateChild() // // The window children are the OBJID_s of the elements that compose the // frame. These are NEGATIVE values. Hence we override the validation. // // -------------------------------------------------------------------------- BOOL CWindow::ValidateChild(VARIANT* pvar) { // // This validates a VARIANT parameter and translates missing/empty // params. // TryAgain: // Missing parameter, a la VBA switch (pvar->vt) { case VT_VARIANT | VT_BYREF: VariantCopy(pvar, pvar->pvarVal); goto TryAgain; case VT_ERROR: if (pvar->scode != DISP_E_PARAMNOTFOUND) return(FALSE); // FALL THRU case VT_EMPTY: pvar->vt = VT_I4; pvar->lVal = 0; break; // remove this! VT_I2 is not valid!! #ifdef VT_I2_IS_VALID // it isn't now... case VT_I2: pvar->vt = VT_I4; pvar->lVal = (long)pvar->iVal; // FALL THROUGH #endif case VT_I4: if ((pvar->lVal > 0) || (pvar->lVal < (long)OBJID_WINDOW_FIRST)) return(FALSE); break; default: return(FALSE); } return(TRUE); } // -------------------------------------------------------------------------- // // CWindow::get_accParent() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accParent(IDispatch ** ppdispParent) { HWND hwndParent; InitPv(ppdispParent); hwndParent = MyGetAncestor(m_hwnd, GA_PARENT); if (! hwndParent) return(S_FALSE); return(AccessibleObjectFromWindow(hwndParent, OBJID_CLIENT, IID_IDispatch, (void **)ppdispParent)); } // -------------------------------------------------------------------------- // // CWindow::get_accChild() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accChild(VARIANT varChild, IDispatch ** ppdispChild) { InitPv(ppdispChild); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IDispatch, (void**)ppdispChild)); } // -------------------------------------------------------------------------- // // CWindow::get_accName() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accName(VARIANT varChild, BSTR* pszName) { IAccessible * poleacc; HRESULT hr; InitPv(pszName); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); // // If the caller want's our name, forward to the client object // if (varChild.lVal == CHILDID_SELF) varChild.lVal = OBJID_CLIENT; // // Get the name of our child frame object. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); varChild.lVal = CHILDID_SELF; hr = poleacc->get_accName(varChild, pszName); poleacc->Release(); return(hr); } // -------------------------------------------------------------------------- // // CWindow::get_accDescription() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accDescription(VARIANT varChild, BSTR* pszDesc) { InitPv(pszDesc); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); if (varChild.lVal == CHILDID_SELF) { return(S_FALSE); } else { IAccessible * poleacc; HRESULT hr; // // Get the description of our child frame object. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); if (!poleacc) return(S_FALSE); varChild.lVal = CHILDID_SELF; hr = poleacc->get_accDescription(varChild, pszDesc); poleacc->Release(); return(hr); } } // -------------------------------------------------------------------------- // // CWindow::get_accHelp() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accHelp(VARIANT varChild, BSTR* pszHelp) { InitPv(pszHelp); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); if (varChild.lVal == CHILDID_SELF) return(E_NOT_APPLICABLE); else { IAccessible * poleacc; HRESULT hr; // // Get the help for our child frame object. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); if (!poleacc) return(S_FALSE); varChild.lVal = CHILDID_SELF; hr = poleacc->get_accHelp(varChild, pszHelp); poleacc->Release(); return(hr); } } // -------------------------------------------------------------------------- // // CWindow::get_accRole() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accRole(VARIANT varChild, VARIANT* pvarRole) { InitPvar(pvarRole); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); if (varChild.lVal == CHILDID_SELF) { // // Fill in our role. // pvarRole->vt = VT_I4; pvarRole->lVal = ROLE_SYSTEM_WINDOW; } else { IAccessible * poleacc; HRESULT hr; // // Get the role of our child frame object. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); if (!poleacc) return(S_FALSE); varChild.lVal = CHILDID_SELF; hr = poleacc->get_accRole(varChild, pvarRole); poleacc->Release(); return(hr); } return(S_OK); } // -------------------------------------------------------------------------- // // CWindow::get_accState() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accState(VARIANT varChild, VARIANT* pvarState) { HWND hwndParent; InitPvar(pvarState); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); pvarState->vt = VT_I4; pvarState->lVal = 0; if (varChild.lVal == CHILDID_SELF) { // // Get our state. // WINDOWINFO wi; RECT rcParent; if (! MyGetWindowInfo(m_hwnd, &wi)) { pvarState->lVal |= STATE_SYSTEM_INVISIBLE; return(S_OK); } if (!(wi.dwStyle & WS_VISIBLE)) pvarState->lVal |= STATE_SYSTEM_INVISIBLE; if (wi.dwStyle & WS_DISABLED) pvarState->lVal |= STATE_SYSTEM_UNAVAILABLE; if (wi.dwStyle & WS_THICKFRAME) pvarState->lVal |= STATE_SYSTEM_SIZEABLE; if ((wi.dwStyle & WS_CAPTION) == WS_CAPTION) { pvarState->lVal |= STATE_SYSTEM_MOVEABLE; pvarState->lVal |= STATE_SYSTEM_FOCUSABLE; } // Windows are not selectable, so they shouldn't be selected either. #if 0 if (wi.dwWindowStatus & WS_ACTIVECAPTION) pvarState->lVal |= STATE_SYSTEM_SELECTED; #endif if (MyGetFocus() == m_hwnd) pvarState->lVal |= STATE_SYSTEM_FOCUSED; if (GetForegroundWindow() == MyGetAncestor(m_hwnd, GA_ROOT)) pvarState->lVal |= STATE_SYSTEM_FOCUSABLE; // This is the _real_ parent window. if (hwndParent = MyGetAncestor(m_hwnd, GA_PARENT)) { MyGetRect(hwndParent, &rcParent, FALSE); MapWindowPoints(hwndParent, NULL, (LPPOINT)&rcParent, 2); if ( hwndParent == GetDesktopWindow() ) { if ( MonitorFromRect( &wi.rcWindow, MONITOR_DEFAULTTONULL ) == NULL ) pvarState->lVal |= STATE_SYSTEM_INVISIBLE; } else { if ( Rect1IsOutsideRect2( wi.rcWindow, rcParent ) ) { pvarState->lVal |= STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN; } } } } else { IAccessible * poleacc; HRESULT hr; // // Ask the frame element what its state is. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); if (!poleacc) { pvarState->lVal |= STATE_SYSTEM_INVISIBLE; return(S_OK); } varChild.lVal = CHILDID_SELF; hr = poleacc->get_accState(varChild, pvarState); poleacc->Release(); return(hr); } return(S_OK); } // -------------------------------------------------------------------------- // // CWindow::get_accKeyboardShortcut() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszShortcut) { IAccessible * poleacc; HRESULT hr; InitPv(pszShortcut); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); // // If the caller is asking us for our shortcut, forward to the client. // if (varChild.lVal == CHILDID_SELF) varChild.lVal = OBJID_CLIENT; // // Ask the child. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); varChild.lVal = CHILDID_SELF; hr = poleacc->get_accKeyboardShortcut(varChild, pszShortcut); poleacc->Release(); return(hr); } // -------------------------------------------------------------------------- // // CWindow::get_accFocus() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::get_accFocus(VARIANT* pvarChild) { HWND hwndFocus; InitPvar(pvarChild); // // BOGUS! If we are in menu mode, then menu object has focus. If // we are in scrolling mode, scrollbar has the focus. etc. // hwndFocus = MyGetFocus(); if ((m_hwnd == hwndFocus) || IsChild(m_hwnd, hwndFocus)) return(GetNoncObject(m_hwnd, OBJID_CLIENT, pvarChild)); return(S_FALSE); } // -------------------------------------------------------------------------- // // CWindow::accNavigate() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::accNavigate(long dwNavDir, VARIANT varStart, VARIANT* pvarEnd) { InitPvar(pvarEnd); // // Validate parameters // if (! ValidateChild(&varStart) || ! ValidateNavDir(dwNavDir, varStart.lVal)) return(E_INVALIDARG); if (dwNavDir == NAVDIR_FIRSTCHILD) return(FrameNavigate(m_hwnd, 0, NAVDIR_NEXT, pvarEnd)); else if (dwNavDir == NAVDIR_LASTCHILD) return(FrameNavigate(m_hwnd, OBJID_SIZEGRIP-1, NAVDIR_PREVIOUS, pvarEnd)); else if (varStart.lVal == CHILDID_SELF) { HWND hwndParent; hwndParent = MyGetAncestor(m_hwnd, GA_PARENT); if (!hwndParent) return(S_FALSE); return (GetParentToNavigate(HWNDIDFromHwnd(hwndParent, m_hwnd), hwndParent, OBJID_CLIENT, dwNavDir, pvarEnd)); } else return(FrameNavigate(m_hwnd, varStart.lVal, dwNavDir, pvarEnd)); } // -------------------------------------------------------------------------- // // CWindow::accSelect() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::accSelect(long lSelFlags, VARIANT varChild) { if (! ValidateChild(&varChild) || ! ValidateSelFlags(lSelFlags)) return E_INVALIDARG; if (lSelFlags != SELFLAG_TAKEFOCUS) return E_NOT_APPLICABLE; if (varChild.lVal) return S_FALSE ; MySetFocus( m_hwnd ); return S_OK; } // -------------------------------------------------------------------------- // // CWindow::accLocation() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild) { RECT rc; InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight); // // Validate parameters // if (! ValidateChild(&varChild)) return(E_INVALIDARG); if (varChild.lVal == 0) { MyGetRect(m_hwnd, &rc, TRUE); *pxLeft = rc.left; *pyTop = rc.top; *pcxWidth = rc.right - rc.left; *pcyHeight = rc.bottom - rc.top; } else { // // Ask the child. // IAccessible * poleacc; HRESULT hr; // // Get the help for our child frame object. // poleacc = NULL; hr = AccessibleObjectFromWindow(m_hwnd, varChild.lVal, IID_IAccessible, (void **)&poleacc); if (!SUCCEEDED(hr)) return(hr); if (!poleacc) return(S_FALSE); varChild.lVal = CHILDID_SELF; hr = poleacc->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild); poleacc->Release(); return(hr); } return(S_OK); } // -------------------------------------------------------------------------- // // CWindow::accHitTest() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::accHitTest(long xLeft, long yTop, VARIANT* pvarHit) { WINDOWINFO wi; long lEnd; long lHit; POINT pt; InitPvar(pvarHit); lEnd = 0; if (! MyGetWindowInfo(m_hwnd, &wi)) return(S_FALSE); // // Find out where point is. But special case the client area! // pt.x = xLeft; pt.y = yTop; if (PtInRect(&wi.rcClient, pt)) goto ReallyTheClient; lHit = SendMessageINT(m_hwnd, WM_NCHITTEST, 0, MAKELONG(xLeft, yTop)); switch (lHit) { case HTERROR: case HTNOWHERE: return(S_FALSE); case HTCAPTION: case HTMINBUTTON: case HTMAXBUTTON: case HTHELP: case HTCLOSE: // case HTIME! lEnd = OBJID_TITLEBAR; break; case HTMENU: lEnd = OBJID_MENU; break; case HTSYSMENU: lEnd = OBJID_SYSMENU; break; case HTHSCROLL: lEnd = OBJID_HSCROLL; break; case HTVSCROLL: lEnd = OBJID_VSCROLL; break; case HTCLIENT: case HTTRANSPARENT: ReallyTheClient: lEnd = OBJID_CLIENT; break; case HTGROWBOX: lEnd = OBJID_SIZEGRIP; break; case HTBOTTOMRIGHT: // Note that for sizeable windows, being over the size grip may // return in fact HTBOTTOMRIGHT for sizing purposes. If this // point is inside the window borders, that is the case. if ((xLeft < wi.rcWindow.right - (int)wi.cxWindowBorders) && (yTop < wi.rcWindow.bottom - (int)wi.cyWindowBorders)) { lEnd = OBJID_SIZEGRIP; } break; // Includes borders! default: break; } if (lEnd) return(GetNoncObject(m_hwnd, lEnd, pvarHit)); else { pvarHit->vt = VT_I4; pvarHit->lVal = lEnd; } return(S_OK); } // -------------------------------------------------------------------------- // // CWindow::Next() // // We do loop from 0 to cChildren, it's just that the IDs are NEGATIVE, // not positive. We accept child ids that are OBJIDs. // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::Next(ULONG celt, VARIANT* rgvar, ULONG* pceltFetched) { VARIANT* pvar; long cFetched; long iCur; // Can be NULL if (pceltFetched) *pceltFetched = 0; pvar = rgvar; cFetched = 0; iCur = m_idChildCur; // // Loop through our items // while ((cFetched < (long)celt) && (iCur < m_cChildren)) { cFetched++; iCur++; // // Note this gives us -((index)+1), which means we start at -1 and // decrement. Conveniently, this corresponds to OBJID values! // pvar->vt = VT_I4; pvar->lVal = 0 - iCur; ++pvar; } // // Advance the current position // m_idChildCur = iCur; // // Fill in the number fetched // if (pceltFetched) *pceltFetched = cFetched; // // Return S_FALSE if we grabbed fewer items than requested // return((cFetched < (long)celt) ? S_FALSE : S_OK); } // -------------------------------------------------------------------------- // // CWindow::Clone() // // -------------------------------------------------------------------------- STDMETHODIMP CWindow::Clone(IEnumVARIANT ** ppenum) { InitPv(ppenum); // Look for (and create) a suitable proxy/handler if one // exists. Use CreateWindowThing as default if none found. // (TRUE => use window, as opposed to client, classes) return FindAndCreateWindowClass( m_hwnd, TRUE, CLASS_WindowObject, OBJID_WINDOW, m_idChildCur, IID_IEnumVARIANT, (void**)ppenum ); } // -------------------------------------------------------------------------- // // FrameNavigate() // // Default handling of navigation among frame children. The standard // frame widget handlers (titlebar, menubar, scrollbar, etc.) hand off // peer navigation to us, their parent. There are two big reasons for this: // // (1) It saves on code and ease of implementation, since the knowledge of // what is to the left of what, what is below what, etc. only has to // be coded in one place. // // (2) It allows apps that want to manage their own frame and e.g. add a // new element that acts like a frame piece yet still have navigation // work properly. Their frame handler can hand off to the default // implementation but trap navigation. // // -------------------------------------------------------------------------- HRESULT FrameNavigate(HWND hwndFrame, long lStart, long dwNavDir, VARIANT * pvarEnd) { long lEnd; long lMask; WINDOWINFO wi; TCHAR szClassName[128]; BOOL bFound = FALSE; IAccessible * poleacc; IDispatch * pdispEl; HRESULT hr; // // Currently, we get an index (fix validation layer so IDs are OBJIDs) // lEnd = 0; lStart = IndexFromObjid(lStart); // // Figure out what is present, what isn't. // if (!MyGetWindowInfo(hwndFrame, &wi)) return(E_FAIL); lMask = 0; lMask |= MaskBit(IndexFromObjid(OBJID_CLIENT)); if ((wi.dwStyle & WS_CAPTION)== WS_CAPTION) lMask |= MaskBit(IndexFromObjid(OBJID_TITLEBAR)); if (wi.dwStyle & WS_SYSMENU) lMask |= MaskBit(IndexFromObjid(OBJID_SYSMENU)); if (wi.dwStyle & WS_VSCROLL) lMask |= MaskBit(IndexFromObjid(OBJID_VSCROLL)); if (wi.dwStyle & WS_HSCROLL) lMask |= MaskBit(IndexFromObjid(OBJID_HSCROLL)); if ((wi.dwStyle & (WS_HSCROLL | WS_VSCROLL)) == (WS_HSCROLL | WS_VSCROLL)) lMask |= MaskBit(IndexFromObjid(OBJID_SIZEGRIP)); if (!(wi.dwStyle & WS_CHILD) && GetMenu(hwndFrame)) lMask |= MaskBit(IndexFromObjid(OBJID_MENU)); // HACKISH BIT for new IE4/Shell Menubands // The menus aren't menus, so we have to see if this thing // has menubands. // First, check the classname - only the browser and shell // windows have these things... // The reason we have to do this is because the IE4 guys are // slackers and didn't do very much for accessibility. GetClassName (hwndFrame, szClassName,ARRAYSIZE(szClassName)); if ((0 == lstrcmp (szClassName,TEXT("IEFrame"))) || (0 == lstrcmp (szClassName,TEXT("CabinetWClass")))) { HWND hwndWorker; HWND hwndRebar; HWND hwndSysPager; HWND hwndToolbar; // We can just send a WM_GETOBJECT to the menuband window, // we just have to find it. Let's use FindWindowEx to do that. // This is not easy: There are 4 children of an IEFrame Window, // and I am not sure how many children of a shell window (CabinetWClass). // For IEFrame windows, the menuband is the: // ToolbarWindow32 child of a SysPager that is the child of a // RebarWindow32 that is the child of a Worker. // But there are 2 Worker windows at the 1st level down, // and 2 SysPagers that are children of the RebarWindow32. bFound = FALSE; hwndWorker = NULL; while (!bFound) { hwndWorker = FindWindowEx (hwndFrame,hwndWorker,TEXT("Worker"),NULL); if (!hwndWorker) break; hwndRebar = FindWindowEx (hwndWorker,NULL,TEXT("RebarWindow32"),NULL); if (!hwndRebar) continue; hwndSysPager = NULL; while (!bFound) { hwndSysPager = FindWindowEx (hwndRebar,hwndSysPager,TEXT("SysPager"),NULL); if (!hwndSysPager) break; hwndToolbar = FindWindowEx (hwndSysPager,NULL,TEXT("ToolbarWindow32"),NULL); hr = AccessibleObjectFromWindow (hwndToolbar,OBJID_MENU, IID_IAccessible, (void **)&poleacc); if (SUCCEEDED(hr)) { bFound = TRUE; lMask |= MaskBit(IndexFromObjid(OBJID_MENU)); } } } } // end if we are talking to something that might have a menuband switch (dwNavDir) { case NAVDIR_NEXT: lEnd = lStart; while (++lEnd <= CCHILDREN_FRAME) { // Is the next item present? if (lMask & MaskBit(lEnd)) break; } if (lEnd > CCHILDREN_FRAME) lEnd = 0; break; case NAVDIR_PREVIOUS: lEnd = lStart; while (--lEnd > 0) { // Is the previous item present? if (lMask & MaskBit(lEnd)) break; } Assert(lEnd >= 0); break; case NAVDIR_UP: case NAVDIR_DOWN: case NAVDIR_LEFT: case NAVDIR_RIGHT: lEnd = lStart; while (lEnd = rgFrameNavigate[lEnd-1].NavPeer[IndexFromNavDir(dwNavDir)]) { // Is this item around? if (lMask & MaskBit(lEnd)) break; } break; } if (lEnd) { // now finish up our hackish work. For normal things, we just // return GetNoncObject, which is basically just a call to // AccessibleObjectFromWindow with the id of the frame element, // and then it just stuffs the return value (an IDispatch) into // the VARIANT. // For IE4 hackish stuff, we have an IAccessible, we'll QI for // IDispatch, Release the IAccessible, and stuff the IDispatch // into a VARIANT. if (bFound && lEnd == IndexFromObjid(OBJID_MENU)) { hr = poleacc->QueryInterface(IID_IDispatch,(void**)&pdispEl); poleacc->Release(); if (!SUCCEEDED(hr)) return(hr); if (!pdispEl) return(E_FAIL); pvarEnd->vt = VT_DISPATCH; pvarEnd->pdispVal = pdispEl; return (S_OK); } else return(GetNoncObject(hwndFrame, ObjidFromIndex(lEnd), pvarEnd)); } else return(S_FALSE); }