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.JsValue;
020: import com.google.gwt.dev.shell.LowLevel;
021:
022: import org.eclipse.swt.internal.ole.win32.COM;
023: import org.eclipse.swt.internal.ole.win32.DISPPARAMS;
024: import org.eclipse.swt.internal.ole.win32.EXCEPINFO;
025: import org.eclipse.swt.internal.ole.win32.GUID;
026: import org.eclipse.swt.internal.ole.win32.IDispatch;
027: import org.eclipse.swt.internal.ole.win32.IUnknown;
028: import org.eclipse.swt.internal.win32.OS;
029: import org.eclipse.swt.ole.win32.OleAutomation;
030: import org.eclipse.swt.ole.win32.Variant;
031:
032: /**
033: * Represents an IE JavaScript value.
034: */
035: public class JsValueIE6 extends JsValue {
036:
037: private static class JsCleanupIE6 implements JsCleanup {
038: private Variant variant;
039:
040: public JsCleanupIE6(Variant variant) {
041: this .variant = variant;
042: }
043:
044: public void doCleanup() {
045: variant.dispose();
046: }
047: }
048:
049: private static Variant maybeCopyVariant(Variant variant) {
050: if (variant == null) {
051: return new Variant();
052: }
053: switch (variant.getType()) {
054: case COM.VT_DISPATCH: {
055: IDispatch dispatch = variant.getDispatch();
056: dispatch.AddRef();
057: return new Variant(dispatch);
058: }
059: case COM.VT_UNKNOWN: {
060: IUnknown unknown = variant.getUnknown();
061: unknown.AddRef();
062: return new Variant(unknown);
063: }
064: }
065: return variant;
066: }
067:
068: // a null variant means the JsValue is undefined (void)
069: private Variant variant;
070:
071: /**
072: * Create a null JsValue.
073: */
074: public JsValueIE6() {
075: this .variant = null;
076: }
077:
078: /**
079: * Create a JsValue given a variant.
080: *
081: * @param variant JS value
082: */
083: public JsValueIE6(Variant variant) {
084: this .variant = maybeCopyVariant(variant);
085: }
086:
087: /*
088: * (non-Javadoc)
089: *
090: * @see com.google.gwt.dev.shell.JsValue#getBoolean()
091: */
092: @Override
093: public boolean getBoolean() {
094: return variant.getBoolean();
095: }
096:
097: /*
098: * (non-Javadoc)
099: *
100: * @see com.google.gwt.dev.shell.JsValue#getInt()
101: */
102: @Override
103: public int getInt() {
104: return variant.getInt();
105: }
106:
107: /*
108: * (non-Javadoc)
109: *
110: * @see com.google.gwt.dev.shell.JsValue#getNumber()
111: */
112: @Override
113: public double getNumber() {
114: return variant.getDouble();
115: }
116:
117: /*
118: * (non-Javadoc)
119: *
120: * @see com.google.gwt.dev.shell.JsValue#getString()
121: */
122: @Override
123: public String getString() {
124: return variant.getString();
125: }
126:
127: /*
128: * (non-Javadoc)
129: *
130: * @see com.google.gwt.dev.shell.JsValue#getTypeString()
131: */
132: @Override
133: public String getTypeString() {
134: switch (variant.getType()) {
135: case COM.VT_BOOL:
136: return "boolean";
137: case COM.VT_I1:
138: case COM.VT_I2:
139: case COM.VT_I4:
140: case COM.VT_I8:
141: case COM.VT_UI1:
142: case COM.VT_UI2:
143: case COM.VT_UI4:
144: case COM.VT_R4:
145: case COM.VT_R8:
146: return "number";
147: case COM.VT_BSTR:
148: return "string";
149: case COM.VT_EMPTY:
150: return "undefined";
151: case COM.VT_NULL:
152: return "null";
153: case COM.VT_DISPATCH:
154: return isWrappedJavaObject() ? "Java Object"
155: : "JavaScript object";
156: default:
157: return "unexpected Variant type";
158: }
159: }
160:
161: /**
162: * Return the underlying Variant object. PLATFORM-SPECIFIC.
163: */
164: public Variant getVariant() {
165: return maybeCopyVariant(variant);
166: }
167:
168: /*
169: * (non-Javadoc)
170: *
171: * @see com.google.gwt.dev.shell.JsValue#getWrappedJavaObject()
172: */
173: @Override
174: public Object getWrappedJavaObject() {
175: return tryToUnwrapWrappedJavaObject();
176: }
177:
178: /*
179: * (non-Javadoc)
180: *
181: * @see com.google.gwt.dev.shell.JsValue#isBoolean()
182: */
183: @Override
184: public boolean isBoolean() {
185: return variant != null && variant.getType() == COM.VT_BOOL;
186: }
187:
188: /*
189: * (non-Javadoc)
190: *
191: * @see com.google.gwt.dev.shell.JsValue#isInt()
192: */
193: @Override
194: public boolean isInt() {
195: if (variant == null) {
196: return false;
197: }
198: switch (variant.getType()) {
199: case COM.VT_I1:
200: case COM.VT_I2:
201: case COM.VT_I4:
202: case COM.VT_UI1:
203: case COM.VT_UI2:
204: // note that VT_UI4 is excluded since it may not fit in an int
205: return true;
206: default:
207: return false;
208: }
209: }
210:
211: /*
212: * (non-Javadoc)
213: *
214: * @see com.google.gwt.dev.shell.JsValue#isJavaScriptObject()
215: */
216: @Override
217: public boolean isJavaScriptObject() {
218: if (variant == null) {
219: return false;
220: }
221: if (variant.getType() != COM.VT_DISPATCH) {
222: return false;
223: }
224: return tryToUnwrapWrappedJavaObject() == null;
225: }
226:
227: /*
228: * (non-Javadoc)
229: *
230: * @see com.google.gwt.dev.shell.JsValue#isNull()
231: */
232: @Override
233: public boolean isNull() {
234: return variant != null && variant.getType() == COM.VT_NULL;
235: }
236:
237: /*
238: * (non-Javadoc)
239: *
240: * @see com.google.gwt.dev.shell.JsValue#isNumber()
241: */
242: @Override
243: public boolean isNumber() {
244: if (variant == null) {
245: return false;
246: }
247: switch (variant.getType()) {
248: case COM.VT_I1:
249: case COM.VT_I2:
250: case COM.VT_I4:
251: case COM.VT_I8:
252: case COM.VT_UI1:
253: case COM.VT_UI2:
254: case COM.VT_UI4:
255: case COM.VT_R4:
256: case COM.VT_R8:
257: return true;
258: default:
259: return false;
260: }
261: }
262:
263: /*
264: * (non-Javadoc)
265: *
266: * @see com.google.gwt.dev.shell.JsValue#isString()
267: */
268: @Override
269: public boolean isString() {
270: if (variant == null) {
271: return false;
272: }
273: if (variant.getType() == COM.VT_BSTR) {
274: return true;
275: }
276: // see if the variant is a wrapper object
277: if (variant.getType() != COM.VT_DISPATCH) {
278: return false;
279: }
280: OleAutomation auto = null;
281: Variant result = null;
282: try {
283: auto = new OleAutomation(variant.getDispatch());
284: // see if it has a valueOf method
285: int[] ids = auto.getIDsOfNames(new String[] { "valueOf" });
286: if (ids == null) {
287: return false;
288: }
289: result = auto.invoke(ids[0]);
290: /*
291: * If the return type of the valueOf method is string, we assume it is a
292: * String wrapper object.
293: */
294: return result.getType() == COM.VT_BSTR;
295: } finally {
296: if (auto != null) {
297: auto.dispose();
298: }
299: if (result != null) {
300: result.dispose();
301: }
302: }
303: }
304:
305: /*
306: * (non-Javadoc)
307: *
308: * @see com.google.gwt.dev.shell.JsValue#isUndefined()
309: */
310: @Override
311: public boolean isUndefined() {
312: return variant == null || variant.getType() == COM.VT_EMPTY;
313: }
314:
315: /*
316: * (non-Javadoc)
317: *
318: * @see com.google.gwt.dev.shell.JsValue#isWrappedJavaObject()
319: */
320: @Override
321: public boolean isWrappedJavaObject() {
322: if (variant == null) {
323: return false;
324: }
325: if (variant.getType() != COM.VT_DISPATCH) {
326: return false;
327: }
328: return tryToUnwrapWrappedJavaObject() != null;
329: }
330:
331: /*
332: * (non-Javadoc)
333: *
334: * @see com.google.gwt.dev.shell.JsValue#setBoolean(boolean)
335: */
336: @Override
337: public void setBoolean(boolean val) {
338: setVariant(new Variant(val));
339: }
340:
341: /*
342: * (non-Javadoc)
343: *
344: * @see com.google.gwt.dev.shell.JsValue#setByte(byte)
345: */
346: @Override
347: public void setByte(byte val) {
348: setVariant(new Variant(val));
349: }
350:
351: /*
352: * (non-Javadoc)
353: *
354: * @see com.google.gwt.dev.shell.JsValue#setChar(char)
355: */
356: @Override
357: public void setChar(char val) {
358: setVariant(new Variant(val));
359: }
360:
361: /*
362: * (non-Javadoc)
363: *
364: * @see com.google.gwt.dev.shell.JsValue#setDouble(double)
365: */
366: @Override
367: public void setDouble(double val) {
368: setVariant(new Variant(val));
369: }
370:
371: /*
372: * (non-Javadoc)
373: *
374: * @see com.google.gwt.dev.shell.JsValue#setInt(int)
375: */
376: @Override
377: public void setInt(int val) {
378: setVariant(new Variant(val));
379: }
380:
381: /*
382: * (non-Javadoc)
383: *
384: * @see com.google.gwt.dev.shell.JsValue#setNull()
385: */
386: @Override
387: public void setNull() {
388: setVariant(new Variant(0, COM.VT_NULL));
389: }
390:
391: /*
392: * (non-Javadoc)
393: *
394: * @see com.google.gwt.dev.shell.JsValue#setShort(short)
395: */
396: @Override
397: public void setShort(short val) {
398: setVariant(new Variant(val));
399: }
400:
401: /*
402: * (non-Javadoc)
403: *
404: * @see com.google.gwt.dev.shell.JsValue#setString(java.lang.String)
405: */
406: @Override
407: public void setString(String val) {
408: setVariant(new Variant(val));
409: }
410:
411: /*
412: * (non-Javadoc)
413: *
414: * @see com.google.gwt.dev.shell.JsValue#setUndefined()
415: */
416: @Override
417: public void setUndefined() {
418: setVariant(null);
419: }
420:
421: @Override
422: public void setValue(JsValue other) {
423: setVariant(maybeCopyVariant(((JsValueIE6) other).variant));
424: }
425:
426: /*
427: * (non-Javadoc)
428: *
429: * @see com.google.gwt.dev.shell.JsValue#setWrappedJavaObject(com.google.gwt.dev.shell.CompilingClassLoader,
430: * java.lang.Object)
431: */
432: @Override
433: public <T> void setWrappedJavaObject(CompilingClassLoader cl, T val) {
434: IDispatchImpl dispObj;
435: if (val == null) {
436: setNull();
437: return;
438: } else if (val instanceof IDispatchImpl) {
439: dispObj = (IDispatchImpl) val;
440: } else {
441: dispObj = new IDispatchProxy(cl, val);
442: }
443: IDispatch disp = new IDispatch(dispObj.getAddress());
444: disp.AddRef();
445: setVariant(new Variant(disp));
446: }
447:
448: /*
449: * (non-Javadoc)
450: *
451: * @see com.google.gwt.dev.shell.JsValue#createCleanupObject()
452: */
453: @Override
454: protected JsCleanup createCleanupObject() {
455: return new JsCleanupIE6(variant);
456: }
457:
458: /**
459: * Reset the underlying variant, freeing the old one if necessary.
460: *
461: * @param val the new Variant to store
462: */
463: protected void setVariant(Variant val) {
464: if (variant != null) {
465: variant.dispose();
466: }
467: variant = val;
468: }
469:
470: private <T> T tryToUnwrapWrappedJavaObject() {
471: /*
472: * This implementation copied from OleAutomation.invoke(). We used to have a
473: * varArg.getAutomation().invoke() implementation, but it turns out the
474: * querying for typeInfo that occurs in the OleAutomation(IDispatch)
475: * constructor will cause a VM crash on some kinds of JavaScript objects,
476: * such as the window.alert function. So we do it by hand.
477: */
478: IDispatch dispatch = variant.getDispatch();
479: Variant result = new Variant();
480: int pVarResultAddress = 0;
481: int globalRef = 0;
482: try {
483: pVarResultAddress = OS.GlobalAlloc(OS.GMEM_FIXED
484: | OS.GMEM_ZEROINIT, Variant.sizeof);
485: int[] pArgErr = new int[1];
486: int hr = dispatch.Invoke(
487: IDispatchProxy.DISPID_MAGIC_GETGLOBALREF,
488: new GUID(), COM.LOCALE_USER_DEFAULT,
489: COM.DISPATCH_METHOD, new DISPPARAMS(),
490: pVarResultAddress, new EXCEPINFO(), pArgErr);
491:
492: if (hr >= COM.S_OK) {
493: result = Variant.win32_new(pVarResultAddress);
494: globalRef = result.getInt();
495: }
496: if (globalRef != 0) {
497: // This is really a Java object being passed back via an IDispatchProxy.
498: IDispatchProxy proxy = (IDispatchProxy) LowLevel
499: .objFromGlobalRefInt(globalRef);
500: return (T) proxy.getTarget();
501: }
502: return null;
503: } finally {
504: if (result != null) {
505: result.dispose();
506: }
507: if (pVarResultAddress != 0) {
508: COM.VariantClear(pVarResultAddress);
509: OS.GlobalFree(pVarResultAddress);
510: }
511: }
512: }
513:
514: }
|