/************************************************************************************************* * Description: Implementation of the ListProvider class, which implements a * UI Automation provider for a custom list control. * * See EntryPoint.cpp for a full description of this sample. * * * Copyright (C) Microsoft Corporation. All rights reserved. * * This source code is intended only as a supplement to Microsoft * Development Tools and/or on-line documentation. See these other * materials for detailed information regarding Microsoft code samples. * * THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. * *************************************************************************************************/ #define INITGUID #include #include #include #include #include "UIAProviders.h" #include "CustomControl.h" HFONT GetFont(LONG ht); ListProvider::ListProvider(CustomListControl* pControl): m_refCount(1), m_pControl(pControl) { m_controlHwnd = pControl->GetHwnd(); } ListProvider::~ListProvider() { } // Retrieves the UI Automation provider for a list item. // ListItemProvider* ListProvider::GetItemProviderByIndex(int index) { if ((index < 0) || (index >= m_pControl->GetCount())) { return NULL; } LISTITERATOR iter = m_pControl->GetItemAt(index); CustomListItem* pItem = static_cast(*iter); if (pItem == NULL) { return NULL; } return pItem->GetListItemProvider(); } // Raises an event when a list item is selected. // // IUnknown implementation. // IFACEMETHODIMP_(ULONG) ListProvider::AddRef() { return InterlockedIncrement(&m_refCount); } IFACEMETHODIMP_(ULONG) ListProvider::Release() { long val = InterlockedDecrement(&m_refCount); if (val == 0) { delete this; } return val; } IFACEMETHODIMP ListProvider::QueryInterface(REFIID riid, void** ppInterface) { if(riid == __uuidof(IUnknown)) *ppInterface =static_cast(this); else if(riid == __uuidof(IRawElementProviderSimple)) *ppInterface =static_cast(this); else if(riid == __uuidof(IRawElementProviderFragment)) *ppInterface =static_cast(this); else if(riid == __uuidof(IRawElementProviderFragmentRoot)) *ppInterface =static_cast(this); else if(riid == __uuidof(ISelectionProvider)) *ppInterface =static_cast(this); else { *ppInterface = NULL; return E_NOINTERFACE; } (static_cast(*ppInterface))->AddRef(); return S_OK; } // IRawElementProviderSimple implementation // // Implementation of IRawElementProviderSimple::get_ProviderOptions. // Gets UI Automation provider options. // IFACEMETHODIMP ListProvider::get_ProviderOptions(ProviderOptions* pRetVal) { *pRetVal = ProviderOptions_ServerSideProvider; return S_OK; } // Implementation of IRawElementProviderSimple::get_PatternProvider. // Gets the object that supports ISelectionPattern. // IFACEMETHODIMP ListProvider::GetPatternProvider(PATTERNID patternId, IUnknown** pRetVal) { *pRetVal = NULL; if (patternId == UIA_SelectionPatternId) { *pRetVal =static_cast(this); AddRef(); } return S_OK; } // Implementation of IRawElementProviderSimple::get_PropertyValue. // Gets custom properties. // IFACEMETHODIMP ListProvider::GetPropertyValue(PROPERTYID propertyId, VARIANT* pRetVal) { // Although it is hard-coded for the purposes of this sample, localizable // text should be stored in, and loaded from, the resource file (.rc). if (propertyId == UIA_LocalizedControlTypePropertyId) { pRetVal->vt = VT_BSTR; pRetVal->bstrVal = SysAllocString(L"contact list"); } else if (propertyId == UIA_ControlTypePropertyId) { pRetVal->vt = VT_I4; pRetVal->lVal = UIA_ListControlTypeId; } else if (propertyId == UIA_IsKeyboardFocusablePropertyId) { pRetVal->vt = VT_BOOL; pRetVal->boolVal = VARIANT_TRUE; } // else pRetVal is empty, and UI Automation will attempt to get the property from // the HostRawElementProvider, which is the default provider for the HWND. // Note that the Name property comes from the Caption property of the control window, // if it has one. else { pRetVal->vt = VT_EMPTY; } return S_OK; } // Implementation of IRawElementProviderSimple::get_HostRawElementProvider. // Gets the default UI Automation provider for the host window. This provider // supplies many properties. // IFACEMETHODIMP ListProvider::get_HostRawElementProvider(IRawElementProviderSimple** pRetVal) { if (m_controlHwnd == NULL) { return UIA_E_ELEMENTNOTAVAILABLE; } HRESULT hr = UiaHostProviderFromHwnd(m_controlHwnd, pRetVal); return hr; } // IRawElementProviderFragment implementation // // Implementation of IRawElementProviderFragment::Navigate. // Enables UI Automation to locate the element in the tree. // Navigation to the parent is handled by the host window provider. // IFACEMETHODIMP ListProvider::Navigate(NavigateDirection direction, IRawElementProviderFragment** pRetVal) { CustomListControl* pListControl = this->m_pControl; CustomListItem* pDest = NULL; IRawElementProviderFragment* pFrag = NULL; LISTITERATOR iter; switch(direction) { case NavigateDirection_FirstChild: iter = pListControl->GetItemAt(0); pDest = (CustomListItem*)(*iter); pFrag = pDest->GetListItemProvider(); break; case NavigateDirection_LastChild: iter = pListControl->GetItemAt(pListControl->GetCount()-1); pDest = (CustomListItem*)(*iter); pFrag = pDest->GetListItemProvider(); break; } if (pFrag != NULL) { pFrag->AddRef(); } *pRetVal = pFrag; return S_OK; } // Implementation of IRawElementProviderFragment::GetRuntimeId. // UI Automation gets this value from the host window provider, so supply NULL here. // IFACEMETHODIMP ListProvider::GetRuntimeId(SAFEARRAY** pRetVal) { *pRetVal = NULL; return S_OK; } // Implementation of IRawElementProviderFragment::get_BoundingRectangle. // // Retrieves the screen location and size of the control. Controls hosted in // Win32 windows can return an empty rectangle; UI Automation will // retrieve the rectangle from the HWND provider. However, the method is // implemented here so that it can be used by the list items to calculate // their own bounding rectangles. // // UI Spy uses the bounding rectangle to draw a red border around the element. // IFACEMETHODIMP ListProvider::get_BoundingRectangle(UiaRect* pRetVal) { RECT rect; GetClientRect(m_controlHwnd, &rect); InflateRect(&rect, -2, -2); POINT upperLeft; upperLeft.x = rect.left; upperLeft.y = rect.top; ClientToScreen(m_controlHwnd, &upperLeft); pRetVal->left = upperLeft.x; pRetVal->top = upperLeft.y; pRetVal->width = rect.right - rect.left; pRetVal->height = rect.bottom - rect.top; return S_OK; } // Implementation of IRawElementProviderFragment::GetEmbeddedFragmentRoots. // Retrieves other fragment roots that may be hosted in this one. // IFACEMETHODIMP ListProvider::GetEmbeddedFragmentRoots(SAFEARRAY** pRetVal) { *pRetVal = NULL; return S_OK; } // Implementation of IRawElementProviderFragment::SetFocus. // Responds to the control receiving focus through a UI Automation request. // For HWND-based controls, this is handled by the host window provider. // IFACEMETHODIMP ListProvider::SetFocus() { return S_OK; } // Implementation of IRawElementProviderFragment::get_FragmentRoot. // Retrieves the root element of this fragment. // IFACEMETHODIMP ListProvider::get_FragmentRoot(IRawElementProviderFragmentRoot** pRetVal) { *pRetVal = static_cast(this); AddRef(); return S_OK; } // IRawElementProviderFragmentRoot implementation // // Implementation of IRawElementProviderFragmentRoot::ElementProviderFromPoint. // Retrieves the IRawElementProviderFragment interface for the item at the specified // point (in client coordinates). // UI Spy uses this to determine what element is under the cursor when Ctrl is pressed. // IFACEMETHODIMP ListProvider::ElementProviderFromPoint(double x, double y, IRawElementProviderFragment** pRetVal) { POINT pt; pt.x = (LONG)x; pt.y = (LONG)y; ScreenToClient(m_controlHwnd, &pt); int itemIndex = m_pControl->IndexFromY(pt.y); ListItemProvider* pItem = GetItemProviderByIndex(itemIndex); if (pItem != NULL) { *pRetVal = static_cast(pItem); pItem->AddRef(); } else { *pRetVal = NULL; } return S_OK; } // Implementation of IRawElementProviderFragmentRoot::GetFocus. // Retrieves the provider for the list item that is selected when the control gets focus. // IFACEMETHODIMP ListProvider::GetFocus(IRawElementProviderFragment** pRetVal) { *pRetVal = NULL; ListItemProvider* pItem = GetItemProviderByIndex(m_pControl->GetSelectedIndex()); if (pItem != NULL) { pItem->AddRef(); *pRetVal = pItem; } return S_OK; } // ISelectionProvider implementation // // Implementation of ISelectionProvider::GetSelection. // Gets the provider(s) for the items(s) selected in the list box. // In this case, only a single item can be selected. // IFACEMETHODIMP ListProvider::GetSelection(SAFEARRAY** pRetVal) { SAFEARRAY *psa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1); int index = m_pControl->GetSelectedIndex(); ListItemProvider* pItem = GetItemProviderByIndex(index); if (pItem != NULL) { LONG i = 0; SafeArrayPutElement(psa, &i, pItem); } *pRetVal = psa; return S_OK; } // Implementation of ISelectionProvider::get_CanSelectMultiple. // IFACEMETHODIMP ListProvider::get_CanSelectMultiple(BOOL *pRetVal) { *pRetVal = FALSE; return S_OK; } // Implementation of ISelectionProvider::get_IsSelectionRequired. // IFACEMETHODIMP ListProvider::get_IsSelectionRequired(BOOL *pRetVal) { *pRetVal = TRUE; return S_OK; }