1 
2 #include "studiox_includes.h"
3 #include "uiautomation.h"
4 #include "resource_item_provider.h"
5 #include "resource_view_provider.h"
6 
7 ///////////////////////////////////////////////////////////////////////////////
resource_view_provider(resource_view * pControl)8 resource_view_provider::resource_view_provider(resource_view* pControl)
9 {
10     m_refCount = 1;
11     m_pResViewControl = pControl;
12     m_resViewControlHwnd = pControl->GetSafeHwnd();
13 }
14 
15 ///////////////////////////////////////////////////////////////////////////////
~resource_view_provider()16 resource_view_provider::~resource_view_provider()
17 {
18 }
19 
20 ///////////////////////////////////////////////////////////////////////////////
21 // IUnknown implementation.
22 //
23 ///////////////////////////////////////////////////////////////////////////////
IFACEMETHODIMP_(ULONG)24 IFACEMETHODIMP_(ULONG) resource_view_provider::AddRef()
25 {
26     return InterlockedIncrement(&m_refCount);
27 }
28 
29 ///////////////////////////////////////////////////////////////////////////////
IFACEMETHODIMP_(ULONG)30 IFACEMETHODIMP_(ULONG) resource_view_provider::Release()
31 {
32     long val = InterlockedDecrement(&m_refCount);
33     if (val == 0)
34     {
35         delete this;
36     }
37     return val;
38 }
39 
40 ///////////////////////////////////////////////////////////////////////////////
QueryInterface(REFIID riid,void ** ppInterface)41 IFACEMETHODIMP resource_view_provider::QueryInterface(REFIID riid, void** ppInterface)
42 {
43     if (riid == __uuidof(IUnknown))                              *ppInterface = static_cast<IRawElementProviderSimple*>(this);
44     else if (riid == __uuidof(IRawElementProviderSimple))        *ppInterface = static_cast<IRawElementProviderSimple*>(this);
45     else if (riid == __uuidof(IRawElementProviderFragment))      *ppInterface = static_cast<IRawElementProviderFragment*>(this);
46     else if (riid == __uuidof(IRawElementProviderFragmentRoot))  *ppInterface = static_cast<IRawElementProviderFragmentRoot*>(this);
47     else if (riid == __uuidof(ISelectionProvider))               *ppInterface = static_cast<ISelectionProvider*>(this);
48     else
49     {
50         *ppInterface = NULL;
51         return E_NOINTERFACE;
52     }
53     (static_cast<IUnknown*>(*ppInterface))->AddRef();
54     return S_OK;
55 }
56 
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 // IRawElementProviderSimple implementation
60 //
61 // Implementation of IRawElementProviderSimple::get_ProviderOptions.
62 // Gets UI Automation provider options.
63 //
64 ///////////////////////////////////////////////////////////////////////////////
get_ProviderOptions(ProviderOptions * pRetVal)65 IFACEMETHODIMP resource_view_provider::get_ProviderOptions(ProviderOptions* pRetVal)
66 {
67     *pRetVal = ProviderOptions_ServerSideProvider;
68     return S_OK;
69 }
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 // Implementation of IRawElementProviderSimple::get_PatternProvider.
73 // Gets the object that supports ISelectionPattern.
74 //
75 ///////////////////////////////////////////////////////////////////////////////
GetPatternProvider(PATTERNID patternId,IUnknown ** pRetVal)76 IFACEMETHODIMP resource_view_provider::GetPatternProvider(PATTERNID patternId, IUnknown** pRetVal)
77 {
78     *pRetVal = NULL;
79     if (patternId == UIA_SelectionPatternId)
80     {
81         *pRetVal = static_cast<IRawElementProviderSimple*>(this);
82         AddRef();
83     }
84     return S_OK;
85 }
86 
87 ///////////////////////////////////////////////////////////////////////////////
88 // Implementation of IRawElementProviderSimple::get_PropertyValue.
89 // Gets custom properties.
90 //
91 ///////////////////////////////////////////////////////////////////////////////
GetPropertyValue(PROPERTYID propertyId,VARIANT * pRetVal)92 IFACEMETHODIMP resource_view_provider::GetPropertyValue(PROPERTYID propertyId, VARIANT* pRetVal)
93 {
94     if (propertyId == UIA_LocalizedControlTypePropertyId)
95     {
96         pRetVal->vt = VT_BSTR;
97         pRetVal->bstrVal = SysAllocString(L"resource tree");
98     }
99     else if (propertyId == UIA_ControlTypePropertyId)
100     {
101         pRetVal->vt = VT_I4;
102         pRetVal->lVal = UIA_TreeControlTypeId;
103     }
104     else if (propertyId == UIA_IsKeyboardFocusablePropertyId)
105     {
106         pRetVal->vt = VT_BOOL;
107         pRetVal->boolVal = VARIANT_TRUE;
108     }
109     else
110     {
111         pRetVal->vt = VT_EMPTY;
112     }
113     return S_OK;
114 }
115 
116 ///////////////////////////////////////////////////////////////////////////////
117 // Implementation of IRawElementProviderSimple::get_HostRawElementProvider.
118 // Gets the default UI Automation provider for the host window. This provider
119 // supplies many properties.
120 //
121 ///////////////////////////////////////////////////////////////////////////////
get_HostRawElementProvider(IRawElementProviderSimple ** pRetVal)122 IFACEMETHODIMP resource_view_provider::get_HostRawElementProvider(IRawElementProviderSimple** pRetVal)
123 {
124     if (m_resViewControlHwnd == NULL)
125     {
126         return UIA_E_ELEMENTNOTAVAILABLE;
127     }
128     HRESULT hr = UiaHostProviderFromHwnd(m_resViewControlHwnd, pRetVal);
129     return hr;
130 }
131 
132 ///////////////////////////////////////////////////////////////////////////////
133 // IRawElementProviderFragment implementation
134 //
135 // Implementation of IRawElementProviderFragment::Navigate.
136 // Enables UI Automation to locate the element in the tree.
137 // Navigation to the parent is handled by the host window provider.
138 //
139 ///////////////////////////////////////////////////////////////////////////////
Navigate(NavigateDirection direction,IRawElementProviderFragment ** pRetVal)140 IFACEMETHODIMP resource_view_provider::Navigate(NavigateDirection direction, IRawElementProviderFragment** pRetVal)
141 {
142     resource_item* pDest = NULL;
143     IRawElementProviderFragment* pFrag = NULL;
144 
145     switch (direction)
146     {
147     case NavigateDirection_FirstChild:
148         pDest = m_pResViewControl->GetResTree()->GetRoot();
149 
150         if (pDest)
151         {
152             pDest = pDest->NavigateFirst();
153         }
154         break;
155 
156     case NavigateDirection_LastChild:
157         pDest = m_pResViewControl->GetResTree()->GetRoot();
158 
159         if (pDest)
160         {
161             pDest = pDest->NavigateLast();
162         }
163         break;
164     }
165 
166     if (pDest)
167     {
168         pFrag = pDest->GetResItemProvider();
169     }
170 
171     if (pFrag != NULL)
172     {
173         pFrag->AddRef();
174     }
175     *pRetVal = pFrag;
176     return S_OK;
177 }
178 
179 ///////////////////////////////////////////////////////////////////////////////
180 // Implementation of IRawElementProviderFragment::GetRuntimeId.
181 // UI Automation gets this value from the host window provider, so supply NULL here.
182 //
183 ///////////////////////////////////////////////////////////////////////////////
GetRuntimeId(SAFEARRAY ** pRetVal)184 IFACEMETHODIMP resource_view_provider::GetRuntimeId(SAFEARRAY** pRetVal)
185 {
186     *pRetVal = NULL;
187     return S_OK;
188 }
189 
190 ///////////////////////////////////////////////////////////////////////////////
191 // Implementation of IRawElementProviderFragment::get_BoundingRectangle.
192 //
193 // Retrieves the screen location and size of the control. Controls hosted in
194 // Win32 windows can return an empty rectangle; UI Automation will
195 // retrieve the rectangle from the HWND provider. However, the method is
196 // implemented here so that it can be used by the list items to calculate
197 // their own bounding rectangles.
198 //
199 // UI Spy uses the bounding rectangle to draw a red border around the element.
200 //
201 ///////////////////////////////////////////////////////////////////////////////
get_BoundingRectangle(UiaRect * pRetVal)202 IFACEMETHODIMP resource_view_provider::get_BoundingRectangle(UiaRect* pRetVal)
203 {
204     RECT rect;
205     m_pResViewControl->GetClientRect(&rect);
206     m_pResViewControl->ClientToScreen(&rect);
207 
208     pRetVal->left = rect.left;
209     pRetVal->top = rect.top;
210     pRetVal->width = rect.right - rect.left;
211     pRetVal->height = rect.bottom - rect.top;
212     return S_OK;
213 }
214 
215 ///////////////////////////////////////////////////////////////////////////////
216 // Implementation of IRawElementProviderFragment::GetEmbeddedFragmentRoots.
217 // Retrieves other fragment roots that may be hosted in this one.
218 //
219 ///////////////////////////////////////////////////////////////////////////////
GetEmbeddedFragmentRoots(SAFEARRAY ** pRetVal)220 IFACEMETHODIMP resource_view_provider::GetEmbeddedFragmentRoots(SAFEARRAY** pRetVal)
221 {
222     *pRetVal = NULL;
223     return S_OK;
224 }
225 
226 ///////////////////////////////////////////////////////////////////////////////
227 // Implementation of IRawElementProviderFragment::SetFocus.
228 // Responds to the control receiving focus through a UI Automation request.
229 // For HWND-based controls, this is handled by the host window provider.
230 //
231 ///////////////////////////////////////////////////////////////////////////////
SetFocus()232 IFACEMETHODIMP resource_view_provider::SetFocus()
233 {
234     return S_OK;
235 }
236 
237 ///////////////////////////////////////////////////////////////////////////////
238 // Implementation of IRawElementProviderFragment::get_FragmentRoot.
239 // Retrieves the root element of this fragment.
240 //
241 ///////////////////////////////////////////////////////////////////////////////
get_FragmentRoot(IRawElementProviderFragmentRoot ** pRetVal)242 IFACEMETHODIMP resource_view_provider::get_FragmentRoot(IRawElementProviderFragmentRoot** pRetVal)
243 {
244     *pRetVal = static_cast<IRawElementProviderFragmentRoot*>(this);
245     AddRef();
246     return S_OK;
247 }
248 
249 ///////////////////////////////////////////////////////////////////////////////
250 // IRawElementProviderFragmentRoot implementation
251 //
252 // Implementation of IRawElementProviderFragmentRoot::ElementProviderFromPoint.
253 // Retrieves the IRawElementProviderFragment interface for the item at the specified
254 // point (in client coordinates).
255 // UI Spy uses this to determine what element is under the cursor when Ctrl is pressed.
256 //
257 ///////////////////////////////////////////////////////////////////////////////
ElementProviderFromPoint(double x,double y,IRawElementProviderFragment ** pRetVal)258 IFACEMETHODIMP resource_view_provider::ElementProviderFromPoint(double x, double y, IRawElementProviderFragment** pRetVal)
259 {
260     POINT pt;
261     pt.x = (LONG)x;
262     pt.y = (LONG)y;
263 
264     m_pResViewControl->ScreenToClient(&pt);
265     resource_tree* pResTree = m_pResViewControl->GetResTree();
266     resource_item* pRoot = pResTree->GetRoot();
267 
268     if (!pRoot)
269     {
270         return NULL;
271     }
272 
273     resource_item* pItem = pResTree->FindItem(pRoot, pt);
274 
275     if (pItem == NULL)
276     {
277         return NULL;
278     }
279 
280     resource_item_provider *pItemProvider = pItem->GetResItemProvider();
281 
282     if (pItemProvider != NULL)
283     {
284         *pRetVal = static_cast<IRawElementProviderFragment*>(pItemProvider);
285         pItemProvider->AddRef();
286     }
287     else
288     {
289         *pRetVal = NULL;
290     }
291     return S_OK;
292 }
293 
294 ///////////////////////////////////////////////////////////////////////////////
295 // Implementation of IRawElementProviderFragmentRoot::GetFocus.
296 // Retrieves the provider for the list item that is selected when the control gets focus.
297 //
298 ///////////////////////////////////////////////////////////////////////////////
GetFocus(IRawElementProviderFragment ** pRetVal)299 IFACEMETHODIMP resource_view_provider::GetFocus(IRawElementProviderFragment** pRetVal)
300 {
301     *pRetVal = NULL;
302     resource_item* pSelectItem = m_pResViewControl->GetCurrentItem();
303     if (pSelectItem)
304     {
305         resource_item_provider* pItemProvider = pSelectItem->GetResItemProvider();
306 
307         if (pItemProvider != NULL)
308         {
309             pItemProvider->AddRef();
310             *pRetVal = pItemProvider;
311         }
312     }
313     return S_OK;
314 }
315 
316 ///////////////////////////////////////////////////////////////////////////////
317 // ISelectionProvider implementation
318 //
319 // Implementation of ISelectionProvider::GetSelection.
320 // Gets the provider(s) for the items(s) selected in the list box.
321 // In this case, only a single item can be selected.
322 //
323 ///////////////////////////////////////////////////////////////////////////////
GetSelection(SAFEARRAY ** pRetVal)324 IFACEMETHODIMP resource_view_provider::GetSelection(SAFEARRAY** pRetVal)
325 {
326     SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
327     resource_item* pSelectItem = m_pResViewControl->GetCurrentItem();
328 
329     if (pSelectItem)
330     {
331         resource_item_provider* pItemProvider = pSelectItem->GetResItemProvider();
332         if (pItemProvider != NULL)
333         {
334             LONG i = 0;
335             SafeArrayPutElement(psa, &i, pItemProvider);
336         }
337     }
338     *pRetVal = psa;
339     return S_OK;
340 }
341 
342 ///////////////////////////////////////////////////////////////////////////////
343 // Implementation of ISelectionProvider::get_CanSelectMultiple.
344 //
345 ///////////////////////////////////////////////////////////////////////////////
get_CanSelectMultiple(BOOL * pRetVal)346 IFACEMETHODIMP resource_view_provider::get_CanSelectMultiple(BOOL* pRetVal)
347 {
348     *pRetVal = FALSE;
349     return S_OK;
350 }
351 
352 ///////////////////////////////////////////////////////////////////////////////
353 // Implementation of ISelectionProvider::get_IsSelectionRequired.
354 //
355 ///////////////////////////////////////////////////////////////////////////////
get_IsSelectionRequired(BOOL * pRetVal)356 IFACEMETHODIMP resource_view_provider::get_IsSelectionRequired(BOOL* pRetVal)
357 {
358     *pRetVal = TRUE;
359     return S_OK;
360 }
361 
362