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

453 lines
12 KiB
C++

// Copyright (c) 1996-1999 Microsoft Corporation
// --------------------------------------------------------------------------
//
// HEADER.CPP
//
// This knows how to talk to COMCTL32's header control.
//
// --------------------------------------------------------------------------
#include "oleacc_p.h"
#include "default.h"
#include "client.h"
#include "header.h"
#include "Win64Helper.h"
#define MAX_HEADER_TEXT 80
// --------------------------------------------------------------------------
//
// CreateHeaderClient()
//
// --------------------------------------------------------------------------
HRESULT CreateHeaderClient(HWND hwnd, long idChildCur, REFIID riid, void** ppvHeader)
{
CHeader32 * pheader;
HRESULT hr;
InitPv(ppvHeader);
pheader = new CHeader32(hwnd, idChildCur);
if (!pheader)
return(E_OUTOFMEMORY);
hr = pheader->QueryInterface(riid, ppvHeader);
if (!SUCCEEDED(hr))
delete pheader;
return(hr);
}
// --------------------------------------------------------------------------
//
// CHeader32::CHeader32()
//
// --------------------------------------------------------------------------
CHeader32::CHeader32(HWND hwnd, long idChildCur)
: CClient( CLASS_HeaderClient )
{
Initialize(hwnd, idChildCur);
}
// --------------------------------------------------------------------------
//
// CHeader32::get_accName()
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::get_accName(VARIANT varChild, BSTR* pszName)
{
InitPv(pszName);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal)
return(CClient::get_accName(varChild, pszName));
TCHAR tchText[MAX_HEADER_TEXT + 1] = {0};
HDITEM hdi;
memset(&hdi, 0, sizeof(HDITEM));
hdi.mask = HDI_TEXT;
hdi.pszText = tchText;
hdi.cchTextMax = MAX_HEADER_TEXT;
if (SUCCEEDED(XSend_HeaderCtrl_GetItem(m_hwnd, HDM_GETITEM, varChild.lVal-1, &hdi)))
{
if (*hdi.pszText)
*pszName = TCharSysAllocString(hdi.pszText);
}
//
// BOGUS! On failure, use tooltip trick like toolbar.
//
return(*pszName ? S_OK : S_FALSE);
}
// --------------------------------------------------------------------------
//
// CHeader32::get_accRole()
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::get_accRole(VARIANT varChild, VARIANT* pvarRole)
{
InitPvar(pvarRole);
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
pvarRole->vt = VT_I4;
if (!varChild.lVal)
pvarRole->lVal = ROLE_SYSTEM_LIST;
else
pvarRole->lVal = ROLE_SYSTEM_COLUMNHEADER;
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CHeader32::get_accState()
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::get_accState(VARIANT varChild, VARIANT *pvarState)
{
WINDOWINFO wi;
InitPvar(pvarState);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
pvarState->vt = VT_I4;
pvarState->lVal = 0;
pvarState->lVal |= STATE_SYSTEM_READONLY;
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 & HDS_HIDDEN)
pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
// Check for clipped, but only if this is a child item, and it's not
// already invisible...
if( varChild.lVal != CHILDID_SELF
&& ! ( pvarState->lVal & STATE_SYSTEM_INVISIBLE )
&& IsClippedByWindow( this, varChild, m_hwnd ) )
{
pvarState->lVal |= STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN;
}
if (wi.dwStyle & HDS_BUTTONS)
pvarState->lVal |= 0; // BOGUS! Indicate whether you can click or not.
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CHeader32::get_accDefaultAction()
//
// Since the default action for a header is really determined by the
// creator of the header control, the best we can do is click on
// the thing, and return "click" as the default action string.
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::get_accDefaultAction(VARIANT varChild, BSTR* pszDefAction)
{
WINDOWINFO wi;
InitPv(pszDefAction);
//
// Validate.
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (MyGetWindowInfo(m_hwnd, &wi))
{
if (wi.dwStyle & WS_VISIBLE)
{
if (!(wi.dwStyle & HDS_HIDDEN))
{
if (wi.dwStyle & HDS_BUTTONS)
return (HrCreateString(STR_CLICK, pszDefAction));
}
}
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CHeader32::accDoDefaultAction()
//
// As noted above, we really don't know what the default action for a
// header is, so unless the parent overrides us, we'll just do a
// click on the thing.
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::accDoDefaultAction(VARIANT varChild)
{
WINDOWINFO wi;
RECT rcLoc;
HRESULT hr;
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (MyGetWindowInfo(m_hwnd, &wi))
{
if (wi.dwStyle & WS_VISIBLE)
{
if (!(wi.dwStyle & HDS_HIDDEN))
{
if (wi.dwStyle & HDS_BUTTONS)
{
hr = accLocation(&rcLoc.left,&rcLoc.top,&rcLoc.right,&rcLoc.bottom,varChild);
if (!SUCCEEDED (hr))
return (hr);
if (ClickOnTheRect(&rcLoc,m_hwnd,FALSE))
return (S_OK);
}
}
}
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CHeader32::accLocation()
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::accLocation(long* pxLeft, long* pyTop,
long* pcxWidth, long* pcyHeight, VARIANT varChild)
{
LPRECT lprc;
HANDLE hProcess;
RECT rcItem;
InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal)
return(CClient::accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild));
//
// Allocate a shared memory LPRECT and get the item's rectangle.
//
lprc = (LPRECT)SharedAlloc(sizeof(RECT),m_hwnd,&hProcess);
if (!lprc)
return(E_OUTOFMEMORY);
if (SendMessage(m_hwnd, HDM_GETITEMRECT, varChild.lVal-1, (LPARAM)lprc))
{
SharedRead (lprc,&rcItem,sizeof(RECT),hProcess);
MapWindowPoints(m_hwnd, NULL, (LPPOINT)&rcItem, 2);
*pxLeft = rcItem.left;
*pyTop = rcItem.top;
*pcxWidth = rcItem.right - rcItem.left;
*pcyHeight = rcItem.bottom - rcItem.top;
}
SharedFree(lprc,hProcess);
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CHeader32::accNavigate()
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::accNavigate(long dwNavDir, VARIANT varStart,
VARIANT* pvarEnd)
{
LPINT lpiShared;
LPINT lpiLocal;
long lPosition = 0;
int iOrder;
HANDLE hProcess;
InitPvar(pvarEnd);
if (!ValidateChild(&varStart) ||
!ValidateNavDir(dwNavDir, varStart.lVal))
return(E_INVALIDARG);
Assert(NAVDIR_LASTCHILD > NAVDIR_FIRSTCHILD);
Assert(NAVDIR_MAX == NAVDIR_LASTCHILD+1);
// Peer navigation among frame elements
if ((!varStart.lVal) && (dwNavDir < NAVDIR_FIRSTCHILD))
return(CClient::accNavigate(dwNavDir, varStart, pvarEnd));
//
// Get the order array.
//
lpiShared = (LPINT)SharedAlloc((m_cChildren*sizeof(INT)),m_hwnd,&hProcess);
if (!lpiShared)
return(E_OUTOFMEMORY);
lpiLocal = (LPINT)LocalAlloc (LPTR,(m_cChildren*sizeof(INT)));
if (!lpiLocal)
{
SharedFree (lpiShared,hProcess);
return(E_OUTOFMEMORY);
}
SendMessage(m_hwnd, HDM_GETORDERARRAY, m_cChildren, (LPARAM)lpiShared);
//
// BOGUS! Only works for column headers (horizontal), not row
// headers (vertical).
//
SharedRead (lpiShared,lpiLocal,(m_cChildren*sizeof(INT)),hProcess);
// Get the position of the item we want to move to
switch (dwNavDir)
{
case NAVDIR_FIRSTCHILD:
lPosition = 0;
break;
case NAVDIR_LASTCHILD:
if (!m_cChildren)
goto NavigateEnd;
lPosition = m_cChildren - 1;
break;
case NAVDIR_NEXT:
case NAVDIR_RIGHT:
lPosition = lpiLocal[varStart.lVal-1];
++lPosition;
if (lPosition >= m_cChildren)
goto NavigateEnd;
break;
case NAVDIR_PREVIOUS:
case NAVDIR_LEFT:
lPosition = lpiLocal[varStart.lVal-1];
if (!lPosition)
goto NavigateEnd;
--lPosition;
break;
case NAVDIR_UP:
case NAVDIR_DOWN:
goto NavigateEnd;
break;
}
//
// Find the item with this positional value
//
for (iOrder = 0; iOrder < m_cChildren; iOrder++)
{
if (lpiLocal[iOrder] == lPosition)
{
pvarEnd->vt = VT_I4;
pvarEnd->lVal = iOrder+1;
break;
}
}
NavigateEnd:
SharedFree(lpiShared,hProcess);
LocalFree (lpiLocal);
return((pvarEnd->vt == VT_EMPTY) ? S_FALSE : S_OK);
}
// --------------------------------------------------------------------------
//
// CHeader32::accHitTest()
//
// --------------------------------------------------------------------------
STDMETHODIMP CHeader32::accHitTest(long x, long y, VARIANT* pvarEnd)
{
HRESULT hr;
LPHDHITTESTINFO lphi;
HANDLE hProcess;
POINT ptTest;
InitPvar(pvarEnd);
SetupChildren();
//
// Is the point in our client? If not, bail.
//
hr = CClient::accHitTest(x, y, pvarEnd);
// #11150, CWO, 1/27/97, Replaced !SUCCEEDED with !S_OK
if ((hr != S_OK) || (pvarEnd->vt != VT_I4) || (pvarEnd->lVal != 0))
return(hr);
//
// It is. Do hit test stuff.
//
lphi = (LPHDHITTESTINFO)SharedAlloc(sizeof(HDHITTESTINFO),m_hwnd,&hProcess);
if (!lphi)
return(E_OUTOFMEMORY);
ptTest.x = x;
ptTest.y = y;
ScreenToClient(m_hwnd, &ptTest);
SharedWrite (&ptTest,&lphi->pt,sizeof(POINT),hProcess);
if (SendMessage(m_hwnd, HDM_HITTEST, 0, (LPARAM)lphi) != -1)
{
SharedRead (&lphi->iItem,&pvarEnd->lVal,sizeof(int),hProcess);
pvarEnd->lVal++;
}
SharedFree(lphi,hProcess);
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CHeader32::SetupChildren()
//
// --------------------------------------------------------------------------
void CHeader32::SetupChildren(void)
{
m_cChildren = SendMessageINT(m_hwnd, HDM_GETITEMCOUNT, 0, 0L);
}