1 /*
2  * The contents of this file is dual-licensed under 2
3  * alternative Open Source/Free licenses: LGPL 2.1 or later and
4  * Apache License 2.0. (starting with JNA version 4.0.0).
5  *
6  * You can freely decide which license you want to apply to
7  * the project.
8  *
9  * You may obtain a copy of the LGPL License at:
10  *
11  * http://www.gnu.org/licenses/licenses.html
12  *
13  * A copy is also included in the downloadable source code package
14  * containing JNA, in file "LGPL2.1".
15  *
16  * You may obtain a copy of the Apache License at:
17  *
18  * http://www.apache.org/licenses/
19  *
20  * A copy is also included in the downloadable source code package
21  * containing JNA, in file "AL2.0".
22  */
23 package com.sun.jna.platform.win32.COM;
24 
25 import com.sun.jna.Pointer;
26 import com.sun.jna.platform.win32.Ole32;
27 import java.util.Iterator;
28 import java.util.NoSuchElementException;
29 
30 import com.sun.jna.platform.win32.Variant;
31 import com.sun.jna.platform.win32.Variant.VARIANT;
32 import com.sun.jna.platform.win32.WinDef.LONG;
33 
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 
38 import static org.junit.Assert.*;
39 
40 public class ShellApplicationWindowsTest {
41 
42     static {
43         ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
44     }
45 
46     @Before
setUp()47     public void setUp() throws Exception {
48         Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
49 
50         // Launch IE in a manner that should ensure it opens even if the system default browser is Chrome, Firefox, or something else.
51         Runtime.getRuntime().exec("cmd /c start iexplore.exe -nohome \"about:blank\"");
52 
53         // Even when going to "about:blank", IE still needs a few seconds to start up and add itself to Shell.Application.Windows
54         // Removing this delay will cause the test to fail even on the fastest boxes I can find.
55         Thread.sleep(3000);
56     }
57 
58     @Test
testWindowsCount()59     public void testWindowsCount()
60     {
61         ShellApplication sa = new ShellApplication();
62 
63         // IE is open, so there should be at least one present.
64         // More may exist if Windows Explorer windows are open.
65         assertTrue("No shell application windows found",
66                    sa.Windows().Count() > 0);
67 
68         boolean pageFound = false;
69         for (InternetExplorer ie : sa.Windows())
70         {
71             // For reasons unknown, Shell.Application.Windows can have null members inside it.
72             // All I care about is whether or not the collection contains the window I opened.
73             if (ie != null && "about:blank".equals(ie.getURL()))
74             {
75                 pageFound = true;
76             }
77         }
78 
79         // Finally, did we find our page in the collection?
80         assertTrue("No IE page was found", pageFound);
81 
82         Ole32.INSTANCE.CoUninitialize();
83     }
84 
85     @After
tearDown()86     public void tearDown() throws Exception
87     {
88         Runtime.getRuntime().exec("taskkill.exe /f /im iexplore.exe");
89     }
90 
91     /**
92      * A COM representation of the Windows shell.
93      */
94     private static class ShellApplication extends COMLateBindingObject
95     {
ShellApplication()96         public ShellApplication() throws COMException
97         {
98             super("Shell.Application", false);
99         }
100 
101         /**
102          * @return Creates and returns a ShellWindows object.<br>
103          *         This object represents a collection of all of the open windows that belong to the Shell.
104          */
Windows()105         public ShellWindows Windows()
106         {
107             return new ShellWindows((IDispatch) invoke("Windows").getValue());
108         }
109 
110         /**
111          * Represents a collection of the open windows that belong to the Shell.<br>
112          * Methods associated with this objects can control and execute commands within the Shell, and obtain other Shell-related objects.
113          */
114         public static class ShellWindows extends COMLateBindingObject implements Iterable<InternetExplorer>
115         {
116 
117             private static class ShellWindowsIterator implements Iterator<InternetExplorer>
118             {
119 
120                 private ShellWindows source;
121 
122                 private int          count;
123 
124                 private int          max;
125 
ShellWindowsIterator(ShellWindows collection)126                 public ShellWindowsIterator(ShellWindows collection)
127                 {
128                     source = collection;
129                     max = source.Count();
130                 }
131 
132                 @Override
hasNext()133                 public boolean hasNext()
134                 {
135                     return count < max;
136                 }
137 
138                 @Override
next()139                 public InternetExplorer next()
140                 {
141                     if (!hasNext())
142                     {
143                         throw new NoSuchElementException();
144                     }
145                     return source.Item(count++);
146                 }
147 
148                 @Override
remove()149                 public void remove()
150                 {
151                     throw new UnsupportedOperationException();
152                 }
153 
154             }
155 
ShellWindows(IDispatch iDispatch)156             public ShellWindows(IDispatch iDispatch)
157             {
158                 super(iDispatch);
159             }
160 
161             /**
162              * Retrieves an InternetExplorer object that represents the Shell window.
163              *
164              * @param idx
165              *            The zero-based index of the item to retrieve.<br>
166              *            This value must be less than the value of the Count property.
167              * @return an InternetExplorer object that represents the Shell window.
168              */
Item(int idx)169             public InternetExplorer Item(int idx)
170             {
171                 VARIANT arg = new VARIANT();
172                 arg.setValue(Variant.VT_I4, new LONG(idx));
173                 IDispatch result = (IDispatch) invoke("Item", arg).getValue();
174                 if (result == null)
175                 {
176                     return null;
177                 }
178                 return new InternetExplorer(result);
179             }
180 
181             /**
182              * @return the number of items in the collection.
183              */
Count()184             public int Count()
185             {
186                 return getIntProperty("Count");
187             }
188 
189             @SuppressWarnings({"unchecked", "rawtypes"})
190             @Override
iterator()191             public Iterator iterator()
192             {
193                 return new ShellWindowsIterator(this);
194             }
195         }
196 
197     }
198 
199     /**
200      * InternetExplorer / IWebBrowser2 - see http://msdn.microsoft.com/en-us/library/aa752127(v=vs.85).aspx
201      */
202     private static class InternetExplorer extends COMLateBindingObject
203     {
204 
InternetExplorer(IDispatch iDispatch)205         public InternetExplorer(IDispatch iDispatch)
206         {
207             super(iDispatch);
208         }
209 
210         /**
211          * IWebBrowser2::get_LocationURL<br>
212          * Read-only COM property.<br>
213          *
214          * @return the URL of the resource that is currently displayed.
215          */
getURL()216         public String getURL()
217         {
218             return getStringProperty("LocationURL");
219         }
220     }
221 }
222