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.ModuleSpace;
021: import com.google.gwt.dev.shell.ModuleSpaceHost;
022: import com.google.gwt.dev.shell.ie.IDispatchImpl.HResultException;
023:
024: import org.eclipse.swt.internal.ole.win32.IDispatch;
025: import org.eclipse.swt.ole.win32.OleAutomation;
026: import org.eclipse.swt.ole.win32.Variant;
027:
028: /**
029: * An implementation of {@link com.google.gwt.dev.shell.ModuleSpace} for
030: * Internet Explorer 6.
031: */
032: public class ModuleSpaceIE6 extends ModuleSpace {
033: /**
034: * Invoke a JavaScript function. The static function exists to allow
035: * platform-dependent code to make JavaScript calls without having a
036: * ModuleSpaceIE6 (and all that entails) if it is not required.
037: *
038: * @param window the window containing the function
039: * @param name the name of the function
040: * @param vArgs the array of arguments. vArgs[0] is the this parameter
041: * supplied to the function, which must be null if it is static.
042: * @return the return value of the JavaScript function
043: */
044: protected static Variant doInvokeOnWindow(OleAutomation window,
045: String name, Variant[] vArgs) {
046: OleAutomation funcObj = null;
047: Variant funcObjVar = null;
048: try {
049:
050: // Get the function object and its 'call' method.
051: //
052: int[] ids = window.getIDsOfNames(new String[] { name });
053: if (ids == null) {
054: throw new RuntimeException(
055: "Could not find a native method with the signature '"
056: + name + "'");
057: }
058: int functionId = ids[0];
059: funcObjVar = window.getProperty(functionId);
060: funcObj = funcObjVar.getAutomation();
061: int callDispId = funcObj
062: .getIDsOfNames(new String[] { "call" })[0];
063:
064: // Invoke it and return the result.
065: //
066: return funcObj.invoke(callDispId, vArgs);
067:
068: } finally {
069: if (funcObjVar != null) {
070: funcObjVar.dispose();
071: }
072:
073: if (funcObj != null) {
074: funcObj.dispose();
075: }
076: }
077: }
078:
079: // CHECKSTYLE_OFF
080: private static int CODE(int hresult) {
081: return hresult & 0xFFFF;
082: }
083:
084: // CHECKSTYLE_ON
085:
086: private final OleAutomation window;
087:
088: /**
089: * Constructs a browser interface for use with an IE6 'window' automation
090: * object.
091: *
092: * @param moduleName
093: */
094: public ModuleSpaceIE6(ModuleSpaceHost host,
095: IDispatch scriptFrameWindow, String moduleName, Object key) {
096: super (host, moduleName, key);
097:
098: window = new OleAutomation(scriptFrameWindow);
099: }
100:
101: public void createNative(String file, int line,
102: String jsniSignature, String[] paramNames, String js) {
103: // Execute the function definition within the browser, which will define
104: // a new top-level function.
105: //
106: String newScript = createNativeMethodInjector(jsniSignature,
107: paramNames, js);
108: try {
109: // TODO: somehow insert file/line info into the script
110: Variant result = execute(newScript);
111: if (result != null) {
112: result.dispose();
113: }
114: } catch (RuntimeException e) {
115: throw new RuntimeException(
116: file
117: + "("
118: + line
119: + "): Failed to create JSNI method with signature '"
120: + jsniSignature + "'", e);
121: }
122: }
123:
124: @Override
125: public void dispose() {
126: // Dispose everything else.
127: if (window != null) {
128: window.dispose();
129: }
130: super .dispose();
131: }
132:
133: /**
134: * Invokes a native javascript function.
135: *
136: * @param name the name of the function to invoke
137: * @param jthis the function's 'this' context
138: * @param types the type of each argument
139: * @param args the arguments to be passed
140: * @return the return value as a Variant.
141: */
142: @Override
143: protected JsValue doInvoke(String name, Object jthis ,
144: Class<?>[] types, Object[] args) throws Throwable {
145: Variant[] vArgs = null;
146: try {
147: CompilingClassLoader isolatedClassLoader = getIsolatedClassLoader();
148:
149: // Build the argument list, including 'jthis'.
150: //
151: int len = args.length;
152: vArgs = new Variant[len + 1];
153: Class<?> jthis Type = (jthis == null) ? Object.class : jthis
154: .getClass();
155: vArgs[0] = SwtOleGlue.convertObjectToVariant(
156: isolatedClassLoader, jthis Type, jthis );
157:
158: for (int i = 0; i < len; ++i) {
159: vArgs[i + 1] = SwtOleGlue.convertObjectToVariant(
160: isolatedClassLoader, types[i], args[i]);
161: }
162:
163: Variant result = doInvokeOnWindow(window, name, vArgs);
164: try {
165: return new JsValueIE6(result);
166: } finally {
167: if (result != null) {
168: result.dispose();
169: }
170: }
171: } finally {
172: // We allocated variants for all arguments, so we must dispose them all.
173: //
174: for (int i = 0; i < vArgs.length; ++i) {
175: if (vArgs[i] != null) {
176: vArgs[i].dispose();
177: }
178: }
179: }
180: }
181:
182: @Override
183: protected Object getStaticDispatcher() {
184: return new IDispatchProxy(getIsolatedClassLoader());
185: }
186:
187: @Override
188: protected boolean isExceptionSame(Throwable original, int number,
189: String name, String message) {
190: HResultException hre = new HResultException(original);
191: return CODE(hre.getHResult()) == CODE(number)
192: && hre.getMessage().equals(message);
193: }
194:
195: private Variant execute(String code) {
196: int[] dispIds = window.getIDsOfNames(new String[] {
197: "execScript", "code" });
198: Variant[] vArgs = new Variant[1];
199: vArgs[0] = new Variant(code);
200: int[] namedArgs = new int[1];
201: namedArgs[0] = dispIds[1];
202: Variant result = window.invoke(dispIds[0], vArgs, namedArgs);
203: vArgs[0].dispose();
204: if (result == null) {
205: String lastError = window.getLastError();
206: throw new RuntimeException("Error (" + lastError
207: + ") executing JavaScript:\n" + code);
208: }
209: return result;
210: }
211: }
|