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

1037 lines
30 KiB
C++

// Copyright (c) 1996-1999 Microsoft Corporation
// --------------------------------------------------------------------------
//
// COMBO.CPP
//
// --------------------------------------------------------------------------
#include "oleacc_p.h"
#include <olectl.h>
#include "default.h"
#include "window.h"
#include "client.h"
#include "combo.h"
STDAPI_(LPTSTR) MyPathFindFileName(LPCTSTR pPath); // in listbox.cpp
HWND IsInComboEx(HWND hwnd); // in listbox.cpp
BOOL IsTridentControl( HWND hWnd, BOOL fCombo, BOOL fComboList ); // inlistbox.cpp
// Variation of HrGetWindowName which never uses a label
// (unlike the original HrGetWindowName which always uses a label if
// the text is an empty string - using label then is not approprite for
// combo value field.)
// Implemented near end of this file. Original is in client.cpp.
HRESULT HrGetWindowNameNoLabel(HWND hwnd, BSTR* pszName);
// --------------------------------------------------------------------------
//
// CreateComboClient()
//
// --------------------------------------------------------------------------
HRESULT CreateComboClient(HWND hwnd, long idChildCur, REFIID riid, void** ppvCombo)
{
CCombo * pcombo;
HRESULT hr;
InitPv(ppvCombo);
pcombo = new CCombo(hwnd, idChildCur);
if (!pcombo)
return(E_OUTOFMEMORY);
hr = pcombo->QueryInterface(riid, ppvCombo);
if (!SUCCEEDED(hr))
delete pcombo;
return(hr);
}
// --------------------------------------------------------------------------
//
// CCombo::CCombo()
//
// --------------------------------------------------------------------------
CCombo::CCombo(HWND hwnd, long idChildCur)
: CClient( CLASS_ComboClient )
{
LONG lStyle;
Initialize(hwnd, idChildCur);
m_cChildren = CCHILDREN_COMBOBOX;
m_fUseLabel = TRUE;
// If in a ComboEx, use its style, instead of our own.
// Important, because the real Combo will be DROPDOWNLIST (doesn't
// have edit) when the ComboEx is DROPDOWN (has edit) - the ComboEx
// supplies an EDIT, but the Combo doesn't know about it.
HWND hWndEx = IsInComboEx(hwnd);
if (hWndEx)
{
lStyle = GetWindowLong(hWndEx, GWL_STYLE);
}
else
{
lStyle = GetWindowLong(hwnd, GWL_STYLE);
}
switch (lStyle & CBS_DROPDOWNLIST)
{
case 0:
m_cChildren = 0; // Window not valid!
break;
case CBS_SIMPLE:
m_fHasButton = FALSE;
m_fHasEdit = TRUE;
break;
case CBS_DROPDOWN:
m_fHasButton = TRUE;
m_fHasEdit = TRUE;
break;
case CBS_DROPDOWNLIST:
m_fHasButton = TRUE;
m_fHasEdit = FALSE;
break;
}
}
// --------------------------------------------------------------------------
//
// CCombo::get_accChildCount()
//
// Since this is a known constant, hand directly to CAccessible. No
// need to count up fixed + window children.
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accChildCount(long* pcCount)
{
return(CAccessible::get_accChildCount(pcCount));
}
// --------------------------------------------------------------------------
//
// CCombo::get_accChild()
//
// Succeeds for listbox, and for item if editable. This is because we
// manipulate our children by ID, since they are known.
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accChild(VARIANT varChild, IDispatch** ppdisp)
{
COMBOBOXINFO cbi;
HWND hwndChild;
InitPv(ppdisp);
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
hwndChild = NULL;
switch (varChild.lVal)
{
case INDEX_COMBOBOX:
return(E_INVALIDARG);
case INDEX_COMBOBOX_ITEM:
hwndChild = cbi.hwndItem;
break;
case INDEX_COMBOBOX_LIST:
hwndChild = cbi.hwndList;
break;
}
if (!hwndChild)
return(S_FALSE);
else
return(AccessibleObjectFromWindow(hwndChild, OBJID_WINDOW, IID_IDispatch,
(void**)ppdisp));
}
// --------------------------------------------------------------------------
//
// CCombo::get_accName()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accName(VARIANT varChild, BSTR* pszName)
{
COMBOBOXINFO cbi;
InitPv(pszName);
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
//
// The name of the combobox, the edit inside of it, and the dropdown
// are all the same. The name of the button is Drop down/Pop up
//
if (varChild.lVal != INDEX_COMBOBOX_BUTTON)
{
HWND hwndComboEx = IsInComboEx(m_hwnd);
if( ! hwndComboEx )
{
// combo/edit/dropdown all use the name of the client itself,
// so call through with childid of CHILDID_SELF...
varChild.lVal = CHILDID_SELF;
return(CClient::get_accName(varChild, pszName));
}
else
{
// Special case if we're in a comboex - since we're one level deep,
// reach up to parent for its name...
IAccessible * pAcc;
HRESULT hr = AccessibleObjectFromWindow( hwndComboEx, OBJID_CLIENT, IID_IAccessible, (void **) & pAcc );
if( hr != S_OK )
return hr;
VARIANT varChild;
varChild.vt = VT_I4;
varChild.lVal = CHILDID_SELF;
hr = pAcc->get_accName( varChild, pszName );
pAcc->Release();
return hr;
}
}
else
{
if (! MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
if (IsWindowVisible(cbi.hwndList))
return (HrCreateString(STR_DROPDOWN_HIDE,pszName));
else
return(HrCreateString(STR_DROPDOWN_SHOW, pszName));
}
}
// --------------------------------------------------------------------------
//
// CCombo::get_accValue()
//
// The value of the combobox and the combobox item is the current text of
// the thing.
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accValue(VARIANT varChild, BSTR* pszValue)
{
InitPv(pszValue);
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
switch (varChild.lVal)
{
case INDEX_COMBOBOX:
case INDEX_COMBOBOX_ITEM:
{
// HACK ALERT
// The IE4 combobox is a superclassed standard combobox,
// but if I use SendMessageA (which I do) to get the
// text, I get back garbage. They keep everything
// in Unicode. It is a bug in the Trident MSHTML
// implementation, but even if they fixed it and gave me
// back an ANSI string, I wouldn't know what code page to
// use to convert the ANSI string to Unicode - web pages
// can be in a different language than the one the user's
// computer uses! Since they already have everything in
// Unicode, we decided on a private message that will fill
// in the Unicode string, and I use that just like I would
// normally use WM_GETTEXT.
// I was going to base this on the classname of the listbox
// window, which is "Internet Explorer_TridentCmboBx", but
// the list part of a combo doesn't have a special class
// name, so instead I am going to base the special case on
// the file name of the module that owns the window.
// GetWindowModuleFileName(m_hwnd,szModuleName,ARRAYSIZE(szModuleName));
// lpszModuleName = MyPathFindFileName (szModuleName);
// if (0 == lstrcmp(lpszModuleName,TEXT("MSHTML.DLL")))
// Update: (BrendanM)
// GetWindowModuleFilename is broken on Win2k...
// IsTridentControl goes back to using classnames, and knows
// how to cope with ComboLBoxes...
if( IsTridentControl( m_hwnd, TRUE, FALSE ) )
{
OLECHAR* lpszUnicodeText = NULL;
OLECHAR* lpszLocalText = NULL;
HANDLE hProcess;
UINT cch;
cch = SendMessageINT(m_hwnd, OCM__BASE + WM_GETTEXTLENGTH, 0, 0);
lpszUnicodeText = (OLECHAR *)SharedAlloc((cch+1)*sizeof(OLECHAR),
m_hwnd,
&hProcess);
lpszLocalText = (OLECHAR*)LocalAlloc(LPTR,(cch+1)*sizeof(OLECHAR));
if (!lpszUnicodeText || !lpszLocalText)
return(E_OUTOFMEMORY);
cch = SendMessageINT(m_hwnd, OCM__BASE + WM_GETTEXT, cch, (LPARAM)lpszUnicodeText);
SharedRead (lpszUnicodeText,lpszLocalText,(cch+1)*sizeof(OLECHAR),hProcess);
*pszValue = SysAllocString(lpszLocalText);
SharedFree(lpszUnicodeText,hProcess);
LocalFree(lpszLocalText);
return (S_OK);
}
else
{
// If we're a comboex, ask the comboex instead of us...
HWND hwnd;
if( ! ( hwnd = IsInComboEx( m_hwnd ) ) )
hwnd = m_hwnd;
// uh-oh - don't want to use HrGetWindowName, since
// it will look for a label (even though we specify FALSE)
// if we are in a dialog and out text is "".
if( ! IsComboEx( hwnd ) )
{
// Regular combo - gettext works for both edit and droplist...
return HrGetWindowNameNoLabel( hwnd, pszValue);
}
else
{
// comboex - special case for droplist...
DWORD dwStyle = GetWindowLong( hwnd, GWL_STYLE );
if( ! ( dwStyle & CBS_DROPDOWNLIST ) )
{
// Not a droplist - can use normal technique...
return HrGetWindowNameNoLabel( hwnd, pszValue);
}
else
{
// Get the selected item, and get its text...
int iSel = SendMessageINT( hwnd, CB_GETCURSEL, 0, 0 );
if( iSel == CB_ERR )
return S_FALSE; // no item selected
int cch = SendMessageINT( hwnd, CB_GETLBTEXTLEN, iSel, 0);
// Some apps do not handle CB_GETTEXTLEN correctly, and
// always return a small number, like 2.
if (cch < 1024)
cch = 1024;
LPTSTR lpszText;
lpszText = (LPTSTR)LocalAlloc(LPTR, (cch+1)*sizeof(TCHAR));
if (!lpszText)
return(E_OUTOFMEMORY);
SendMessage( hwnd, CB_GETLBTEXT, iSel, (LPARAM)lpszText);
*pszValue = TCharSysAllocString(lpszText);
LocalFree((HANDLE)lpszText);
return S_OK;
}
}
}
}
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CCombo::get_accRole()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accRole(VARIANT varChild, VARIANT* pvarRole)
{
InitPvar(pvarRole);
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
pvarRole->vt = VT_I4;
switch (varChild.lVal)
{
case INDEX_COMBOBOX:
pvarRole->lVal = ROLE_SYSTEM_COMBOBOX;
break;
case INDEX_COMBOBOX_ITEM:
if (m_fHasEdit)
pvarRole->lVal = ROLE_SYSTEM_TEXT;
else
pvarRole->lVal = ROLE_SYSTEM_STATICTEXT;
break;
case INDEX_COMBOBOX_BUTTON:
pvarRole->lVal = ROLE_SYSTEM_PUSHBUTTON;
break;
case INDEX_COMBOBOX_LIST:
pvarRole->lVal = ROLE_SYSTEM_LIST;
break;
default:
AssertStr( TEXT("Invalid ChildID for child of combo box") );
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CCombo::get_accState()
//
// The state of the combo is the state of the client.
// The state of the item is the state of the edit field if present;
// read-only if static.
// The state of the button is pushed and/or hottracked.
// The state of the dropdown is floating (if not simple) and the state
// of the list window.
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accState(VARIANT varChild, VARIANT* pvarState)
{
COMBOBOXINFO cbi;
VARIANT var;
IAccessible* poleacc;
HRESULT hr;
HWND hwndActive;
InitPvar(pvarState);
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!MyGetComboBoxInfo(m_hwnd, &cbi))
{
pvarState->vt = VT_I4;
pvarState->lVal = STATE_SYSTEM_INVISIBLE;
return(S_FALSE);
}
switch (varChild.lVal)
{
case INDEX_COMBOBOX:
return(CClient::get_accState(varChild, pvarState));
case INDEX_COMBOBOX_BUTTON:
pvarState->vt = VT_I4;
pvarState->lVal = cbi.stateButton;
break;
case INDEX_COMBOBOX_ITEM:
if (!cbi.hwndItem)
{
pvarState->vt = VT_I4;
pvarState->lVal = 0;
hwndActive = GetForegroundWindow();
if (hwndActive == MyGetAncestor(m_hwnd, GA_ROOT))
pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
if (MyGetFocus() == m_hwnd)
pvarState->lVal |= STATE_SYSTEM_FOCUSED;
}
else
{
// Forward state to edit field.
VariantInit(&var);
hr = GetWindowObject(cbi.hwndItem, &var);
goto AskTheChild;
}
break;
case INDEX_COMBOBOX_LIST:
// Forward state to listbox
VariantInit(&var);
hr = GetWindowObject(cbi.hwndList, &var);
AskTheChild:
if (!SUCCEEDED(hr))
return(hr);
Assert(var.vt == VT_DISPATCH);
//
// Get the child acc object
//
poleacc = NULL;
hr = var.pdispVal->QueryInterface(IID_IAccessible,
(void**)&poleacc);
var.pdispVal->Release();
if (!SUCCEEDED(hr))
return(hr);
//
// Ask the child its state
//
VariantInit(&var);
hr = poleacc->get_accState(var, pvarState);
poleacc->Release();
if (!SUCCEEDED(hr))
return(hr);
break;
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CCombo::get_accKeyboardShortcut()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszShortcut)
{
TCHAR szKey[20];
//
// Shortcut for combo is label's hotkey.
// Shortcut for dropdown (if button) is Alt+F4.
// CWO, 12/5/96, Alt+F4? F4, by itself brings down the combo box,
// but we add "Alt" to the string. Bad! Now use
// down arrow and add Alt to it via HrMakeShortcut()
// As documented in the UI style guide.
//
// As always, shortcuts only apply if the container has "focus". In other
// words, the hotkey for the combo does nothing if the parent dialog
// isn't active. And the hotkey for the dropdown does nothing if the
// combobox/edit isn't focused.
//
InitPv(pszShortcut);
//
// Validate parameters
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (varChild.lVal == INDEX_COMBOBOX || varChild.lVal == INDEX_COMBOBOX_ITEM)
{
HWND hwndComboEx = IsInComboEx(m_hwnd);
if( ! hwndComboEx )
{
// combo/edit/dropdown all use the name of the client itself,
// so call through with childid of CHILDID_SELF...
varChild.lVal = CHILDID_SELF;
return(CClient::get_accKeyboardShortcut(varChild, pszShortcut));
}
else
{
// Special case if we're in a comboex - since we're one level deep,
// reach up to parent for its name...
IAccessible * pAcc;
HRESULT hr = AccessibleObjectFromWindow( hwndComboEx, OBJID_CLIENT, IID_IAccessible, (void **) & pAcc );
if( hr != S_OK )
return hr;
VARIANT varChild;
varChild.vt = VT_I4;
varChild.lVal = CHILDID_SELF;
hr = pAcc->get_accKeyboardShortcut( varChild, pszShortcut );
pAcc->Release();
return hr;
}
}
else if (varChild.lVal == INDEX_COMBOBOX_BUTTON)
{
if (m_fHasButton)
{
LoadString(hinstResDll, STR_COMBOBOX_LIST_SHORTCUT, szKey,
ARRAYSIZE(szKey));
return(HrMakeShortcut(szKey, pszShortcut));
}
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CCombo::get_accDefaultAction()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::get_accDefaultAction(VARIANT varChild, BSTR* pszDef)
{
COMBOBOXINFO cbi;
InitPv(pszDef);
//
// Validate parameters
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if ((varChild.lVal != INDEX_COMBOBOX_BUTTON) || !m_fHasButton)
return(E_NOT_APPLICABLE);
//
// Default action of button is to press it. If pressed already, pressing
// it will pop dropdown back up. If not pressed, pressing it will pop
// dropdown down.
//
if (! MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
if (IsWindowVisible(cbi.hwndList))
return(HrCreateString(STR_DROPDOWN_HIDE, pszDef));
else
return(HrCreateString(STR_DROPDOWN_SHOW, pszDef));
}
// --------------------------------------------------------------------------
//
// CCombo::accLocation()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
long* pcyHeight, VARIANT varChild)
{
COMBOBOXINFO cbi;
InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (! varChild.lVal)
return(CClient::accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild));
if (! MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
switch (varChild.lVal)
{
case INDEX_COMBOBOX_BUTTON:
if (!m_fHasButton)
return(S_FALSE);
*pcxWidth = cbi.rcButton.right - cbi.rcButton.left;
*pcyHeight = cbi.rcButton.bottom - cbi.rcButton.top;
ClientToScreen(m_hwnd, (LPPOINT)&cbi.rcButton);
*pxLeft = cbi.rcButton.left;
*pyTop = cbi.rcButton.top;
break;
case INDEX_COMBOBOX_ITEM:
*pcxWidth = cbi.rcItem.right - cbi.rcItem.left;
*pcyHeight = cbi.rcItem.bottom - cbi.rcItem.top;
ClientToScreen(m_hwnd, (LPPOINT)&cbi.rcItem);
*pxLeft = cbi.rcItem.left;
*pyTop = cbi.rcItem.top;
break;
case INDEX_COMBOBOX_LIST:
MyGetRect(cbi.hwndList, &cbi.rcItem, TRUE);
*pxLeft = cbi.rcItem.left;
*pyTop = cbi.rcItem.top;
*pcxWidth = cbi.rcItem.right - cbi.rcItem.left;
*pcyHeight = cbi.rcItem.bottom - cbi.rcItem.top;
break;
default:
AssertStr( TEXT("Invalid ChildID for child of combo box") );
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CCombo::accNavigate()
//
// Navigates among children of combobox.
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::accNavigate(long dwNav, VARIANT varStart, VARIANT* pvarEnd)
{
COMBOBOXINFO cbi;
long lEnd;
InitPvar(pvarEnd);
//
// Validate parameters
//
if ((!ValidateChild(&varStart) && !ValidateHwnd(&varStart)) ||
!ValidateNavDir(dwNav, varStart.lVal))
return(E_INVALIDARG);
if (! MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
lEnd = 0;
if (dwNav == NAVDIR_FIRSTCHILD)
{
lEnd = INDEX_COMBOBOX_ITEM;
goto GetTheChild;
}
else if (dwNav == NAVDIR_LASTCHILD)
{
dwNav = NAVDIR_PREVIOUS;
varStart.lVal = m_cChildren + 1;
}
else if (!varStart.lVal)
return(CClient::accNavigate(dwNav, varStart, pvarEnd));
//
// Map HWNDID to normal ID. We work with both (it is easier).
//
if (IsHWNDID(varStart.lVal))
{
HWND hWndTemp = HwndFromHWNDID(m_hwnd, varStart.lVal);
if (hWndTemp == cbi.hwndItem)
varStart.lVal = INDEX_COMBOBOX_ITEM;
else if (hWndTemp == cbi.hwndList)
varStart.lVal = INDEX_COMBOBOX_LIST;
else
// Don't know what the heck this is
return(S_FALSE);
}
switch (dwNav)
{
case NAVDIR_UP:
if (varStart.lVal == INDEX_COMBOBOX_LIST)
lEnd = INDEX_COMBOBOX_ITEM;
break;
case NAVDIR_DOWN:
if ((varStart.lVal != INDEX_COMBOBOX_LIST) &&
IsWindowVisible(cbi.hwndList))
{
lEnd = INDEX_COMBOBOX_LIST;
}
break;
case NAVDIR_LEFT:
if (varStart.lVal == INDEX_COMBOBOX_BUTTON)
lEnd = INDEX_COMBOBOX_ITEM;
break;
case NAVDIR_RIGHT:
if ((varStart.lVal == INDEX_COMBOBOX_ITEM) &&
!(cbi.stateButton & STATE_SYSTEM_INVISIBLE))
{
lEnd = INDEX_COMBOBOX_BUTTON;
}
break;
case NAVDIR_PREVIOUS:
lEnd = varStart.lVal - 1;
if ((lEnd == INDEX_COMBOBOX_LIST) && !IsWindowVisible(cbi.hwndList))
--lEnd;
if ((lEnd == INDEX_COMBOBOX_BUTTON) && !m_fHasButton)
--lEnd;
break;
case NAVDIR_NEXT:
lEnd = varStart.lVal + 1;
if (lEnd > m_cChildren)
lEnd = 0;
else
{
if ((lEnd == INDEX_COMBOBOX_BUTTON) && !m_fHasButton)
lEnd++;
if ((lEnd == INDEX_COMBOBOX_LIST) && !IsWindowVisible(cbi.hwndList))
lEnd = 0;
}
break;
}
GetTheChild:
if (lEnd)
{
if ((lEnd == INDEX_COMBOBOX_ITEM) && cbi.hwndItem)
return(GetWindowObject(cbi.hwndItem, pvarEnd));
else if ((lEnd == INDEX_COMBOBOX_LIST) && cbi.hwndList)
return(GetWindowObject(cbi.hwndList, pvarEnd));
pvarEnd->vt = VT_I4;
pvarEnd->lVal = lEnd;
return(S_OK);
}
return(S_FALSE);
}
// --------------------------------------------------------------------------
//
// CCombo::accHitTest()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::accHitTest(long x, long y, VARIANT* pvarEnd)
{
POINT pt;
COMBOBOXINFO cbi;
RECT rc;
InitPvar(pvarEnd);
if (!MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
pt.x = x;
pt.y = y;
// Check list first, in case it is a dropdown.
MyGetRect(cbi.hwndList, &rc, TRUE);
if (PtInRect(&rc, pt) && IsWindowVisible(cbi.hwndList))
return(GetWindowObject(cbi.hwndList, pvarEnd));
else
{
ScreenToClient(m_hwnd, &pt);
MyGetRect(m_hwnd, &rc, FALSE);
if (! PtInRect(&rc, pt))
return(S_FALSE);
if (PtInRect(&cbi.rcButton, pt))
{
pvarEnd->vt = VT_I4;
pvarEnd->lVal = INDEX_COMBOBOX_BUTTON;
}
else if (PtInRect(&cbi.rcItem, pt))
{
if (m_fHasEdit)
return(GetWindowObject(cbi.hwndItem, pvarEnd));
else
{
pvarEnd->vt = VT_I4;
pvarEnd->lVal = INDEX_COMBOBOX_ITEM;
}
}
else
{
pvarEnd->vt = VT_I4;
pvarEnd->lVal = 0;
}
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CCombo::accDoDefaultAction()
//
// The default action of the button is to toggle the dropdown list up or
// down. Note that we don't just pop up the listbox, we pop it up AND
// accept amu changes in the selected item..
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::accDoDefaultAction(VARIANT varChild)
{
COMBOBOXINFO cbi;
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if ((varChild.lVal == INDEX_COMBOBOX_BUTTON) && m_fHasButton)
{
if (!MyGetComboBoxInfo(m_hwnd, &cbi))
return(S_FALSE);
if (IsWindowVisible(cbi.hwndList))
PostMessage(m_hwnd, WM_KEYDOWN, VK_RETURN, 0);
else
PostMessage(m_hwnd, CB_SHOWDROPDOWN, TRUE, 0);
return(S_OK);
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CCombo::put_accValue()
//
// This works if (1) the combo is editable or (2) the text matches a list
// item exactly.
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::put_accValue(VARIANT varChild, BSTR szValue)
{
//
// Validate
//
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
LPTSTR lpszValue;
#ifdef UNICODE
// On unicode, no conversion needed...
lpszValue = szValue;
#else
// On non-unicode, need to convert to multibyte...
// We may be dealing with DBCS chars - assume worst case where every character is
// two bytes...
UINT cchValue = SysStringLen(szValue) * 2;
lpszValue = (LPTSTR)LocalAlloc(LPTR, (cchValue+1)*sizeof(TCHAR));
if (!lpszValue)
return(E_OUTOFMEMORY);
WideCharToMultiByte(CP_ACP, 0, szValue, -1, lpszValue, cchValue+1, NULL,
NULL);
#endif
//
// If this is editable, set the text directly. If this is a dropdown
// list, select the exact match for this text.
//
if (m_fHasEdit)
SendMessage(m_hwnd, WM_SETTEXT, 0, (LPARAM)lpszValue);
else
SendMessage(m_hwnd, CB_SELECTSTRING, (UINT)-1, (LPARAM)lpszValue);
#ifndef UNICODE
// On non-unicode, free the temp string we alloc'd above...
LocalFree((HANDLE)lpszValue);
#endif
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CCombo::Next()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::Next(ULONG celt, VARIANT* rgvar, ULONG* pceltFetched)
{
return(CAccessible::Next(celt, rgvar, pceltFetched));
}
// --------------------------------------------------------------------------
//
// CCombo::Skip()
//
// --------------------------------------------------------------------------
STDMETHODIMP CCombo::Skip(ULONG celt)
{
return(CAccessible::Skip(celt));
}
// --------------------------------------------------------------------------
//
// HrGetWindowNameNoLabel()
//
// This variation of HrGetWindowName (originally from client.cpp)
// never uses a label. (HrGetWindowName would alway use a label
// if window text was "" and window was in a dialog. That's not
// appropriate for getting combo value text, though...)
//
// --------------------------------------------------------------------------
HRESULT HrGetWindowNameNoLabel(HWND hwnd, BSTR* pszName)
{
LPTSTR lpText = NULL;
if( ! IsWindow( hwnd ) )
return E_INVALIDARG;
// Look for a name property!
lpText = GetTextString( hwnd, FALSE );
if( ! lpText )
return S_FALSE;
// Strip out the mnemonic.
StripMnemonic(lpText);
// Get a BSTR
*pszName = TCharSysAllocString( lpText );
// Free our buffer
LocalFree( (HANDLE)lpText );
// Did the BSTR succeed?
if( ! *pszName )
return E_OUTOFMEMORY;
return S_OK;
}