package com4j;

import java.io.File;
import java.lang.reflect.Proxy;

/**
 * The root of the COM4J library.
 *
 * <p>
 * Provides various global services that don't fit into the rest of classes.
 *
 * @author Kohsuke Kawaguchi (kk@kohsuke.org)
 */
public abstract class COM4J {
    private COM4J() {} // no instanciation allowed

    public static<T extends Com4jObject>
    T createInstance( Class<T> primaryInterface, GUID guid ) {
        return createInstance(primaryInterface,guid.toString());
    }

    public static<T extends Com4jObject>
    T createInstance( Class<T> primaryInterface, String clsid ) {

        GUID iid = getIID(primaryInterface);

        // create instance
        return wrap( primaryInterface, Native.createInstance(clsid,iid.v[0],iid.v[1]) );
    }

    /**
     * Gets the interface GUID associated with the given interface.
     */
    public static GUID getIID( Class<? extends Com4jObject> _interface ) {
        IID iid = _interface.getAnnotation(IID.class);
        return new GUID(iid.value());
    }

    /**
     * Loads a type library from a given file and returns its IUnknown.
     */
    public static Com4jObject loadTypeLibrary( File typeLibraryFile ) {
        return wrap(Com4jObject.class, Native.loadTypeLibrary(typeLibraryFile.getAbsolutePath()));
    }

    /**
     * GUID of IUnknown.
     */
    public static final GUID IID_IUnknown = new GUID("{00000000-0000-0000-C000-000000000046}");

    /**
     * GUID of IDispatch.
     */
    public static final GUID IID_IDispatch = new GUID("{00020400-0000-0000-C000-000000000046}");


    static <T>
    T wrap( Class<T> primaryInterface, int ptr ) {
        return primaryInterface.cast(Proxy.newProxyInstance(
            primaryInterface.getClassLoader(),
            new Class<?>[]{primaryInterface},
            new Wrapper(ptr)));
    }

    static int queryInterface( int ptr, GUID iid ) {
        return Native.queryInterface(ptr,iid.v[0],iid.v[1]);
    }

    static Wrapper unwrap( Com4jObject obj ) {
        return (Wrapper)Proxy.getInvocationHandler(obj);
    }

    static {
        System.loadLibrary("com4j");
    }
}

@@ -61,16 +61,37 @@
 t.Proxy;
+%0Aimport java.net.URL;
 %0A%0A/**%0A *
@@ -2117,33 +2117,995 @@
     
-System.loadLibrary(%22com4j
+loadNativeLibrary();%0A    %7D%0A%0A    private static void loadNativeLibrary() %7B%0A        try %7B%0A            // load the native part of the code.%0A            // first try java.library.path%0A            System.loadLibrary(%22com4j%22);%0A            return;%0A        %7D catch( Throwable t ) %7B%0A            ;%0A        %7D%0A%0A        // try loading com4j.dll in the same directory as com4j.jar%0A        URL res = COM4J.class.getClassLoader().getResource(%22com4j/COM4J.class%22);%0A        String url = res.toExternalForm();%0A        if(url.startsWith(%22jar://%22)) %7B%0A            int idx = url.lastIndexOf('!');%0A            String filePortion = url.substring(6,idx);%0A            if(filePortion.startsWith(%22file://%22)) %7B%0A                File jarFile = new File(filePortion.substring(7));%0A                File dllFile = new File(jarFile.getParentFile(),%22com4j.dll%22);%0A                System.load(dllFile.getPath());%0A                return;%0A            %7D%0A        %7D%0A%0A        throw new UnsatisfiedLinkError(%22Unable to load com4j.dll
 %22);%0A

improved the logic of loading the native DLL.