1398 lines
38 KiB
C++
1398 lines
38 KiB
C++
// Copyright (c) 1996-1999 Microsoft Corporation
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// LISTBOX.CPP
|
|
//
|
|
// Listbox client class.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
|
|
#include "oleacc_p.h"
|
|
#include "default.h"
|
|
#include "client.h"
|
|
#include "window.h"
|
|
#include "listbox.h"
|
|
|
|
const TCHAR szComboExName[] = TEXT("ComboBoxEx32");
|
|
|
|
STDAPI_(LPTSTR) MyPathFindFileName(LPCTSTR pPath);
|
|
|
|
|
|
BOOL IsTridentControl( HWND hWnd, BOOL fCombo, BOOL fComboList );
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CreateListBoxClient()
|
|
//
|
|
// EXTERNAL for CClient.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
HRESULT CreateListBoxClient(HWND hwnd, long idChildCur, REFIID riid, void** ppvListBox)
|
|
{
|
|
CListBox * plist;
|
|
HRESULT hr;
|
|
|
|
InitPv(ppvListBox);
|
|
|
|
plist = new CListBox(hwnd, idChildCur);
|
|
if (!plist)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
hr = plist->QueryInterface(riid, ppvListBox);
|
|
if (!SUCCEEDED(hr))
|
|
delete plist;
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::CListBox()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
CListBox::CListBox(HWND hwnd, long idChildCur)
|
|
: CClient( CLASS_ListBoxClient )
|
|
{
|
|
Initialize(hwnd, idChildCur);
|
|
|
|
//
|
|
// Check both the style and the CBOX data--SQL srvr creates controls
|
|
// with bogus styles sometimes and could fool us into thinking this
|
|
// was a combo. USER's listbox creation code does the same check.
|
|
//
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & LBS_COMBOBOX)
|
|
{
|
|
COMBOBOXINFO cbi;
|
|
|
|
if (MyGetComboBoxInfo(hwnd, &cbi))
|
|
{
|
|
m_fComboBox = TRUE;
|
|
if (!(cbi.stateButton & STATE_SYSTEM_INVISIBLE))
|
|
m_fDropDown = TRUE;
|
|
}
|
|
}
|
|
|
|
m_fUseLabel = !m_fComboBox;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::SetupChildren()
|
|
//
|
|
// Sets the # of items we have.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
void CListBox::SetupChildren(void)
|
|
{
|
|
m_cChildren = SendMessageINT(m_hwnd, LB_GETCOUNT, 0, 0L);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accName()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accName(VARIANT varChild, BSTR *pszName)
|
|
{
|
|
InitPv(pszName);
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
if (! ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
if (varChild.lVal == CHILDID_SELF)
|
|
{
|
|
if (m_fComboBox)
|
|
{
|
|
IAccessible* pacc;
|
|
HRESULT hr;
|
|
COMBOBOXINFO cbi;
|
|
|
|
//
|
|
// Forward request up to combobox to get its name.
|
|
//
|
|
if (!MyGetComboBoxInfo(m_hwnd, &cbi))
|
|
return(S_FALSE);
|
|
|
|
pacc = NULL;
|
|
hr = AccessibleObjectFromWindow(cbi.hwndCombo, OBJID_CLIENT,
|
|
IID_IAccessible, (void**)&pacc);
|
|
if (!SUCCEEDED(hr) || !pacc)
|
|
return(S_FALSE);
|
|
|
|
Assert(varChild.lVal == 0);
|
|
hr = pacc->get_accName(varChild, pszName);
|
|
pacc->Release();
|
|
|
|
return(hr);
|
|
}
|
|
else
|
|
return(CClient::get_accName(varChild, pszName));
|
|
}
|
|
else
|
|
{
|
|
UINT cch;
|
|
COMBOBOXINFO cbi;
|
|
UINT msgLen;
|
|
UINT msgText;
|
|
HWND hwndAsk;
|
|
|
|
//
|
|
// For a combobox, ask the COMBO for its text. A lot of apps have
|
|
// ownerdraw items, but actually subclass combos and return real
|
|
// text for the items.
|
|
//
|
|
if (m_fComboBox && MyGetComboBoxInfo(m_hwnd, &cbi))
|
|
{
|
|
HWND hwndT;
|
|
|
|
hwndAsk = cbi.hwndCombo;
|
|
if (hwndT = IsInComboEx(cbi.hwndCombo))
|
|
hwndAsk = hwndT;
|
|
|
|
msgLen = CB_GETLBTEXTLEN;
|
|
msgText = CB_GETLBTEXT;
|
|
}
|
|
else
|
|
{
|
|
hwndAsk = m_hwnd;
|
|
msgLen = LB_GETTEXTLEN;
|
|
msgText = LB_GETTEXT;
|
|
}
|
|
|
|
//
|
|
// Get the item text.
|
|
//
|
|
cch = SendMessageINT(hwndAsk, msgLen, varChild.lVal-1, 0);
|
|
|
|
// Some apps do not handle LB_GETTEXTLEN correctly, and
|
|
// always return a small number, like 2.
|
|
if (cch < 1024)
|
|
cch = 1024;
|
|
|
|
if (cch)
|
|
{
|
|
// HACK ALERT
|
|
// The IE4 listbox is a superclassed standard listbox,
|
|
// but if I use SendMessageA (which I do) to get the
|
|
// text, I just get back one character. 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 LB_GETTEXT.
|
|
// I was going to base this on the classname of the listbox
|
|
// window, which is "Internet Explorer_TridentLstBox", 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.
|
|
|
|
// TCHAR szModuleName[MAX_PATH];
|
|
// LPTSTR lpszModuleName;
|
|
// GetWindowModuleFileName(hwndAsk,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, m_fComboBox, m_fComboBox ) )
|
|
{
|
|
OLECHAR* lpszUnicodeText = NULL;
|
|
OLECHAR* lpszLocalText = NULL;
|
|
HANDLE hProcess;
|
|
|
|
if (msgText == LB_GETTEXT)
|
|
msgText = WM_USER+LB_GETTEXT;
|
|
else if (msgText == CB_GETLBTEXT)
|
|
msgText = WM_USER+CB_GETLBTEXT;
|
|
|
|
lpszUnicodeText = (OLECHAR *)SharedAlloc((cch+1)*sizeof(OLECHAR),
|
|
hwndAsk,
|
|
&hProcess);
|
|
lpszLocalText = (OLECHAR*)LocalAlloc(LPTR,(cch+1)*sizeof(OLECHAR));
|
|
|
|
if (!lpszUnicodeText || !lpszLocalText)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
cch = SendMessageINT(hwndAsk, msgText, varChild.lVal-1, (LPARAM)lpszUnicodeText);
|
|
SharedRead (lpszUnicodeText,lpszLocalText,(cch+1)*sizeof(OLECHAR),hProcess);
|
|
|
|
*pszName = SysAllocString(lpszLocalText);
|
|
|
|
SharedFree(lpszUnicodeText,hProcess);
|
|
LocalFree(lpszLocalText);
|
|
}
|
|
else // normal, non IE4 code here:
|
|
{
|
|
LPTSTR lpszText;
|
|
|
|
lpszText = (LPTSTR)LocalAlloc(LPTR, (cch+1)*sizeof(TCHAR));
|
|
if (!lpszText)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
SendMessage(hwndAsk, msgText, varChild.lVal-1, (LPARAM)lpszText);
|
|
*pszName = TCharSysAllocString(lpszText);
|
|
|
|
LocalFree((HANDLE)lpszText);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accRole()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accRole(VARIANT varChild, VARIANT* pvarRole)
|
|
{
|
|
InitPvar(pvarRole);
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
if (! ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
pvarRole->vt = VT_I4;
|
|
|
|
if (varChild.lVal)
|
|
pvarRole->lVal = ROLE_SYSTEM_LISTITEM;
|
|
else
|
|
pvarRole->lVal = ROLE_SYSTEM_LIST;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accState()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accState(VARIANT varChild, VARIANT *pvarState)
|
|
{
|
|
RECT rcItem;
|
|
long lStyle;
|
|
|
|
InitPvar(pvarState);
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
if (! ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
if (varChild.lVal == CHILDID_SELF)
|
|
return(CClient::get_accState(varChild, pvarState));
|
|
|
|
|
|
--varChild.lVal;
|
|
|
|
pvarState->vt = VT_I4;
|
|
pvarState->lVal = 0;
|
|
|
|
//
|
|
// Is this item selected?
|
|
//
|
|
if (SendMessage(m_hwnd, LB_GETSEL, varChild.lVal, 0))
|
|
pvarState->lVal |= STATE_SYSTEM_SELECTED;
|
|
|
|
//
|
|
// Does it have the focus? Remember that we decremented the lVal so it
|
|
// is zero-based like listbox indeces.
|
|
//
|
|
if (MyGetFocus() == m_hwnd)
|
|
{
|
|
pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
|
|
|
|
if (SendMessage(m_hwnd, LB_GETCARETINDEX, 0, 0) == varChild.lVal)
|
|
pvarState->lVal |= STATE_SYSTEM_FOCUSED;
|
|
}
|
|
else if (m_fComboBox)
|
|
{
|
|
COMBOBOXINFO cbi;
|
|
if (MyGetComboBoxInfo(m_hwnd, &cbi))
|
|
{
|
|
// if this list is part of a combo box, AND the list
|
|
// is showing (m_fDropdown is true), then say we are
|
|
// focusable.
|
|
if (m_fDropDown)
|
|
{
|
|
pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
|
|
if (MyGetFocus() == cbi.hwndCombo && IsWindowVisible( m_hwnd ) )
|
|
{
|
|
if (SendMessage(m_hwnd, LB_GETCARETINDEX, 0, 0) == varChild.lVal)
|
|
pvarState->lVal |= STATE_SYSTEM_FOCUSED;
|
|
}
|
|
} // end if it is dropped
|
|
} // end if we got combo box info
|
|
} // end if this is a combox box list
|
|
|
|
//
|
|
// Is the listbox read-only?
|
|
//
|
|
lStyle = GetWindowLong(m_hwnd, GWL_STYLE);
|
|
|
|
if (lStyle & LBS_NOSEL)
|
|
pvarState->lVal |= STATE_SYSTEM_READONLY;
|
|
else
|
|
{
|
|
pvarState->lVal |= STATE_SYSTEM_SELECTABLE;
|
|
|
|
//
|
|
// Is the listbox multiple and/or extended sel? NOTE: We have
|
|
// no way to implement accSelect() EXTENDSELECTION so don't.
|
|
//
|
|
if (lStyle & LBS_MULTIPLESEL)
|
|
pvarState->lVal |= STATE_SYSTEM_MULTISELECTABLE;
|
|
}
|
|
|
|
//
|
|
// Is the item in view?
|
|
//
|
|
// SMD 09/16/97 Offscreen things are things never on the screen,
|
|
// and that doesn't apply to this. Changed from OFFSCREEN to
|
|
// INVISIBLE.
|
|
if( ! IsWindowVisible( m_hwnd ) )
|
|
{
|
|
pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
|
|
}
|
|
else if( ! SendMessage(m_hwnd, LB_GETITEMRECT, varChild.lVal, (LPARAM)&rcItem))
|
|
{
|
|
// LB_GETITEMRECT returns FALSE if the item is clipped...
|
|
pvarState->lVal |= STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN;
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accKeyboardShortcut()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszShortcut)
|
|
{
|
|
InitPv(pszShortcut);
|
|
|
|
//
|
|
// Validate
|
|
//
|
|
if (! ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
if ((varChild.lVal == 0) && !m_fComboBox)
|
|
return(CClient::get_accKeyboardShortcut(varChild, pszShortcut));
|
|
|
|
return(E_NOT_APPLICABLE);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accFocus()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accFocus(VARIANT *pvarChild)
|
|
{
|
|
InitPvar(pvarChild);
|
|
|
|
//
|
|
// Are we the focus?
|
|
//
|
|
if (MyGetFocus() == m_hwnd)
|
|
{
|
|
long lCaret;
|
|
|
|
pvarChild->vt = VT_I4;
|
|
|
|
lCaret = SendMessageINT(m_hwnd, LB_GETCARETINDEX, 0, 0L);
|
|
if (lCaret != LB_ERR)
|
|
pvarChild->lVal = lCaret+1;
|
|
else
|
|
pvarChild->lVal = 0;
|
|
|
|
return(S_OK);
|
|
}
|
|
else
|
|
return(S_FALSE);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accSelection()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accSelection(VARIANT *pvarSelection)
|
|
{
|
|
return(GetListBoxSelection(m_hwnd, pvarSelection));
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::get_accDefaultAction()
|
|
//
|
|
// Since the default action for a listbox item is really determined by the
|
|
// creator of the listbox control, the best we can do is double click on
|
|
// the thing, and return "double click" as the default action string.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::get_accDefaultAction(VARIANT varChild, BSTR* pszDefAction)
|
|
{
|
|
InitPv(pszDefAction);
|
|
|
|
//
|
|
// Validate.
|
|
//
|
|
if (!ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
if (varChild.lVal)
|
|
return (HrCreateString(STR_DOUBLE_CLICK, pszDefAction));
|
|
|
|
return(E_NOT_APPLICABLE);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::accDoDefaultAction()
|
|
//
|
|
// As noted above, we really don't know what the default action for a list
|
|
// box item is, so unless the parent overrides us, we'll just do a double
|
|
// click on the thing.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::accDoDefaultAction(VARIANT varChild)
|
|
{
|
|
RECT rcLoc;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Validate
|
|
//
|
|
if (!ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
if (varChild.lVal)
|
|
{
|
|
hr = accLocation(&rcLoc.left,&rcLoc.top,&rcLoc.right,&rcLoc.bottom,varChild);
|
|
if (!SUCCEEDED (hr))
|
|
return (hr);
|
|
|
|
// this will check if WindowFromPoint at the click point is the same
|
|
// as m_hwnd, and if not, it won't click. Cool!
|
|
if (ClickOnTheRect(&rcLoc,m_hwnd,TRUE))
|
|
return (S_OK);
|
|
}
|
|
return(E_NOT_APPLICABLE);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::accSelect()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::accSelect(long selFlags, VARIANT varChild)
|
|
{
|
|
long lStyle;
|
|
int nFocusedItem;
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
if (! ValidateChild(&varChild) ||
|
|
! ValidateSelFlags(selFlags))
|
|
return(E_INVALIDARG);
|
|
|
|
if (!varChild.lVal)
|
|
return(CClient::accSelect(selFlags, varChild));
|
|
|
|
varChild.lVal--;
|
|
|
|
lStyle = GetWindowLong(m_hwnd, GWL_STYLE);
|
|
if (lStyle & LBS_NOSEL)
|
|
return(E_NOT_APPLICABLE);
|
|
|
|
|
|
if (selFlags & SELFLAG_TAKEFOCUS)
|
|
{
|
|
MySetFocus(m_hwnd);
|
|
}
|
|
|
|
|
|
// note that LB_SETCURSEL doesn't work for extended or multi-select
|
|
// listboxes, have to use LB_SELITEMRANGE or LB_SETSEL.
|
|
if ((lStyle & LBS_MULTIPLESEL) ||
|
|
(lStyle & LBS_EXTENDEDSEL))
|
|
{
|
|
// get the focused item here in case we change it.
|
|
nFocusedItem = SendMessageINT(m_hwnd,LB_GETCARETINDEX,0,0);
|
|
|
|
if (selFlags & SELFLAG_TAKEFOCUS)
|
|
{
|
|
if (MyGetFocus() != m_hwnd)
|
|
return(S_FALSE);
|
|
SendMessage (m_hwnd, LB_SETCARETINDEX,varChild.lVal,0);
|
|
}
|
|
|
|
// These seem to be weird - when you tell it to set the selection, it
|
|
// also sets the focus. So we remember focus and reset it at the end.
|
|
if (selFlags & SELFLAG_TAKESELECTION)
|
|
{
|
|
// deselect the whole range of items
|
|
SendMessage(m_hwnd, LB_SETSEL,FALSE,-1);
|
|
// Select this one
|
|
SendMessage(m_hwnd, LB_SETSEL, TRUE, varChild.lVal);
|
|
}
|
|
|
|
if (selFlags & SELFLAG_EXTENDSELECTION)
|
|
{
|
|
BOOL bSelected;
|
|
|
|
if ((selFlags & SELFLAG_ADDSELECTION) || (selFlags & SELFLAG_REMOVESELECTION))
|
|
SendMessage (m_hwnd,LB_SELITEMRANGE,(selFlags & SELFLAG_ADDSELECTION),MAKELPARAM(nFocusedItem,varChild.lVal));
|
|
else
|
|
{
|
|
bSelected = SendMessageINT(m_hwnd,LB_GETSEL,nFocusedItem,0);
|
|
SendMessage (m_hwnd,LB_SELITEMRANGE,bSelected,MAKELPARAM(nFocusedItem,varChild.lVal));
|
|
}
|
|
}
|
|
else // not extending, check add/remove
|
|
{
|
|
if ((selFlags & SELFLAG_ADDSELECTION) || (selFlags & SELFLAG_REMOVESELECTION))
|
|
SendMessage(m_hwnd, LB_SETSEL, (selFlags & SELFLAG_ADDSELECTION),varChild.lVal);
|
|
}
|
|
// set focus to where it was before if SELFLAG_TAKEFOCUS not set
|
|
if ((selFlags & SELFLAG_TAKEFOCUS) == 0)
|
|
SendMessage (m_hwnd, LB_SETCARETINDEX,nFocusedItem,0);
|
|
}
|
|
else // listbox is single select
|
|
{
|
|
if (selFlags & (SELFLAG_ADDSELECTION |
|
|
SELFLAG_REMOVESELECTION |
|
|
SELFLAG_EXTENDSELECTION))
|
|
return (E_INVALIDARG);
|
|
|
|
// single select listboxes do not allow you to set the
|
|
// focus independently of the selection, so we send a
|
|
// LB_SETCURSEL for both TAKESELECTION and TAKEFOCUS
|
|
if ((selFlags & SELFLAG_TAKESELECTION) ||
|
|
(selFlags & SELFLAG_TAKEFOCUS))
|
|
SendMessage(m_hwnd, LB_SETCURSEL, varChild.lVal, 0);
|
|
} // end if listbox is single select
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::accLocation()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::accLocation(long* pxLeft, long *pyTop, long* pcxWidth,
|
|
long* pcyHeight, VARIANT varChild)
|
|
{
|
|
RECT rc;
|
|
|
|
InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
|
|
|
|
//
|
|
// Validate params
|
|
//
|
|
if (! ValidateChild(&varChild))
|
|
return(E_INVALIDARG);
|
|
|
|
if (!varChild.lVal)
|
|
return(CClient::accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild));
|
|
|
|
//
|
|
// Get item rect.
|
|
//
|
|
if (SendMessage(m_hwnd, LB_GETITEMRECT, varChild.lVal-1, (LPARAM)&rc))
|
|
{
|
|
MapWindowPoints(m_hwnd, NULL, (LPPOINT)&rc, 2);
|
|
|
|
*pxLeft = rc.left;
|
|
*pyTop = rc.top;
|
|
*pcxWidth = rc.right - rc.left;
|
|
*pcyHeight = rc.bottom - rc.top;
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::accNavigate()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::accNavigate(long dwNavDir, VARIANT varStart, VARIANT *pvarEnd)
|
|
{
|
|
long lEnd;
|
|
long lRows;
|
|
|
|
InitPvar(pvarEnd);
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
if (! ValidateChild(&varStart) ||
|
|
! ValidateNavDir(dwNavDir, varStart.lVal))
|
|
return(E_INVALIDARG);
|
|
|
|
//
|
|
// Is this something for the client (or combobox) to handle?
|
|
//
|
|
if (dwNavDir == NAVDIR_FIRSTCHILD)
|
|
{
|
|
lEnd = 1;
|
|
if (lEnd > m_cChildren)
|
|
lEnd = 0;
|
|
}
|
|
else if (dwNavDir == NAVDIR_LASTCHILD)
|
|
lEnd = m_cChildren;
|
|
else if (varStart.lVal == CHILDID_SELF)
|
|
return(CClient::accNavigate(dwNavDir, varStart, pvarEnd));
|
|
else
|
|
{
|
|
long lT;
|
|
|
|
lRows = MyGetListBoxInfo(m_hwnd);
|
|
if (!lRows)
|
|
return(S_FALSE);
|
|
|
|
lEnd = 0;
|
|
|
|
lT = varStart.lVal - 1;
|
|
|
|
switch (dwNavDir)
|
|
{
|
|
case NAVDIR_LEFT:
|
|
//
|
|
// Are there any items to the left of us?
|
|
//
|
|
if (lT >= lRows)
|
|
lEnd = varStart.lVal - lRows;
|
|
break;
|
|
|
|
case NAVDIR_RIGHT:
|
|
//
|
|
// Are there are any items to the right of us?
|
|
//
|
|
if (lT + lRows < m_cChildren)
|
|
lEnd = varStart.lVal + lRows;
|
|
break;
|
|
|
|
case NAVDIR_UP:
|
|
//
|
|
// Are we in the top-most row?
|
|
//
|
|
if ((lT % lRows) != 0)
|
|
lEnd = varStart.lVal - 1;
|
|
break;
|
|
|
|
case NAVDIR_DOWN:
|
|
//
|
|
// Are we the last item or in the bottom-most row?
|
|
//
|
|
if (((lT+1) % lRows) != 0)
|
|
{
|
|
lEnd = varStart.lVal + 1;
|
|
if (lEnd > m_cChildren)
|
|
lEnd = 0;
|
|
}
|
|
break;
|
|
|
|
case NAVDIR_PREVIOUS:
|
|
lEnd = varStart.lVal - 1;
|
|
break;
|
|
|
|
case NAVDIR_NEXT:
|
|
lEnd = varStart.lVal + 1;
|
|
if (lEnd > m_cChildren)
|
|
lEnd = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lEnd)
|
|
{
|
|
pvarEnd->vt = VT_I4;
|
|
pvarEnd->lVal = lEnd;
|
|
}
|
|
|
|
return(lEnd ? S_OK : S_FALSE);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBox::accHitTest()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBox::accHitTest(long xLeft, long yTop, VARIANT *pvarHit)
|
|
{
|
|
POINT pt;
|
|
RECT rc;
|
|
long l;
|
|
|
|
InitPvar(pvarHit);
|
|
|
|
//
|
|
// Is the point in our client area?
|
|
//
|
|
pt.x = xLeft;
|
|
pt.y = yTop;
|
|
ScreenToClient(m_hwnd, &pt);
|
|
|
|
MyGetRect(m_hwnd, &rc, FALSE);
|
|
|
|
if (!PtInRect(&rc, pt))
|
|
return(S_FALSE);
|
|
|
|
//
|
|
// What item is here?
|
|
//
|
|
l = SendMessageINT(m_hwnd, LB_ITEMFROMPOINT, 0, MAKELONG(pt.x, pt.y));
|
|
|
|
pvarHit->vt = VT_I4;
|
|
|
|
if (HIWORD(l))
|
|
{
|
|
// Outside bounds, in white space.
|
|
pvarHit->lVal = 0;
|
|
}
|
|
else
|
|
{
|
|
pvarHit->lVal = (int)(short)LOWORD(l) + 1;
|
|
}
|
|
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CreateListBoxWindow()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
HRESULT CreateListBoxWindow(HWND hwnd, long idChildCur, REFIID riid, void** ppvListBoxW)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CListBoxFrame * plframe;
|
|
|
|
InitPv(ppvListBoxW);
|
|
|
|
plframe = new CListBoxFrame(hwnd, idChildCur);
|
|
if (!plframe)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
hr = plframe->QueryInterface(riid, ppvListBoxW);
|
|
if (!SUCCEEDED(hr))
|
|
delete plframe;
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxFrame::CListBoxFrame()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
CListBoxFrame::CListBoxFrame(HWND hwnd, long iChildCur)
|
|
: CWindow( CLASS_ListBoxWindow )
|
|
{
|
|
Initialize(hwnd, iChildCur);
|
|
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & LBS_COMBOBOX)
|
|
{
|
|
COMBOBOXINFO cbi;
|
|
|
|
if (MyGetComboBoxInfo(hwnd, &cbi))
|
|
{
|
|
m_fComboBox = TRUE;
|
|
if (!(cbi.stateButton & STATE_SYSTEM_INVISIBLE))
|
|
m_fDropDown = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxFrame::get_accParent()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxFrame::get_accParent(IDispatch** ppdispParent)
|
|
{
|
|
InitPv(ppdispParent);
|
|
|
|
//
|
|
// We need to handle combo dropdowns specially, since they are made
|
|
// children of the desktop for free floating.
|
|
//
|
|
if (m_fComboBox && m_fDropDown)
|
|
{
|
|
COMBOBOXINFO cbi;
|
|
|
|
if (!MyGetComboBoxInfo(m_hwnd, &cbi))
|
|
return(S_FALSE);
|
|
|
|
//
|
|
// Get the combo info and create our combobox parent.
|
|
//
|
|
return(AccessibleObjectFromWindow(cbi.hwndCombo, OBJID_CLIENT,
|
|
IID_IDispatch, (void**)ppdispParent));
|
|
}
|
|
else
|
|
return(CWindow::get_accParent(ppdispParent));
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxFrame::get_accState()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxFrame::get_accState(VARIANT varStart, VARIANT *pvarState)
|
|
{
|
|
HRESULT hr;
|
|
|
|
InitPvar(pvarState);
|
|
|
|
if (! ValidateChild(&varStart))
|
|
return(E_INVALIDARG);
|
|
|
|
//
|
|
// Get the window's state
|
|
//
|
|
hr = CWindow::get_accState(varStart, pvarState);
|
|
if (SUCCEEDED(hr) && m_fComboBox && m_fDropDown && (varStart.lVal == 0))
|
|
{
|
|
pvarState->lVal |= STATE_SYSTEM_FLOATING;
|
|
}
|
|
return(hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note: this code was never used - the signature of accNavigate here is
|
|
// incorrect - it should be (long dwNavDir, VARIANT varStart, VARIANT *pVarEnd).
|
|
//
|
|
// However, while enabling this version does solve some problems, it introduces
|
|
// more of its own.
|
|
//
|
|
// eg. while navigating through top-level windows, if you hit a combolbox window,
|
|
// you get stuck, and can't navigate back out again.
|
|
//
|
|
// So, for the moment, it's being left disabled; but remains here for reference.
|
|
// It may be possible to re-enable it, but other code would have to be altered
|
|
// to make it work consistently.
|
|
#if 0
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxFrame::accNavigate()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxFrame::accNavigate(VARIANT varStart, long dwNavDir,
|
|
VARIANT* pvarEnd)
|
|
{
|
|
COMBOBOXINFO cbi;
|
|
|
|
InitPvar(pvarEnd);
|
|
|
|
//
|
|
// Validate.
|
|
//
|
|
if (! ValidateChild(&varStart) ||
|
|
! ValidateNavDir(dwNavDir, varStart.lVal))
|
|
return(E_INVALIDARG);
|
|
|
|
//
|
|
// Hand off to CWindow if (1) first child, (2) non-zero start.
|
|
//
|
|
Assert(NAVDIR_LASTCHILD > NAVDIR_FIRSTCHILD);
|
|
|
|
if (!m_fComboBox || (dwNavDir >= NAVDIR_FIRSTCHILD) || varStart.lVal)
|
|
return(CWindow::accNavigate(dwNavDir, varStart, pvarEnd));
|
|
|
|
//
|
|
// Get our parent window
|
|
//
|
|
if (! MyGetComboBoxInfo(m_hwnd, &cbi))
|
|
return(S_FALSE);
|
|
|
|
return(GetParentToNavigate(INDEX_COMBOBOX_LIST, cbi.hwndCombo,
|
|
OBJID_CLIENT, dwNavDir, pvarEnd));
|
|
}
|
|
// Unused CListBoxFrame::accNavigate implementation
|
|
// See comment at top for more information.
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MULTIPLE SELECTION LISTBOX SUPPORT
|
|
//
|
|
// If a listbox has more than one item selected, we create an object
|
|
// that is a clone. It keeps a list of the selected items. Its sole
|
|
// purpose is to respond to IEnumVARIANT, a collection. The caller should
|
|
// either
|
|
// (a) Pass the child ID to the parent object to get acc info
|
|
// (b) Call the child directly if VT_DISPATCH.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// GetListBoxSelection()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
HRESULT GetListBoxSelection(HWND hwnd, VARIANT* pvarSelection)
|
|
{
|
|
int cSelected;
|
|
LPINT lpSelected;
|
|
long lRet;
|
|
CListBoxSelection * plbs;
|
|
|
|
InitPvar(pvarSelection);
|
|
|
|
cSelected = SendMessageINT(hwnd, LB_GETSELCOUNT, 0, 0);
|
|
|
|
if (cSelected <= 1)
|
|
{
|
|
//
|
|
// cSelected is -1, 0, or 1.
|
|
// -1 means this is a single sel listbox.
|
|
// 0 or 1 means this is multisel
|
|
//
|
|
lRet = SendMessageINT(hwnd, LB_GETCURSEL, 0, 0);
|
|
if (lRet == -1)
|
|
return(S_FALSE);
|
|
|
|
pvarSelection->vt = VT_I4;
|
|
pvarSelection->lVal = lRet+1;
|
|
return(S_OK);
|
|
}
|
|
|
|
//
|
|
// Multiple items; must make a collection
|
|
//
|
|
|
|
//
|
|
// Allocate memory for the list of item IDs
|
|
//
|
|
lpSelected = (LPINT)LocalAlloc(LPTR, cSelected*sizeof(INT));
|
|
if (!lpSelected)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
//
|
|
// Get the list of selected item IDs
|
|
//
|
|
plbs = NULL;
|
|
|
|
lRet = SendMessageINT(hwnd, LB_GETSELITEMS, cSelected, (LPARAM)lpSelected);
|
|
if (lRet != LB_ERR)
|
|
{
|
|
plbs = new CListBoxSelection(0, lRet, lpSelected);
|
|
if (plbs)
|
|
{
|
|
pvarSelection->vt = VT_UNKNOWN;
|
|
plbs->QueryInterface(IID_IUnknown, (void**)&(pvarSelection->punkVal));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the list memory; the constructor will make a copy. This is
|
|
// because the constructor is called both from create and clone.
|
|
//
|
|
LocalFree((HANDLE)lpSelected);
|
|
|
|
if (!plbs)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::CListBoxSelection()
|
|
//
|
|
// We AddRef() once plistFrom so that it won't go away out from us. When
|
|
// we are destroyed, we will Release() it.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
CListBoxSelection::CListBoxSelection(int iChildCur, int cSelected, LPINT lpSelection)
|
|
{
|
|
m_idChildCur = iChildCur;
|
|
|
|
m_lpSelected = (LPINT)LocalAlloc(LPTR, cSelected*sizeof(int));
|
|
if (!m_lpSelected)
|
|
m_cSelected = 0;
|
|
else
|
|
{
|
|
m_cSelected = cSelected;
|
|
CopyMemory(m_lpSelected, lpSelection, cSelected*sizeof(int));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::~CListBoxSelection()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
CListBoxSelection::~CListBoxSelection()
|
|
{
|
|
//
|
|
// Free item memory
|
|
//
|
|
if (m_lpSelected)
|
|
{
|
|
LocalFree((HANDLE)m_lpSelected);
|
|
m_lpSelected = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::QueryInterface()
|
|
//
|
|
// We only respond to IUnknown and IEnumVARIANT! It is the responsibility
|
|
// of the caller to loop through the items using IEnumVARIANT interfaces,
|
|
// and get the child IDs to then pass to the parent object (or call
|
|
// directly if VT_DISPATCH--not in this case they aren't though).
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxSelection::QueryInterface(REFIID riid, void** ppunk)
|
|
{
|
|
*ppunk = NULL;
|
|
|
|
if ((riid == IID_IUnknown) ||
|
|
(riid == IID_IEnumVARIANT))
|
|
{
|
|
*ppunk = this;
|
|
}
|
|
else
|
|
return(E_NOINTERFACE);
|
|
|
|
((LPUNKNOWN) *ppunk)->AddRef();
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::AddRef()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CListBoxSelection::AddRef(void)
|
|
{
|
|
return(++m_cRef);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::Release()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CListBoxSelection::Release(void)
|
|
{
|
|
if ((--m_cRef) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return(m_cRef);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::Next()
|
|
//
|
|
// This returns a VT_I4 which is the child ID for the parent listbox that
|
|
// returned this object for the selection collection. The caller turns
|
|
// around and passes this variant to the listbox object to get acc info
|
|
// about it.
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxSelection::Next(ULONG celt, VARIANT* rgvar, ULONG *pceltFetched)
|
|
{
|
|
VARIANT* pvar;
|
|
long cFetched;
|
|
long iCur;
|
|
|
|
// Can be NULL
|
|
if (pceltFetched)
|
|
*pceltFetched = 0;
|
|
|
|
//
|
|
// Initialize VARIANTs
|
|
// This is so bogus
|
|
//
|
|
pvar = rgvar;
|
|
for (iCur = 0; iCur < (long)celt; iCur++, pvar++)
|
|
VariantInit(pvar);
|
|
|
|
pvar = rgvar;
|
|
cFetched = 0;
|
|
iCur = m_idChildCur;
|
|
|
|
//
|
|
// Loop through our items
|
|
//
|
|
while ((cFetched < (long)celt) && (iCur < m_cSelected))
|
|
{
|
|
pvar->vt = VT_I4;
|
|
pvar->lVal = m_lpSelected[iCur] + 1;
|
|
|
|
++cFetched;
|
|
++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);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::Skip()
|
|
//
|
|
// -------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxSelection::Skip(ULONG celt)
|
|
{
|
|
m_idChildCur += celt;
|
|
if (m_idChildCur > m_cSelected)
|
|
m_idChildCur = m_cSelected;
|
|
|
|
//
|
|
// We return S_FALSE if at the end.
|
|
//
|
|
return((m_idChildCur >= m_cSelected) ? S_FALSE : S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::Reset()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxSelection::Reset(void)
|
|
{
|
|
m_idChildCur = 0;
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// CListBoxSelection::Clone()
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
STDMETHODIMP CListBoxSelection::Clone(IEnumVARIANT **ppenum)
|
|
{
|
|
CListBoxSelection * plistselnew;
|
|
|
|
InitPv(ppenum);
|
|
|
|
plistselnew = new CListBoxSelection(m_idChildCur, m_cSelected, m_lpSelected);
|
|
if (!plistselnew)
|
|
return(E_OUTOFMEMORY);
|
|
|
|
return(plistselnew->QueryInterface(IID_IEnumVARIANT, (void**)ppenum));
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// IsComboEx()
|
|
//
|
|
// Returns TRUE if this window is a comboex32
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
BOOL IsComboEx(HWND hwnd)
|
|
{
|
|
TCHAR szClass[128];
|
|
|
|
return MyGetWindowClass(hwnd, szClass, ARRAYSIZE(szClass) ) &&
|
|
! lstrcmpi(szClass, szComboExName);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// IsInComboEx()
|
|
//
|
|
// Returns the COMBOEX window if the combo is embedded in a COMBOEX (like
|
|
// on the toolbar).
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
HWND IsInComboEx(HWND hwnd)
|
|
{
|
|
HWND hwndParent = MyGetAncestor(hwnd, GA_PARENT);
|
|
if( hwndParent && IsComboEx(hwndParent) )
|
|
return hwndParent;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Copied from shlwapi\path.c
|
|
//
|
|
// Returns a pointer to the last component of a path string.
|
|
//
|
|
// in:
|
|
// path name, either fully qualified or not
|
|
//
|
|
// returns:
|
|
// pointer into the path where the path is. if none is found
|
|
// returns a poiter to the start of the path
|
|
//
|
|
// c:\foo\bar -> bar
|
|
// c:\foo -> foo
|
|
// c:\foo\ -> c:\foo\ (REVIEW: is this case busted?)
|
|
// c:\ -> c:\ (REVIEW: this case is strange)
|
|
// c: -> c:
|
|
// foo -> foo
|
|
// --------------------------------------------------------------------------
|
|
|
|
STDAPI_(LPTSTR)
|
|
MyPathFindFileName(LPCTSTR pPath)
|
|
{
|
|
LPCTSTR pT;
|
|
|
|
for (pT = pPath; *pPath; pPath = CharNext(pPath)) {
|
|
if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':') || pPath[0] == TEXT('/'))
|
|
&& pPath[1] && pPath[1] != TEXT('\\') && pPath[1] != TEXT('/'))
|
|
pT = pPath + 1;
|
|
}
|
|
|
|
return (LPTSTR)pT; // const -> non const
|
|
}
|
|
|
|
|
|
/*
|
|
* IsTridentControl
|
|
*
|
|
* HWND hWnd
|
|
* window to test against
|
|
* BOOL fCombo
|
|
* TRUE if this is a combo or a combolbox
|
|
* BOOL fComboList
|
|
* TRUE if this is a combolbox (the drop-down list box associated with a combo)
|
|
*
|
|
* This works by comparing class names - "Internet Explorer_TridentCmboBx"
|
|
* for combos, and "Internet Explorer_TridentLstBox" for listboxes.
|
|
* The drop-lists of combos don't have a special class, so instead we get
|
|
* the 'parent' combo, and check it against "Internet Explorer_TridentCmboBx".
|
|
*
|
|
*/
|
|
BOOL IsTridentControl( HWND hWnd, BOOL fCombo, BOOL fComboList )
|
|
{
|
|
// If this is a drop-list, get the associated combo...
|
|
if( fComboList )
|
|
{
|
|
COMBOBOXINFO cbi;
|
|
if( ! MyGetComboBoxInfo( hWnd, & cbi ) || cbi.hwndCombo == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hWnd = cbi.hwndCombo;
|
|
}
|
|
|
|
// Get class name...
|
|
TCHAR szClass[64];
|
|
szClass[0] = '\0';
|
|
GetClassName( hWnd, szClass, ARRAYSIZE( szClass ) );
|
|
|
|
// Compare against expected string...
|
|
TCHAR * pszCompare;
|
|
if( fCombo )
|
|
pszCompare = TEXT("Internet Explorer_TridentCmboBx");
|
|
else
|
|
pszCompare = TEXT("Internet Explorer_TridentLstBox");
|
|
|
|
|
|
return lstrcmp( szClass, pszCompare ) == 0;
|
|
} |