Sealyu

--- 博客已迁移至: http://www.sealyu.com/blog

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  618 随笔 :: 87 文章 :: 225 评论 :: 0 Trackbacks
最近用到了SWT 中的Browser类,这个类不允许被继承,在网上搜索的时候发现了下面的帖子。这个类实际上是使用OLE,将IE直接嵌套进SWT程序中去。下面代码的 修改实际上将SWT中的WebBrowser类的子类IE直接和Browser 类合到一起,而同时也就没有了原来SWT中的跨平台的优点。该作者添加了setHtml这个函数和_text属性。从而得到对应的网页的html内容。

/*******************************************************************************
 * Copyright (c) 2003, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.***.browser;

import java.text.Collator;
import java.util.Locale;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.ole.win32.*;
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.ole.win32.*;
import org.eclipse.swt.widgets.*;

/**
 * Instances of this class implement the browser user interface metaphor. It
 * allows the user to visualize and navigate through HTML documents.
 * <p>
 * Note that although this class is a subclass of <code>Composite</code>, it
 * does not make sense to set a layout on it.
 * </p>
 * <p>
 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
 * </p>
 *
 * @since 3.0
 */
public class Browser extends Composite {

 static int CodePage = OS.GetACP();

 public static int maxBrowserId = 0;
 private int browserId = 0;
 private BrowserInfo browserInfo = null;

 OleFrame frame;
 OleControlSite site;
 OleAutomation auto;

 boolean back, forward, navigate, delaySetText;
 Point location;
 Point size;
 boolean addressBar = true, menuBar = true, statusBar = true, toolBar = true;
 int info;

 int globalDispatch;
 String _text;
 String html;

 /* External Listener management */
 CloseWindowListener[] closeWindowListeners = new CloseWindowListener[0];
 LocationListener[] locationListeners = new LocationListener[0];
 OpenWindowListener[] openWindowListeners = new OpenWindowListener[0];
 ProgressListener[] progressListeners = new ProgressListener[0];
 StatusTextListener[] statusTextListeners = new StatusTextListener[0];
 TitleListener[] titleListeners = new TitleListener[0];
 VisibilityWindowListener[] visibilityWindowListeners = new VisibilityWindowListener[0];

 static final int BeforeNavigate2 = 0xfa;
 static final int CommandStateChange = 0x69;
 static final int DocumentComplete = 0x103;
 static final int NavigateComplete2 = 0xfc;
 static final int NewWindow2 = 0xfb;
 static final int OnMenuBar = 0x100;
 static final int OnStatusBar = 0x101;
 static final int OnToolBar = 0xff;
 static final int OnVisible = 0xfe;
 static final int ProgressChange = 0x6c;
 static final int RegisterAsBrowser = 0x228;
 static final int StatusTextChange = 0x66;
 static final int TitleChange = 0x71;
 static final int WindowClosing = 0x107;
 static final int WindowSetHeight = 0x10b;
 static final int WindowSetLeft = 0x108;
 static final int WindowSetResizable = 0x106;
 static final int WindowSetTop = 0x109;
 static final int WindowSetWidth = 0x10a;

 static final short CSC_NAVIGATEFORWARD = 1;
 static final short CSC_NAVIGATEBACK = 2;
 static final int INET_E_DEFAULT_ACTION = 0x800C0011;
 static final int READYSTATE_COMPLETE = 4;
 static final int URLPOLICY_ALLOW = 0x00;
 static final int URLPOLICY_DISALLOW = 0x03;
 static final int URLZONE_LOCAL_MACHINE = 0;
 static final int URLZONE_INTRANET = 1;
 static final int URLACTION_ACTIVEX_MIN = 0x00001200;
 static final int URLACTION_ACTIVEX_MAX = 0x000013ff;
 static final int URLACTION_ACTIVEX_RUN = 0x00001200;
 static final int URLACTION_JAVA_MIN = 0x00001C00;
 static final int URLPOLICY_JAVA_LOW = 0x00030000;
 static final int URLACTION_JAVA_MAX = 0x00001Cff;

 static final int DISPID_AMBIENT_DLCONTROL = -5512;
 static final int DLCTL_DLIMAGES = 0x00000010;
 static final int DLCTL_VIDEOS = 0x00000020;
 static final int DLCTL_BGSOUNDS = 0x00000040;
 static final int DLCTL_NO_SCRIPTS = 0x00000080;
 static final int DLCTL_NO_JAVA = 0x00000100;
 static final int DLCTL_NO_RUNACTIVEXCTLS = 0x00000200;
 static final int DLCTL_NO_DLACTIVEXCTLS = 0x00000400;
 static final int DLCTL_DOWNLOADONLY = 0x00000800;
 static final int DLCTL_NO_FRAMEDOWNLOAD = 0x00001000;
 static final int DLCTL_RESYNCHRONIZE = 0x00002000;
 static final int DLCTL_PRAGMA_NO_CACHE = 0x00004000;
 static final int DLCTL_FORCEOFFLINE = 0x10000000;
 static final int DLCTL_NO_CLIENTPULL = 0x20000000;
 static final int DLCTL_SILENT = 0x40000000;
 static final int DOCHOSTUIFLAG_THEME = 0x00040000;
 static final int DOCHOSTUIFLAG_NO3DBORDER = 0x0000004;
 static final int DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000;

 static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
 static final String URL_DIRECTOR = "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab"; //$NON-NLS-1$

 /* Package Name */
 static final String PACKAGE_PREFIX = "com.macrosoft.browser."; //$NON-NLS-1$

 /**
  * Constructs a new instance of this class given its parent and a style
  * value describing its behavior and appearance.
  * <p>
  * The style value is either one of the style constants defined in class
  * <code>SWT</code> which is applicable to instances of this class, or
  * must be built by <em>bitwise OR</em>'ing together (that is, using the
  * <code>int</code> "|" operator) two or more of those <code>SWT</code>
  * style constants. The class description lists the style constants that are
  * applicable to the class. Style bits are also inherited from superclasses.
  * </p>
  *
  * @param parent
  *            a widget which will be the parent of the new instance (cannot
  *            be null)
  * @param style
  *            the style of widget to construct
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
  *                </ul>
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
  *                thread that created the parent</li>
  *                </ul>
  * @exception SWTError
  *                <ul>
  *                <li>ERROR_NO_HANDLES if a handle could not be obtained
  *                for browser creation</li>
  *                </ul>
  *
  * @see Widget#getStyle
  *
  * @since 3.0
  */
 public Browser(Composite parent, int style) {
  super(parent, style & ~SWT.BORDER);

  this.browserId = ++maxBrowserId;
  browserInfo = new BrowserInfo(this.browserId);//BorserInfo是我自己创建的类,没有必要用
  BrowserManager.addBrowserInfo(browserInfo);// ????????browser

  info = Browser.DOCHOSTUIFLAG_THEME;
  if ((style & SWT.BORDER) == 0)
   info |= Browser.DOCHOSTUIFLAG_NO3DOUTERBORDER;
  frame = new OleFrame(this, SWT.NONE);
  try {
   site = new WebSite(frame, SWT.NONE, "Shell.Explorer"); //$NON-NLS-1$
  } catch (SWTException e) {
   dispose();
   SWT.error(SWT.ERROR_NO_HANDLES);
  }

  site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
  auto = new OleAutomation(site);

  Listener listener = new Listener() {
   public void handleEvent(Event e) {
    switch (e.type) {
    case SWT.Dispose: {
     if (auto != null)
      auto.dispose();
     auto = null;
     break;
    }
    case SWT.Resize: {
     frame.setBounds(getClientArea());
     break;
    }
    case SWT.KeyDown:
    case SWT.KeyUp: {
     notifyListeners(e.type, e);
     break;
    }
    }
   }
  };
  addListener(SWT.Dispose, listener);
  addListener(SWT.Resize, listener);
  site.addListener(SWT.KeyDown, listener);
  site.addListener(SWT.KeyUp, listener);

  // addListener(SWT.FocusIn, new Listener() {
  // public void handleEvent(Event e) {
  // System.out.println("Browser " + browserId + " Selected");
  // }
  // });

  OleListener oleListener = new OleListener() {
   public void handleEvent(OleEvent event) {
    switch (event.type) {
    case BeforeNavigate2: {
     Variant varResult = event.arguments[1];
     String url = varResult.getString();
     LocationEvent newEvent = new LocationEvent(Browser.this);
     newEvent.display = getDisplay();
     newEvent.widget = Browser.this;
     newEvent.location = url;
     newEvent.doit = true;
     for (int i = 0; i < locationListeners.length; i++)
      locationListeners[i].changing(newEvent);

     // browserInfo.setUrl(event.arguments[1].getString());
     //开出该段代码读取请求的url和postdata
     //Variant postData = event.arguments[4];
     //if (!browserInfo.isOpenWindow()) {
     // System.out.println("URL = " + event.arguments[1].getString());
     // System.out.println("PostData = " + readSafeArray(postData));
     // browserInfo.setPostData(readSafeArray(postData));
     //}

     Variant cancel = event.arguments[6];
     if (cancel != null) {
      int pCancel = cancel.getByRef();
      COM
        .MoveMemory(pCancel,
          new short[] { newEvent.doit ? COM.VARIANT_FALSE : COM.VARIANT_TRUE }, 2);
     }
     break;
    }
    case CommandStateChange: {
     boolean enabled = false;
     Variant varResult = event.arguments[0];
     int command = varResult.getInt();
     varResult = event.arguments[1];
     enabled = varResult.getBoolean();
     switch (command) {
     case CSC_NAVIGATEBACK:
      back = enabled;
      break;
     case CSC_NAVIGATEFORWARD:
      forward = enabled;
      break;
     }
     break;
    }
    case DocumentComplete: {
     Variant varResult = event.arguments[0];
     IDispatch dispatch = varResult.getDispatch();

     varResult = event.arguments[1];
     String url = varResult.getString();
     if (html != null && url.equals(ABOUT_BLANK)) {
      Runnable runnable = new Runnable() {
       public void run() {
        if (isDisposed() || html == null)
         return;
        int charCount = html.length();
        char[] chars = new char[charCount];
        html.getChars(0, charCount, chars, 0);
        _text = html;
        html = null;
        int byteCount = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, charCount, null, 0, null,
          null);
        /*
         * Note. Internet Explorer appears to treat the
         * data loaded with nsIPersistStreamInit.Load as
         * if it were encoded using the default local
         * charset. There does not seem to be an API to
         * set the desired charset explicitely in this
         * case. The fix is to prepend the UTF-8 Byte
         * Order Mark signature to the data.
         */
        byte[] UTF8BOM = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };
        int hGlobal = OS.GlobalAlloc(OS.GMEM_FIXED, UTF8BOM.length + byteCount);
        if (hGlobal != 0) {
         OS.MoveMemory(hGlobal, UTF8BOM, UTF8BOM.length);
         OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, charCount, hGlobal + UTF8BOM.length,
           byteCount, null, null);
         int[] ppstm = new int[1];
         /*
          * Note. CreateStreamOnHGlobal is called
          * with the flag fDeleteOnRelease. If the
          * call succeeds the buffer hGlobal is freed
          * automatically when the IStream object is
          * released. If the call fails, free the
          * buffer hGlobal.
          */
         if (OS.CreateStreamOnHGlobal(hGlobal, true, ppstm) == OS.S_OK) {
          int[] rgdispid = auto.getIDsOfNames(new String[] { "Document" }); //$NON-NLS-1$
          Variant pVarResult = auto.getProperty(rgdispid[0]);
          IDispatch dispatchDocument = pVarResult.getDispatch();
          int[] ppvObject = new int[1];
          int result = dispatchDocument.QueryInterface(COM.IIDIPersistStreamInit,
            ppvObject);
          if (result == OS.S_OK) {
           IPersistStreamInit persistStreamInit = new IPersistStreamInit(ppvObject[0]);
           if (persistStreamInit.InitNew() == OS.S_OK) {
            persistStreamInit.Load(ppstm[0]);
           }
           persistStreamInit.Release();
          }
          pVarResult.dispose();
          /*
           * This code is intentionally commented.
           * The IDispatch obtained from a Variant
           * did not increase the reference count
           * for the enclosed interface.
           */
          // dispatchDocument.Release();
          IUnknown stream = new IUnknown(ppstm[0]);
          stream.Release();
         } else {
          OS.GlobalFree(hGlobal);
         }
        }
       }
      };
      if (delaySetText) {
       delaySetText = false;
       getDisplay().asyncExec(runnable);
      } else {
       runnable.run();
      }
     } else {
      setHTML();

      Variant variant = new Variant(auto);
      IDispatch top = variant.getDispatch();
      LocationEvent locationEvent = new LocationEvent(Browser.this);
      locationEvent.display = getDisplay();
      locationEvent.widget = Browser.this;
      locationEvent.location = url;
      locationEvent.top = top.getAddress() == dispatch.getAddress();
      for (int i = 0; i < locationListeners.length; i++)
       locationListeners[i].changed(locationEvent);
      /*
       * This code is intentionally commented. A Variant
       * constructed from an OleAutomation object does not
       * increase its reference count. The IDispatch obtained
       * from this Variant did not increase the reference
       * count for the OleAutomation instance either.
       */
      // top.Release();
      // variant.dispose();
      /*
       * Note. The completion of the page loading is detected
       * as described in the MSDN article "Determine when a
       * page is done loading in WebBrowser Control".
       */
      if (globalDispatch != 0 && dispatch.getAddress() == globalDispatch) {
       /* final document complete */
       globalDispatch = 0;
       ProgressEvent progressEvent = new ProgressEvent(Browser.this);
       progressEvent.display = getDisplay();
       progressEvent.widget = Browser.this;
       for (int i = 0; i < progressListeners.length; i++)
        progressListeners[i].completed(progressEvent);
      }
     }

     /*
      * This code is intentionally commented. This IDispatch was
      * received as an argument from the OleEvent and it will be
      * disposed along with the other arguments.
      */
     // dispatch.Release();
     break;
    }
    case NavigateComplete2: {
     Variant varResult = event.arguments[0];
     IDispatch dispatch = varResult.getDispatch();
     if (globalDispatch == 0)
      globalDispatch = dispatch.getAddress();
     break;
    }
    case NewWindow2: {
     Variant cancel = event.arguments[1];
     int pCancel = cancel.getByRef();
     WindowEvent newEvent = new WindowEvent(Browser.this);
     newEvent.display = getDisplay();
     newEvent.widget = Browser.this;
     newEvent.required = false;
     for (int i = 0; i < openWindowListeners.length; i++)
      openWindowListeners[i].open(newEvent);
     Browser browser = newEvent.browser;
     boolean doit = browser != null && !browser.isDisposed();
     if (doit) {
      Variant variant = new Variant(browser.auto);
      IDispatch iDispatch = variant.getDispatch();
      Variant ppDisp = event.arguments[0];
      int byref = ppDisp.getByRef();
      if (byref != 0)
       COM.MoveMemory(byref, new int[] { iDispatch.getAddress() }, 4);
      /*
       * This code is intentionally commented. A Variant
       * constructed from an OleAutomation object does not
       * increase its reference count. The IDispatch obtained
       * from this Variant did not increase the reference
       * count for the OleAutomation instance either.
       */
      // variant.dispose();
      // iDispatch.Release();
     }
     if (newEvent.required) {
      COM.MoveMemory(pCancel, new short[] { doit ? COM.VARIANT_FALSE : COM.VARIANT_TRUE }, 2);
     }
     break;
    }
    case OnMenuBar: {
     Variant arg0 = event.arguments[0];
     menuBar = arg0.getBoolean();
     break;
    }
    case OnStatusBar: {
     Variant arg0 = event.arguments[0];
     statusBar = arg0.getBoolean();
     break;
    }
    case OnToolBar: {
     Variant arg0 = event.arguments[0];
     toolBar = arg0.getBoolean();
     /*
      * Feature in Internet Explorer. OnToolBar FALSE is emitted
      * when both tool bar, address bar and menu bar must not be
      * visible. OnToolBar TRUE is emitted when either of tool
      * bar, address bar or menu bar is visible.
      */
     if (!toolBar) {
      addressBar = false;
      menuBar = false;
     }
     break;
    }
    case OnVisible: {
     Variant arg1 = event.arguments[0];
     boolean visible = arg1.getBoolean();
     WindowEvent newEvent = new WindowEvent(Browser.this);
     newEvent.display = getDisplay();
     newEvent.widget = Browser.this;
     if (visible) {
      if (addressBar) {
       /*
        * Bug in Internet Explorer. There is no distinct
        * notification for the address bar. If neither
        * address, menu or tool bars are visible, OnToolBar
        * FALSE is emitted. For some reason, querying the
        * value of AddressBar in this case returns true
        * even though it should not be set visible. The
        * workaround is to only query the value of
        * AddressBar when OnToolBar FALSE has not been
        * emitted.
        */
       int[] rgdispid = auto.getIDsOfNames(new String[] { "AddressBar" }); //$NON-NLS-1$
       Variant pVarResult = auto.getProperty(rgdispid[0]);
       if (pVarResult != null && pVarResult.getType() == OLE.VT_BOOL)
        addressBar = pVarResult.getBoolean();
      }
      newEvent.addressBar = addressBar;
      newEvent.menuBar = menuBar;
      newEvent.statusBar = statusBar;
      newEvent.toolBar = toolBar;
      newEvent.location = location;
      newEvent.size = size;
      for (int i = 0; i < visibilityWindowListeners.length; i++) {
       visibilityWindowListeners[i].show(newEvent);
      }
      location = null;
      size = null;
     } else {
      for (int i = 0; i < visibilityWindowListeners.length; i++)
       visibilityWindowListeners[i].hide(newEvent);
     }
     break;
    }
    case ProgressChange: {
     Variant arg1 = event.arguments[0];
     int nProgress = arg1.getType() != OLE.VT_I4 ? 0 : arg1.getInt(); // may
                      // be
                      // -1
     Variant arg2 = event.arguments[1];
     int nProgressMax = arg2.getType() != OLE.VT_I4 ? 0 : arg2.getInt();
     ProgressEvent newEvent = new ProgressEvent(Browser.this);
     newEvent.display = getDisplay();
     newEvent.widget = Browser.this;
     newEvent.current = nProgress;
     newEvent.total = nProgressMax;
     if (nProgress != -1) {
      for (int i = 0; i < progressListeners.length; i++)
       progressListeners[i].changed(newEvent);
     }
     break;
    }
    case StatusTextChange: {
     Variant arg1 = event.arguments[0];
     if (arg1.getType() == OLE.VT_BSTR) {
      String text = arg1.getString();
      StatusTextEvent newEvent = new StatusTextEvent(Browser.this);
      newEvent.display = getDisplay();
      newEvent.widget = Browser.this;
      newEvent.text = text;
      for (int i = 0; i < statusTextListeners.length; i++)
       statusTextListeners[i].changed(newEvent);
     }
     break;
    }
    case TitleChange: {
     Variant arg1 = event.arguments[0];
     if (arg1.getType() == OLE.VT_BSTR) {
      String title = arg1.getString();
      TitleEvent newEvent = new TitleEvent(Browser.this);
      newEvent.display = getDisplay();
      newEvent.widget = Browser.this;
      newEvent.title = title;
      for (int i = 0; i < titleListeners.length; i++)
       titleListeners[i].changed(newEvent);
     }
     break;
    }
    case WindowClosing: {
     WindowEvent newEvent = new WindowEvent(Browser.this);
     newEvent.display = getDisplay();
     newEvent.widget = Browser.this;
     for (int i = 0; i < closeWindowListeners.length; i++)
      closeWindowListeners[i].close(newEvent);
     Variant cancel = event.arguments[1];
     int pCancel = cancel.getByRef();
     COM.MoveMemory(pCancel, new short[] { COM.VARIANT_FALSE }, 2);
     dispose();
     break;
    }
    case WindowSetHeight: {
     if (size == null)
      size = new Point(0, 0);
     Variant arg1 = event.arguments[0];
     size.y = arg1.getInt();
     break;
    }
    case WindowSetLeft: {
     if (location == null)
      location = new Point(0, 0);
     Variant arg1 = event.arguments[0];
     location.x = arg1.getInt();
     break;
    }
    case WindowSetTop: {
     if (location == null)
      location = new Point(0, 0);
     Variant arg1 = event.arguments[0];
     location.y = arg1.getInt();
     break;
    }
    case WindowSetWidth: {
     if (size == null)
      size = new Point(0, 0);
     Variant arg1 = event.arguments[0];
     size.x = arg1.getInt();
     break;
    }
    }
    /*
     * Dispose all arguments passed in the OleEvent. This must be
     * done to properly release any IDispatch reference that was
     * automatically addRef'ed when constructing the OleEvent.
     */
    Variant[] arguments = event.arguments;
    for (int i = 0; i < arguments.length; i++)
     arguments[i].dispose();
   }
  };
  site.addEventListener(BeforeNavigate2, oleListener);
  site.addEventListener(CommandStateChange, oleListener);
  site.addEventListener(DocumentComplete, oleListener);
  site.addEventListener(NavigateComplete2, oleListener);
  site.addEventListener(NewWindow2, oleListener);
  site.addEventListener(OnMenuBar, oleListener);
  site.addEventListener(OnStatusBar, oleListener);
  site.addEventListener(OnToolBar, oleListener);
  site.addEventListener(OnVisible, oleListener);
  site.addEventListener(ProgressChange, oleListener);
  site.addEventListener(StatusTextChange, oleListener);
  site.addEventListener(TitleChange, oleListener);
  site.addEventListener(WindowClosing, oleListener);
  site.addEventListener(WindowSetHeight, oleListener);
  site.addEventListener(WindowSetLeft, oleListener);
  site.addEventListener(WindowSetTop, oleListener);
  site.addEventListener(WindowSetWidth, oleListener);

  Variant variant = new Variant(true);
  auto.setProperty(RegisterAsBrowser, variant);
  variant.dispose();

  variant = new Variant(false);
  int[] rgdispid = auto.getIDsOfNames(new String[] { "RegisterAsDropTarget" }); //$NON-NLS-1$
  if (rgdispid != null)
   auto.setProperty(rgdispid[0], variant);
  variant.dispose();
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when the window hosting the receiver should be closed.
  * <p>
  * This notification occurs when a javascript command such as
  * <code>window.close</code> gets executed by a <code>Browser</code>.
  * </p>
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addCloseWindowListener(CloseWindowListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length + 1];
  System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, closeWindowListeners.length);
  closeWindowListeners = newCloseWindowListeners;
  closeWindowListeners[closeWindowListeners.length - 1] = listener;
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when the current location has changed or is about to change.
  * <p>
  * This notification typically occurs when the application navigates to a
  * new location with {@link #setUrl(String)} or when the user activates a
  * hyperlink.
  * </p>
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addLocationListener(LocationListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  LocationListener[] newLocationListeners = new LocationListener[locationListeners.length + 1];
  System.arraycopy(locationListeners, 0, newLocationListeners, 0, locationListeners.length);
  locationListeners = newLocationListeners;
  locationListeners[locationListeners.length - 1] = listener;
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when a new window needs to be created.
  * <p>
  * This notification occurs when a javascript command such as
  * <code>window.open</code> gets executed by a <code>Browser</code>.
  * </p>
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addOpenWindowListener(OpenWindowListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length + 1];
  System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, openWindowListeners.length);
  openWindowListeners = newOpenWindowListeners;
  openWindowListeners[openWindowListeners.length - 1] = listener;
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when a progress is made during the loading of the current URL or when the
  * loading of the current URL has been completed.
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addProgressListener(ProgressListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length + 1];
  System.arraycopy(progressListeners, 0, newProgressListeners, 0, progressListeners.length);
  progressListeners = newProgressListeners;
  progressListeners[progressListeners.length - 1] = listener;
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when the status text is changed.
  * <p>
  * The status text is typically displayed in the status bar of a browser
  * application.
  * </p>
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addStatusTextListener(StatusTextListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length + 1];
  System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, statusTextListeners.length);
  statusTextListeners = newStatusTextListeners;
  statusTextListeners[statusTextListeners.length - 1] = listener;
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when the title of the current document is available or has changed.
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addTitleListener(TitleListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  TitleListener[] newTitleListeners = new TitleListener[titleListeners.length + 1];
  System.arraycopy(titleListeners, 0, newTitleListeners, 0, titleListeners.length);
  titleListeners = newTitleListeners;
  titleListeners[titleListeners.length - 1] = listener;
 }

 /**
  * Adds the listener to the collection of listeners who will be notified
  * when a window hosting the receiver needs to be displayed or hidden.
  *
  * @param listener
  *            the listener which should be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void addVisibilityWindowListener(VisibilityWindowListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length + 1];
  System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0,
    visibilityWindowListeners.length);
  visibilityWindowListeners = newVisibilityWindowListeners;
  visibilityWindowListeners[visibilityWindowListeners.length - 1] = listener;
 }

 /**
  * Navigate to the previous session history item.
  *
  * @return <code>true</code> if the operation was successful and
  *         <code>false</code> otherwise
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @see #forward
  *
  * @since 3.0
  */
 public boolean back() {
  checkWidget();
  if (!back)
   return false;
  int[] rgdispid = auto.getIDsOfNames(new String[] { "GoBack" }); //$NON-NLS-1$
  Variant pVarResult = auto.invoke(rgdispid[0]);
  return pVarResult != null && pVarResult.getType() == OLE.VT_EMPTY;
 }

 protected void checkSubclass() {
  String name = getClass().getName();
  int index = name.lastIndexOf('.');
  if (!name.substring(0, index + 1).equals(PACKAGE_PREFIX)) {
   SWT.error(SWT.ERROR_INVALID_SUBCLASS);
  }
 }

 /**
  * Execute the specified script.
  *
  * <p>
  * Execute a script containing javascript commands in the context of the
  * current document.
  *
  * @param script
  *            the script with javascript commands
  *
  * @return <code>true</code> if the operation was successful and
  *         <code>false</code> otherwise
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the script is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.1
  */
 public boolean execute(String script) {
  checkWidget();
  if (script == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);

  /* get IHTMLDocument2 */
  int[] rgdispid = auto.getIDsOfNames(new String[] { "Document" }); //$NON-NLS-1$
  int dispIdMember = rgdispid[0];
  Variant pVarResult = auto.getProperty(dispIdMember);
  if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY)
   return false;
  OleAutomation document = pVarResult.getAutomation();
  pVarResult.dispose();

  /* get IHTMLWindow2 */
  rgdispid = document.getIDsOfNames(new String[] { "parentWindow" }); //$NON-NLS-1$
  dispIdMember = rgdispid[0];
  pVarResult = document.getProperty(dispIdMember);
  OleAutomation ihtmlWindow2 = pVarResult.getAutomation();
  pVarResult.dispose();
  document.dispose();

  rgdispid = ihtmlWindow2.getIDsOfNames(new String[] { "execScript", "code" }); //$NON-NLS-1$  //$NON-NLS-2$
  Variant[] rgvarg = new Variant[1];
  rgvarg[0] = new Variant(script);
  int[] rgdispidNamedArgs = new int[1];
  rgdispidNamedArgs[0] = rgdispid[1];
  pVarResult = ihtmlWindow2.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
  rgvarg[0].dispose();
  ihtmlWindow2.dispose();
  if (pVarResult == null)
   return false;
  pVarResult.dispose();
  return true;
 }

 /**
  * Navigate to the next session history item.
  *
  * @return <code>true</code> if the operation was successful and
  *         <code>false</code> otherwise
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @see #back
  *
  * @since 3.0
  */
 public boolean forward() {
  checkWidget();
  if (!forward)
   return false;
  int[] rgdispid = auto.getIDsOfNames(new String[] { "GoForward" }); //$NON-NLS-1$
  Variant pVarResult = auto.invoke(rgdispid[0]);
  return pVarResult != null && pVarResult.getType() == OLE.VT_EMPTY;
 }

 /**
  * Returns <code>true</code> if the receiver can navigate to the previous
  * session history item, and <code>false</code> otherwise.
  *
  * @return the receiver's back command enabled state
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
  *                disposed</li>
  *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
  *                thread that created the receiver</li>
  *                </ul>
  *
  * @see #back
  */
 public boolean isBackEnabled() {
  checkWidget();
  return back;
 }

 /**
  * Returns <code>true</code> if the receiver can navigate to the next
  * session history item, and <code>false</code> otherwise.
  *
  * @return the receiver's forward command enabled state
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
  *                disposed</li>
  *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
  *                thread that created the receiver</li>
  *                </ul>
  *
  * @see #forward
  */
 public boolean isForwardEnabled() {
  checkWidget();
  return forward;
 }

 /**
  * Returns the current URL.
  *
  * @return the current URL or an empty <code>String</code> if there is no
  *         current URL
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @see #setUrl
  *
  * @since 3.0
  */
 public String getUrl() {
  checkWidget();
  int[] rgdispid = auto.getIDsOfNames(new String[] { "LocationURL" }); //$NON-NLS-1$
  Variant pVarResult = auto.getProperty(rgdispid[0]);
  if (pVarResult == null || pVarResult.getType() != OLE.VT_BSTR)
   return "";
  String result = pVarResult.getString();
  pVarResult.dispose();
  return result;
 }

 /**
  * Refresh the current page.
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void refresh() {
  checkWidget();
  int[] rgdispid = auto.getIDsOfNames(new String[] { "Refresh" }); //$NON-NLS-1$
  auto.invoke(rgdispid[0]);
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when the window hosting the receiver should be closed.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeCloseWindowListener(CloseWindowListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (closeWindowListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < closeWindowListeners.length; i++) {
   if (listener == closeWindowListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (closeWindowListeners.length == 1) {
   closeWindowListeners = new CloseWindowListener[0];
   return;
  }
  CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length - 1];
  System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, index);
  System.arraycopy(closeWindowListeners, index + 1, newCloseWindowListeners, index, closeWindowListeners.length
    - index - 1);
  closeWindowListeners = newCloseWindowListeners;
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when the current location is changed or about to be changed.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeLocationListener(LocationListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (locationListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < locationListeners.length; i++) {
   if (listener == locationListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (locationListeners.length == 1) {
   locationListeners = new LocationListener[0];
   return;
  }
  LocationListener[] newLocationListeners = new LocationListener[locationListeners.length - 1];
  System.arraycopy(locationListeners, 0, newLocationListeners, 0, index);
  System.arraycopy(locationListeners, index + 1, newLocationListeners, index, locationListeners.length - index
    - 1);
  locationListeners = newLocationListeners;
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when a new window needs to be created.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeOpenWindowListener(OpenWindowListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (openWindowListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < openWindowListeners.length; i++) {
   if (listener == openWindowListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (openWindowListeners.length == 1) {
   openWindowListeners = new OpenWindowListener[0];
   return;
  }
  OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length - 1];
  System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, index);
  System.arraycopy(openWindowListeners, index + 1, newOpenWindowListeners, index, openWindowListeners.length
    - index - 1);
  openWindowListeners = newOpenWindowListeners;
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when a progress is made during the loading of the current URL or
  * when the loading of the current URL has been completed.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeProgressListener(ProgressListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (progressListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < progressListeners.length; i++) {
   if (listener == progressListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (progressListeners.length == 1) {
   progressListeners = new ProgressListener[0];
   return;
  }
  ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length - 1];
  System.arraycopy(progressListeners, 0, newProgressListeners, 0, index);
  System.arraycopy(progressListeners, index + 1, newProgressListeners, index, progressListeners.length - index
    - 1);
  progressListeners = newProgressListeners;
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when the status text is changed.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeStatusTextListener(StatusTextListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (statusTextListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < statusTextListeners.length; i++) {
   if (listener == statusTextListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (statusTextListeners.length == 1) {
   statusTextListeners = new StatusTextListener[0];
   return;
  }
  StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length - 1];
  System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, index);
  System.arraycopy(statusTextListeners, index + 1, newStatusTextListeners, index, statusTextListeners.length
    - index - 1);
  statusTextListeners = newStatusTextListeners;
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when the title of the current document is available or has
  * changed.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeTitleListener(TitleListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (titleListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < titleListeners.length; i++) {
   if (listener == titleListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (titleListeners.length == 1) {
   titleListeners = new TitleListener[0];
   return;
  }
  TitleListener[] newTitleListeners = new TitleListener[titleListeners.length - 1];
  System.arraycopy(titleListeners, 0, newTitleListeners, 0, index);
  System.arraycopy(titleListeners, index + 1, newTitleListeners, index, titleListeners.length - index - 1);
  titleListeners = newTitleListeners;
 }

 /**
  * Removes the listener from the collection of listeners who will be
  * notified when a window hosting the receiver needs to be displayed or
  * hidden.
  *
  * @param listener
  *            the listener which should no longer be notified
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void removeVisibilityWindowListener(VisibilityWindowListener listener) {
  checkWidget();
  if (listener == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (visibilityWindowListeners.length == 0)
   return;
  int index = -1;
  for (int i = 0; i < visibilityWindowListeners.length; i++) {
   if (listener == visibilityWindowListeners[i]) {
    index = i;
    break;
   }
  }
  if (index == -1)
   return;
  if (visibilityWindowListeners.length == 1) {
   visibilityWindowListeners = new VisibilityWindowListener[0];
   return;
  }
  VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length - 1];
  System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, index);
  System.arraycopy(visibilityWindowListeners, index + 1, newVisibilityWindowListeners, index,
    visibilityWindowListeners.length - index - 1);
  visibilityWindowListeners = newVisibilityWindowListeners;
 }

 /**
  * Renders HTML.
  *
  * <p>
  * The html parameter is Unicode encoded since it is a java
  * <code>String</code>. As a result, the HTML meta tag charset should not
  * be set. The charset is implied by the <code>String</code> itself.
  *
  * @param html
  *            the HTML content to be rendered
  *
  * @return true if the operation was successful and false otherwise.
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the html is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @see #setUrl
  *
  * @since 3.0
  */
 public boolean setText(String html) {
  checkWidget();
  if (html == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);

  /*
   * If the html field is non-null then the about:blank page is already
   * being loaded, so no Stop or Navigate is required. Just set the html
   * that is to be shown.
   */
  boolean blankLoading = this.html != null;
  this.html = html;
  if (blankLoading)
   return true;

  /*
   * Navigate to the blank page and insert the given html when receiving
   * the next DocumentComplete notification. See the MSDN article "Loading
   * HTML content from a Stream".
   *
   * Note. Stop any pending request. This is required to avoid displaying
   * a blank page as a result of consecutive calls to setUrl and/or
   * setText. The previous request would otherwise render the new html
   * content and reset the html field before the browser actually
   * navigates to the blank page as requested below.
   *
   * Feature in Internet Explorer. Stopping pending requests when no
   * request is pending causes a default page 'Action cancelled' to be
   * displayed. The workaround is to not invoke 'stop' when no request has
   * been set since that instance was created.
   */
  int[] rgdispid;
  if (navigate) {
   /*
    * Stopping the loading of a page causes DocumentComplete events
    * from previous requests to be received before the DocumentComplete
    * for this page. In such cases we must be sure to not set the html
    * into the browser too soon, since doing so could result in its
    * page being cleared out by a subsequent DocumentComplete. The
    * Browser's ReadyState can be used to determine whether these extra
    * events will be received or not.
    */
   rgdispid = auto.getIDsOfNames(new String[] { "ReadyState" }); //$NON-NLS-1$
   Variant pVarResult = auto.getProperty(rgdispid[0]);
   if (pVarResult == null)
    return false;
   delaySetText = pVarResult.getInt() != READYSTATE_COMPLETE;
   pVarResult.dispose();
   rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
   auto.invoke(rgdispid[0]);
  }
  rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
  navigate = true;
  Variant[] rgvarg = new Variant[1];
  rgvarg[0] = new Variant(ABOUT_BLANK);
  int[] rgdispidNamedArgs = new int[1];
  rgdispidNamedArgs[0] = rgdispid[1];
  Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
  rgvarg[0].dispose();
  if (pVarResult == null)
   return false;
  boolean result = pVarResult.getType() == OLE.VT_EMPTY;
  pVarResult.dispose();
  return result;
 }

 /**
  * Loads a URL.
  *
  * @param url
  *            the URL to be loaded
  *
  * @return true if the operation was successful and false otherwise.
  *
  * @exception IllegalArgumentException
  *                <ul>
  *                <li>ERROR_NULL_ARGUMENT - if the url is null</li>
  *                </ul>
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @see #getUrl
  *
  * @since 3.0
  */
 public boolean setUrl(String url) {
  checkWidget();
  if (url == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  html = null;

  /*
   * Bug in Internet Explorer. For some reason, Navigating to an xml
   * document before a previous Navigate has completed will leave the
   * Browser in a bad state if the Navigate to the xml document does not
   * complete. This bad state causes a GP when the parent window is
   * eventually disposed. The workaround is to issue a Stop before
   * navigating to any xml document.
   */
  if (url.endsWith(".xml")) { //$NON-NLS-1$
   /*
    * Feature in Internet Explorer. Stopping pending requests when no
    * request has been issued causes a default 'Action cancelled' page
    * to be displayed. Since Stop must be issued here, the workaround
    * is to first Navigate to the about:blank page before issuing Stop
    * so that the 'Action cancelled' page is not displayed.
    */
   if (!navigate) {
    int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
    Variant[] rgvarg = new Variant[1];
    rgvarg[0] = new Variant(ABOUT_BLANK);
    int[] rgdispidNamedArgs = new int[1];
    rgdispidNamedArgs[0] = rgdispid[1];
    auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
    rgvarg[0].dispose();
   }
   int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
   auto.invoke(rgdispid[0]);
  }

  int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
  navigate = true;
  Variant[] rgvarg = new Variant[1];
  rgvarg[0] = new Variant(url);
  int[] rgdispidNamedArgs = new int[1];
  rgdispidNamedArgs[0] = rgdispid[1];
  Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
  rgvarg[0].dispose();
  if (pVarResult == null)
   return false;
  boolean result = pVarResult.getType() == OLE.VT_EMPTY;
  pVarResult.dispose();
  return result;
 }


 public boolean setUrl(String url, String postData) {
  checkWidget();
  if (url == null)
   SWT.error(SWT.ERROR_NULL_ARGUMENT);
  html = null;

  /*
   * Bug in Internet Explorer. For some reason, Navigating to an xml
   * document before a previous Navigate has completed will leave the
   * Browser in a bad state if the Navigate to the xml document does not
   * complete. This bad state causes a GP when the parent window is
   * eventually disposed. The workaround is to issue a Stop before
   * navigating to any xml document.
   */
  if (url.endsWith(".xml")) { //$NON-NLS-1$
   /*
    * Feature in Internet Explorer. Stopping pending requests when no
    * request has been issued causes a default 'Action cancelled' page
    * to be displayed. Since Stop must be issued here, the workaround
    * is to first Navigate to the about:blank page before issuing Stop
    * so that the 'Action cancelled' page is not displayed.
    */
   if (!navigate) {
    int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
    Variant[] rgvarg = new Variant[1];
    rgvarg[0] = new Variant(ABOUT_BLANK);
    int[] rgdispidNamedArgs = new int[1];
    rgdispidNamedArgs[0] = rgdispid[1];
    auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
    rgvarg[0].dispose();
   }
   int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
   auto.invoke(rgdispid[0]);
  }

  int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL", "PostData" }); //$NON-NLS-1$ //$NON-NLS-2$
  navigate = true;
  Variant[] rgvarg = new Variant[2];
  rgvarg[0] = new Variant(url);
  rgvarg[1] = writeSafeArray(postData);
  int[] rgdispidNamedArgs = new int[2];
  rgdispidNamedArgs[0] = rgdispid[1];
  rgdispidNamedArgs[1] = rgdispid[2];
  Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);

//  int[] rgdispid = automation.getIDsOfNames(new String[] { "Navigate", "URL", "PostData" });
//  int dispIdMember = rgdispid[0];
//  Variant[] rgvarg = new Variant[2];
//  rgvarg[0] = new Variant(text.getText());
//  rgvarg[1] = writeSafeArray("hello world");
//  int[] rgdispidNamedArgs = new int[2];
//  rgdispidNamedArgs[0] = rgdispid[1];
//  rgdispidNamedArgs[1] = rgdispid[2];
//  automation.invoke(dispIdMember, rgvarg, rgdispidNamedArgs);

  rgvarg[0].dispose();
  if (pVarResult == null)
   return false;
  boolean result = pVarResult.getType() == OLE.VT_EMPTY;
  pVarResult.dispose();
  return result;
 }

 /**
  * Stop any loading and rendering activity.
  *
  * @exception SWTException
  *                <ul>
  *                <li>ERROR_THREAD_INVALID_ACCESS when called from the
  *                wrong thread</li>
  *                <li>ERROR_WIDGET_DISPOSED when the widget has been
  *                disposed</li>
  *                </ul>
  *
  * @since 3.0
  */
 public void stop() {
  checkWidget();
  int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
  auto.invoke(rgdispid[0]);
 }

 static String readSafeArray(Variant variantByRef) {
  // Read a safearray that contains data of
  // type VT_UI1 (unsigned shorts) which contains
  // a text stream.
  int pPostData = variantByRef.getByRef();
  short[] vt_type = new short[1];
  OS.MoveMemory(vt_type, pPostData, 2);
  String result = null;
  if (vt_type[0] == (short) (OLE.VT_BYREF | OLE.VT_VARIANT)) {
   int[] pVariant = new int[1];
   OS.MoveMemory(pVariant, pPostData + 8, 4);
   vt_type = new short[1];
   OS.MoveMemory(vt_type, pVariant[0], 2);
   if (vt_type[0] == (short) (OLE.VT_ARRAY | OLE.VT_UI1)) {
    int[] pSafearray = new int[1];
    OS.MoveMemory(pSafearray, pVariant[0] + 8, 4);
    short[] cDims = new short[1];
    OS.MoveMemory(cDims, pSafearray[0], 2);
    int[] pvData = new int[1];
    OS.MoveMemory(pvData, pSafearray[0] + 12, 4);
    int safearrayboundOffset = 0;
    for (int i = 0; i < cDims[0]; i++) {
     int[] cElements = new int[1];
     OS.MoveMemory(cElements, pSafearray[0] + 16 + safearrayboundOffset, 4);
     safearrayboundOffset += 8;
     int cchWideChar = OS.MultiByteToWideChar(CodePage, OS.MB_PRECOMPOSED, pvData[0], -1, null, 0);
     if (cchWideChar == 0)
      return null;
     char[] lpWideCharStr = new char[cchWideChar - 1];
     OS.MultiByteToWideChar(CodePage, OS.MB_PRECOMPOSED, pvData[0], -1, lpWideCharStr,
       lpWideCharStr.length);
     result = new String(lpWideCharStr);
    }
   }
  }
  return result;
 }

 static Variant writeSafeArray(String string) {
  // Create a one dimensional safearray containing two VT_UI1 values
  // where VT_UI1 is an unsigned char

  // Define cDims, fFeatures and cbElements
  short cDims = 1;
  short FADF_FIXEDSIZE = 0x10;
  short FADF_HAVEVARTYPE = 0x80;
  short fFeatures = (short) (FADF_FIXEDSIZE | FADF_HAVEVARTYPE);
  int cbElements = 1;
  // Create a pointer and copy the data into it
  int count = string.length();
  char[] chars = new char[count + 1];
  string.getChars(0, count, chars, 0);
  int cchMultiByte = OS.WideCharToMultiByte(CodePage, 0, chars, -1, null, 0, null, null);
  if (cchMultiByte == 0)
   return null;
  int pvData = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
  OS.WideCharToMultiByte(CodePage, 0, chars, -1, pvData, cchMultiByte, null, null);
  int cElements1 = cchMultiByte;
  int lLbound1 = 0;
  // Create a safearray in memory
  // 12 bytes for cDims, fFeatures and cbElements + 4 bytes for pvData +
  // number of dimensions * (size of safearraybound)
  int sizeofSafeArray = 12 + 4 + 1 * 8;
  int pSafeArray = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, sizeofSafeArray);
  // Copy the data into the safe array
  int offset = 0;
  OS.MoveMemory(pSafeArray + offset, new short[] { cDims }, 2);
  offset += 2;
  OS.MoveMemory(pSafeArray + offset, new short[] { fFeatures }, 2);
  offset += 2;
  OS.MoveMemory(pSafeArray + offset, new int[] { cbElements }, 4);
  offset += 4;
  OS.MoveMemory(pSafeArray + offset, new int[] { 0 }, 4);
  offset += 4;
  OS.MoveMemory(pSafeArray + offset, new int[] { pvData }, 4);
  offset += 4;
  OS.MoveMemory(pSafeArray + offset, new int[] { cElements1 }, 4);
  offset += 4;
  OS.MoveMemory(pSafeArray + offset, new int[] { lLbound1 }, 4);
  offset += 4;
  // Create a variant in memory to hold the safearray
  int pVariant = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, Variant.sizeof);
  short vt = (short) (OLE.VT_ARRAY | OLE.VT_UI1);
  OS.MoveMemory(pVariant, new short[] { vt }, 2);
  OS.MoveMemory(pVariant + 8, new int[] { pSafeArray }, 4);
  // Create a by ref variant
  Variant variantByRef = new Variant(pVariant, (short) (OLE.VT_BYREF | OLE.VT_VARIANT));
  return variantByRef;
 }

 public int getBrowserId() {
  return this.browserId;
 }

 public String getText() {
  return _text;
 }

 /**
  * Modified by TMB on 8/15/2005
  *
  * Sets the html between the root node of the Document automation object.
  * The root node will generally start at the <HTML> node
  *
  * From MSDN: With Internet Explorer 6 and later, when you use the !DOCTYPE
  * declaration to specify standards-compliant mode, this element represents
  * the canvas—the entire surface onto which a document's contents can be
  * rendered. When you switch on standards-compliant mode, this element also
  * becomes the positioning container for positioned elements that don't have
  * a positioned parent. When the !DOCTYPE declaration does not specify
  * standards-compliant mode, and with earler versions of Internet Explorer,
  * the body object represents the entire surface onto which a document's
  * contents can be rendered.
  *
  * By retrieving the documentElement, we do not care what tag represents the
  * canvas. This method allows us to take what we are given and work with it,
  * including malformed HTML.
  *
  */
 private void setHTML() {
  Variant pVarResult = null;
  OleAutomation autox = null;
  int[] rgdispid = auto.getIDsOfNames(new String[] { "Document" }); //$NON-NLS-1$
  if (rgdispid != null) {
   pVarResult = auto.getProperty(rgdispid[0]);
   autox = pVarResult.getAutomation();
   rgdispid = autox.getIDsOfNames(new String[] { "documentElement" });
   if (rgdispid != null) {
    pVarResult = autox.getProperty(rgdispid[0]);
    autox = pVarResult.getAutomation();
    rgdispid = autox.getIDsOfNames(new String[] { "innerHTML" });
    if (rgdispid != null) {
     pVarResult = autox.getProperty(rgdispid[0]);
     _text = pVarResult.getString();
    }
   }
  }
  // be sure to dispose of any native references so that Release() is
  // called on their IUnknown pointer
  if (pVarResult != null) {
   pVarResult.dispose();
  }
  if (autox != null) {
   autox.dispose();
  }
 }
}


posted on 2008-04-10 22:35 seal 阅读(1216) 评论(0)  编辑  收藏 所属分类: Eclipse SWT/JFace RCP

只有注册用户登录后才能发表评论。


网站导航: