001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell.ie;
017:
018: import com.google.gwt.dev.shell.CompilingClassLoader;
019: import com.google.gwt.dev.shell.ModuleSpace;
020: import com.google.gwt.dev.util.log.AbstractTreeLogger;
021:
022: import org.eclipse.swt.internal.ole.win32.COM;
023: import org.eclipse.swt.internal.ole.win32.COMObject;
024: import org.eclipse.swt.internal.ole.win32.DISPPARAMS;
025: import org.eclipse.swt.internal.ole.win32.GUID;
026: import org.eclipse.swt.internal.win32.OS;
027: import org.eclipse.swt.ole.win32.OleAutomation;
028: import org.eclipse.swt.ole.win32.Variant;
029:
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032: import java.util.Arrays;
033:
034: /**
035: * Basic IDispatch implementation for use by
036: * {@link com.google.gwt.shell.ie.IDispatchProxy} and
037: * {@link com.google.gwt.shell.ie.IDispatchStatic}.
038: */
039: abstract class IDispatchImpl extends COMObject {
040:
041: /**
042: * An exception for wrapping bad HR's.
043: */
044: protected static class HResultException extends Exception {
045: private int hr;
046:
047: private String source;
048:
049: /**
050: * Constructs a standard bad HR exception.
051: */
052: public HResultException(int hr) {
053: super (Integer.toString(hr));
054: this .hr = hr;
055: source = "Java";
056: }
057:
058: /**
059: * Constructs a DISP_E_EXCEPTION bad HR.
060: */
061: public HResultException(String message) {
062: super (message);
063: hr = COM.DISP_E_EXCEPTION;
064: source = "Java";
065: }
066:
067: /**
068: * Constructs a DISP_E_EXCEPTION bad HR.
069: */
070: public HResultException(Throwable e) {
071: super (AbstractTreeLogger.getStackTraceAsString(e), e);
072: hr = COM.DISP_E_EXCEPTION;
073: source = "Java";
074: }
075:
076: /**
077: * If the HR is DISP_E_EXCEPTION, this method will fill in the EXCEPINFO
078: * structure. Otherwise, it does nothing.
079: */
080: public void fillExcepInfo(int pExcepInfo) {
081: if (hr == COM.DISP_E_EXCEPTION) {
082: String desc = getMessage();
083: // 0: wCode (size = 2)
084: // 4: bstrSource (size = 4)
085: // 8: bstrDescription (size = 4)
086: // 28: scode (size = 4)
087: //
088: OS.MoveMemory(pExcepInfo + 0,
089: new short[] { (short) hr }, 2);
090:
091: if (source != null) {
092: int bstrSource = SwtOleGlue.sysAllocString(source);
093: OS.MoveMemory(pExcepInfo + 4,
094: new int[] { bstrSource }, 4);
095: }
096:
097: if (desc != null) {
098: int bstrDesc = SwtOleGlue.sysAllocString(desc);
099: OS.MoveMemory(pExcepInfo + 8,
100: new int[] { bstrDesc }, 4);
101: }
102:
103: OS.MoveMemory(pExcepInfo + 28, new int[] { 0 }, 4);
104: }
105: }
106:
107: /**
108: * Gets the HR.
109: */
110: public int getHResult() {
111: return hr;
112: }
113: }
114:
115: // This one isn't defined in SWT for some reason.
116: protected static final int DISP_E_UNKNOWNNAME = 0x80020006;
117:
118: protected static Variant callMethod(CompilingClassLoader cl,
119: Object jthis , Variant[] params, Method method)
120: throws InvocationTargetException, HResultException {
121: // TODO: make sure we have enough args! It's okay if there are too many.
122: Object[] javaParams = SwtOleGlue.convertVariantsToObjects(
123: method.getParameterTypes(), params, "Calling method '"
124: + method.getName() + "'");
125:
126: Object result = null;
127: try {
128: try {
129: result = method.invoke(jthis , javaParams);
130: } catch (IllegalAccessException e) {
131: // should never, ever happen
132: e.printStackTrace();
133: throw new RuntimeException(e);
134: }
135: } catch (NullPointerException e) {
136: /*
137: * The JavaScript expected the method to be static, having forgotten an
138: * instance reference (most often "this.").
139: */
140: StringBuffer sb = new StringBuffer();
141: sb.append("Instance method '");
142: sb.append(method.getName());
143: sb.append("' needed a qualifying instance ");
144: sb
145: .append("(did you forget to prefix the call with 'this.'?)");
146: throw new HResultException(sb.toString());
147: } finally {
148: for (int i = 0; i < javaParams.length; i++) {
149: if (javaParams[i] instanceof OleAutomation) {
150: OleAutomation tmp = (OleAutomation) javaParams[i];
151: tmp.dispose();
152: }
153: }
154: }
155:
156: // Convert it to a variant (if the return type is void, return
157: // a VT_EMPTY variant -- 'undefined' in JavaScript).
158: //
159: Class<?> returnType = method.getReturnType();
160: if (returnType.equals(Void.TYPE)) {
161: return new Variant();
162: }
163: return SwtOleGlue
164: .convertObjectToVariant(cl, returnType, result);
165: }
166:
167: protected int refCount;
168:
169: public IDispatchImpl() {
170: super (new int[] { 2, 0, 0, 1, 3, 5, 8 });
171: }
172:
173: // CHECKSTYLE_OFF
174: public int AddRef() {
175: return ++refCount;
176: }
177:
178: // CHECKSTYLE_ON
179:
180: @Override
181: public int method0(int[] args) {
182: return QueryInterface(args[0], args[1]);
183: }
184:
185: @Override
186: public int method1(int[] args) {
187: return AddRef();
188: }
189:
190: // method3 GetTypeInfoCount - not implemented
191:
192: // method4 GetTypeInfo - not implemented
193:
194: @Override
195: public int method2(int[] args) {
196: return Release();
197: }
198:
199: @Override
200: public int method5(int[] args) {
201: return GetIDsOfNames(args[0], args[1], args[2], args[3],
202: args[4]);
203: }
204:
205: @Override
206: public int method6(int[] args) {
207: return Invoke(args[0], args[1], args[2], args[3], args[4],
208: args[5], args[6], args[7]);
209: }
210:
211: // CHECKSTYLE_OFF
212: public int QueryInterface(int riid, int ppvObject) {
213: if (riid == 0 || ppvObject == 0) {
214: return COM.E_NOINTERFACE;
215: }
216: GUID guid = new GUID();
217: COM.MoveMemory(guid, riid, GUID.sizeof);
218:
219: if (COM.IsEqualGUID(guid, COM.IIDIUnknown)) {
220: OS.MoveMemory(ppvObject, new int[] { getAddress() }, 4);
221: AddRef();
222: return COM.S_OK;
223: }
224:
225: if (COM.IsEqualGUID(guid, COM.IIDIDispatch)) {
226: OS.MoveMemory(ppvObject, new int[] { getAddress() }, 4);
227: AddRef();
228: return COM.S_OK;
229: }
230:
231: OS.MoveMemory(ppvObject, new int[] { 0 }, 4);
232: return COM.E_NOINTERFACE;
233: }
234:
235: public int Release() {
236: if (--refCount == 0) {
237: dispose();
238: }
239: return refCount;
240: }
241:
242: // CHECKSTYLE_ON
243:
244: /**
245: * Override this method to implement GetIDsOfNames().
246: */
247: protected abstract void getIDsOfNames(String[] names, int[] ids)
248: throws HResultException;
249:
250: /**
251: * Override this method to implement Invoke().
252: */
253: protected abstract Variant invoke(int dispId, int flags,
254: Variant[] params) throws HResultException,
255: InvocationTargetException;
256:
257: private Variant[] extractVariantArrayFromDispParamsPtr(
258: int pDispParams) {
259: DISPPARAMS dispParams = new DISPPARAMS();
260: COM.MoveMemory(dispParams, pDispParams, DISPPARAMS.sizeof);
261: Variant[] variants = new Variant[dispParams.cArgs];
262: // Reverse the order as we pull the variants in.
263: for (int i = 0, n = dispParams.cArgs; i < n; ++i) {
264: int varArgAddr = dispParams.rgvarg + Variant.sizeof * i;
265: variants[n - i - 1] = Variant.win32_new(varArgAddr);
266: }
267: return variants;
268: }
269:
270: // CHECKSTYLE_OFF
271: private final int GetIDsOfNames(int riid, int rgszNames,
272: int cNames, int lcid, int rgDispId) {
273:
274: try {
275: if (cNames < 1) {
276: return COM.E_INVALIDARG;
277: }
278:
279: // Extract the requested names and build an answer array init'ed with -1.
280: //
281: String[] names = SwtOleGlue
282: .extractStringArrayFromOleCharPtrPtr(rgszNames,
283: cNames);
284: int[] ids = new int[names.length];
285: Arrays.fill(ids, -1);
286:
287: getIDsOfNames(names, ids);
288: OS.MoveMemory(rgDispId, ids, ids.length * 4);
289: } catch (HResultException e) {
290: return e.getHResult();
291: } catch (Throwable e) {
292: e.printStackTrace();
293: return COM.E_FAIL;
294: }
295:
296: return COM.S_OK;
297: }
298:
299: private int Invoke(int dispIdMember, int riid, int lcid,
300: int dwFlags, int pDispParams, int pVarResult,
301: int pExcepInfo, int pArgErr) {
302:
303: HResultException ex = null;
304: Variant[] vArgs = null;
305: Variant result = null;
306: try {
307: vArgs = extractVariantArrayFromDispParamsPtr(pDispParams);
308: result = invoke(dispIdMember, dwFlags, vArgs);
309: if (pVarResult != 0) {
310: Variant.win32_copy(pVarResult, result);
311: }
312: } catch (HResultException e) {
313: // Log to the console for detailed examination.
314: //
315: e.printStackTrace();
316: ex = e;
317:
318: } catch (InvocationTargetException e) {
319: // If we get here, it means an exception is being thrown from
320: // Java back into JavaScript
321:
322: Throwable t = e.getTargetException();
323: ex = new HResultException(t);
324: ModuleSpace.setThrownJavaException(t);
325: } catch (Exception e) {
326: // Log to the console for detailed examination.
327: //
328: e.printStackTrace();
329: ex = new HResultException(e);
330: } finally {
331: // We allocated variants for all arguments, so we must dispose them all.
332: //
333: for (int i = 0; i < vArgs.length; ++i) {
334: if (vArgs[i] != null) {
335: vArgs[i].dispose();
336: }
337: }
338:
339: if (result != null) {
340: result.dispose();
341: }
342: }
343:
344: if (ex != null) {
345: // Set up an exception for IE to throw.
346: //
347: ex.fillExcepInfo(pExcepInfo);
348: return ex.getHResult();
349: }
350:
351: return COM.S_OK;
352: }
353: // CHECKSTYLE_ON
354: }
|