WindowsXP-SP1/windows/oleacc/oleacc/window.cpp
2020-09-30 16:53:49 +02:00

1098 lines
29 KiB
C++

// 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);
}