001: package watij.runtime.ie;
002:
003: import com.jniwrapper.*;
004: import com.jniwrapper.win32.automation.IDispatch;
005: import com.jniwrapper.win32.automation.OleMessageLoop;
006: import com.jniwrapper.win32.automation.impl.IDispatchImpl;
007: import com.jniwrapper.win32.automation.server.IDispatchVTBL;
008: import com.jniwrapper.win32.automation.types.BStr;
009: import com.jniwrapper.win32.automation.types.Variant;
010: import com.jniwrapper.win32.automation.types.VariantBool;
011: import com.jniwrapper.win32.com.IClassFactory;
012: import com.jniwrapper.win32.com.impl.IUnknownImpl;
013: import com.jniwrapper.win32.com.server.CoClassMetaInfo;
014: import com.jniwrapper.win32.com.server.IClassFactoryServer;
015: import com.jniwrapper.win32.com.types.ClsCtx;
016: import com.jniwrapper.win32.com.types.IID;
017: import com.jniwrapper.win32.ie.AuthenticateHandler;
018: import com.jniwrapper.win32.ie.BrowserSupport;
019: import com.jniwrapper.win32.ie.KeyFilter;
020: import com.jniwrapper.win32.ie.WebBrowser;
021: import com.jniwrapper.win32.ie.dom.DomFactory;
022: import com.jniwrapper.win32.ie.dom.HTMLDocument;
023: import com.jniwrapper.win32.ie.event.*;
024: import com.jniwrapper.win32.mshtml.IHTMLDocument2;
025: import com.jniwrapper.win32.mshtml.impl.IHTMLDocument2Impl;
026: import com.jniwrapper.win32.ole.IConnectionPoint;
027: import com.jniwrapper.win32.ole.IConnectionPointContainer;
028: import com.jniwrapper.win32.ole.impl.IConnectionPointContainerImpl;
029: import com.jniwrapper.win32.shdocvw.DWebBrowserEvents2;
030: import com.jniwrapper.win32.shdocvw.IWebBrowser2;
031: import com.jniwrapper.win32.shdocvw.InternetExplorer;
032: import com.jniwrapper.win32.shdocvw.impl.IWebBrowser2Impl;
033: import com.jniwrapper.win32.shdocvw.server.DWebBrowserEvents2Server;
034: import com.jniwrapper.win32.ui.Wnd;
035: import watij.dialogs.ModalDialog;
036: import watij.time.Ready;
037: import watij.time.Waiter;
038: import watij.time.WaiterImpl;
039: import watij.utilities.Debug;
040:
041: import java.beans.PropertyChangeListener;
042: import java.util.ArrayList;
043: import java.util.List;
044:
045: public class ModalDialogSupport extends BrowserSupport {
046:
047: private String additionalHttpHeaders;
048: DWebBrowserEvents2Handler dWebBrowserEvents2Handler;
049: List<ModalDialogSupport> childBrowsers;
050: long hwnd;
051: private static int _browsersIndex = 0;
052:
053: HTMLDocument htmlDocument;
054:
055: public ModalDialogSupport(OleMessageLoop oleMessageLoop)
056: throws Exception {
057: super (oleMessageLoop);
058: super .initialize();
059: }
060:
061: public ModalDialogSupport() throws Exception {
062: this (createOleMessageLoop());
063: createIWebBrowser2();
064: setupIWebBrowser2();
065: }
066:
067: public ModalDialogSupport(
068: ModalDialogSupport parentModalDialogSupport)
069: throws Exception {
070: this (parentModalDialogSupport.getOleMessageLoop());
071: createIWebBrowser2();
072: setupIWebBrowser2();
073: setParentBrowser(parentModalDialogSupport);
074: parentModalDialogSupport.childBrowsers.add(this );
075: }
076:
077: public ModalDialogSupport(IWebBrowser2 iWebBrowser2,
078: OleMessageLoop oleMessageLoop) throws Exception {
079: this (oleMessageLoop);
080: setBrowser(iWebBrowser2);
081: setupIWebBrowser2();
082: }
083:
084: public static OleMessageLoop createOleMessageLoop() {
085: OleMessageLoop result = new OleMessageLoop("IESupportLoop."
086: + _browsersIndex++);
087: result.doStart();
088: return result;
089: }
090:
091: private void createIWebBrowser2() throws Exception {
092: getOleMessageLoop().doInvokeAndWait(new Runnable() {
093: public void run() {
094: try {
095: IWebBrowser2 browser = InternetExplorer
096: .create(ClsCtx.LOCAL_SERVER);
097: setBrowser(browser);
098: } catch (Exception e1) {
099: e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
100: }
101: }
102: });
103: }
104:
105: public HTMLDocument getDocument() {
106: return htmlDocument;
107: }
108:
109: public void setDocument(HTMLDocument htmlDocument) {
110: this .htmlDocument = htmlDocument;
111: }
112:
113: private void setupIWebBrowser2() throws Exception {
114: //getOleMessageLoop().doInvokeLater(new Runnable() { //This is to support JExplorer 1.7.470
115: getOleMessageLoop().doInvokeAndWait(new Runnable() {
116: public void run() {
117: try {
118: setupListener(iWebBrowser2());
119: iWebBrowser2().setVisible(VariantBool.TRUE);
120: hwnd = iWebBrowser2().getHWND().getValue();
121: childBrowsers = new ArrayList<ModalDialogSupport>();
122: } catch (Exception e1) {
123: e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
124: }
125: }
126: });
127: waitForIWebBrowser2Initialized(iWebBrowser2());
128: }
129:
130: private void waitForIWebBrowser2Initialized(
131: final IWebBrowser2 iWebBrowser2) throws Exception {
132: new WaiterImpl(30000, 200).waitUntil(new Ready() {
133: Throwable throwable;
134: boolean notNull = false, notBusy = false, hasHwnd = false;
135:
136: public boolean isReady() throws Exception {
137: try {
138: notNull = !iWebBrowser2.isNull();
139: notBusy = !iWebBrowser2.getBusy().getBooleanValue();
140: hasHwnd = iWebBrowser2.getHWND().getValue() != 0;
141: return notNull && notBusy && hasHwnd;
142: } catch (Throwable t) {
143: Debug.handleException(t);
144: throwable = t;
145: return false;
146: }
147: }
148:
149: public String getNotReadyReason() {
150: if (throwable != null) {
151: return "Browser is not initialized...the following exception was thrown: "
152: + throwable;
153: }
154: return "Browser is not initialized......its last known state was notNull:"
155: + notNull
156: + " notBusy:"
157: + notBusy
158: + " hasHwnd:"
159: + hasHwnd;
160: }
161: });
162: }
163:
164: public void waitForChildBrowser(final int i) throws Exception {
165: Waiter waiter = new WaiterImpl(60000, 1000);
166: waiter.waitUntil(new Ready() {
167: public boolean isReady() {
168: return childBrowsers.size() > i;
169: }
170:
171: public String getNotReadyReason() {
172: return "ChildBrowser does not exist yet";
173: }
174: });
175: }
176:
177: public ModalDialogSupport getChildBrowser(int index) {
178: return childBrowsers.get(index);
179: }
180:
181: protected int getChildBrowserSize() {
182: return childBrowsers.size();
183: }
184:
185: protected void removeSelfFromParent() {
186: if (getParentBrowser() != null) {
187: ((ModalDialogSupport) getParentBrowser()).childBrowsers
188: .remove(this );
189: setParentBrowser(null);
190: }
191: }
192:
193: public IWebBrowser2 iWebBrowser2() {
194: return (IWebBrowser2) getBrowserPeer();
195: }
196:
197: public ModalDialog getModalDialog() throws Exception {
198: final OleMessageLoop modalDialogMessageLoop = new OleMessageLoop(
199: "modalDialogMessageLoop");
200: final ModalDialogFinder modalDialogFinder = new ModalDialogFinder(
201: (int) hwnd, modalDialogMessageLoop);
202: modalDialogMessageLoop.doStart();
203: modalDialogMessageLoop.doInvokeAndWait(modalDialogFinder);
204: return new IEModalDialog(modalDialogFinder.getHtmlDocument(),
205: modalDialogMessageLoop, new IE(modalDialogFinder
206: .getWebBrowser()));
207: }
208:
209: static class ModalDialogFinder implements Runnable {
210: Pointer.Void popupDocPointer = new Pointer.Void();
211: Int hWndParent = new Int();
212: HTMLDocument htmlDocument = null;
213: OleMessageLoop oleMessageLoop;
214: WebBrowser webBrowser;
215:
216: // define some win32api constants
217: final UInt GW_ENABLEDPOPUP = new UInt(6);
218: final UInt GW_CHILD = new UInt(5);
219: final UInt GW_HWNDNEXT = new UInt(2);
220: final UInt SMTO_ABORTIFHUNG = new UInt(2);
221:
222: // temporary variables
223: Int32 hWnd = new Int32(0), hWnd2 = new Int32(0);
224: AnsiString className = new AnsiString();
225:
226: public ModalDialogFinder(int _hWndParent,
227: OleMessageLoop oleMessageLoop) {
228: hWndParent.setValue(_hWndParent);
229: this .oleMessageLoop = oleMessageLoop;
230: }
231:
232: public HTMLDocument getHtmlDocument() {
233: return htmlDocument;
234: }
235:
236: public Wnd getModalWnd() {
237: return new Wnd(hWnd.getValue());
238: }
239:
240: public WebBrowser getWebBrowser() {
241: return webBrowser;
242: }
243:
244: public void run() {
245: try {
246: final Library user32 = new Library("user32");
247:
248: new WaiterImpl(60000, 200).waitUntil(new Ready() {
249: public boolean isReady() throws Exception {
250: user32.getFunction("GetWindow").invoke(hWnd2,
251: new Int32(hWndParent), GW_ENABLEDPOPUP);
252: return hWnd2.getValue() != 0;
253: }
254:
255: public String getNotReadyReason() {
256: return "Handle to Browser not found";
257: }
258: });
259:
260: new WaiterImpl(60000, 200).waitUntil(new Ready() {
261: public boolean isReady() throws Exception {
262: user32.getFunction("GetWindow").invoke(hWnd,
263: hWnd2, GW_CHILD);
264: if (hWnd.getValue() != 0) {
265: do {
266: user32.getFunction("GetClassNameA")
267: .invoke(null, hWnd, className,
268: new UInt(255));
269: if (className.getValue().compareTo(
270: "Internet Explorer_Server") == 0) {
271: return true;
272: }
273: user32.getFunction("GetWindow").invoke(
274: hWnd, hWnd, GW_HWNDNEXT);
275: } while (hWnd.getValue() != 0);
276: }
277: return false;
278: }
279:
280: public String getNotReadyReason() {
281: return "Handle to Internet Explorer_Server not found";
282: }
283: });
284:
285: // ok - we have it
286: Int lResult = new Int(0);
287: Pointer lresPointer = new Pointer(lResult);
288:
289: UInt nMsg = new UInt(0);
290: user32.getFunction("RegisterWindowMessageA").invoke(
291: nMsg, new AnsiString("WM_HTML_GETOBJECT"));
292:
293: Parameter[] params = new Parameter[] { hWnd, nMsg,
294: new UInt(0), new UInt(0), SMTO_ABORTIFHUNG,
295: new UInt(100), lresPointer };
296:
297: user32.getFunction("SendMessageTimeoutA").invoke(null,
298: params);
299:
300: IHTMLDocument2Impl doc2Impl = new IHTMLDocument2Impl();
301:
302: Pointer ppDoc = new Pointer(popupDocPointer);
303: Int retVal = new Int(0);
304: Function.call("oleacc", "ObjectFromLresult", retVal,
305: lResult, new Pointer(doc2Impl.getIID()),
306: new UInt(0), ppDoc);
307: IHTMLDocument2 doc2 = new IHTMLDocument2Impl(
308: new IUnknownImpl(popupDocPointer));
309: IEUtil.waitUntilDocumentComplete(doc2);
310: webBrowser = new ModalDialogSupport(oleMessageLoop);
311: htmlDocument = DomFactory.getInstance(webBrowser)
312: .createDocument(doc2);
313:
314: } catch (Exception e) {
315: Debug.handleException(e);
316: }
317: }
318: }
319:
320: private String getAdditionalHttpHeaders() {
321: return additionalHttpHeaders;
322: }
323:
324: public void setAdditionalHttpHeaders(String additionalHttpHeaders) {
325: this .additionalHttpHeaders = additionalHttpHeaders;
326: }
327:
328: public void setupListener(IWebBrowser2 iWebBrowser2)
329: throws Exception {
330: DWebBrowserEvents2Handler dWebBrowserEvents2Handler;
331:
332: // Create class factory server for our DWebBrowserEvents2Impl
333: IClassFactoryServer server = new IClassFactoryServer(
334: DWebBrowserEvents2Handler.class);
335: server.registerInterface(IDispatch.class, new IDispatchVTBL(
336: server));
337: server.registerInterface(DWebBrowserEvents2.class,
338: new IDispatchVTBL(server));
339: server.setDefaultInterface(IDispatch.class);
340:
341: IClassFactory factory = server.createIClassFactory();
342:
343: // Create instance of DWebBrowserEvents2Handler with a class factory
344: IDispatchImpl handler = new IDispatchImpl();
345: factory.createInstance(null, handler.getIID(), handler);
346:
347: // Create IConnectionPointContainer to ActiveX object, which is embedded
348: //into OleContainer
349: IConnectionPointContainer connectionPointContainer = new IConnectionPointContainerImpl(
350: iWebBrowser2);
351: // Find a necessary connection point
352: IConnectionPoint connectionPoint = connectionPointContainer
353: .findConnectionPoint(new IID(
354: DWebBrowserEvents2.INTERFACE_IDENTIFIER));
355:
356: // Advise our handler
357: Int32 int32 = connectionPoint.advise(handler);
358:
359: dWebBrowserEvents2Handler = (DWebBrowserEvents2Handler) server
360: .getInstances().get(0);
361: dWebBrowserEvents2Handler.setIESupport(this );
362: this .dWebBrowserEvents2Handler = dWebBrowserEvents2Handler;
363: }
364:
365: public static class DWebBrowserEvents2Handler extends
366: DWebBrowserEvents2Server {
367:
368: ModalDialogSupport modalDialogSupport = null;
369: boolean onQuit = false;
370: boolean documentComplete = false;
371:
372: public DWebBrowserEvents2Handler(CoClassMetaInfo coClassMetaInfo) {
373: super (coClassMetaInfo);
374: }
375:
376: public void setIESupport(ModalDialogSupport modalDialogSupport) {
377: this .modalDialogSupport = modalDialogSupport;
378: }
379:
380: public void trackOnQuit() {
381: onQuit = false;
382: }
383:
384: public void trackDocumentComplete() {
385: documentComplete = false;
386: }
387:
388: public boolean isOnQuit() {
389: return onQuit;
390: }
391:
392: public boolean isDocumentComplete() {
393: return documentComplete;
394: }
395:
396: public void newWindow3(IDispatch /*[in,out]*/ppDisp,
397: VariantBool /*[in,out]*/Cancel,
398: UInt32 /*[in]*/dwFlags, BStr /*[in]*/bstrUrlContext,
399: BStr /*[in]*/bstrUrl) {
400: Debug
401: .getInstance()
402: .println(
403: "ModalDialogSupport$DWebBrowserEvents2Handler.newWindow3");
404: final IDispatch /*[in,out]*/inOut = ppDisp;
405: try {
406: ModalDialogSupport newModalDialogSupport = new ModalDialogSupport(
407: modalDialogSupport);
408: final IWebBrowser2 browser = newModalDialogSupport
409: .iWebBrowser2();
410: newModalDialogSupport.getOleMessageLoop()
411: .doInvokeAndWait(new Runnable() {
412: public void run() {
413: browser
414: .setRegisterAsBrowser(VariantBool.TRUE);
415: ((IDispatchImpl) inOut)
416: .setValue(browser);
417: }
418: });
419:
420: } catch (Throwable t) {
421: Debug.handleException(t);
422: }
423: }
424:
425: public void onQuit() {
426: Debug
427: .getInstance()
428: .println(
429: "ModalDialogSupport$DWebBrowserEvents2Handler.onQuit");
430: onQuit = true;
431: modalDialogSupport.removeSelfFromParent();
432: }
433:
434: public void documentComplete(IDispatch iDispatch,
435: Variant variant) {
436: documentComplete = true;
437: }
438:
439: /**
440: * BeforeNavigate2 event handler.
441: * <p/>
442: * args[0] Object that evaluates to the top-level or frame
443: * WebBrowser object corresponding to the navigation.
444: * args[1] String expression that evaluates to the URL to
445: * which the browser is navigating.
446: * args[2] Flags
447: * args[3] String expression that evaluates to the name of
448: * the frame in which the resource will be displayed,
449: * or Null if no named frame is targeted for the resource.
450: * args[4] Data to send to the server if the HTTP POST transaction
451: * is being used.
452: * args[5] Value that specifies the additional HTTP headers to send to the
453: * server (HTTP URLs only). The headers can specify such things as
454: * the action required of the server, the type of data being passed
455: * to the server, or a status code.
456: * args[6] Boolean value that the container can set to True to cancel the
457: * navigation operation, or to False to allow it to proceed.
458: */
459: private boolean hasNavigated = false;
460:
461: public void beforeNavigate2(IDispatch /*[in]*/pDisp,
462: Variant /*[in]*/URL, Variant /*[in]*/Flags,
463: Variant /*[in]*/TargetFrameName,
464: Variant /*[in]*/PostData, Variant /*[in]*/Headers,
465: VariantBool /*[in,out]*/Cancel) {
466: Debug
467: .getInstance()
468: .println(
469: "ModalDialogSupport$DWebBrowserEvents2Handler.beforeNavigate2");
470: if (modalDialogSupport.getAdditionalHttpHeaders() != null
471: && !hasNavigated) {
472: String newAddHeaders = existingHeadersValue(Headers)
473: + modalDialogSupport.getAdditionalHttpHeaders();
474: IWebBrowser2 iWebBrowser2 = new IWebBrowser2Impl(pDisp);
475: iWebBrowser2.stop();
476: iWebBrowser2.navigate2(new Variant(URL.getBstrVal()),
477: new Variant(Flags.getIntVal()), new Variant(
478: TargetFrameName.getBstrVal()),
479: new Variant(PostData.getCiVal()), new Variant(
480: newAddHeaders));
481: Cancel.setBooleanValue(true);
482: hasNavigated = true;
483: }
484: // debug("end IEController$DWebBrowserEvents2Handler.beforeNavigate2");
485: }
486:
487: private String existingHeadersValue(Variant existingHeaders) {
488: String string = existingHeaders.getBstrVal().getValue();
489: return string == null ? "" : string;
490: }
491:
492: /**
493: * NavigateComplete2 event handler
494: * <p/>
495: * args[0] Object that evaluates to the top-level or frame
496: * WebBrowser object corresponding to the navigation.
497: * args[1] String that specifies the URL, Universal Naming Convention
498: * (UNC) file name, or pointer to an item identifier list (PIDL)
499: * of the loaded document.
500: */
501:
502: public void navigateComplete2(IDispatch /*[in]*/pDisp,
503: Variant /*[in]*/URL) {
504: Debug
505: .getInstance()
506: .println(
507: "ModalDialogSupport$DWebBrowserEvents2Handler.navigateComplete2");
508: hasNavigated = false;
509: }
510: }
511:
512: protected Wnd getBrowserWindow() {
513: return new Wnd(iWebBrowser2().getHWND().getValue());
514: }
515:
516: public void addPropertyChangeListener(String string,
517: PropertyChangeListener propertyChangeListener) {
518: //To change body of implemented methods use File | Settings | File Templates.
519: }
520:
521: public void removePropertyChangeListener(String string,
522: PropertyChangeListener propertyChangeListener) {
523: //To change body of implemented methods use File | Settings | File Templates.
524: }
525:
526: public void addNavigationListener(
527: NavigationEventListener navigationEventListener) {
528: //To change body of implemented methods use File | Settings | File Templates.
529: }
530:
531: public void removeNavigationListener(
532: NavigationEventListener navigationEventListener) {
533: //To change body of implemented methods use File | Settings | File Templates.
534: }
535:
536: public List getNavigationListeners() {
537: return null; //To change body of implemented methods use File | Settings | File Templates.
538: }
539:
540: public void addStatusListener(
541: StatusEventListener statusEventListener) {
542: //To change body of implemented methods use File | Settings | File Templates.
543: }
544:
545: public void removeStatusListener(
546: StatusEventListener statusEventListener) {
547: //To change body of implemented methods use File | Settings | File Templates.
548: }
549:
550: public List getStatusListeners() {
551: return null; //To change body of implemented methods use File | Settings | File Templates.
552: }
553:
554: public void setEventHandler(
555: WebBrowserEventsHandler webBrowserEventsHandler) {
556: //To change body of implemented methods use File | Settings | File Templates.
557: }
558:
559: public WebBrowserEventsHandler getEventHandler() {
560: return null; //To change body of implemented methods use File | Settings | File Templates.
561: }
562:
563: public void setDialogEventHandler(
564: DialogEventHandler dialogEventHandler) {
565: //To change body of implemented methods use File | Settings | File Templates.
566: }
567:
568: public DialogEventHandler getDialogEventHandler() {
569: return null; //To change body of implemented methods use File | Settings | File Templates.
570: }
571:
572: public void setScriptErrorListener(
573: ScriptErrorListener scriptErrorListener) {
574: //To change body of implemented methods use File | Settings | File Templates.
575: }
576:
577: public ScriptErrorListener getScriptErrorListener() {
578: return null; //To change body of implemented methods use File | Settings | File Templates.
579: }
580:
581: public void close() {
582: dWebBrowserEvents2Handler.trackOnQuit();
583: try {
584: iWebBrowser2().quit();
585: new WaiterImpl(5000, 200).waitUntil(new Ready() {
586: public boolean isReady() throws Exception {
587: Debug.getInstance().println("closing");
588: return dWebBrowserEvents2Handler.isOnQuit();
589: }
590:
591: public String getNotReadyReason() {
592: return "iWebBrowser2 could not be closed.";
593: }
594: });
595: } catch (Throwable t) {
596: Debug.handleException(t);
597: }
598: }
599:
600: public void setNewWindowHandler(
601: NewWindowEventHandler newWindowEventHandler) {
602: //To change body of implemented methods use File | Settings | File Templates.
603: }
604:
605: public NewWindowEventHandler getNewWindowHandler() {
606: return null; //To change body of implemented methods use File | Settings | File Templates.
607: }
608:
609: public void addNewWindowListener(
610: NewWindowEventListener newWindowEventListener) {
611: //To change body of implemented methods use File | Settings | File Templates.
612: }
613:
614: public void removeNewWindowListener(
615: NewWindowEventListener newWindowEventListener) {
616: //To change body of implemented methods use File | Settings | File Templates.
617: }
618:
619: public List getNewWindowListeners() {
620: return null; //To change body of implemented methods use File | Settings | File Templates.
621: }
622:
623: public void setKeyFilter(KeyFilter keyFilter) {
624: //To change body of implemented methods use File | Settings | File Templates.
625: }
626:
627: public KeyFilter getKeyFilter() {
628: return null; //To change body of implemented methods use File | Settings | File Templates.
629: }
630:
631: public void trackChildren() {
632: //To change body of implemented methods use File | Settings | File Templates.
633: }
634:
635: public WebBrowser getRecentChild() {
636: return null; //To change body of implemented methods use File | Settings | File Templates.
637: }
638:
639: public WebBrowser waitChildCreation() {
640: return null; //To change body of implemented methods use File | Settings | File Templates.
641: }
642:
643: public WebBrowser waitChildCreation(Runnable runnable) {
644: return null; //To change body of implemented methods use File | Settings | File Templates.
645: }
646:
647: public void setAuthenticateHandler(
648: AuthenticateHandler authenticateHandler) {
649: //To change body of implemented methods use File | Settings | File Templates.
650: }
651:
652: public AuthenticateHandler getAuthenticateHandler() {
653: return null; //To change body of implemented methods use File | Settings | File Templates.
654: }// private synchronized static IWebBrowser2 createBrowserLocal() throws Exception {
655: // StringBuffer command = new StringBuffer();
656: // command.append("iexplore.exe");
657: // command.append(" about:blank#" + (++allBrowserCount));
658: // Runtime runtime = Runtime.getRuntime();
659: // try {
660: // runtime.exec(command.toString());
661: // } catch (IOException e) {
662: // e.printStackTrace();
663: // }
664: //
665: // return attachByUrl("about:blank#" + allBrowserCount).iWebBrowser2;
666: // }
667: }
|