1 package com4j; 2 3 import java.lang.reflect.InvocationHandler ; 4 import java.lang.reflect.InvocationTargetException ; 5 import java.lang.reflect.Method ; 6 import java.lang.reflect.Proxy ; 7 import java.util.Collections ; 8 import java.util.Map ; 9 import java.util.WeakHashMap ; 10 11 16 final class Wrapper implements InvocationHandler , Com4jObject { 17 18 21 private int ptr; 22 23 26 private int hashCode=0; 27 28 31 Wrapper next; 32 33 36 private final ComThread thread; 37 38 43 private Map <Method ,MethodInfo> cache = Collections.synchronizedMap( 44 new WeakHashMap <Method ,MethodInfo>()); 45 46 private Wrapper(int ptr) { 47 if(ptr==0) throw new IllegalArgumentException (); 48 assert ComThread.isComThread(); 49 50 this.ptr = ptr; 51 thread = ComThread.get(); 52 } 53 54 59 static <T extends Com4jObject> 60 T create( Class <T> primaryInterface, int ptr ) { 61 Wrapper w = new Wrapper(ptr); 62 T r = primaryInterface.cast(Proxy.newProxyInstance( 63 primaryInterface.getClassLoader(), 64 new Class <?>[]{primaryInterface}, 65 w)); 66 w.thread.addLiveObject(r); 67 return r; 68 } 69 70 75 static Com4jObject create( int ptr ) { 76 Wrapper w = new Wrapper(ptr); 77 w.thread.addLiveObject(w); 78 return w; 79 } 80 81 82 int getPtr() { 83 return ptr; 84 } 85 86 protected void finalize() throws Throwable { 87 if(ptr!=0) 88 thread.addToFreeList(this); 89 } 90 91 private static final Object [] EMPTY_ARRAY = new Object [0]; 92 93 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable { 94 if(ptr==0) 95 throw new IllegalStateException ("COM object is already disposed"); 96 if(args==null) args = EMPTY_ARRAY; 98 99 Class <?> declClazz = method.getDeclaringClass(); 100 101 if( declClazz==Com4jObject.class || declClazz==Object .class ) { 102 try { 104 return method.invoke(this,args); 105 } catch( IllegalAccessException e ) { 106 throw new IllegalAccessError (e.getMessage()); 107 } catch( InvocationTargetException e ) { 108 throw e.getTargetException(); 109 } 110 } 111 112 if(invCache==null) 113 invCache = new InvocationThunk(); 114 return invCache.invoke(getMethodInfo(method),args); 115 } 116 117 private MethodInfo getMethodInfo(Method method) { 118 MethodInfo r = cache.get(method); 119 if(r!=null) return r; 120 r = new MethodInfo(method); 121 cache.put(method,r); 122 return r; 123 } 124 125 public void dispose() { 126 if(ptr!=0) { 127 thread.execute(new Task<Object >() { 128 public Object call() { 129 dispose0(); 130 return null; 131 } 132 }); 133 } 134 } 135 136 139 boolean dispose0() { 140 boolean r = ptr!=0; 141 Native.release(ptr); 142 ptr=0; 143 return r; 144 } 145 146 public <T extends Com4jObject> boolean is( Class <T> comInterface ) { 147 try { 148 GUID iid = COM4J.getIID(comInterface); 149 return new QITestTask(iid).execute(thread)!=0; 150 } catch( ComException e ) { 151 return false; 152 } 153 } 154 155 public <T extends Com4jObject> T queryInterface( final Class <T> comInterface ) { 156 return new Task<T>() { 157 public T call() { 158 GUID iid = COM4J.getIID(comInterface); 159 int nptr = Native.queryInterface(ptr,iid.v[0],iid.v[1]); 160 if(nptr==0) 161 return null; return create( comInterface, nptr ); 163 } 164 }.execute(thread); 165 } 166 167 public String toString() { 168 return "ComObject:"+Integer.toHexString(ptr); 169 } 170 171 public final int hashCode() { 172 if(hashCode==0) { 173 if(ptr!=0) { 174 hashCode = new QITestTask(COM4J.IID_IUnknown).execute(thread); 175 } else { 176 hashCode = 0; 177 } 178 } 179 return hashCode; 180 } 181 182 public final boolean equals( Object rhs ) { 183 if(!(rhs instanceof Com4jObject)) return false; 184 return hashCode()==rhs.hashCode(); 185 } 186 187 191 private class InvocationThunk extends Task<Object > { 192 private MethodInfo method; 193 private Object [] args; 194 195 199 public synchronized Object invoke( MethodInfo method, Object [] args ) { 200 invCache = null; 201 this.method = method; 202 this.args = args; 203 204 try { 205 return execute(thread); 206 } finally { 207 invCache = this; 208 } 209 } 210 211 214 public synchronized Object call() { 215 Object r = method.invoke(ptr,args); 216 method = null; 218 args = null; 219 return r; 220 } 221 } 222 223 226 InvocationThunk invCache; 227 228 229 230 234 private final class QITestTask extends Task<Integer > { 235 private final GUID iid; 236 237 public QITestTask(GUID iid) { 238 this.iid = iid; 239 } 240 241 public Integer call() { 242 int nptr = Native.queryInterface(ptr,iid.v[0],iid.v[1]); 243 if(nptr!=0) 244 Native.release(nptr); 245 return nptr; 246 } 247 } 248 } 249 | Popular Tags |