001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj.cpp.com; 032 033import java.lang.reflect.Type; 034import java.lang.reflect.Method; 035 036import org.bridj.ValuedEnum; 037import org.bridj.FlagSet; 038import org.bridj.BridJ; 039import org.bridj.Pointer; 040import org.bridj.CRuntime; 041import org.bridj.NativeObject; 042import org.bridj.Platform; 043import org.bridj.Pointer.StringType; 044import org.bridj.ann.Convention; 045import org.bridj.ann.Library; 046import org.bridj.ann.Ptr; 047import org.bridj.ann.Runtime; 048import org.bridj.cpp.CPPRuntime; 049import static org.bridj.cpp.com.VARENUM.*; 050import org.bridj.cpp.com.VARIANT.__VARIANT_NAME_1_union; 051import org.bridj.cpp.com.VARIANT.__VARIANT_NAME_1_union.__tagVARIANT; 052import org.bridj.cpp.com.VARIANT.__VARIANT_NAME_1_union.__tagVARIANT.__VARIANT_NAME_3_union; 053import org.bridj.util.Utils; 054import static org.bridj.Pointer.*; 055import org.bridj.PointerIO; 056import org.bridj.StructObject; 057import org.bridj.cpp.CPPObject; 058import static org.bridj.cpp.com.OLELibrary.*; 059import static org.bridj.cpp.com.OLEAutomationLibrary.*; 060 061/* 062 * Adding Icons, Previews and Shortcut Menus : 063 * http://msdn.microsoft.com/en-us/library/bb266530(VS.85).aspx 064 * 065 * TODO CoCreateInstanceEx 066 * TODO CoRegisterClassObject 067 * TODO CoRevokeClassObject 068 * TODO CoCreateGuid 069 * 070 * IDL syntax : 071 * http://caml.inria.fr/pub/old_caml_site/camlidl/htmlman/main002.html 072 * 073 * Registering a Running EXE Server : 074 * http://msdn.microsoft.com/en-us/library/ms680076(VS.85).aspx 075 */ 076/** 077 * Microsoft COM runtime, along with useful constants and methods.<br> 078 * All COM classes must extends {@link org.bridj.cpp.com.IUnknown} and hence 079 * inherit from it the correct {@link org.bridj.ann.Runtime} annotation that 080 * references {@link org.bridj.cpp.com.COMRuntime}. 081 */ 082@Library("Ole32") 083@Runtime(CRuntime.class) 084@Convention(Convention.Style.StdCall) 085public class COMRuntime extends CPPRuntime { 086 087 static { 088 if (Platform.isWindows()) { 089 BridJ.register(); 090 } 091 } 092 public static final int CLSCTX_INPROC_SERVER = 0x1, 093 CLSCTX_INPROC_HANDLER = 0x2, 094 CLSCTX_LOCAL_SERVER = 0x4, 095 CLSCTX_INPROC_SERVER16 = 0x8, 096 CLSCTX_REMOTE_SERVER = 0x10, 097 CLSCTX_INPROC_HANDLER16 = 0x20, 098 CLSCTX_RESERVED1 = 0x40, 099 CLSCTX_RESERVED2 = 0x80, 100 CLSCTX_RESERVED3 = 0x100, 101 CLSCTX_RESERVED4 = 0x200, 102 CLSCTX_NO_CODE_DOWNLOAD = 0x400, 103 CLSCTX_RESERVED5 = 0x800, 104 CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, 105 CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, 106 CLSCTX_NO_FAILURE_LOG = 0x4000, 107 CLSCTX_DISABLE_AAA = 0x8000, 108 CLSCTX_ENABLE_AAA = 0x10000, 109 CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, 110 CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000, 111 CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000, 112 CLSCTX_ENABLE_CLOAKING = 0x100000, 113 CLSCTX_PS_DLL = 0x80000000; 114 public static final int CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, 115 CLSCTX_ALL = (CLSCTX_INPROC_SERVER 116 | CLSCTX_INPROC_HANDLER 117 | CLSCTX_LOCAL_SERVER 118 | CLSCTX_REMOTE_SERVER), 119 CLSCTX_SERVER = (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER); 120 public static final int S_OK = 0, 121 S_FALSE = 1, 122 REGDB_E_CLASSNOTREG = 0x80040154, 123 CLASS_E_NOAGGREGATION = 0x80040110, 124 CO_E_NOTINITIALIZED = 0x800401F0; 125 public static final int E_UNEXPECTED = 0x8000FFFF; 126 public static final int E_NOTIMPL = 0x80004001; 127 public static final int E_OUTOFMEMORY = 0x8007000E; 128 public static final int E_INVALIDARG = 0x80070057; 129 public static final int E_NOINTERFACE = 0x80004002; 130 public static final int E_POINTER = 0x80004003; 131 public static final int E_HANDLE = 0x80070006; 132 public static final int E_ABORT = 0x80004004; 133 public static final int E_FAIL = 0x80004005; 134 public static final int E_ACCESSDENIED = 0x80070005; 135 public static final int DISP_E_BADVARTYPE = -2147352568; 136 public static final int DISP_E_NOTACOLLECTION = -2147352559; 137 public static final int DISP_E_MEMBERNOTFOUND = -2147352573; 138 public static final int DISP_E_ARRAYISLOCKED = -2147352563; 139 public static final int DISP_E_EXCEPTION = -2147352567; 140 public static final int DISP_E_TYPEMISMATCH = -2147352571; 141 public static final int DISP_E_BADINDEX = -2147352565; 142 public static final int DISP_E_BADCALLEE = -2147352560; 143 public static final int DISP_E_OVERFLOW = -2147352566; 144 public static final int DISP_E_UNKNOWNINTERFACE = -2147352575; 145 public static final int DISP_E_DIVBYZERO = -2147352558; 146 public static final int DISP_E_UNKNOWNLCID = -2147352564; 147 public static final int DISP_E_PARAMNOTOPTIONAL = -2147352561; 148 public static final int DISP_E_PARAMNOTFOUND = -2147352572; 149 public static final int DISP_E_BADPARAMCOUNT = -2147352562; 150 public static final int DISP_E_BUFFERTOOSMALL = -2147352557; 151 public static final int DISP_E_UNKNOWNNAME = -2147352570; 152 public static final int DISP_E_NONAMEDARGS = -2147352569; 153 154 public static interface COINIT { 155 156 public final int COINIT_APARTMENTTHREADED = 0x2, // Apartment model 157 COINIT_MULTITHREADED = 0x0, // OLE calls objects on any thread. 158 COINIT_DISABLE_OLE1DDE = 0x4, // Don't use DDE for Ole1 support. 159 COINIT_SPEED_OVER_MEMORY = 0x8; 160 } 161 162 @Deprecated 163 public static native int CoCreateInstance( 164 Pointer<Byte> rclsid, 165 Pointer<IUnknown> pUnkOuter, 166 int dwClsContext, 167 Pointer<Byte> riid, 168 Pointer<Pointer<?>> ppv); 169 170 static native int CoInitializeEx(@Ptr long pvReserved, int dwCoInit); 171 172 static native int CoInitialize(@Ptr long pvReserved); 173 174 static native void CoUninitialize(); 175 176 static void error(int err) { 177 switch (err) { 178 case S_OK: 179 return; 180 case E_UNEXPECTED: 181 throw new RuntimeException("Unexpected error"); 182 case E_OUTOFMEMORY: 183 throw new RuntimeException("Memory could not be allocated."); 184 case CO_E_NOTINITIALIZED: 185 throw new RuntimeException("CoInitialized wasn't called !!"); 186 case E_NOINTERFACE: 187 throw new RuntimeException("Interface does not inherit from class"); 188 case E_POINTER: 189 throw new RuntimeException("Allocated pointer pointer is null !!"); 190 case DISP_E_ARRAYISLOCKED: 191 throw new RuntimeException("The variant contains an array that is locked."); 192 case DISP_E_BADVARTYPE: 193 throw new RuntimeException("The variant type is not valid."); 194 case E_INVALIDARG: 195 throw new RuntimeException("One of the arguments is invalid."); 196 default: 197 throw new RuntimeException("Unexpected COM error code : " + err); 198 } 199 } 200 201 /** 202 * Get the IID declared for a class using the {@link IID} annotation. 203 * 204 * @throws RuntimeException if the class isn't annotated with IID 205 */ 206 public static <I extends IUnknown> Pointer<Byte> getIID(Class<I> type) { 207 IID id = type.getAnnotation(IID.class); 208 if (id == null) { 209 throw new RuntimeException("No " + IID.class.getName() + " annotation set on type " + type.getName() + " !"); 210 } 211 212 return (Pointer) parseGUID(id.value()); 213 } 214 215 /** 216 * Get the CLSID declared for a class using the {@link CLSID} annotation. 217 * 218 * @throws RuntimeException if the class isn't annotated with CLSID 219 */ 220 public static <I extends IUnknown> Pointer<Byte> getCLSID(Class<I> type) { 221 CLSID id = type.getAnnotation(CLSID.class); 222 if (id == null) { 223 throw new RuntimeException("No " + CLSID.class.getName() + " annotation set on type " + type.getName() + " !"); 224 } 225 226 return (Pointer) parseGUID(id.value()); 227 } 228 static ThreadLocal<Object> comInitializer = new ThreadLocal<Object>() { 229 @Override 230 protected Object initialValue() { 231 error(CoInitializeEx(0, COINIT.COINIT_MULTITHREADED)); 232 return new Object() { 233 @Override 234 protected void finalize() throws Throwable { 235 CoUninitialize(); 236 } 237 }; 238 } 239 }; 240 241 @Override 242 protected boolean isSymbolOptional(Method method) { 243 return true; 244 } 245 246 /** 247 * Initialize COM the current thread (uninitialization is done automatically 248 * upon thread death).<br> 249 * Calls CoInitialize with COINIT_MULTITHREADED max once per thread.<br> 250 * This is called automatically in {@link COMRuntime#newInstance(Class)}, so 251 * you'll typically never need to call this method by hand. 252 */ 253 public static void initialize() { 254 comInitializer.get(); 255 } 256 257 public static <I extends IUnknown> I newInstance(Class<I> type) throws ClassNotFoundException { 258 return newInstance(type, type); 259 } 260 261 public static <T extends IUnknown, I extends IUnknown> I newInstance(Class<T> instanceClass, Class<I> instanceInterface) throws ClassNotFoundException { 262 initialize(); 263 264 Pointer<Pointer<?>> p = Pointer.allocatePointer(); 265 Pointer<Byte> clsid = getCLSID(instanceClass), uuid = getIID(instanceInterface); 266 try { 267 int ret = CoCreateInstance(clsid, null, CLSCTX_ALL, uuid, p); 268 if (ret == REGDB_E_CLASSNOTREG) { 269 throw new ClassNotFoundException("COM class is not registered : " + instanceClass.getSimpleName() + " (clsid = " + clsid.getCString() + ")"); 270 } 271 error(ret); 272 273 Pointer<?> inst = p.getPointer(); 274 if (inst == null) { 275 throw new RuntimeException("Serious low-level issue : CoCreateInstance executed fine but we only retrieved a null pointer !"); 276 } 277 278 I instance = inst.getNativeObject(instanceInterface); 279 return instance; 280 } finally { 281 Pointer.release(p, clsid, uuid); 282 } 283 } 284 285 public class VARIANTTypeInfo extends CTypeInfo<VARIANT> { 286 287 public VARIANTTypeInfo() { 288 super(VARIANT.class); 289 } 290 Pointer.Releaser VARIANTReleaser = new Pointer.Releaser() { 291 @Override 292 public void release(Pointer<?> p) { 293 error(VariantClear((Pointer<VARIANT>) p)); 294 } 295 }; 296 297 @Override 298 public void initialize(VARIANT instance, int constructorId, Object... args) { 299 assert constructorId < 0 && args.length == 0; 300 Pointer<VARIANT> peer = allocateCOMMemory(pointerIO).withReleaser(VARIANTReleaser); 301 setNativeObjectPeer(instance, peer); 302 VariantInit(peer); 303 } 304 305 @Override 306 public VARIANT clone(VARIANT instance) throws CloneNotSupportedException { 307 return COMRuntime.clone(instance); 308 } 309 } 310 311 @Override 312 public <T extends NativeObject> TypeInfo<T> getTypeInfo(final Type type) { 313 if (type == VARIANT.class) { 314 return (TypeInfo<T>) new VARIANTTypeInfo(); 315 } else if (type instanceof Class) { 316 if (CPPObject.class.isAssignableFrom((Class) type)) { 317 return (TypeInfo<T>) new CPPTypeInfo<CPPObject>(type) { 318 @Override 319 protected <V> Pointer<V> allocateStructMemory(PointerIO<V> pointerIO) { 320 return allocateCOMMemory(pointerIO); 321 } 322 }; 323 } 324 if (StructObject.class.isAssignableFrom((Class) type)) { 325 return new CTypeInfo<T>(type) { 326 @Override 327 protected <V> Pointer<V> allocateStructMemory(PointerIO<V> pointerIO) { 328 return allocateCOMMemory(pointerIO); 329 } 330 }; 331 } 332 } 333 return super.getTypeInfo(type); 334 } 335 private static final String model = "00000000-0000-0000-0000-000000000000"; 336 337 // Need to parse as (int, short, short, char[8]) 338 public static Pointer<?> parseGUID(String descriptor) { 339 Pointer<?> out = Pointer.allocateBytes(16 + 4); 340 descriptor = descriptor.replaceAll("-", ""); 341 if (descriptor.length() != 32) { 342 throw new RuntimeException("Expected something like :\n" + model + "\nBut got instead :\n" + descriptor); 343 } 344 345 out.setIntAtOffset(0, (int) Long.parseLong(descriptor.substring(0, 8), 16)); 346 out.setShortAtOffset(4, (short) Long.parseLong(descriptor.substring(8, 12), 16)); 347 out.setShortAtOffset(6, (short) Long.parseLong(descriptor.substring(12, 16), 16)); 348 for (int i = 0; i < 8; i++) { 349 out.setByteAtOffset(8 + i, (byte) Long.parseLong(descriptor.substring(16 + i * 2, 16 + i * 2 + 2), 16)); 350 } 351 352 return out; 353 } 354 355 static ValuedEnum<VARENUM> getType(VARIANT v) { 356 __VARIANT_NAME_1_union v1 = v.__VARIANT_NAME_1(); 357 __tagVARIANT v2 = v1.__VARIANT_NAME_2(); 358 short vt = v2.vt(); 359 return FlagSet.fromValue(vt, VARENUM.class); 360 } 361 362 static VARIANT setType(VARIANT v, ValuedEnum<VARENUM> vt) { 363 __VARIANT_NAME_1_union v1 = v.__VARIANT_NAME_1(); 364 __tagVARIANT v2 = v1.__VARIANT_NAME_2(); 365 v2.vt((short) vt.value()); 366 return v; 367 } 368 369 static VARIANT.__VARIANT_NAME_1_union.__tagVARIANT.__VARIANT_NAME_3_union getValues(VARIANT v) { 370 __VARIANT_NAME_1_union v1 = v.__VARIANT_NAME_1(); 371 __tagVARIANT v2 = v1.__VARIANT_NAME_2(); 372 __VARIANT_NAME_3_union v3 = v2.__VARIANT_NAME_3(); 373 return v3; 374 } 375 376 /** 377 * Convert the VARIANT value to an equivalent Java value. 378 * 379 * @throws UnsupportedOperationException if the VARIANT type is not handled 380 * yet 381 * @throws RuntimeException if the VARIANT is invalid 382 */ 383 public static Object getValue(VARIANT v) { 384 385 FlagSet<VARENUM> vt = FlagSet.fromValue(getType(v)); 386 __VARIANT_NAME_3_union values = getValues(v); 387 if (vt.has(VT_BYREF)) { 388 switch (vt.without(VT_BYREF).toEnum()) { 389 case VT_DISPATCH: 390 return values.ppdispVal(); 391 case VT_UNKNOWN: 392 return values.ppunkVal(); 393 case VT_VARIANT: 394 return values.pvarVal(); 395 case VT_I1: 396 case VT_UI1: 397 return values.pbVal(); 398 /* UINT16 */ 399 case VT_I2: 400 case VT_UI2: 401 return values.piVal(); 402 /* UINT32 */ 403 case VT_I4: 404 case VT_UI4: 405 return values.plVal(); 406 case VT_R4: 407 return values.pfltVal(); 408 case VT_R8: 409 return values.pdblVal(); 410 /* UINT64 */ 411 case VT_I8: 412 case VT_UI8: 413 return values.pllVal(); 414 /* BOOL */ 415 case VT_BOOL: 416 return values.pbVal().as(Boolean.class); 417 418 case VT_BSTR: 419 return values.pbstrVal(); 420 case VT_LPSTR: 421 return values.byref().getCString(); 422 case VT_LPWSTR: 423 return values.byref().getWideCString(); 424 case VT_PTR: 425 default: 426 return values.byref(); 427 } 428 } 429 switch (vt.toEnum()) { 430 /* UINT8 */ 431 case VT_I1: 432 case VT_UI1: 433 return values.bVal(); 434 /* UINT16 */ 435 case VT_I2: 436 case VT_UI2: 437 return values.uiVal(); 438 /* UINT32 */ 439 case VT_I4: 440 case VT_UI4: 441 return values.ulVal(); 442 /* UINT64 */ 443 case VT_I8: 444 case VT_UI8: 445 return values.ullVal(); 446 /* BOOL */ 447 case VT_BOOL: 448 return values.bVal() != 0; 449 case VT_R4: 450 return values.fltVal(); 451 case VT_R8: 452 return values.dblVal(); 453 case VT_BSTR: 454 return values.bstrVal().getString(StringType.BSTR); 455 case VT_EMPTY: 456 return null; 457 default: 458 throw new UnsupportedOperationException("Conversion not implemented yet from VARIANT type " + vt + " to Java !"); 459 } 460 } 461 462 static void change(VARIANT v, ValuedEnum<VARENUM> vt) { 463 Pointer<VARIANT> pv = getPointer(v); 464 int res = VariantChangeType(pv, pv, (short) 0, (short) vt.value()); 465 assert res == S_OK; 466 } 467 468 public static VARIANT setValue(VARIANT v, Object value) { 469 //ValuedEnum<VARENUM> vt; 470 __VARIANT_NAME_3_union values = getValues(v); 471 if (value == null) { 472 change(v, VT_EMPTY); 473 //values.byref(null); 474 } else if (value instanceof Integer) { 475 change(v, VT_I4); 476 values.lVal((Integer) value); 477 } else if (value instanceof Long) { 478 change(v, VT_I8); 479 values.llval((Long) value); 480 } else if (value instanceof Short) { 481 change(v, VT_I2); 482 values.iVal((Short) value); 483 } else if (value instanceof Byte) { 484 change(v, VT_I1); 485 values.bVal((Byte) value); 486 } else if (value instanceof Float) { 487 change(v, VT_R4); 488 values.fltVal((Float) value); 489 } else if (value instanceof Double) { 490 change(v, VT_I8); 491 values.dblVal((Double) value); 492 } else if (value instanceof Character) { 493 change(v, VT_I2); 494 values.iVal((short) ((Character) value).charValue()); 495 } else if (value instanceof String) { 496 change(v, VT_BSTR); 497 /*String str = (String)value; 498 int len = str.length(); 499 int capacity = SysStringLen(values.bstrVal()); 500 /Pointer<Character> chars = 501 if (len > capacity) 502 SysReAllocStringLen values.bstrVal() 503 SysReAllocString(values.bstrVal().getReference(), 504 */ 505 values.bstrVal().setString((String) value, StringType.BSTR); 506 } else if (value instanceof Pointer) { 507 Pointer ptr = (Pointer) value; 508 Type targetType = ptr.getTargetType(); 509 Class targetClass = Utils.getClass(targetType); 510 if (targetClass == null) { 511 change(v, VT_PTR); 512 } else { 513 VARENUM ve; 514 if (targetClass == Integer.class || targetClass == int.class) { 515 ve = VT_I4; 516 } else if (targetClass == Long.class || targetClass == long.class) { 517 ve = VT_I8; 518 } else if (targetClass == Short.class || targetClass == short.class) { 519 ve = VT_I2; 520 } else if (targetClass == Byte.class || targetClass == byte.class) { 521 ve = VT_I1; 522 } else if (targetClass == Character.class || targetClass == char.class) { 523 ve = VT_LPWSTR; // TODO 524 } else if (targetClass == Boolean.class || targetClass == boolean.class) { 525 ve = VT_BOOL; 526 } else if (targetClass == Float.class || targetClass == float.class) { 527 ve = VT_R4; 528 } else if (targetClass == Double.class || targetClass == double.class) { 529 ve = VT_R8; 530 } else if (Pointer.class.isAssignableFrom(targetClass)) { 531 ve = VT_PTR; 532 } else { 533 ve = null; // TODO 534 } 535 change(v, FlagSet.fromValues(VT_BYREF, ve)); 536 } 537 } else { 538 throw new UnsupportedOperationException("Unable to convert an object of type " + value.getClass().getName() + " to a COM VARIANT object !"); 539 } 540 541 //setType(v, vt); 542 return v; 543 } 544 545 @Override 546 protected boolean warnAboutMissingVTables() { 547 return false; 548 } 549 550 public static String toString(VARIANT v) { 551 StringBuilder b = new StringBuilder("Variant(value = "); 552 try { 553 b.append(getValue(v)); 554 } catch (Throwable th) { 555 b.append("?"); 556 } 557 b.append(", type = ").append(getType(v)).append(")"); 558 559 return b.toString(); 560 } 561 562 public static VARIANT clone(VARIANT instance) { 563 if (instance == null) { 564 return null; 565 } 566 VARIANT clone = new VARIANT(); 567 error(VariantCopy(getPointer(clone), getPointer(instance))); 568 return clone; 569 } 570 571 protected <V> Pointer<V> allocateCOMMemory(PointerIO<V> pointerIO) { 572 return allocateCOMMemory(pointerIO.getTargetSize(), pointerIO); 573 } 574 575 public static <V> Pointer<V> allocateCOMMemory(long byteCount, PointerIO<V> pointerIO) { 576 if (byteCount <= 0) { 577 return null; 578 } 579 long peer = CoTaskMemAlloc$raw(byteCount); 580 if (peer == 0) { 581 throw new OutOfMemoryError("Failed to allocate " + byteCount + " bytes with CoTaskMemAlloc"); 582 } 583 Pointer p = Pointer.pointerToAddress(peer, byteCount, pointerIO, new Pointer.Releaser() { 584 public void release(Pointer<?> p) { 585 CoTaskMemFree(p); 586 } 587 }); 588 if (p != null) { 589 p.clearValidBytes(); 590 } 591 return p; 592 } 593}