Могу ли я использовать COM из Java через JNA? - PullRequest
4 голосов
/ 11 апреля 2011

Возможно, я сумасшедший, но я начинаю получать удовольствие от этой идеи, даже если это просто для обучения: я пытаюсь использовать COM из Java, вызывая функции Ole32.dll через ЮНА . Согласно спецификации COM указатель COM-интерфейса - это просто указатель на указатель, который указывает на массив указателей на функции. Я думал, так как JNA позволяет вызывать указатели на функции, я должен иметь возможность вызывать методы интерфейса COM, если я могу получить VMT (массив указателей на функции).

Вот мой IUnknown интерфейс:

@IId("00000000-0000-0000-C000-000000000046")
public interface IUnknown {
    int QueryInterface(Guid riid, PointerByReference ppvObject);
    int AddRef();
    int Release();
}

А вот немного кода для создания интерфейса IUnkown с CLSID:

public static IUnknown createInstance(Guid clsId) {
    IId iidA = IUnknown.class.getAnnotation(IId.class);
    if (iidA == null)
        throw new IllegalArgumentException("Interface needs to be annotated with an IId");
    Guid iId = new Guid(iidA.value());
    Ole32 ole32 = WindowsJna.OLE32.get();
    PointerByReference p = new PointerByReference();
    int res = ole32.CoCreateInstance(clsId, null, Ole32.CLSCTX_INPROC, iId, p);
    if (res != Ole32.S_OK)
        throw new WinApiException(res);
    final Pointer interfacePointer = p.getValue();
    final Pointer vTablePointer = interfacePointer.getPointer(0);
    final Pointer[] vTable = new Pointer[3];
    vTablePointer.read(0, vTable, 0, 3);
    return new IUnknown() {
        public int QueryInterface(Guid riid, PointerByReference ppvObject) {
            Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer, riid, ppvObject });
        }
        public int AddRef() {
            Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer });
        }
        public int Release() {
            Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer });
        }
    };
}

Я все еще немного новичок в JNA, поэтому я хотел бы знать, имеет ли код смысл? Не могу заставить его работать, потому что я застрял в какой-то другой глупой ошибке, прежде чем этот код будет вызван.

Будет ли этот способ работы с COM слишком медленным или он действительно станет возможным способом сделать это из Java, особенно если добавить один динамический прокси Java вместе с IDispatch COM?

Я знаю о JACOB и других COM-библиотеках из Java, и я их использовал. Просто пробую что-то новое для, как я уже говорил, опыта обучения.

1 Ответ

2 голосов
/ 01 июля 2011

Учитывая, что нативный COM все построен на C (не на C ++), это будет технически работать, если нативный код использует соглашения о вызовах C или stdcall. JNA предоставляет вам все инструменты, которые вам нужны для работы с собственной памятью и настройки стека для вызова функции.

В конечном счете вы захотите получить что-то, что может проанализировать библиотеку типов и сгенерировать интерфейсы, которые вам действительно нужны, что, как я полагаю, и делают JACOB и com4j.

EDIT

JNA теперь обеспечивает достаточно полную поддержку COM, включая чтение библиотек типов и обратных вызовов событий.

...