Package com.google.gdt.eclipse.designer.ie.jsni

Source Code of com.google.gdt.eclipse.designer.ie.jsni.IDispatchImpl

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gdt.eclipse.designer.ie.jsni;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;

import org.eclipse.swt.internal.ole.win32.COM;
import org.eclipse.swt.internal.ole.win32.COMObject;
import org.eclipse.swt.internal.ole.win32.DISPPARAMS;
import org.eclipse.swt.internal.ole.win32.GUID;
import org.eclipse.swt.internal.win32.OS;
import org.eclipse.swt.ole.win32.OleAutomation;
import org.eclipse.swt.ole.win32.Variant;

import com.google.gdt.eclipse.designer.ie.util.Utils;
import com.google.gwt.dev.shell.designtime.DispatchIdOracle;
import com.google.gwt.dev.shell.designtime.MethodAdaptor;
import com.google.gwt.dev.shell.designtime.ModuleSpace;

/**
* Basic IDispatch implementation for use by {@link com.google.gwt.shell.ie.IDispatchProxy} and
* {@link com.google.gwt.shell.ie.IDispatchStatic}.
*/
public abstract class IDispatchImpl extends COMObject {
  /**
   * An exception for wrapping bad HR's.
   */
  public static class HResultException extends Exception {
    private final int hr;
    private final String source;

    /**
     * Constructs a standard bad HR exception.
     */
    public HResultException(int hr) {
      super(Integer.toString(hr));
      this.hr = hr;
      source = "Java";
    }

    /**
     * Constructs a DISP_E_EXCEPTION bad HR.
     */
    public HResultException(String message) {
      super(message);
      hr = COM.DISP_E_EXCEPTION;
      source = "Java";
    }

    /**
     * Constructs a DISP_E_EXCEPTION bad HR.
     */
    public HResultException(Throwable e) {
      super(getStackTraceAsString(e), e);
      hr = COM.DISP_E_EXCEPTION;
      source = "Java";
    }

    /**
     * If the HR is DISP_E_EXCEPTION, this method will fill in the EXCEPINFO structure. Otherwise,
     * it does nothing.
     */
    public void fillExcepInfo(int pExcepInfo) {
      if (hr == COM.DISP_E_EXCEPTION) {
        String desc = getMessage();
        // 0: wCode (size = 2)
        // 4: bstrSource (size = 4)
        // 8: bstrDescription (size = 4)
        // 28: scode (size = 4)
        //
        OS.MoveMemory(pExcepInfo + 0, new short[]{(short) hr}, 2);
        if (source != null && source.length() != 0) {
          int bstrSource = SwtOleGlue.sysAllocString(source);
          OS.MoveMemory(pExcepInfo + 4, new int[]{bstrSource}, 4);
        }
        if (desc != null && desc.length() != 0) {
          int bstrDesc = SwtOleGlue.sysAllocString(desc);
          OS.MoveMemory(pExcepInfo + 8, new int[]{bstrDesc}, 4);
        }
        OS.MoveMemory(pExcepInfo + 28, new int[]{0}, 4);
      }
    }

    /**
     * Gets the HR.
     */
    public int getHResult() {
      return hr;
    }
  }

  // This one isn't defined in SWT for some reason.
  protected static final int DISP_E_UNKNOWNNAME = 0x80020006;

  protected static Variant callMethod(ClassLoader cl,
      DispatchIdOracle ora,
      Object jthis,
      Variant[] params,
      MethodAdaptor method) throws InstantiationException, InvocationTargetException,
      HResultException {
    // TODO: make sure we have enough args! It's okay if there are too many.
    Object[] javaParams =
        SwtOleGlue.convertVariantsToObjects(
          cl,
          method.getParameterTypes(),
          params,
          "Calling method '" + method.getName() + "'");
    Object result = null;
    try {
      try {
        result = method.invoke(jthis, javaParams);
      } catch (IllegalAccessException e) {
        // should never, ever happen
        e.printStackTrace();
        throw new RuntimeException(e);
      }
    } catch (NullPointerException e) {
      /*
       * The JavaScript expected the method to be static, having forgotten an
       * instance reference (most often "this.").
       */
      StringBuffer sb = new StringBuffer();
      sb.append("Instance method '");
      sb.append(method.getName());
      sb.append("' needed a qualifying instance ");
      sb.append("(did you forget to prefix the call with 'this.'?)");
      throw new HResultException(sb.toString());
    } finally {
      for (int i = 0; i < javaParams.length; i++) {
        if (javaParams[i] instanceof OleAutomation) {
          OleAutomation tmp = (OleAutomation) javaParams[i];
          tmp.dispose();
        }
      }
    }
    return SwtOleGlue.convertObjectToVariant(cl, ora, method.getReturnType(), result);
  }

  protected int refCount;

  public IDispatchImpl() {
    super(new int[]{2, 0, 0, 1, 3, 5, 8});
  }

  // CHECKSTYLE_OFF
  public int AddRef() {
    return ++refCount;
  }

  // CHECKSTYLE_ON
  @Override
  public int method0(int[] args) {
    return QueryInterface(args[0], args[1]);
  }

  @Override
  public int method1(int[] args) {
    return AddRef();
  }

  // method3 GetTypeInfoCount - not implemented
  // method4 GetTypeInfo - not implemented
  @Override
  public int method2(int[] args) {
    return Release();
  }

  @Override
  public int method5(int[] args) {
    return GetIDsOfNames(args[0], args[1], args[2], args[3], args[4]);
  }

  @Override
  public int method6(int[] args) {
    return Invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
  }

  // CHECKSTYLE_OFF
  public int QueryInterface(int riid, int ppvObject) {
    if (riid == 0 || ppvObject == 0) {
      return COM.E_NOINTERFACE;
    }
    GUID guid = new GUID();
    COM.MoveMemory(guid, riid, GUID.sizeof);
    if (COM.IsEqualGUID(guid, COM.IIDIUnknown)) {
      OS.MoveMemory(ppvObject, new int[]{getAddress()}, 4);
      AddRef();
      return COM.S_OK;
    }
    if (COM.IsEqualGUID(guid, COM.IIDIDispatch)) {
      OS.MoveMemory(ppvObject, new int[]{getAddress()}, 4);
      AddRef();
      return COM.S_OK;
    }
    OS.MoveMemory(ppvObject, new int[]{0}, 4);
    return COM.E_NOINTERFACE;
  }

  public int Release() {
    if (--refCount == 0) {
      dispose();
    }
    return refCount;
  }

  // CHECKSTYLE_ON
  /**
   * Override this method to implement GetIDsOfNames().
   */
  protected abstract void getIDsOfNames(String[] names, int[] ids) throws HResultException;

  /**
   * Override this method to implement Invoke().
   */
  protected abstract Variant invoke(int dispId, int flags, Variant[] params)
      throws HResultException, InstantiationException, InvocationTargetException;

  private Variant[] extractVariantArrayFromDispParamsPtr(int pDispParams) {
    DISPPARAMS dispParams = new DISPPARAMS();
    COM.MoveMemory(dispParams, pDispParams, DISPPARAMS.sizeof);
    Variant[] variants = new Variant[dispParams.cArgs];
    // Reverse the order as we pull the variants in.
    for (int i = 0, n = dispParams.cArgs; i < n; ++i) {
      int varArgAddr = dispParams.rgvarg + Variant.sizeof * i;
      variants[n - i - 1] = Utils.win32_new(varArgAddr);
    }
    return variants;
  }

  // CHECKSTYLE_OFF
  @SuppressWarnings("unused")
  private final int GetIDsOfNames(int riid, int rgszNames, int cNames, int lcid, int rgDispId) {
    try {
      if (cNames < 1) {
        return COM.E_INVALIDARG;
      }
      // Extract the requested names and build an answer array init'ed with -1.
      //
      String[] names = SwtOleGlue.extractStringArrayFromOleCharPtrPtr(rgszNames, cNames);
      int[] ids = new int[names.length];
      Arrays.fill(ids, -1);
      getIDsOfNames(names, ids);
      OS.MoveMemory(rgDispId, ids, ids.length * 4);
    } catch (HResultException e) {
      return e.getHResult();
    } catch (Throwable e) {
      e.printStackTrace();
      return COM.E_FAIL;
    }
    return COM.S_OK;
  }

  @SuppressWarnings("unused")
  private int Invoke(int dispIdMember,
      int riid,
      int lcid,
      int dwFlags,
      int pDispParams,
      int pVarResult,
      int pExcepInfo,
      int pArgErr) {
    HResultException ex = null;
    Variant[] vArgs = null;
    Variant result = null;
    try {
      vArgs = extractVariantArrayFromDispParamsPtr(pDispParams);
      result = invoke(dispIdMember, dwFlags, vArgs);
      if (pVarResult != 0) {
        Utils.win32_copy(pVarResult, result);
      }
    } catch (HResultException e) {
      // Log to the console for detailed examination.
      //
      e.printStackTrace();
      ex = e;
    } catch (InvocationTargetException e) {
      // If we get here, it means an exception is being thrown from
      // Java back into JavaScript
      Throwable t = e.getTargetException();
      ex = new HResultException(t);
      ModuleSpace.setThrownJavaException(t);
    } catch (Exception e) {
      // Log to the console for detailed examination.
      //
      e.printStackTrace();
      ex = new HResultException(e);
    } finally {
      // We allocated variants for all arguments, so we must dispose them all.
      //
      for (int i = 0; i < vArgs.length; ++i) {
        if (vArgs[i] != null) {
          vArgs[i].dispose();
        }
      }
      if (result != null) {
        result.dispose();
      }
    }
    if (ex != null) {
      // Set up an exception for IE to throw.
      //
      ex.fillExcepInfo(pExcepInfo);
      return ex.getHResult();
    }
    return COM.S_OK;
  }

  // CHECKSTYLE_ON
  private static String getStackTraceAsString(Throwable e) {
    // Show the exception info for anything other than "UnableToComplete".
    if (e == null || e.getClass().getName().equals("UnableToCompleteException")) {
      return null;
    }
    // For each cause, print the requested number of entries of its stack
    // trace, being careful to avoid getting stuck in an infinite loop.
    //
    StringBuffer message = new StringBuffer();
    Throwable currentCause = e;
    String causedBy = "";
    HashSet<Throwable> seenCauses = new HashSet<Throwable>();
    while (currentCause != null && !seenCauses.contains(currentCause)) {
      seenCauses.add(currentCause);
      message.append(causedBy);
      causedBy = "\nCaused by: "; // after 1st, all say "caused by"
      message.append(currentCause.getClass().getName());
      message.append(": " + currentCause.getMessage());
      StackTraceElement[] stackElems = currentCause.getStackTrace();
      if (stackElems != null) {
        for (int i = 0; i < stackElems.length; ++i) {
          message.append("\n\tat ");
          message.append(stackElems[i].toString());
        }
      }
      currentCause = currentCause.getCause();
    }
    return message.toString();
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.ie.jsni.IDispatchImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.