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}