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